Running object table are not using 0 as a valid index anymore.
[wine.git] / graphics / x11drv / text.c
blob2445f79f9955876333ce19759adee779bc12a947
1 /*
2 * X11 graphics driver text functions
4 * Copyright 1993,1994 Alexandre Julliard
5 */
7 #include "config.h"
9 #ifndef X_DISPLAY_MISSING
11 #include <X11/Xatom.h>
12 #include "ts_xlib.h"
14 #include <stdlib.h>
15 #include "windef.h"
16 #include <math.h>
17 #include "dc.h"
18 #include "gdi.h"
19 #include "heap.h"
20 #include "x11font.h"
21 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(text)
25 #define SWAP_INT(a,b) { int t = a; a = b; b = t; }
26 #define IROUND(x) (int)((x)>0? (x)+0.5 : (x) - 0.5)
28 /***********************************************************************
29 * X11DRV_ExtTextOut
31 BOOL
32 X11DRV_ExtTextOut( DC *dc, INT x, INT y, UINT flags,
33 const RECT *lprect, LPCWSTR wstr, UINT count,
34 const INT *lpDx )
36 int i;
37 fontObject* pfo;
38 INT width, ascent, descent, xwidth, ywidth;
39 XFontStruct* font;
40 RECT rect;
41 char dfBreakChar, lfUnderline, lfStrikeOut;
42 BOOL rotated = FALSE;
43 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
44 XChar2b *str2b;
46 if (!X11DRV_SetupGCForText( dc )) return TRUE;
48 pfo = XFONT_GetFontObject( physDev->font );
49 font = pfo->fs;
51 if (pfo->lf.lfEscapement && pfo->lpX11Trans)
52 rotated = TRUE;
53 dfBreakChar = (char)pfo->fi->df.dfBreakChar;
54 lfUnderline = (pfo->fo_flags & FO_SYNTH_UNDERLINE) ? 1 : 0;
55 lfStrikeOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT) ? 1 : 0;
57 TRACE("hdc=%04x df=%04x %d,%d %s, %d flags=%d lpDx=%p\n",
58 dc->hSelf, (UINT16)(physDev->font), x, y,
59 debugstr_wn (wstr, count), count, flags, lpDx);
61 /* some strings sent here end in a newline for whatever reason. I have no
62 clue what the right treatment should be in general, but ignoring
63 terminating newlines seems ok. MW, April 1998. */
64 if (count > 0 && wstr[count - 1] == '\n') count--;
66 if (lprect != NULL) TRACE("\trect=(%d,%d - %d,%d)\n",
67 lprect->left, lprect->top,
68 lprect->right, lprect->bottom );
69 /* Setup coordinates */
71 if (dc->w.textAlign & TA_UPDATECP)
73 x = dc->w.CursPosX;
74 y = dc->w.CursPosY;
77 if (flags & (ETO_OPAQUE | ETO_CLIPPED)) /* there's a rectangle */
79 if (!lprect) /* not always */
81 SIZE sz;
82 if (flags & ETO_CLIPPED) /* Can't clip with no rectangle */
83 return FALSE;
84 if (!X11DRV_GetTextExtentPoint( dc, wstr, count, &sz ))
85 return FALSE;
86 rect.left = XLPTODP( dc, x );
87 rect.right = XLPTODP( dc, x+sz.cx );
88 rect.top = YLPTODP( dc, y );
89 rect.bottom = YLPTODP( dc, y+sz.cy );
91 else
93 rect.left = XLPTODP( dc, lprect->left );
94 rect.right = XLPTODP( dc, lprect->right );
95 rect.top = YLPTODP( dc, lprect->top );
96 rect.bottom = YLPTODP( dc, lprect->bottom );
98 if (rect.right < rect.left) SWAP_INT( rect.left, rect.right );
99 if (rect.bottom < rect.top) SWAP_INT( rect.top, rect.bottom );
102 x = XLPTODP( dc, x );
103 y = YLPTODP( dc, y );
105 TRACE("\treal coord: x=%i, y=%i, rect=(%d,%d - %d,%d)\n",
106 x, y, rect.left, rect.top, rect.right, rect.bottom);
108 /* Draw the rectangle */
110 if (flags & ETO_OPAQUE)
112 TSXSetForeground( display, physDev->gc, physDev->backgroundPixel );
113 TSXFillRectangle( display, physDev->drawable, physDev->gc,
114 dc->w.DCOrgX + rect.left, dc->w.DCOrgY + rect.top,
115 rect.right-rect.left, rect.bottom-rect.top );
117 if (!count) return TRUE; /* Nothing more to do */
119 /* Compute text starting position */
121 if (lpDx) /* have explicit character cell x offsets in logical coordinates */
123 int extra = dc->wndExtX / 2;
124 for (i = width = 0; i < count; i++) width += lpDx[i];
125 width = (width * dc->vportExtX + extra ) / dc->wndExtX;
127 else
129 SIZE sz;
130 if (!X11DRV_GetTextExtentPoint( dc, wstr, count, &sz ))
131 return FALSE;
132 width = XLSTODS(dc, sz.cx);
134 ascent = pfo->lpX11Trans ? pfo->lpX11Trans->ascent : font->ascent;
135 descent = pfo->lpX11Trans ? pfo->lpX11Trans->descent : font->descent;
136 xwidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->a /
137 pfo->lpX11Trans->pixelsize : width;
138 ywidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->b /
139 pfo->lpX11Trans->pixelsize : 0;
141 switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
143 case TA_LEFT:
144 if (dc->w.textAlign & TA_UPDATECP) {
145 dc->w.CursPosX = XDPTOLP( dc, x + xwidth );
146 dc->w.CursPosY = YDPTOLP( dc, y - ywidth );
148 break;
149 case TA_RIGHT:
150 x -= xwidth;
151 y += ywidth;
152 if (dc->w.textAlign & TA_UPDATECP) {
153 dc->w.CursPosX = XDPTOLP( dc, x );
154 dc->w.CursPosY = YDPTOLP( dc, y );
156 break;
157 case TA_CENTER:
158 x -= xwidth / 2;
159 y += ywidth / 2;
160 break;
163 switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
165 case TA_TOP:
166 x -= pfo->lpX11Trans ? ascent * pfo->lpX11Trans->c /
167 pfo->lpX11Trans->pixelsize : 0;
168 y += pfo->lpX11Trans ? ascent * pfo->lpX11Trans->d /
169 pfo->lpX11Trans->pixelsize : ascent;
170 break;
171 case TA_BOTTOM:
172 x += pfo->lpX11Trans ? descent * pfo->lpX11Trans->c /
173 pfo->lpX11Trans->pixelsize : 0;
174 y -= pfo->lpX11Trans ? descent * pfo->lpX11Trans->d /
175 pfo->lpX11Trans->pixelsize : descent;
176 break;
177 case TA_BASELINE:
178 break;
181 /* Set the clip region */
183 if (flags & ETO_CLIPPED)
185 SaveVisRgn16( dc->hSelf );
186 CLIPPING_IntersectVisRect( dc, rect.left, rect.top, rect.right,
187 rect.bottom, FALSE );
190 /* Draw the text background if necessary */
192 if (dc->w.backgroundMode != TRANSPARENT)
194 /* If rectangle is opaque and clipped, do nothing */
195 if (!(flags & ETO_CLIPPED) || !(flags & ETO_OPAQUE))
197 /* Only draw if rectangle is not opaque or if some */
198 /* text is outside the rectangle */
199 if (!(flags & ETO_OPAQUE) ||
200 (x < rect.left) ||
201 (x + width >= rect.right) ||
202 (y - ascent < rect.top) ||
203 (y + descent >= rect.bottom))
205 TSXSetForeground( display, physDev->gc,
206 physDev->backgroundPixel );
207 TSXFillRectangle( display, physDev->drawable, physDev->gc,
208 dc->w.DCOrgX + x,
209 dc->w.DCOrgY + y - ascent,
210 width,
211 ascent + descent );
216 /* Draw the text (count > 0 verified) */
217 str2b = HeapAlloc( GetProcessHeap(), 0, count * sizeof(XChar2b) );
218 for(i = 0; i < count; i++) {
219 str2b[i].byte1 = wstr[i] >> 8;
220 str2b[i].byte2 = wstr[i] & 0xff;
223 TSXSetForeground( display, physDev->gc, physDev->textPixel );
224 if(!rotated)
226 if (!dc->w.charExtra && !dc->w.breakExtra && !lpDx)
228 TSXDrawString16( display, physDev->drawable, physDev->gc,
229 dc->w.DCOrgX + x, dc->w.DCOrgY + y, str2b, count );
231 else /* Now the fun begins... */
233 XTextItem16 *items, *pitem;
234 int delta;
236 /* allocate max items */
238 pitem = items = HEAP_xalloc( GetProcessHeap(), 0,
239 count * sizeof(XTextItem16) );
240 delta = i = 0;
241 if( lpDx ) /* explicit character widths */
243 int extra = dc->wndExtX / 2;
245 while (i < count)
247 /* initialize text item with accumulated delta */
249 pitem->chars = str2b + i;
250 pitem->delta = delta;
251 pitem->nchars = 0;
252 pitem->font = None;
253 delta = 0;
255 /* add characters to the same XTextItem until new delta
256 * becomes non-zero */
260 delta += (lpDx[i] * dc->vportExtX + extra) / dc->wndExtX
261 - TSXTextWidth16( font, str2b + i, 1);
262 pitem->nchars++;
263 } while ((++i < count) && !delta);
264 pitem++;
267 else /* charExtra or breakExtra */
269 while (i < count)
271 pitem->chars = str2b + i;
272 pitem->delta = delta;
273 pitem->nchars = 0;
274 pitem->font = None;
275 delta = 0;
279 delta += dc->w.charExtra;
280 if (str2b[i].byte2 == (char)dfBreakChar)
281 delta += dc->w.breakExtra;
282 pitem->nchars++;
283 } while ((++i < count) && !delta);
284 pitem++;
288 TSXDrawText16( display, physDev->drawable, physDev->gc,
289 dc->w.DCOrgX + x, dc->w.DCOrgY + y, items, pitem - items );
290 HeapFree( GetProcessHeap(), 0, items );
293 else /* rotated */
295 /* have to render character by character. */
296 double offset = 0.0;
297 int i;
299 for (i=0; i<count; i++)
301 int char_metric_offset = str2b[i].byte2 + (str2b[i].byte1 << 8)
302 - font->min_char_or_byte2;
303 int x_i = IROUND((double) (dc->w.DCOrgX + x) + offset *
304 pfo->lpX11Trans->a / pfo->lpX11Trans->pixelsize );
305 int y_i = IROUND((double) (dc->w.DCOrgY + y) - offset *
306 pfo->lpX11Trans->b / pfo->lpX11Trans->pixelsize );
308 TSXDrawString16( display, physDev->drawable, physDev->gc,
309 x_i, y_i, &str2b[i], 1);
310 if (lpDx)
311 offset += XLSTODS(dc, lpDx[i]);
312 else
314 offset += (double) (font->per_char ?
315 font->per_char[char_metric_offset].attributes:
316 font->min_bounds.attributes)
317 * pfo->lpX11Trans->pixelsize / 1000.0;
318 offset += dc->w.charExtra;
319 if (str2b[i].byte2 == (char)dfBreakChar)
320 offset += dc->w.breakExtra;
324 HeapFree( GetProcessHeap(), 0, str2b );
326 /* Draw underline and strike-out if needed */
328 if (lfUnderline)
330 long linePos, lineWidth;
332 if (!TSXGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
333 linePos = descent - 1;
334 if (!TSXGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
335 lineWidth = 0;
336 else if (lineWidth == 1) lineWidth = 0;
337 TSXSetLineAttributes( display, physDev->gc, lineWidth,
338 LineSolid, CapRound, JoinBevel );
339 TSXDrawLine( display, physDev->drawable, physDev->gc,
340 dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos,
341 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y + linePos );
343 if (lfStrikeOut)
345 long lineAscent, lineDescent;
346 if (!TSXGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
347 lineAscent = ascent / 2;
348 if (!TSXGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
349 lineDescent = -lineAscent * 2 / 3;
350 TSXSetLineAttributes( display, physDev->gc, lineAscent + lineDescent,
351 LineSolid, CapRound, JoinBevel );
352 TSXDrawLine( display, physDev->drawable, physDev->gc,
353 dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent,
354 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y - lineAscent );
357 if (flags & ETO_CLIPPED)
358 RestoreVisRgn16( dc->hSelf );
360 return TRUE;
363 #endif /* !defined(X_DISPLAY_MISSING) */