2 * X11 graphics driver text functions
4 * Copyright 1993,1994 Alexandre Julliard
9 #ifndef X_DISPLAY_MISSING
11 #include <X11/Xatom.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 /***********************************************************************
32 X11DRV_ExtTextOut( DC *dc, INT x, INT y, UINT flags,
33 const RECT *lprect, LPCWSTR wstr, UINT count,
38 INT width, ascent, descent, xwidth, ywidth;
41 char dfBreakChar, lfUnderline, lfStrikeOut;
43 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
45 BOOL dibUpdateFlag = FALSE;
47 if (!X11DRV_SetupGCForText( dc )) return TRUE;
49 pfo = XFONT_GetFontObject( physDev->font );
52 if (pfo->lf.lfEscapement && pfo->lpX11Trans)
54 dfBreakChar = (char)pfo->fi->df.dfBreakChar;
55 lfUnderline = (pfo->fo_flags & FO_SYNTH_UNDERLINE) ? 1 : 0;
56 lfStrikeOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT) ? 1 : 0;
58 TRACE("hdc=%04x df=%04x %d,%d %s, %d flags=%d lpDx=%p\n",
59 dc->hSelf, (UINT16)(physDev->font), x, y,
60 debugstr_wn (wstr, count), count, flags, lpDx);
62 /* some strings sent here end in a newline for whatever reason. I have no
63 clue what the right treatment should be in general, but ignoring
64 terminating newlines seems ok. MW, April 1998. */
65 if (count > 0 && wstr[count - 1] == '\n') count--;
67 if (lprect != NULL) TRACE("\trect=(%d,%d - %d,%d)\n",
68 lprect->left, lprect->top,
69 lprect->right, lprect->bottom );
70 /* Setup coordinates */
72 if (dc->w.textAlign & TA_UPDATECP)
78 if (flags & (ETO_OPAQUE | ETO_CLIPPED)) /* there's a rectangle */
80 if (!lprect) /* not always */
83 if (flags & ETO_CLIPPED) /* Can't clip with no rectangle */
85 if (!X11DRV_GetTextExtentPoint( dc, wstr, count, &sz ))
87 rect.left = XLPTODP( dc, x );
88 rect.right = XLPTODP( dc, x+sz.cx );
89 rect.top = YLPTODP( dc, y );
90 rect.bottom = YLPTODP( dc, y+sz.cy );
94 rect.left = XLPTODP( dc, lprect->left );
95 rect.right = XLPTODP( dc, lprect->right );
96 rect.top = YLPTODP( dc, lprect->top );
97 rect.bottom = YLPTODP( dc, lprect->bottom );
99 if (rect.right < rect.left) SWAP_INT( rect.left, rect.right );
100 if (rect.bottom < rect.top) SWAP_INT( rect.top, rect.bottom );
103 x = XLPTODP( dc, x );
104 y = YLPTODP( dc, y );
106 TRACE("\treal coord: x=%i, y=%i, rect=(%d,%d - %d,%d)\n",
107 x, y, rect.left, rect.top, rect.right, rect.bottom);
109 /* Draw the rectangle */
111 if (flags & ETO_OPAQUE)
113 X11DRV_DIB_UpdateDIBSection( dc, FALSE );
114 dibUpdateFlag = TRUE;
115 TSXSetForeground( display, physDev->gc, physDev->backgroundPixel );
116 TSXFillRectangle( display, physDev->drawable, physDev->gc,
117 dc->w.DCOrgX + rect.left, dc->w.DCOrgY + rect.top,
118 rect.right-rect.left, rect.bottom-rect.top );
120 if (!count) goto END; /* Nothing more to do */
122 /* Compute text starting position */
124 if (lpDx) /* have explicit character cell x offsets in logical coordinates */
126 int extra = dc->wndExtX / 2;
127 for (i = width = 0; i < count; i++) width += lpDx[i];
128 width = (width * dc->vportExtX + extra ) / dc->wndExtX;
133 if (!X11DRV_GetTextExtentPoint( dc, wstr, count, &sz ))
135 width = XLSTODS(dc, sz.cx);
137 ascent = pfo->lpX11Trans ? pfo->lpX11Trans->ascent : font->ascent;
138 descent = pfo->lpX11Trans ? pfo->lpX11Trans->descent : font->descent;
139 xwidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->a /
140 pfo->lpX11Trans->pixelsize : width;
141 ywidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->b /
142 pfo->lpX11Trans->pixelsize : 0;
144 switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
147 if (dc->w.textAlign & TA_UPDATECP) {
148 dc->w.CursPosX = XDPTOLP( dc, x + xwidth );
149 dc->w.CursPosY = YDPTOLP( dc, y - ywidth );
155 if (dc->w.textAlign & TA_UPDATECP) {
156 dc->w.CursPosX = XDPTOLP( dc, x );
157 dc->w.CursPosY = YDPTOLP( dc, y );
166 switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
169 x -= pfo->lpX11Trans ? ascent * pfo->lpX11Trans->c /
170 pfo->lpX11Trans->pixelsize : 0;
171 y += pfo->lpX11Trans ? ascent * pfo->lpX11Trans->d /
172 pfo->lpX11Trans->pixelsize : ascent;
175 x += pfo->lpX11Trans ? descent * pfo->lpX11Trans->c /
176 pfo->lpX11Trans->pixelsize : 0;
177 y -= pfo->lpX11Trans ? descent * pfo->lpX11Trans->d /
178 pfo->lpX11Trans->pixelsize : descent;
184 /* Set the clip region */
186 if (flags & ETO_CLIPPED)
188 SaveVisRgn16( dc->hSelf );
189 CLIPPING_IntersectVisRect( dc, rect.left, rect.top, rect.right,
190 rect.bottom, FALSE );
193 /* Draw the text background if necessary */
197 X11DRV_DIB_UpdateDIBSection( dc, FALSE );
198 dibUpdateFlag = TRUE;
201 if (dc->w.backgroundMode != TRANSPARENT)
203 /* If rectangle is opaque and clipped, do nothing */
204 if (!(flags & ETO_CLIPPED) || !(flags & ETO_OPAQUE))
206 /* Only draw if rectangle is not opaque or if some */
207 /* text is outside the rectangle */
208 if (!(flags & ETO_OPAQUE) ||
210 (x + width >= rect.right) ||
211 (y - ascent < rect.top) ||
212 (y + descent >= rect.bottom))
214 TSXSetForeground( display, physDev->gc,
215 physDev->backgroundPixel );
216 TSXFillRectangle( display, physDev->drawable, physDev->gc,
218 dc->w.DCOrgY + y - ascent,
225 /* Draw the text (count > 0 verified) */
226 str2b = HeapAlloc( GetProcessHeap(), 0, count * sizeof(XChar2b) );
227 for(i = 0; i < count; i++) {
228 str2b[i].byte1 = wstr[i] >> 8;
229 str2b[i].byte2 = wstr[i] & 0xff;
232 TSXSetForeground( display, physDev->gc, physDev->textPixel );
235 if (!dc->w.charExtra && !dc->w.breakExtra && !lpDx)
237 TSXDrawString16( display, physDev->drawable, physDev->gc,
238 dc->w.DCOrgX + x, dc->w.DCOrgY + y, str2b, count );
240 else /* Now the fun begins... */
242 XTextItem16 *items, *pitem;
245 /* allocate max items */
247 pitem = items = HEAP_xalloc( GetProcessHeap(), 0,
248 count * sizeof(XTextItem16) );
250 if( lpDx ) /* explicit character widths */
252 int extra = dc->wndExtX / 2;
256 /* initialize text item with accumulated delta */
258 pitem->chars = str2b + 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 - TSXTextWidth16( font, str2b + i, 1);
272 } while ((++i < count) && !delta);
276 else /* charExtra or breakExtra */
280 pitem->chars = str2b + i;
281 pitem->delta = delta;
288 delta += dc->w.charExtra;
289 if (str2b[i].byte2 == (char)dfBreakChar)
290 delta += dc->w.breakExtra;
292 } while ((++i < count) && !delta);
297 TSXDrawText16( display, physDev->drawable, physDev->gc,
298 dc->w.DCOrgX + x, dc->w.DCOrgY + y, items, pitem - items );
299 HeapFree( GetProcessHeap(), 0, items );
304 /* have to render character by character. */
308 for (i=0; i<count; i++)
310 int char_metric_offset = str2b[i].byte2 + (str2b[i].byte1 << 8)
311 - font->min_char_or_byte2;
312 int x_i = IROUND((double) (dc->w.DCOrgX + x) + offset *
313 pfo->lpX11Trans->a / pfo->lpX11Trans->pixelsize );
314 int y_i = IROUND((double) (dc->w.DCOrgY + y) - offset *
315 pfo->lpX11Trans->b / pfo->lpX11Trans->pixelsize );
317 TSXDrawString16( display, physDev->drawable, physDev->gc,
318 x_i, y_i, &str2b[i], 1);
320 offset += XLSTODS(dc, lpDx[i]);
323 offset += (double) (font->per_char ?
324 font->per_char[char_metric_offset].attributes:
325 font->min_bounds.attributes)
326 * pfo->lpX11Trans->pixelsize / 1000.0;
327 offset += dc->w.charExtra;
328 if (str2b[i].byte2 == (char)dfBreakChar)
329 offset += dc->w.breakExtra;
333 HeapFree( GetProcessHeap(), 0, str2b );
335 /* Draw underline and strike-out if needed */
339 long linePos, lineWidth;
341 if (!TSXGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
342 linePos = descent - 1;
343 if (!TSXGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
345 else if (lineWidth == 1) lineWidth = 0;
346 TSXSetLineAttributes( display, physDev->gc, lineWidth,
347 LineSolid, CapRound, JoinBevel );
348 TSXDrawLine( display, physDev->drawable, physDev->gc,
349 dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos,
350 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y + linePos );
354 long lineAscent, lineDescent;
355 if (!TSXGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
356 lineAscent = ascent / 2;
357 if (!TSXGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
358 lineDescent = -lineAscent * 2 / 3;
359 TSXSetLineAttributes( display, physDev->gc, lineAscent + lineDescent,
360 LineSolid, CapRound, JoinBevel );
361 TSXDrawLine( display, physDev->drawable, physDev->gc,
362 dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent,
363 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y - lineAscent );
366 if (flags & ETO_CLIPPED)
367 RestoreVisRgn16( dc->hSelf );
370 if (dibUpdateFlag) X11DRV_DIB_UpdateDIBSection( dc, TRUE );
374 #endif /* !defined(X_DISPLAY_MISSING) */