Release 971116
[wine] / objects / text.c
1 /*
2  * text functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  */
7
8 #include <stdlib.h>
9 #include "windows.h"
10 #include "dc.h"
11 #include "gdi.h"
12 #include "heap.h"
13 #include "stddebug.h"
14 /* #define DEBUG_TEXT */
15 #include "debug.h"
16
17 #define TAB     9
18 #define LF     10
19 #define CR     13
20 #define SPACE  32
21 #define PREFIX 38
22
23 #define SWAP_INT(a,b)  { int t = a; a = b; b = t; }
24
25 static int tabstop = 8;
26 static int tabwidth;
27 static int spacewidth;
28 static int prefix_offset;
29
30 static const char *TEXT_NextLine( HDC16 hdc, const char *str, int *count,
31                                   char *dest, int *len, int width, WORD format)
32 {
33     /* Return next line of text from a string.
34      * 
35      * hdc - handle to DC.
36      * str - string to parse into lines.
37      * count - length of str.
38      * dest - destination in which to return line.
39      * len - length of resultant line in dest in chars.
40      * width - maximum width of line in pixels.
41      * format - format type passed to DrawText.
42      *
43      * Returns pointer to next char in str after end of the line
44      * or NULL if end of str reached.
45      */
46
47     int i = 0, j = 0, k;
48     int plen = 0;
49     int numspaces;
50     SIZE16 size;
51     int lasttab = 0;
52     int wb_i = 0, wb_j = 0, wb_count = 0;
53
54     while (*count)
55     {
56         switch (str[i])
57         {
58         case CR:
59         case LF:
60             if (!(format & DT_SINGLELINE))
61             {
62                 if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF))
63                 {
64                     (*count)--;
65                     i++;
66                 }
67                 i++;
68                 *len = j;
69                 (*count)--;
70                 return (&str[i]);
71             }
72             dest[j++] = str[i++];
73             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
74                 (format & DT_WORDBREAK))
75             {
76                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
77                     return NULL;
78                 plen += size.cx;
79             }
80             break;
81             
82         case PREFIX:
83             if (!(format & DT_NOPREFIX) && *count > 1)
84                 {
85                 if (str[++i] == PREFIX)
86                     (*count)--;
87                 else {
88                     prefix_offset = j;
89                     break;
90                 }
91             }
92             dest[j++] = str[i++];
93             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
94                 (format & DT_WORDBREAK))
95             {
96                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
97                     return NULL;
98                 plen += size.cx;
99             }
100             break;
101             
102         case TAB:
103             if (format & DT_EXPANDTABS)
104             {
105                 wb_i = ++i;
106                 wb_j = j;
107                 wb_count = *count;
108
109                 if (!GetTextExtentPoint16(hdc, &dest[lasttab], j - lasttab,
110                                                                  &size))
111                     return NULL;
112
113                 numspaces = (tabwidth - size.cx) / spacewidth;
114                 for (k = 0; k < numspaces; k++)
115                     dest[j++] = SPACE;
116                 plen += tabwidth - size.cx;
117                 lasttab = wb_j + numspaces;
118             }
119             else
120             {
121                 dest[j++] = str[i++];
122                 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
123                     (format & DT_WORDBREAK))
124                 {
125                     if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
126                         return NULL;
127                     plen += size.cx;
128                 }
129             }
130             break;
131
132         case SPACE:
133             dest[j++] = str[i++];
134             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
135                 (format & DT_WORDBREAK))
136             {
137                 wb_i = i;
138                 wb_j = j - 1;
139                 wb_count = *count;
140                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
141                     return NULL;
142                 plen += size.cx;
143             }
144             break;
145
146         default:
147             dest[j++] = str[i++];
148             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
149                 (format & DT_WORDBREAK))
150             {
151                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
152                     return NULL;
153                 plen += size.cx;
154             }
155         }
156
157         (*count)--;
158         if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
159         {
160             if (plen > width)
161             {
162                 if (format & DT_WORDBREAK)
163                 {
164                     if (wb_j)
165                     {
166                         *len = wb_j;
167                         *count = wb_count - 1;
168                         return (&str[wb_i]);
169                     }
170                 }
171                 else
172                 {
173                     *len = j;
174                     return (&str[i]);
175                 }
176             }
177         }
178     }
179     
180     *len = j;
181     return NULL;
182 }
183
184
185 /***********************************************************************
186  *           DrawText16    (USER.85)
187  */
188 INT16 WINAPI DrawText16( HDC16 hdc, LPCSTR str, INT16 i_count,
189                          LPRECT16 rect, UINT16 flags )
190 {
191     SIZE16 size;
192     const char *strPtr;
193     static char line[1024];
194     int len, lh, count=i_count;
195     int prefix_x = 0;
196     int prefix_end = 0;
197     TEXTMETRIC16 tm;
198     int x = rect->left, y = rect->top;
199     int width = rect->right - rect->left;
200     int max_width = 0;
201
202     dprintf_text(stddeb,"DrawText: '%s', %d , [(%d,%d),(%d,%d)]\n", str,
203                  count, rect->left, rect->top, rect->right, rect->bottom);
204     
205     if (count == -1) count = strlen(str);
206     strPtr = str;
207
208     GetTextMetrics16(hdc, &tm);
209     if (flags & DT_EXTERNALLEADING)
210         lh = tm.tmHeight + tm.tmExternalLeading;
211     else
212         lh = tm.tmHeight;
213
214     if (flags & DT_TABSTOP)
215         tabstop = flags >> 8;
216
217     if (flags & DT_EXPANDTABS)
218     {
219         GetTextExtentPoint16(hdc, " ", 1, &size);
220         spacewidth = size.cx;
221         GetTextExtentPoint16(hdc, "o", 1, &size);
222         tabwidth = size.cx * tabstop;
223     }
224
225     if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
226
227     do
228     {
229         prefix_offset = -1;
230         strPtr = TEXT_NextLine(hdc, strPtr, &count, line, &len, width, flags);
231
232         if (prefix_offset != -1)
233         {
234             GetTextExtentPoint16(hdc, line, prefix_offset, &size);
235             prefix_x = size.cx;
236             GetTextExtentPoint16(hdc, line, prefix_offset + 1, &size);
237             prefix_end = size.cx - 1;
238         }
239
240         if (!GetTextExtentPoint16(hdc, line, len, &size)) return 0;
241         if (flags & DT_CENTER) x = (rect->left + rect->right -
242                                     size.cx) / 2;
243         else if (flags & DT_RIGHT) x = rect->right - size.cx;
244
245         if (flags & DT_SINGLELINE)
246         {
247             if (flags & DT_VCENTER) y = rect->top + 
248                 (rect->bottom - rect->top) / 2 - size.cy / 2;
249             else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
250         }
251         if (!(flags & DT_CALCRECT))
252         {
253             if (!ExtTextOut16(hdc, x, y, (flags & DT_NOCLIP) ? 0 : ETO_CLIPPED,
254                               rect, line, len, NULL )) return 0;
255             if (prefix_offset != -1)
256             {
257                 HPEN32 hpen = CreatePen32( PS_SOLID, 1, GetTextColor32(hdc) );
258                 HPEN32 oldPen = SelectObject32( hdc, hpen );
259                 MoveTo(hdc, x + prefix_x, y + tm.tmAscent + 1 );
260                 LineTo32(hdc, x + prefix_end + 1, y + tm.tmAscent + 1 );
261                 SelectObject32( hdc, oldPen );
262                 DeleteObject32( hpen );
263             }
264         }
265         else if (size.cx > max_width)
266             max_width = size.cx;
267
268         y += lh;
269         if (strPtr)
270         {
271             if (!(flags & DT_NOCLIP))
272             {
273                 if (y > rect->bottom - lh)
274                     break;
275             }
276         }
277     }
278     while (strPtr);
279     if (flags & DT_CALCRECT)
280     {
281         rect->right = rect->left + max_width;
282         rect->bottom = y;
283     }
284     return y - rect->top;
285 }
286
287
288 /***********************************************************************
289  *           DrawText32A    (USER32.163)
290  */
291 INT32 WINAPI DrawText32A( HDC32 hdc, LPCSTR str, INT32 count,
292                           LPRECT32 rect, UINT32 flags )
293 {
294     RECT16 rect16;
295     INT16 ret;
296
297     if (!rect)
298         return DrawText16( (HDC16)hdc, str, (INT16)count, NULL, (UINT16)flags);
299     CONV_RECT32TO16( rect, &rect16 );
300     ret = DrawText16( (HDC16)hdc, str, (INT16)count, &rect16, (UINT16)flags );
301     CONV_RECT16TO32( &rect16, rect );
302     return ret;
303 }
304
305
306 /***********************************************************************
307  *           DrawText32W    (USER32.166)
308  */
309 INT32 WINAPI DrawText32W( HDC32 hdc, LPCWSTR str, INT32 count,
310                           LPRECT32 rect, UINT32 flags )
311 {
312     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
313     INT32 ret = DrawText32A( hdc, p, count, rect, flags );
314     HeapFree( GetProcessHeap(), 0, p );
315     return ret;
316 }
317
318 /***********************************************************************
319  *           DrawTextEx32A    (USER32.164)
320  */
321 INT32 DrawTextEx32A( HDC32 hdc, LPCSTR str, INT32 count,
322                      LPRECT32 rect, UINT32 flags, LPDRAWTEXTPARAMS dtp )
323 {
324     fprintf(stderr,"DrawTextEx32A(%d,'%s',%d,%p,0x%08x,%p)\n",
325         hdc,str,count,rect,flags,dtp
326     );
327     /*FIXME: ignores extended functionality ... */
328     return DrawText32A(hdc,str,count,rect,flags);
329 }
330
331 /***********************************************************************
332  *           DrawTextEx32W    (USER32.165)
333  */
334 INT32 DrawTextEx32W( HDC32 hdc, LPCWSTR str, INT32 count,
335                      LPRECT32 rect, UINT32 flags, LPDRAWTEXTPARAMS dtp )
336 {
337     fprintf(stderr,"DrawTextEx32A(%d,%p,%d,%p,0x%08x,%p)\n",
338         hdc,str,count,rect,flags,dtp
339     );
340     /*FIXME: ignores extended functionality ... */
341     return DrawText32W(hdc,str,count,rect,flags);
342 }
343
344 /***********************************************************************
345  *           ExtTextOut16    (GDI.351)
346  */
347 BOOL16 WINAPI ExtTextOut16( HDC16 hdc, INT16 x, INT16 y, UINT16 flags,
348                             const RECT16 *lprect, LPCSTR str, UINT16 count,
349                             const INT16 *lpDx )
350 {
351     BOOL32      ret;
352     int         i;
353     RECT32      rect32;
354     LPINT32     lpdx32 = NULL;
355
356     if (lpDx) lpdx32 = (LPINT32)HEAP_xalloc( GetProcessHeap(), 0,
357                                              sizeof(INT32)*count );
358     if (lprect) CONV_RECT16TO32(lprect,&rect32);
359     if (lpdx32) for (i=count;i--;) lpdx32[i]=lpDx[i];
360     ret = ExtTextOut32A(hdc,x,y,flags,lprect?&rect32:NULL,str,count,lpdx32);
361     if (lpdx32) HeapFree( GetProcessHeap(), 0, lpdx32 );
362     return ret;
363
364
365 }
366
367
368 /***********************************************************************
369  *           ExtTextOut32A    (GDI32.98)
370  */
371 BOOL32 WINAPI ExtTextOut32A( HDC32 hdc, INT32 x, INT32 y, UINT32 flags,
372                              const RECT32 *lprect, LPCSTR str, UINT32 count,
373                              const INT32 *lpDx )
374 {
375     DC * dc = DC_GetDCPtr( hdc );
376     return dc && dc->funcs->pExtTextOut && 
377            dc->funcs->pExtTextOut(dc,x,y,flags,lprect,str,count,lpDx);
378 }
379
380
381 /***********************************************************************
382  *           ExtTextOut32W    (GDI32.99)
383  */
384 BOOL32 WINAPI ExtTextOut32W( HDC32 hdc, INT32 x, INT32 y, UINT32 flags,
385                              const RECT32 *lprect, LPCWSTR str, UINT32 count,
386                              const INT32 *lpDx )
387 {
388     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
389     INT32 ret = ExtTextOut32A( hdc, x, y, flags, lprect, p, count, lpDx );
390     HeapFree( GetProcessHeap(), 0, p );
391     return ret;
392 }
393
394
395 /***********************************************************************
396  *           TextOut16    (GDI.33)
397  */
398 BOOL16 WINAPI TextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR str, INT16 count )
399 {
400     return ExtTextOut16( hdc, x, y, 0, NULL, str, count, NULL );
401 }
402
403
404 /***********************************************************************
405  *           TextOut32A    (GDI32.355)
406  */
407 BOOL32 WINAPI TextOut32A( HDC32 hdc, INT32 x, INT32 y, LPCSTR str, INT32 count )
408 {
409     return ExtTextOut32A( hdc, x, y, 0, NULL, str, count, NULL );
410 }
411
412
413 /***********************************************************************
414  *           TextOut32W    (GDI32.356)
415  */
416 BOOL32 WINAPI TextOut32W(HDC32 hdc, INT32 x, INT32 y, LPCWSTR str, INT32 count)
417 {
418     return ExtTextOut32W( hdc, x, y, 0, NULL, str, count, NULL );
419 }
420
421
422 /***********************************************************************
423  *           GrayString16   (USER.185)
424  */
425 BOOL16 WINAPI GrayString16( HDC16 hdc, HBRUSH16 hbr, GRAYSTRINGPROC16 gsprc,
426                             LPARAM lParam, INT16 cch, INT16 x, INT16 y,
427                             INT16 cx, INT16 cy )
428 {
429     BOOL16 ret;
430     COLORREF current_color;
431
432     if (!cch) cch = lstrlen16( (LPCSTR)PTR_SEG_TO_LIN(lParam) );
433     if (gsprc) return gsprc( hdc, lParam, cch );
434     current_color = SetTextColor32( hdc, GetSysColor32(COLOR_GRAYTEXT) );
435     ret = TextOut16( hdc, x, y, (LPCSTR)PTR_SEG_TO_LIN(lParam), cch );
436     SetTextColor32( hdc, current_color );
437     return ret;
438 }
439
440
441 /***********************************************************************
442  *           GrayString32A   (USER32.314)
443  */
444 BOOL32 WINAPI GrayString32A( HDC32 hdc, HBRUSH32 hbr, GRAYSTRINGPROC32 gsprc,
445                              LPARAM lParam, INT32 cch, INT32 x, INT32 y,
446                              INT32 cx, INT32 cy )
447 {
448     BOOL32 ret;
449     COLORREF current_color;
450
451     if (!cch) cch = lstrlen32A( (LPCSTR)lParam );
452     if (gsprc) return gsprc( hdc, lParam, cch );
453     current_color = SetTextColor32( hdc, GetSysColor32(COLOR_GRAYTEXT) );
454     ret = TextOut32A( hdc, x, y, (LPCSTR)lParam, cch );
455     SetTextColor32( hdc, current_color );
456     return ret;
457 }
458
459
460 /***********************************************************************
461  *           GrayString32W   (USER32.315)
462  */
463 BOOL32 WINAPI GrayString32W( HDC32 hdc, HBRUSH32 hbr, GRAYSTRINGPROC32 gsprc,
464                              LPARAM lParam, INT32 cch, INT32 x, INT32 y,
465                              INT32 cx, INT32 cy )
466 {
467     BOOL32 ret;
468     COLORREF current_color;
469
470     if (!cch) cch = lstrlen32W( (LPCWSTR)lParam );
471     if (gsprc) return gsprc( hdc, lParam, cch );
472     current_color = SetTextColor32( hdc, GetSysColor32(COLOR_GRAYTEXT) );
473     ret = TextOut32W( hdc, x, y, (LPCWSTR)lParam, cch );
474     SetTextColor32( hdc, current_color );
475     return ret;
476 }
477
478
479 /***********************************************************************
480  *           TEXT_TabbedTextOut
481  *
482  * Helper function for TabbedTextOut() and GetTabbedTextExtent().
483  * Note: this doesn't work too well for text-alignment modes other
484  *       than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
485  */
486 LONG TEXT_TabbedTextOut( HDC32 hdc, INT32 x, INT32 y, LPCSTR lpstr,
487                          INT32 count, INT32 cTabStops, const INT16 *lpTabPos16,
488                          const INT32 *lpTabPos32, INT32 nTabOrg,
489                          BOOL32 fDisplayText )
490 {
491     INT32 defWidth;
492     DWORD extent = 0;
493     int i, tabPos = x;
494     int start = x;
495
496     if (cTabStops == 1)
497     {
498         defWidth = lpTabPos32 ? *lpTabPos32 : *lpTabPos16;
499         cTabStops = 0;
500     }
501     else
502     {
503         TEXTMETRIC16 tm;
504         GetTextMetrics16( hdc, &tm );
505         defWidth = 8 * tm.tmAveCharWidth;
506     }
507     
508     while (count > 0)
509     {
510         for (i = 0; i < count; i++)
511             if (lpstr[i] == '\t') break;
512         extent = GetTextExtent( hdc, lpstr, i );
513         if (lpTabPos32)
514         {
515             while ((cTabStops > 0) &&
516                    (nTabOrg + *lpTabPos32 <= x + LOWORD(extent)))
517             {
518                 lpTabPos32++;
519                 cTabStops--;
520             }
521         }
522         else
523         {
524             while ((cTabStops > 0) &&
525                    (nTabOrg + *lpTabPos16 <= x + LOWORD(extent)))
526             {
527                 lpTabPos16++;
528                 cTabStops--;
529             }
530         }
531         if (i == count)
532             tabPos = x + LOWORD(extent);
533         else if (cTabStops > 0)
534             tabPos = nTabOrg + (lpTabPos32 ? *lpTabPos32 : *lpTabPos16);
535         else
536             tabPos = nTabOrg + ((x + LOWORD(extent) - nTabOrg) / defWidth + 1) * defWidth;
537         if (fDisplayText)
538         {
539             RECT32 r;
540             SetRect32( &r, x, y, tabPos, y+HIWORD(extent) );
541             ExtTextOut32A( hdc, x, y,
542                            GetBkMode32(hdc) == OPAQUE ? ETO_OPAQUE : 0,
543                            &r, lpstr, i, NULL );
544         }
545         x = tabPos;
546         count -= i+1;
547         lpstr += i+1;
548     }
549     return MAKELONG(tabPos - start, HIWORD(extent));
550 }
551
552
553 /***********************************************************************
554  *           TabbedTextOut16    (USER.196)
555  */
556 LONG WINAPI TabbedTextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR lpstr,
557                              INT16 count, INT16 cTabStops,
558                              const INT16 *lpTabPos, INT16 nTabOrg )
559 {
560     dprintf_text( stddeb, "TabbedTextOut16: %04x %d,%d '%.*s' %d\n",
561                   hdc, x, y, count, lpstr, count );
562     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
563                                lpTabPos, NULL, nTabOrg, TRUE );
564 }
565
566
567 /***********************************************************************
568  *           TabbedTextOut32A    (USER32.541)
569  */
570 LONG WINAPI TabbedTextOut32A( HDC32 hdc, INT32 x, INT32 y, LPCSTR lpstr,
571                               INT32 count, INT32 cTabStops,
572                               const INT32 *lpTabPos, INT32 nTabOrg )
573 {
574     dprintf_text( stddeb, "TabbedTextOut32A: %04x %d,%d '%.*s' %d\n",
575                   hdc, x, y, count, lpstr, count );
576     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
577                                NULL, lpTabPos, nTabOrg, TRUE );
578 }
579
580
581 /***********************************************************************
582  *           TabbedTextOut32W    (USER32.542)
583  */
584 LONG WINAPI TabbedTextOut32W( HDC32 hdc, INT32 x, INT32 y, LPCWSTR str,
585                               INT32 count, INT32 cTabStops,
586                               const INT32 *lpTabPos, INT32 nTabOrg )
587 {
588     LONG ret;
589     LPSTR p = HEAP_xalloc( GetProcessHeap(), 0, count + 1 );
590     lstrcpynWtoA( p, str, count + 1 );
591     ret = TabbedTextOut32A( hdc, x, y, p, count, cTabStops,
592                             lpTabPos, nTabOrg );
593     HeapFree( GetProcessHeap(), 0, p );
594     return ret;
595 }
596
597
598 /***********************************************************************
599  *           GetTabbedTextExtent16    (USER.197)
600  */
601 DWORD WINAPI GetTabbedTextExtent16( HDC16 hdc, LPCSTR lpstr, INT16 count, 
602                                     INT16 cTabStops, const INT16 *lpTabPos )
603 {
604     dprintf_text( stddeb, "GetTabbedTextExtent: %04x '%.*s' %d\n",
605                   hdc, count, lpstr, count );
606     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
607                                lpTabPos, NULL, 0, FALSE );
608 }
609
610
611 /***********************************************************************
612  *           GetTabbedTextExtent32A    (USER32.292)
613  */
614 DWORD WINAPI GetTabbedTextExtent32A( HDC32 hdc, LPCSTR lpstr, INT32 count, 
615                                      INT32 cTabStops, const INT32 *lpTabPos )
616 {
617     dprintf_text( stddeb, "GetTabbedTextExtent: %04x '%.*s' %d\n",
618                   hdc, count, lpstr, count );
619     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
620                                NULL, lpTabPos, 0, FALSE );
621 }
622
623
624 /***********************************************************************
625  *           GetTabbedTextExtent32W    (USER32.293)
626  */
627 DWORD WINAPI GetTabbedTextExtent32W( HDC32 hdc, LPCWSTR lpstr, INT32 count, 
628                                      INT32 cTabStops, const INT32 *lpTabPos )
629 {
630     LONG ret;
631     LPSTR p = HEAP_xalloc( GetProcessHeap(), 0, count + 1 );
632     lstrcpynWtoA( p, lpstr, count + 1 );
633     ret = GetTabbedTextExtent32A( hdc, p, count, cTabStops, lpTabPos );
634     HeapFree( GetProcessHeap(), 0, p );
635     return ret;
636 }
637
638 /***********************************************************************
639  *           GetTextCharset    (USER32.226) (USER.612)
640  */
641 INT32 WINAPI GetTextCharset32(HDC32 hdc)
642 {
643     fprintf(stdnimp,"GetTextCharset(0x%x)\n",hdc);
644     return DEFAULT_CHARSET; /* FIXME */
645 }
646
647 INT16 WINAPI GetTextCharset16(HDC16 hdc)
648 {
649     return GetTextCharset32(hdc);
650 }