Release 0.6
[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
11 #include "gdi.h"
12
13 #define TAB     9
14 #define LF     10
15 #define CR     13
16 #define SPACE  32
17 #define PREFIX 38
18
19 static int tabstop = 8;
20 static int tabwidth;
21 static int spacewidth;
22 static int prefix_offset;
23
24
25 static char *TEXT_NextLine(HDC hdc, char *str, int *count, char *dest, 
26                            int *len, int width, WORD format)
27 {
28     /* Return next line of text from a string.
29      * 
30      * hdc - handle to DC.
31      * str - string to parse into lines.
32      * count - length of str.
33      * dest - destination in which to return line.
34      * len - length of resultant line in dest in chars.
35      * width - maximum width of line in pixels.
36      * format - format type passed to DrawText.
37      *
38      * Returns pointer to next char in str after end of the line
39      * or NULL if end of str reached.
40      */
41
42     int i = 0, j = 0, k;
43     int plen = 0;
44     int numspaces;
45     SIZE size;
46     int lasttab = 0;
47     int wb_i = 0, wb_j = 0, wb_count;
48
49     while (*count)
50     {
51         switch (str[i])
52         {
53         case CR:
54         case LF:
55             if (!(format & DT_SINGLELINE))
56             {
57                 i++;
58                 if (str[i] == CR || str[i] == LF)
59                     i++;
60                 *len = j;
61                 return (&str[i]);
62             }
63             dest[j++] = str[i++];
64             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
65             {
66                 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
67                     return NULL;
68                 plen += size.cx;
69             }
70             break;
71
72         case PREFIX:
73             if (!(format & DT_NOPREFIX))
74             {
75                 prefix_offset = j + 1;
76                 i++;
77             }
78             else
79             {
80                 dest[j++] = str[i++];
81                 if (!(format & DT_NOCLIP))
82                 {
83                     if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
84                         return NULL;
85                     plen += size.cx;
86                 }
87             }
88             break;
89
90         case TAB:
91             if (format & DT_EXPANDTABS)
92             {
93                 wb_i = ++i;
94                 wb_j = j;
95                 wb_count = *count;
96
97                 if (!GetTextExtentPoint(hdc, &dest[lasttab], j - lasttab,
98                                                                  &size))
99                     return NULL;
100
101                 numspaces = (tabwidth - size.cx) / spacewidth;
102                 for (k = 0; k < numspaces; k++)
103                     dest[j++] = SPACE;
104                 plen += tabwidth - size.cx;
105                 lasttab = wb_j + numspaces;
106             }
107             else
108             {
109                 dest[j++] = str[i++];
110                 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
111                 {
112                     if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
113                         return NULL;
114                     plen += size.cx;
115                 }
116             }
117             break;
118
119         case SPACE:
120             dest[j++] = str[i++];
121             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
122             {
123                 wb_i = i;
124                 wb_j = j - 1;
125                 wb_count = *count;
126                 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
127                     return NULL;
128                 plen += size.cx;
129             }
130             break;
131
132         default:
133             dest[j++] = str[i++];
134             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX))
135             {
136                 if (!GetTextExtentPoint(hdc, &dest[j-1], 1, &size))
137                     return NULL;
138                 plen += size.cx;
139             }
140         }
141
142         (*count)--;
143         if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
144         {
145             if (plen > width)
146             {
147                 if (format & DT_WORDBREAK)
148                 {
149                     *len = wb_j;
150                     *count = wb_count;
151                     return (&str[wb_i]);
152                 }
153                 else
154                 {
155                     *len = j;
156                     return (&str[i]);
157                 }
158             }
159         }
160     }
161     
162     *len = j;
163     return NULL;
164 }
165
166
167 /***********************************************************************
168  *           DrawText    (USER.85)
169  */
170 int DrawText( HDC hdc, LPSTR str, int count, LPRECT rect, WORD flags )
171 {
172     SIZE size;
173     char *strPtr;
174     static char line[1024];
175     int len, lh, prefix_x, prefix_len;
176     TEXTMETRIC tm;
177     int x = rect->left, y = rect->top;
178     int width = rect->right - rect->left;
179
180     if (count == -1) count = strlen(str);
181     strPtr = str;
182
183     GetTextMetrics(hdc, &tm);
184     if (flags & DT_EXTERNALLEADING)
185         lh = tm.tmHeight + tm.tmExternalLeading;
186     else
187         lh = tm.tmHeight;
188
189     if (flags & DT_TABSTOP)
190         tabstop = flags >> 8;
191
192     if (flags & DT_EXPANDTABS)
193     {
194         GetTextExtentPoint(hdc, " ", 1, &size);
195         spacewidth = size.cx;
196         GetTextExtentPoint(hdc, "o", 1, &size);
197         tabwidth = size.cx * tabstop;
198     }
199
200     do
201     {
202         prefix_offset = -1;
203         strPtr = TEXT_NextLine(hdc, strPtr, &count, line, &len, width, flags);
204
205         if (prefix_offset != -1)
206         {
207             GetTextExtentPoint(hdc, line, prefix_offset - 1, &size);
208             prefix_x = size.cx;
209             GetTextExtentPoint(hdc, line + prefix_offset, 1, &size);
210             prefix_len = size.cx;
211         }
212
213         if (!GetTextExtentPoint(hdc, line, len, &size)) return 0;
214         if (flags & DT_CENTER) x = (rect->left + rect->right -
215                                     size.cx) / 2;
216         else if (flags & DT_RIGHT) x = rect->right - size.cx;
217
218         if (flags & DT_SINGLELINE)
219         {
220             if (flags & DT_VCENTER) y = rect->top + 
221                 (rect->bottom - rect->top) / 2 - size.cy / 2;
222             else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
223         }
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) return FALSE;
260     if (!DC_SetupGCForText( dc )) return TRUE;
261     font = dc->u.x.font.fstruct;
262
263     if (dc->w.textAlign & TA_UPDATECP)
264     {
265         x = dc->w.CursPosX;
266         y = dc->w.CursPosY;
267     }
268 #ifdef DEBUG_TEXT
269     printf( "TextOut: %d,%d '%s'\n", x, y, str );
270 #endif
271     x = XLPTODP( dc, x );
272     y = YLPTODP( dc, y );
273
274     XTextExtents( font, str, count, &dir, &ascent, &descent, &info );
275     info.width += count*dc->w.charExtra + dc->w.breakExtra*dc->w.breakCount;
276
277       /* Compute starting position */
278
279     switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
280     {
281       case TA_LEFT:
282           if (dc->w.textAlign & TA_UPDATECP)
283               dc->w.CursPosX = XDPTOLP( dc, x + info.width );
284           break;
285       case TA_RIGHT:
286           x -= info.width;
287           if (dc->w.textAlign & TA_UPDATECP) dc->w.CursPosX = XDPTOLP( dc, x );
288           break;
289       case TA_CENTER:
290           x -= info.width / 2;
291           break;
292     }
293     switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
294     {
295       case TA_TOP:
296           y += font->ascent;
297           break;
298       case TA_BOTTOM:
299           y -= font->descent;
300           break;
301       case TA_BASELINE:
302           break;
303     }
304
305       /* Draw text */
306
307     if (!dc->w.charExtra && !dc->w.breakExtra)
308     {
309         if (dc->w.backgroundMode == TRANSPARENT)
310             XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc, 
311                          dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count );
312         else
313             XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc,
314                               dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count );
315     }
316     else
317     {
318         char * p = str;
319         int xchar = x;
320         for (i = 0; i < count; i++, p++)
321         {
322             XCharStruct * charStr;
323             unsigned char ch = *p;
324             int extraWidth;
325             
326             if ((ch < font->min_char_or_byte2)||(ch > font->max_char_or_byte2))
327                 ch = font->default_char;
328             if (!font->per_char) charStr = &font->min_bounds;
329             else charStr = font->per_char + ch - font->min_char_or_byte2;
330
331             extraWidth = dc->w.charExtra;
332             if (ch == dc->u.x.font.metrics.tmBreakChar)
333                 extraWidth += dc->w.breakExtra;
334
335             if (dc->w.backgroundMode == TRANSPARENT)
336                 XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc,
337                              dc->w.DCOrgX + xchar, dc->w.DCOrgY + y, p, 1 );
338             else
339             {
340                 XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc,
341                                   dc->w.DCOrgX + xchar, dc->w.DCOrgY + y, p, 1 );
342                 XSetForeground( XT_display, dc->u.x.gc, dc->w.backgroundPixel);
343                 XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc,
344                                 dc->w.DCOrgX + xchar + charStr->width,
345                                 dc->w.DCOrgY + y - font->ascent,
346                                 extraWidth, font->ascent + font->descent );
347                 XSetForeground( XT_display, dc->u.x.gc, dc->w.textPixel );
348             }
349             xchar += charStr->width + extraWidth;
350         }
351     }
352
353       /* Draw underline and strike-out if needed */
354
355     if (dc->u.x.font.metrics.tmUnderlined)
356     {
357         long linePos, lineWidth;       
358         if (!XGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
359             linePos = font->descent-1;
360         if (!XGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
361             lineWidth = 0;
362         else if (lineWidth == 1) lineWidth = 0;
363         XSetLineAttributes( XT_display, dc->u.x.gc, lineWidth,
364                             LineSolid, CapRound, JoinBevel ); 
365         XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc,
366                    dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos,
367                    dc->w.DCOrgX + x + info.width, dc->w.DCOrgY + y + linePos );
368     }
369     if (dc->u.x.font.metrics.tmStruckOut)
370     {
371         long lineAscent, lineDescent;
372         if (!XGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
373             lineAscent = font->ascent / 3;
374         if (!XGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
375             lineDescent = -lineAscent;
376         XSetLineAttributes( XT_display, dc->u.x.gc, lineAscent + lineDescent,
377                             LineSolid, CapRound, JoinBevel ); 
378         XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc,
379                    dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent,
380                    dc->w.DCOrgX + x + info.width, dc->w.DCOrgY + y - lineAscent );
381     }
382     
383     return TRUE;
384 }