Release 940524
[wine] / objects / text.c
1 /*
2  * text functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
8
9 #include <X11/Xatom.h>
10 #include "windows.h"
11 #include "gdi.h"
12 #include "metafile.h"
13
14 #define TAB     9
15 #define LF     10
16 #define CR     13
17 #define SPACE  32
18 #define PREFIX 38
19
20 static int tabstop = 8;
21 static int tabwidth;
22 static int spacewidth;
23 static int prefix_offset;
24
25
26 static char *TEXT_NextLine(HDC hdc, char *str, int *count, char *dest, 
27                            int *len, int width, WORD format)
28 {
29     /* Return next line of text from a string.
30      * 
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.
38      *
39      * Returns pointer to next char in str after end of the line
40      * or NULL if end of str reached.
41      */
42
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;
49
50     while (*count)
51     {
52         switch (str[i])
53         {
54         case CR:
55         case LF:
56             if (!(format & DT_SINGLELINE))
57             {
58                 i++;
59                 if (str[i] == CR || str[i] == LF)
60                     i++;
61                 *len = j;
62                 return (&str[i]);
63             }
64             dest[j++] = str[i++];
65             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
66             {
67                 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
68                     return NULL;
69                 plen += size.cx;
70             }
71             break;
72
73         case PREFIX:
74             if (!(format & DT_NOPREFIX))
75             {
76                 prefix_offset = j + 1;
77                 i++;
78             }
79             else
80             {
81                 dest[j++] = str[i++];
82                 if (!(format & DT_NOCLIP))
83                 {
84                     if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
85                         return NULL;
86                     plen += size.cx;
87                 }
88             }
89             break;
90
91         case TAB:
92             if (format & DT_EXPANDTABS)
93             {
94                 wb_i = ++i;
95                 wb_j = j;
96                 wb_count = *count;
97
98                 if (!GetTextExtentPoint(hdc, &dest[lasttab], j - lasttab,
99                                                                  &size))
100                     return NULL;
101
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;
107             }
108             else
109             {
110                 dest[j++] = str[i++];
111                 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
112                 {
113                     if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
114                         return NULL;
115                     plen += size.cx;
116                 }
117             }
118             break;
119
120         case SPACE:
121             dest[j++] = str[i++];
122             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
123             {
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;
130             }
131             break;
132
133         default:
134             dest[j++] = str[i++];
135             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
136             {
137                 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
138                     return NULL;
139                 plen += size.cx;
140             }
141         }
142
143         (*count)--;
144         if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
145         {
146             if (plen > width)
147             {
148                 if (format & DT_WORDBREAK)
149                 {
150                     *len = wb_j;
151                     *count = wb_count;
152                     return (&str[wb_i]);
153                 }
154                 else
155                 {
156                     *len = j;
157                     return (&str[i]);
158                 }
159             }
160         }
161     }
162     
163     *len = j;
164     return NULL;
165 }
166
167
168 /***********************************************************************
169  *           DrawText    (USER.85)
170  */
171 int DrawText( HDC hdc, LPSTR str, int count, LPRECT rect, WORD flags )
172 {
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;
180
181     if (count == -1) count = strlen(str);
182     strPtr = str;
183
184     GetTextMetrics(hdc, &tm);
185     if (flags & DT_EXTERNALLEADING)
186         lh = tm.tmHeight + tm.tmExternalLeading;
187     else
188         lh = tm.tmHeight;
189
190     if (flags & DT_TABSTOP)
191         tabstop = flags >> 8;
192
193     if (flags & DT_EXPANDTABS)
194     {
195         GetTextExtentPoint(hdc, " ", 1, &size);
196         spacewidth = size.cx;
197         GetTextExtentPoint(hdc, "o", 1, &size);
198         tabwidth = size.cx * tabstop;
199     }
200
201     do
202     {
203         prefix_offset = -1;
204         strPtr = TEXT_NextLine(hdc, strPtr, &count, line, &len, width, flags);
205
206         if (prefix_offset != -1)
207         {
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;
212         }
213
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;
218
219         if (flags & DT_SINGLELINE)
220         {
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;
224         }
225         if (!(flags & DT_CALCRECT))
226             if (!TextOut(hdc, x, y, line, len)) return 0;
227         if (prefix_offset != -1)
228         {
229             MoveTo(hdc, x + prefix_x, y + size.cy);
230             LineTo(hdc, x + prefix_x + prefix_len, y + size.cy);
231         }
232
233         if (strPtr)
234         {
235             y += lh;
236             if (!(flags & DT_NOCLIP))
237             {
238                 if (y > rect->bottom - lh)
239                     break;
240             }
241         }
242     }
243     while (strPtr);
244     if (flags & DT_CALCRECT) rect->bottom = y;
245     return 1;
246 }
247
248
249 /***********************************************************************
250  *           TextOut    (GDI.33)
251  */
252 BOOL TextOut( HDC hdc, short x, short y, LPSTR str, short count )
253 {
254     int dir, ascent, descent, i;
255     XCharStruct info;
256     XFontStruct *font;
257
258     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
259     if (!dc) 
260     {
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;
265     }
266
267     if (!DC_SetupGCForText( dc )) return TRUE;
268     font = dc->u.x.font.fstruct;
269
270     if (dc->w.textAlign & TA_UPDATECP)
271     {
272         x = dc->w.CursPosX;
273         y = dc->w.CursPosY;
274     }
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 );
280
281     XTextExtents( font, str, count, &dir, &ascent, &descent, &info );
282     info.width += count*dc->w.charExtra + dc->w.breakExtra*dc->w.breakCount;
283
284       /* Compute starting position */
285
286     switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
287     {
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;
299     }
300     switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
301     {
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;
310     }
311
312       /* Draw text */
313
314     if (!dc->w.charExtra && !dc->w.breakExtra)
315     {
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 );
322     }
323     else
324     {
325         char * p = str;
326         int xchar = x;
327         for (i = 0; i < count; i++, p++)
328         {
329             XCharStruct * charStr;
330             unsigned char ch = *p;
331             int extraWidth;
332             
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;
337
338             extraWidth = dc->w.charExtra;
339             if (ch == dc->u.x.font.metrics.tmBreakChar)
340                 extraWidth += dc->w.breakExtra;
341
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
346             {
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 );
355             }
356             xchar += charStr->width + extraWidth;
357         }
358     }
359
360       /* Draw underline and strike-out if needed */
361
362     if (dc->u.x.font.metrics.tmUnderlined)
363     {
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 );
375     }
376     if (dc->u.x.font.metrics.tmStruckOut)
377     {
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 );
388     }
389     
390     return TRUE;
391 }
392
393 /***********************************************************************
394  *              GrayString (USER.185)
395  */
396 BOOL GrayString(HDC hdc, HBRUSH hbr, FARPROC gsprc, LPARAM lParam, 
397                 INT cch, INT x, INT y, INT cx, INT cy)
398 {
399         int s, current_color;
400
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);
410                 
411                 return s;
412         }
413 }
414
415 /***********************************************************************
416  *                      ExtTextOut                      [GDI.351]
417  */
418 BOOL ExtTextOut(HDC hDC, short x, short y, WORD wOptions, LPRECT lprect,
419                         LPSTR str, WORD count, LPINT lpDx)
420 {
421         printf("EMPTY STUB !!! ExtTextOut(); ! call TextOut() for now !\n");
422         TextOut(hDC, x, y, str, count);
423         return FALSE;
424 }
425
426
427