Correct usage of a scratch array in X11DRV_PolyBezier.
[wine.git] / graphics / x11drv / text.c
blob01d2292b911e48ab2bdc8341ab6ba634c102422a
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, LPCSTR str, 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;
45 if (!X11DRV_SetupGCForText( dc )) return TRUE;
47 pfo = XFONT_GetFontObject( physDev->font );
48 font = pfo->fs;
50 if (pfo->lf.lfEscapement && pfo->lpX11Trans)
51 rotated = TRUE;
52 dfBreakChar = (char)pfo->fi->df.dfBreakChar;
53 lfUnderline = (pfo->fo_flags & FO_SYNTH_UNDERLINE) ? 1 : 0;
54 lfStrikeOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT) ? 1 : 0;
56 TRACE("hdc=%04x df=%04x %d,%d %s, %d flags=%d lpDx=%p\n",
57 dc->hSelf, (UINT16)(physDev->font), x, y,
58 debugstr_an (str, count), count, flags, lpDx);
60 /* some strings sent here end in a newline for whatever reason. I have no
61 clue what the right treatment should be in general, but ignoring
62 terminating newlines seems ok. MW, April 1998. */
63 if (count > 0 && str[count - 1] == '\n') count--;
65 if (lprect != NULL) TRACE("\trect=(%d,%d - %d,%d)\n",
66 lprect->left, lprect->top,
67 lprect->right, lprect->bottom );
68 /* Setup coordinates */
70 if (dc->w.textAlign & TA_UPDATECP)
72 x = dc->w.CursPosX;
73 y = dc->w.CursPosY;
76 if (flags & (ETO_OPAQUE | ETO_CLIPPED)) /* there's a rectangle */
78 if (!lprect) /* not always */
80 SIZE sz;
81 if (flags & ETO_CLIPPED) /* Can't clip with no rectangle */
82 return FALSE;
83 if (!X11DRV_GetTextExtentPoint( dc, str, count, &sz ))
84 return FALSE;
85 rect.left = XLPTODP( dc, x );
86 rect.right = XLPTODP( dc, x+sz.cx );
87 rect.top = YLPTODP( dc, y );
88 rect.bottom = YLPTODP( dc, y+sz.cy );
90 else
92 rect.left = XLPTODP( dc, lprect->left );
93 rect.right = XLPTODP( dc, lprect->right );
94 rect.top = YLPTODP( dc, lprect->top );
95 rect.bottom = YLPTODP( dc, lprect->bottom );
97 if (rect.right < rect.left) SWAP_INT( rect.left, rect.right );
98 if (rect.bottom < rect.top) SWAP_INT( rect.top, rect.bottom );
101 x = XLPTODP( dc, x );
102 y = YLPTODP( dc, y );
104 TRACE("\treal coord: x=%i, y=%i, rect=(%d,%d - %d,%d)\n",
105 x, y, rect.left, rect.top, rect.right, rect.bottom);
107 /* Draw the rectangle */
109 if (flags & ETO_OPAQUE)
111 TSXSetForeground( display, physDev->gc, physDev->backgroundPixel );
112 TSXFillRectangle( display, physDev->drawable, physDev->gc,
113 dc->w.DCOrgX + rect.left, dc->w.DCOrgY + rect.top,
114 rect.right-rect.left, rect.bottom-rect.top );
116 if (!count) return TRUE; /* Nothing more to do */
118 /* Compute text starting position */
120 if (lpDx) /* have explicit character cell x offsets in logical coordinates */
122 int extra = dc->wndExtX / 2;
123 for (i = width = 0; i < count; i++) width += lpDx[i];
124 width = (width * dc->vportExtX + extra ) / dc->wndExtX;
126 else
128 SIZE sz;
129 if (!X11DRV_GetTextExtentPoint( dc, str, count, &sz ))
130 return FALSE;
131 width = XLSTODS(dc, sz.cx);
133 ascent = pfo->lpX11Trans ? pfo->lpX11Trans->ascent : font->ascent;
134 descent = pfo->lpX11Trans ? pfo->lpX11Trans->descent : font->descent;
135 xwidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->a /
136 pfo->lpX11Trans->pixelsize : width;
137 ywidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->b /
138 pfo->lpX11Trans->pixelsize : 0;
140 switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
142 case TA_LEFT:
143 if (dc->w.textAlign & TA_UPDATECP) {
144 dc->w.CursPosX = XDPTOLP( dc, x + xwidth );
145 dc->w.CursPosY = YDPTOLP( dc, y - ywidth );
147 break;
148 case TA_RIGHT:
149 x -= xwidth;
150 y += ywidth;
151 if (dc->w.textAlign & TA_UPDATECP) {
152 dc->w.CursPosX = XDPTOLP( dc, x );
153 dc->w.CursPosY = YDPTOLP( dc, y );
155 break;
156 case TA_CENTER:
157 x -= xwidth / 2;
158 y += ywidth / 2;
159 break;
162 switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
164 case TA_TOP:
165 x -= pfo->lpX11Trans ? ascent * pfo->lpX11Trans->c /
166 pfo->lpX11Trans->pixelsize : 0;
167 y += pfo->lpX11Trans ? ascent * pfo->lpX11Trans->d /
168 pfo->lpX11Trans->pixelsize : ascent;
169 break;
170 case TA_BOTTOM:
171 x += pfo->lpX11Trans ? descent * pfo->lpX11Trans->c /
172 pfo->lpX11Trans->pixelsize : 0;
173 y -= pfo->lpX11Trans ? descent * pfo->lpX11Trans->d /
174 pfo->lpX11Trans->pixelsize : descent;
175 break;
176 case TA_BASELINE:
177 break;
180 /* Set the clip region */
182 if (flags & ETO_CLIPPED)
184 SaveVisRgn16( dc->hSelf );
185 CLIPPING_IntersectVisRect( dc, rect.left, rect.top, rect.right,
186 rect.bottom, FALSE );
189 /* Draw the text background if necessary */
191 if (dc->w.backgroundMode != TRANSPARENT)
193 /* If rectangle is opaque and clipped, do nothing */
194 if (!(flags & ETO_CLIPPED) || !(flags & ETO_OPAQUE))
196 /* Only draw if rectangle is not opaque or if some */
197 /* text is outside the rectangle */
198 if (!(flags & ETO_OPAQUE) ||
199 (x < rect.left) ||
200 (x + width >= rect.right) ||
201 (y - ascent < rect.top) ||
202 (y + descent >= rect.bottom))
204 TSXSetForeground( display, physDev->gc,
205 physDev->backgroundPixel );
206 TSXFillRectangle( display, physDev->drawable, physDev->gc,
207 dc->w.DCOrgX + x,
208 dc->w.DCOrgY + y - ascent,
209 width,
210 ascent + descent );
215 /* Draw the text (count > 0 verified) */
217 TSXSetForeground( display, physDev->gc, physDev->textPixel );
218 if(!rotated)
220 if (!dc->w.charExtra && !dc->w.breakExtra && !lpDx)
222 TSXDrawString( display, physDev->drawable, physDev->gc,
223 dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count );
225 else /* Now the fun begins... */
227 XTextItem *items, *pitem;
228 int delta;
230 /* allocate max items */
232 pitem = items = HEAP_xalloc( GetProcessHeap(), 0,
233 count * sizeof(XTextItem) );
234 delta = i = 0;
235 if( lpDx ) /* explicit character widths */
237 int extra = dc->wndExtX / 2;
239 while (i < count)
241 /* initialize text item with accumulated delta */
243 pitem->chars = (char *)str + i;
244 pitem->delta = delta;
245 pitem->nchars = 0;
246 pitem->font = None;
247 delta = 0;
249 /* add characters to the same XTextItem until new delta
250 * becomes non-zero */
254 delta += (lpDx[i] * dc->vportExtX + extra) / dc->wndExtX
255 - TSXTextWidth( font, str + i, 1);
256 pitem->nchars++;
257 } while ((++i < count) && !delta);
258 pitem++;
261 else /* charExtra or breakExtra */
263 while (i < count)
265 pitem->chars = (char *)str + i;
266 pitem->delta = delta;
267 pitem->nchars = 0;
268 pitem->font = None;
269 delta = 0;
273 delta += dc->w.charExtra;
274 if (str[i] == (char)dfBreakChar) delta += dc->w.breakExtra;
275 pitem->nchars++;
276 } while ((++i < count) && !delta);
277 pitem++;
281 TSXDrawText( display, physDev->drawable, physDev->gc,
282 dc->w.DCOrgX + x, dc->w.DCOrgY + y, items, pitem - items );
283 HeapFree( GetProcessHeap(), 0, items );
286 else /* rotated */
288 /* have to render character by character. */
289 double offset = 0.0;
290 int i;
292 for (i=0; i<count; i++)
294 int char_metric_offset = (unsigned char) str[i]
295 - font->min_char_or_byte2;
296 int x_i = IROUND((double) (dc->w.DCOrgX + x) + offset *
297 pfo->lpX11Trans->a / pfo->lpX11Trans->pixelsize );
298 int y_i = IROUND((double) (dc->w.DCOrgY + y) - offset *
299 pfo->lpX11Trans->b / pfo->lpX11Trans->pixelsize );
301 TSXDrawString( display, physDev->drawable, physDev->gc,
302 x_i, y_i, &str[i], 1);
303 if (lpDx)
304 offset += XLSTODS(dc, lpDx[i]);
305 else
307 offset += (double) (font->per_char ?
308 font->per_char[char_metric_offset].attributes:
309 font->min_bounds.attributes)
310 * pfo->lpX11Trans->pixelsize / 1000.0;
311 offset += dc->w.charExtra;
312 if (str[i] == (char)dfBreakChar)
313 offset += dc->w.breakExtra;
318 /* Draw underline and strike-out if needed */
320 if (lfUnderline)
322 long linePos, lineWidth;
324 if (!TSXGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
325 linePos = descent - 1;
326 if (!TSXGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
327 lineWidth = 0;
328 else if (lineWidth == 1) lineWidth = 0;
329 TSXSetLineAttributes( display, physDev->gc, lineWidth,
330 LineSolid, CapRound, JoinBevel );
331 TSXDrawLine( display, physDev->drawable, physDev->gc,
332 dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos,
333 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y + linePos );
335 if (lfStrikeOut)
337 long lineAscent, lineDescent;
338 if (!TSXGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
339 lineAscent = ascent / 2;
340 if (!TSXGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
341 lineDescent = -lineAscent * 2 / 3;
342 TSXSetLineAttributes( display, physDev->gc, lineAscent + lineDescent,
343 LineSolid, CapRound, JoinBevel );
344 TSXDrawLine( display, physDev->drawable, physDev->gc,
345 dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent,
346 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y - lineAscent );
349 if (flags & ETO_CLIPPED)
350 RestoreVisRgn16( dc->hSelf );
352 return TRUE;
355 #endif /* !defined(X_DISPLAY_MISSING) */