Release 940518
[wine/multimedia.git] / objects / text.c
blob0d9690b8bd3fa5921c7925b9c6ee5e1eef1e5ab5
1 /*
2 * text functions
4 * Copyright 1993 Alexandre Julliard
5 */
7 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
9 #include <X11/Xatom.h>
10 #include "windows.h"
11 #include "gdi.h"
12 #include "metafile.h"
14 #define TAB 9
15 #define LF 10
16 #define CR 13
17 #define SPACE 32
18 #define PREFIX 38
20 static int tabstop = 8;
21 static int tabwidth;
22 static int spacewidth;
23 static int prefix_offset;
26 static char *TEXT_NextLine(HDC hdc, char *str, int *count, char *dest,
27 int *len, int width, WORD format)
29 /* Return next line of text from a string.
31 * hdc - handle to DC.
32 * str - string to parse into lines.
33 * count - length of str.
34 * dest - destination in which to return line.
35 * len - length of resultant line in dest in chars.
36 * width - maximum width of line in pixels.
37 * format - format type passed to DrawText.
39 * Returns pointer to next char in str after end of the line
40 * or NULL if end of str reached.
43 int i = 0, j = 0, k;
44 int plen = 0;
45 int numspaces;
46 SIZE size;
47 int lasttab = 0;
48 int wb_i = 0, wb_j = 0, wb_count;
50 while (*count)
52 switch (str[i])
54 case CR:
55 case LF:
56 if (!(format & DT_SINGLELINE))
58 i++;
59 if (str[i] == CR || str[i] == LF)
60 i++;
61 *len = j;
62 return (&str[i]);
64 dest[j++] = str[i++];
65 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
67 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
68 return NULL;
69 plen += size.cx;
71 break;
73 case PREFIX:
74 if (!(format & DT_NOPREFIX))
76 prefix_offset = j + 1;
77 i++;
79 else
81 dest[j++] = str[i++];
82 if (!(format & DT_NOCLIP))
84 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
85 return NULL;
86 plen += size.cx;
89 break;
91 case TAB:
92 if (format & DT_EXPANDTABS)
94 wb_i = ++i;
95 wb_j = j;
96 wb_count = *count;
98 if (!GetTextExtentPoint(hdc, &dest[lasttab], j - lasttab,
99 &size))
100 return NULL;
102 numspaces = (tabwidth - size.cx) / spacewidth;
103 for (k = 0; k < numspaces; k++)
104 dest[j++] = SPACE;
105 plen += tabwidth - size.cx;
106 lasttab = wb_j + numspaces;
108 else
110 dest[j++] = str[i++];
111 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
113 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
114 return NULL;
115 plen += size.cx;
118 break;
120 case SPACE:
121 dest[j++] = str[i++];
122 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
124 wb_i = i;
125 wb_j = j - 1;
126 wb_count = *count;
127 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
128 return NULL;
129 plen += size.cx;
131 break;
133 default:
134 dest[j++] = str[i++];
135 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
137 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
138 return NULL;
139 plen += size.cx;
143 (*count)--;
144 if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
146 if (plen > width)
148 if (format & DT_WORDBREAK)
150 *len = wb_j;
151 *count = wb_count;
152 return (&str[wb_i]);
154 else
156 *len = j;
157 return (&str[i]);
163 *len = j;
164 return NULL;
168 /***********************************************************************
169 * DrawText (USER.85)
171 int DrawText( HDC hdc, LPSTR str, int count, LPRECT rect, WORD flags )
173 SIZE size;
174 char *strPtr;
175 static char line[1024];
176 int len, lh, prefix_x, prefix_len;
177 TEXTMETRIC tm;
178 int x = rect->left, y = rect->top;
179 int width = rect->right - rect->left;
181 if (count == -1) count = strlen(str);
182 strPtr = str;
184 GetTextMetrics(hdc, &tm);
185 if (flags & DT_EXTERNALLEADING)
186 lh = tm.tmHeight + tm.tmExternalLeading;
187 else
188 lh = tm.tmHeight;
190 if (flags & DT_TABSTOP)
191 tabstop = flags >> 8;
193 if (flags & DT_EXPANDTABS)
195 GetTextExtentPoint(hdc, " ", 1, &size);
196 spacewidth = size.cx;
197 GetTextExtentPoint(hdc, "o", 1, &size);
198 tabwidth = size.cx * tabstop;
203 prefix_offset = -1;
204 strPtr = TEXT_NextLine(hdc, strPtr, &count, line, &len, width, flags);
206 if (prefix_offset != -1)
208 GetTextExtentPoint(hdc, line, prefix_offset - 1, &size);
209 prefix_x = size.cx;
210 GetTextExtentPoint(hdc, line + prefix_offset, 1, &size);
211 prefix_len = size.cx;
214 if (!GetTextExtentPoint(hdc, line, len, &size)) return 0;
215 if (flags & DT_CENTER) x = (rect->left + rect->right -
216 size.cx) / 2;
217 else if (flags & DT_RIGHT) x = rect->right - size.cx;
219 if (flags & DT_SINGLELINE)
221 if (flags & DT_VCENTER) y = rect->top +
222 (rect->bottom - rect->top) / 2 - size.cy / 2;
223 else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
225 if (!(flags & DT_CALCRECT))
226 if (!TextOut(hdc, x, y, line, len)) return 0;
227 if (prefix_offset != -1)
229 MoveTo(hdc, x + prefix_x, y + size.cy);
230 LineTo(hdc, x + prefix_x + prefix_len, y + size.cy);
233 if (strPtr)
235 y += lh;
236 if (!(flags & DT_NOCLIP))
238 if (y > rect->bottom - lh)
239 break;
243 while (strPtr);
244 if (flags & DT_CALCRECT) rect->bottom = y;
245 return 1;
249 /***********************************************************************
250 * TextOut (GDI.33)
252 BOOL TextOut( HDC hdc, short x, short y, LPSTR str, short count )
254 int dir, ascent, descent, i;
255 XCharStruct info;
256 XFontStruct *font;
258 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
259 if (!dc)
261 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
262 if (!dc) return FALSE;
263 MF_TextOut(dc, x, y, str, count);
264 return TRUE;
267 if (!DC_SetupGCForText( dc )) return TRUE;
268 font = dc->u.x.font.fstruct;
270 if (dc->w.textAlign & TA_UPDATECP)
272 x = dc->w.CursPosX;
273 y = dc->w.CursPosY;
275 #ifdef DEBUG_TEXT
276 printf( "TextOut: %d,%d '%s', %d\n", x, y, str, count );
277 #endif
278 x = XLPTODP( dc, x );
279 y = YLPTODP( dc, y );
281 XTextExtents( font, str, count, &dir, &ascent, &descent, &info );
282 info.width += count*dc->w.charExtra + dc->w.breakExtra*dc->w.breakCount;
284 /* Compute starting position */
286 switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
288 case TA_LEFT:
289 if (dc->w.textAlign & TA_UPDATECP)
290 dc->w.CursPosX = XDPTOLP( dc, x + info.width );
291 break;
292 case TA_RIGHT:
293 x -= info.width;
294 if (dc->w.textAlign & TA_UPDATECP) dc->w.CursPosX = XDPTOLP( dc, x );
295 break;
296 case TA_CENTER:
297 x -= info.width / 2;
298 break;
300 switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
302 case TA_TOP:
303 y += font->ascent;
304 break;
305 case TA_BOTTOM:
306 y -= font->descent;
307 break;
308 case TA_BASELINE:
309 break;
312 /* Draw text */
314 if (!dc->w.charExtra && !dc->w.breakExtra)
316 if (dc->w.backgroundMode == TRANSPARENT)
317 XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc,
318 dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count );
319 else
320 XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc,
321 dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count );
323 else
325 char * p = str;
326 int xchar = x;
327 for (i = 0; i < count; i++, p++)
329 XCharStruct * charStr;
330 unsigned char ch = *p;
331 int extraWidth;
333 if ((ch < font->min_char_or_byte2)||(ch > font->max_char_or_byte2))
334 ch = font->default_char;
335 if (!font->per_char) charStr = &font->min_bounds;
336 else charStr = font->per_char + ch - font->min_char_or_byte2;
338 extraWidth = dc->w.charExtra;
339 if (ch == dc->u.x.font.metrics.tmBreakChar)
340 extraWidth += dc->w.breakExtra;
342 if (dc->w.backgroundMode == TRANSPARENT)
343 XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc,
344 dc->w.DCOrgX + xchar, dc->w.DCOrgY + y, p, 1 );
345 else
347 XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc,
348 dc->w.DCOrgX + xchar, dc->w.DCOrgY + y, p, 1 );
349 XSetForeground( XT_display, dc->u.x.gc, dc->w.backgroundPixel);
350 XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc,
351 dc->w.DCOrgX + xchar + charStr->width,
352 dc->w.DCOrgY + y - font->ascent,
353 extraWidth, font->ascent + font->descent );
354 XSetForeground( XT_display, dc->u.x.gc, dc->w.textPixel );
356 xchar += charStr->width + extraWidth;
360 /* Draw underline and strike-out if needed */
362 if (dc->u.x.font.metrics.tmUnderlined)
364 long linePos, lineWidth;
365 if (!XGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
366 linePos = font->descent-1;
367 if (!XGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
368 lineWidth = 0;
369 else if (lineWidth == 1) lineWidth = 0;
370 XSetLineAttributes( XT_display, dc->u.x.gc, lineWidth,
371 LineSolid, CapRound, JoinBevel );
372 XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc,
373 dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos,
374 dc->w.DCOrgX + x + info.width, dc->w.DCOrgY + y + linePos );
376 if (dc->u.x.font.metrics.tmStruckOut)
378 long lineAscent, lineDescent;
379 if (!XGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
380 lineAscent = font->ascent / 3;
381 if (!XGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
382 lineDescent = -lineAscent;
383 XSetLineAttributes( XT_display, dc->u.x.gc, lineAscent + lineDescent,
384 LineSolid, CapRound, JoinBevel );
385 XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc,
386 dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent,
387 dc->w.DCOrgX + x + info.width, dc->w.DCOrgY + y - lineAscent );
390 return TRUE;
393 /***********************************************************************
394 * GrayString (USER.185)
396 BOOL GrayString(HDC hdc, HBRUSH hbr, FARPROC gsprc, LPARAM lParam,
397 INT cch, INT x, INT y, INT cx, INT cy)
399 int s, current_color;
401 if (gsprc) {
402 return CallGrayStringProc(gsprc, hdc, lParam,
403 cch ? cch : lstrlen((LPCSTR) lParam) );
404 } else {
405 current_color = GetTextColor(hdc);
406 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT) );
407 s = TextOut(hdc, x, y, (LPSTR) lParam,
408 cch ? cch : lstrlen((LPCSTR) lParam) );
409 SetTextColor(hdc, current_color);
411 return s;
415 /***********************************************************************
416 * ExtTextOut [GDI.351]
418 BOOL ExtTextOut(HDC hDC, short x, short y, WORD wOptions, LPRECT lprect,
419 LPSTR str, WORD count, LPINT lpDx)
421 printf("EMPTY STUB !!! ExtTextOut(); ! (call TextOut() for new)\n");
422 TextOut(hDC, x, y, str, count);
423 return FALSE;