2 * X11 graphics driver text functions
4 * Copyright 1993,1994 Alexandre Julliard
14 /*#include "callback.h"*/
20 #define SWAP_INT(a,b) { int t = a; a = b; b = t; }
21 #define IROUND(x) (int)((x)>0? (x)+0.5 : (x) - 0.5)
23 /***********************************************************************
27 X11DRV_ExtTextOut( DC *dc, INT32 x, INT32 y, UINT32 flags,
28 const RECT32 *lprect, LPCSTR str, UINT32 count,
33 INT32 width, ascent, descent, xwidth, ywidth;
36 char dfBreakChar, lfUnderline, lfStrikeOut;
37 BOOL32 rotated = FALSE;
39 if (!X11DRV_SetupGCForText( dc )) return TRUE;
41 pfo = XFONT_GetFontObject( dc->u.x.font );
44 if (pfo->lf.lfEscapement && pfo->lpX11Trans)
46 dfBreakChar = (char)pfo->fi->df.dfBreakChar;
47 lfUnderline = (pfo->fo_flags & FO_SYNTH_UNDERLINE) ? 1 : 0;
48 lfStrikeOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT) ? 1 : 0;
50 TRACE(text,"hdc=%04x df=%04x %d,%d %s, %d flags=%d lpDx=%p\n",
51 dc->hSelf, (UINT16)(dc->u.x.font), x, y,
52 debugstr_an (str, count), count, flags, lpDx);
54 /* some strings sent here end in a newline for whatever reason. I have no
55 clue what the right treatment should be in general, but ignoring
56 terminating newlines seems ok. MW, April 1998. */
57 if (count > 0 && str[count - 1] == '\n') count--;
59 if (lprect != NULL) TRACE(text, "\trect=(%d,%d - %d,%d)\n",
60 lprect->left, lprect->top,
61 lprect->right, lprect->bottom );
62 /* Setup coordinates */
64 if (dc->w.textAlign & TA_UPDATECP)
70 if (flags & (ETO_OPAQUE | ETO_CLIPPED)) /* there's a rectangle */
72 if (!lprect) /* not always */
75 if (flags & ETO_CLIPPED) /* Can't clip with no rectangle */
77 if (!X11DRV_GetTextExtentPoint( dc, str, count, &sz ))
79 rect.left = XLPTODP( dc, x );
80 rect.right = XLPTODP( dc, x+sz.cx );
81 rect.top = YLPTODP( dc, y );
82 rect.bottom = YLPTODP( dc, y+sz.cy );
86 rect.left = XLPTODP( dc, lprect->left );
87 rect.right = XLPTODP( dc, lprect->right );
88 rect.top = YLPTODP( dc, lprect->top );
89 rect.bottom = YLPTODP( dc, lprect->bottom );
91 if (rect.right < rect.left) SWAP_INT( rect.left, rect.right );
92 if (rect.bottom < rect.top) SWAP_INT( rect.top, rect.bottom );
98 TRACE(text,"\treal coord: x=%i, y=%i, rect=(%d,%d - %d,%d)\n",
99 x, y, rect.left, rect.top, rect.right, rect.bottom);
101 /* Draw the rectangle */
103 if (flags & ETO_OPAQUE)
105 TSXSetForeground( display, dc->u.x.gc, dc->u.x.backgroundPixel );
106 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
107 dc->w.DCOrgX + rect.left, dc->w.DCOrgY + rect.top,
108 rect.right-rect.left, rect.bottom-rect.top );
110 if (!count) return TRUE; /* Nothing more to do */
112 /* Compute text starting position */
114 if (lpDx) /* have explicit character cell x offsets in logical coordinates */
116 int extra = dc->wndExtX / 2;
117 for (i = width = 0; i < count; i++) width += lpDx[i];
118 width = (width * dc->vportExtX + extra ) / dc->wndExtX;
123 if (!X11DRV_GetTextExtentPoint( dc, str, count, &sz ))
125 width = XLSTODS(dc, sz.cx);
127 ascent = pfo->lpX11Trans ? pfo->lpX11Trans->ascent : font->ascent;
128 descent = pfo->lpX11Trans ? pfo->lpX11Trans->descent : font->descent;
129 xwidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->a /
130 pfo->lpX11Trans->pixelsize : width;
131 ywidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->b /
132 pfo->lpX11Trans->pixelsize : 0;
134 switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
137 if (dc->w.textAlign & TA_UPDATECP) {
138 dc->w.CursPosX = XDPTOLP( dc, x + xwidth );
139 dc->w.CursPosY = YDPTOLP( dc, y - ywidth );
145 if (dc->w.textAlign & TA_UPDATECP) {
146 dc->w.CursPosX = XDPTOLP( dc, x );
147 dc->w.CursPosY = YDPTOLP( dc, y );
156 switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
159 x -= pfo->lpX11Trans ? ascent * pfo->lpX11Trans->c /
160 pfo->lpX11Trans->pixelsize : 0;
161 y += pfo->lpX11Trans ? ascent * pfo->lpX11Trans->d /
162 pfo->lpX11Trans->pixelsize : ascent;
165 x += pfo->lpX11Trans ? descent * pfo->lpX11Trans->c /
166 pfo->lpX11Trans->pixelsize : 0;
167 y -= pfo->lpX11Trans ? descent * pfo->lpX11Trans->d /
168 pfo->lpX11Trans->pixelsize : descent;
174 /* Set the clip region */
176 if (flags & ETO_CLIPPED)
178 SaveVisRgn( dc->hSelf );
179 CLIPPING_IntersectVisRect( dc, rect.left, rect.top, rect.right,
180 rect.bottom, FALSE );
183 /* Draw the text background if necessary */
185 if (dc->w.backgroundMode != TRANSPARENT)
187 /* If rectangle is opaque and clipped, do nothing */
188 if (!(flags & ETO_CLIPPED) || !(flags & ETO_OPAQUE))
190 /* Only draw if rectangle is not opaque or if some */
191 /* text is outside the rectangle */
192 if (!(flags & ETO_OPAQUE) ||
194 (x + width >= rect.right) ||
195 (y - ascent < rect.top) ||
196 (y + descent >= rect.bottom))
198 TSXSetForeground( display, dc->u.x.gc, dc->u.x.backgroundPixel );
199 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
201 dc->w.DCOrgY + y - ascent,
208 /* Draw the text (count > 0 verified) */
210 TSXSetForeground( display, dc->u.x.gc, dc->u.x.textPixel );
211 if (!dc->w.charExtra && !dc->w.breakExtra && !lpDx)
215 TSXDrawString( display, dc->u.x.drawable, dc->u.x.gc,
216 dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count );
220 /* have to render character by character. */
224 for(i=0; i<count; i++) {
225 int char_metric_offset = (unsigned char) str[i]
226 - font->min_char_or_byte2;
227 int x_i = IROUND((double) (dc->w.DCOrgX + x) + offset *
228 pfo->lpX11Trans->a / 1000.0 );
229 int y_i = IROUND((double) (dc->w.DCOrgY + y) - offset *
230 pfo->lpX11Trans->b / 1000.0 );
232 TSXDrawString( display, dc->u.x.drawable, dc->u.x.gc,
233 x_i, y_i, &str[i], 1);
234 offset += (double) (font->per_char ?
235 font->per_char[char_metric_offset].attributes:
236 font->min_bounds.attributes);
240 else /* Now the fun begins... */
242 XTextItem *items, *pitem;
245 /* allocate max items */
247 pitem = items = HEAP_xalloc( GetProcessHeap(), 0,
248 count * sizeof(XTextItem) );
250 if( lpDx ) /* explicit character widths */
252 int extra = dc->wndExtX / 2;
256 /* initialize text item with accumulated delta */
258 pitem->chars = (char *)str + i;
259 pitem->delta = delta;
264 /* add characters to the same XTextItem until new delta
265 * becomes non-zero */
269 delta += (lpDx[i] * dc->vportExtX + extra) / dc->wndExtX
270 - TSXTextWidth( font, str + i, 1);
272 } while ((++i < count) && !delta);
276 else /* charExtra or breakExtra */
280 pitem->chars = (char *)str + i;
281 pitem->delta = delta;
288 delta += dc->w.charExtra;
289 if (str[i] == (char)dfBreakChar) delta += dc->w.breakExtra;
291 } while ((++i < count) && !delta);
296 TSXDrawText( display, dc->u.x.drawable, dc->u.x.gc,
297 dc->w.DCOrgX + x, dc->w.DCOrgY + y, items, pitem - items );
298 HeapFree( GetProcessHeap(), 0, items );
301 /* Draw underline and strike-out if needed */
305 long linePos, lineWidth;
307 if (!TSXGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
308 linePos = descent - 1;
309 if (!TSXGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
311 else if (lineWidth == 1) lineWidth = 0;
312 TSXSetLineAttributes( display, dc->u.x.gc, lineWidth,
313 LineSolid, CapRound, JoinBevel );
314 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
315 dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos,
316 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y + linePos );
320 long lineAscent, lineDescent;
321 if (!TSXGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
322 lineAscent = ascent / 2;
323 if (!TSXGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
324 lineDescent = -lineAscent * 2 / 3;
325 TSXSetLineAttributes( display, dc->u.x.gc, lineAscent + lineDescent,
326 LineSolid, CapRound, JoinBevel );
327 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
328 dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent,
329 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y - lineAscent );
332 if (flags & ETO_CLIPPED)
333 RestoreVisRgn( dc->hSelf );