Fixed the prototype of CreateDIBPatternBrushPt
[wine/multimedia.git] / graphics / x11drv / text.c
blobe1d3f52965747a0103d3a0a0dd470721011fd327
1 /*
2 * X11 graphics driver text functions
4 * Copyright 1993,1994 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include "ts_xlib.h"
9 #include <X11/Xatom.h>
10 #include "windows.h"
11 #include <math.h>
12 #include "dc.h"
13 #include "gdi.h"
14 /*#include "callback.h"*/
15 #include "heap.h"
16 #include "x11font.h"
17 #include "debugstr.h"
18 #include "debug.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 /***********************************************************************
24 * X11DRV_ExtTextOut
26 BOOL32
27 X11DRV_ExtTextOut( DC *dc, INT32 x, INT32 y, UINT32 flags,
28 const RECT32 *lprect, LPCSTR str, UINT32 count,
29 const INT32 *lpDx )
31 int i;
32 fontObject* pfo;
33 INT32 width, ascent, descent, xwidth, ywidth;
34 XFontStruct* font;
35 RECT32 rect;
36 char dfBreakChar, lfUnderline, lfStrikeOut;
37 BOOL32 rotated = FALSE;
38 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
40 if (!X11DRV_SetupGCForText( dc )) return TRUE;
42 pfo = XFONT_GetFontObject( physDev->font );
43 font = pfo->fs;
45 if (pfo->lf.lfEscapement && pfo->lpX11Trans)
46 rotated = TRUE;
47 dfBreakChar = (char)pfo->fi->df.dfBreakChar;
48 lfUnderline = (pfo->fo_flags & FO_SYNTH_UNDERLINE) ? 1 : 0;
49 lfStrikeOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT) ? 1 : 0;
51 TRACE(text,"hdc=%04x df=%04x %d,%d %s, %d flags=%d lpDx=%p\n",
52 dc->hSelf, (UINT16)(physDev->font), x, y,
53 debugstr_an (str, count), count, flags, lpDx);
55 /* some strings sent here end in a newline for whatever reason. I have no
56 clue what the right treatment should be in general, but ignoring
57 terminating newlines seems ok. MW, April 1998. */
58 if (count > 0 && str[count - 1] == '\n') count--;
60 if (lprect != NULL) TRACE(text, "\trect=(%d,%d - %d,%d)\n",
61 lprect->left, lprect->top,
62 lprect->right, lprect->bottom );
63 /* Setup coordinates */
65 if (dc->w.textAlign & TA_UPDATECP)
67 x = dc->w.CursPosX;
68 y = dc->w.CursPosY;
71 if (flags & (ETO_OPAQUE | ETO_CLIPPED)) /* there's a rectangle */
73 if (!lprect) /* not always */
75 SIZE32 sz;
76 if (flags & ETO_CLIPPED) /* Can't clip with no rectangle */
77 return FALSE;
78 if (!X11DRV_GetTextExtentPoint( dc, str, count, &sz ))
79 return FALSE;
80 rect.left = XLPTODP( dc, x );
81 rect.right = XLPTODP( dc, x+sz.cx );
82 rect.top = YLPTODP( dc, y );
83 rect.bottom = YLPTODP( dc, y+sz.cy );
85 else
87 rect.left = XLPTODP( dc, lprect->left );
88 rect.right = XLPTODP( dc, lprect->right );
89 rect.top = YLPTODP( dc, lprect->top );
90 rect.bottom = YLPTODP( dc, lprect->bottom );
92 if (rect.right < rect.left) SWAP_INT( rect.left, rect.right );
93 if (rect.bottom < rect.top) SWAP_INT( rect.top, rect.bottom );
96 x = XLPTODP( dc, x );
97 y = YLPTODP( dc, y );
99 TRACE(text,"\treal coord: x=%i, y=%i, rect=(%d,%d - %d,%d)\n",
100 x, y, rect.left, rect.top, rect.right, rect.bottom);
102 /* Draw the rectangle */
104 if (flags & ETO_OPAQUE)
106 TSXSetForeground( display, physDev->gc, physDev->backgroundPixel );
107 TSXFillRectangle( display, physDev->drawable, physDev->gc,
108 dc->w.DCOrgX + rect.left, dc->w.DCOrgY + rect.top,
109 rect.right-rect.left, rect.bottom-rect.top );
111 if (!count) return TRUE; /* Nothing more to do */
113 /* Compute text starting position */
115 if (lpDx) /* have explicit character cell x offsets in logical coordinates */
117 int extra = dc->wndExtX / 2;
118 for (i = width = 0; i < count; i++) width += lpDx[i];
119 width = (width * dc->vportExtX + extra ) / dc->wndExtX;
121 else
123 SIZE32 sz;
124 if (!X11DRV_GetTextExtentPoint( dc, str, count, &sz ))
125 return FALSE;
126 width = XLSTODS(dc, sz.cx);
128 ascent = pfo->lpX11Trans ? pfo->lpX11Trans->ascent : font->ascent;
129 descent = pfo->lpX11Trans ? pfo->lpX11Trans->descent : font->descent;
130 xwidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->a /
131 pfo->lpX11Trans->pixelsize : width;
132 ywidth = pfo->lpX11Trans ? width * pfo->lpX11Trans->b /
133 pfo->lpX11Trans->pixelsize : 0;
135 switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
137 case TA_LEFT:
138 if (dc->w.textAlign & TA_UPDATECP) {
139 dc->w.CursPosX = XDPTOLP( dc, x + xwidth );
140 dc->w.CursPosY = YDPTOLP( dc, y - ywidth );
142 break;
143 case TA_RIGHT:
144 x -= xwidth;
145 y += ywidth;
146 if (dc->w.textAlign & TA_UPDATECP) {
147 dc->w.CursPosX = XDPTOLP( dc, x );
148 dc->w.CursPosY = YDPTOLP( dc, y );
150 break;
151 case TA_CENTER:
152 x -= xwidth / 2;
153 y += ywidth / 2;
154 break;
157 switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
159 case TA_TOP:
160 x -= pfo->lpX11Trans ? ascent * pfo->lpX11Trans->c /
161 pfo->lpX11Trans->pixelsize : 0;
162 y += pfo->lpX11Trans ? ascent * pfo->lpX11Trans->d /
163 pfo->lpX11Trans->pixelsize : ascent;
164 break;
165 case TA_BOTTOM:
166 x += pfo->lpX11Trans ? descent * pfo->lpX11Trans->c /
167 pfo->lpX11Trans->pixelsize : 0;
168 y -= pfo->lpX11Trans ? descent * pfo->lpX11Trans->d /
169 pfo->lpX11Trans->pixelsize : descent;
170 break;
171 case TA_BASELINE:
172 break;
175 /* Set the clip region */
177 if (flags & ETO_CLIPPED)
179 SaveVisRgn( dc->hSelf );
180 CLIPPING_IntersectVisRect( dc, rect.left, rect.top, rect.right,
181 rect.bottom, FALSE );
184 /* Draw the text background if necessary */
186 if (dc->w.backgroundMode != TRANSPARENT)
188 /* If rectangle is opaque and clipped, do nothing */
189 if (!(flags & ETO_CLIPPED) || !(flags & ETO_OPAQUE))
191 /* Only draw if rectangle is not opaque or if some */
192 /* text is outside the rectangle */
193 if (!(flags & ETO_OPAQUE) ||
194 (x < rect.left) ||
195 (x + width >= rect.right) ||
196 (y - ascent < rect.top) ||
197 (y + descent >= rect.bottom))
199 TSXSetForeground( display, physDev->gc,
200 physDev->backgroundPixel );
201 TSXFillRectangle( display, physDev->drawable, physDev->gc,
202 dc->w.DCOrgX + x,
203 dc->w.DCOrgY + y - ascent,
204 width,
205 ascent + descent );
210 /* Draw the text (count > 0 verified) */
212 TSXSetForeground( display, physDev->gc, physDev->textPixel );
213 if(!rotated)
215 if (!dc->w.charExtra && !dc->w.breakExtra && !lpDx)
217 TSXDrawString( display, physDev->drawable, physDev->gc,
218 dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count );
220 else /* Now the fun begins... */
222 XTextItem *items, *pitem;
223 int delta;
225 /* allocate max items */
227 pitem = items = HEAP_xalloc( GetProcessHeap(), 0,
228 count * sizeof(XTextItem) );
229 delta = i = 0;
230 if( lpDx ) /* explicit character widths */
232 int extra = dc->wndExtX / 2;
234 while (i < count)
236 /* initialize text item with accumulated delta */
238 pitem->chars = (char *)str + i;
239 pitem->delta = delta;
240 pitem->nchars = 0;
241 pitem->font = None;
242 delta = 0;
244 /* add characters to the same XTextItem until new delta
245 * becomes non-zero */
249 delta += (lpDx[i] * dc->vportExtX + extra) / dc->wndExtX
250 - TSXTextWidth( font, str + i, 1);
251 pitem->nchars++;
252 } while ((++i < count) && !delta);
253 pitem++;
256 else /* charExtra or breakExtra */
258 while (i < count)
260 pitem->chars = (char *)str + i;
261 pitem->delta = delta;
262 pitem->nchars = 0;
263 pitem->font = None;
264 delta = 0;
268 delta += dc->w.charExtra;
269 if (str[i] == (char)dfBreakChar) delta += dc->w.breakExtra;
270 pitem->nchars++;
271 } while ((++i < count) && !delta);
272 pitem++;
276 TSXDrawText( display, physDev->drawable, physDev->gc,
277 dc->w.DCOrgX + x, dc->w.DCOrgY + y, items, pitem - items );
278 HeapFree( GetProcessHeap(), 0, items );
281 else /* rotated */
283 /* have to render character by character. */
284 double offset = 0.0;
285 int i;
287 for (i=0; i<count; i++)
289 int char_metric_offset = (unsigned char) str[i]
290 - font->min_char_or_byte2;
291 int x_i = IROUND((double) (dc->w.DCOrgX + x) + offset *
292 pfo->lpX11Trans->a / pfo->lpX11Trans->pixelsize );
293 int y_i = IROUND((double) (dc->w.DCOrgY + y) - offset *
294 pfo->lpX11Trans->b / pfo->lpX11Trans->pixelsize );
296 TSXDrawString( display, physDev->drawable, physDev->gc,
297 x_i, y_i, &str[i], 1);
298 if (lpDx)
299 offset += XLSTODS(dc, lpDx[i]);
300 else
302 offset += (double) (font->per_char ?
303 font->per_char[char_metric_offset].attributes:
304 font->min_bounds.attributes)
305 * pfo->lpX11Trans->pixelsize / 1000.0;
306 offset += dc->w.charExtra;
307 if (str[i] == (char)dfBreakChar)
308 offset += dc->w.breakExtra;
313 /* Draw underline and strike-out if needed */
315 if (lfUnderline)
317 long linePos, lineWidth;
319 if (!TSXGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
320 linePos = descent - 1;
321 if (!TSXGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
322 lineWidth = 0;
323 else if (lineWidth == 1) lineWidth = 0;
324 TSXSetLineAttributes( display, physDev->gc, lineWidth,
325 LineSolid, CapRound, JoinBevel );
326 TSXDrawLine( display, physDev->drawable, physDev->gc,
327 dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos,
328 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y + linePos );
330 if (lfStrikeOut)
332 long lineAscent, lineDescent;
333 if (!TSXGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
334 lineAscent = ascent / 2;
335 if (!TSXGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
336 lineDescent = -lineAscent * 2 / 3;
337 TSXSetLineAttributes( display, physDev->gc, lineAscent + lineDescent,
338 LineSolid, CapRound, JoinBevel );
339 TSXDrawLine( display, physDev->drawable, physDev->gc,
340 dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent,
341 dc->w.DCOrgX + x + width, dc->w.DCOrgY + y - lineAscent );
344 if (flags & ETO_CLIPPED)
345 RestoreVisRgn( dc->hSelf );
347 return TRUE;