Fixed the displaying of the FOURCC codes in _dump_pixelformat.
[wine] / dlls / user / text.c
1 /*
2  * USER text functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  */
7
8 #include <string.h>
9
10 #include "windef.h"
11 #include "wingdi.h"
12 #include "wine/winuser16.h"
13 #include "winbase.h"
14 #include "winerror.h"
15 #include "winnls.h"
16 #include "cache.h"
17 #include "ldt.h"
18 #include "debugtools.h"
19
20 DEFAULT_DEBUG_CHANNEL(text);
21
22 #define TAB     9
23 #define LF     10
24 #define CR     13
25 #define SPACE  32
26 #define PREFIX 38
27
28 #define SWAP_INT(a,b)  { int t = a; a = b; b = t; }
29
30 static int tabstop = 8;
31 static int tabwidth;
32 static int spacewidth;
33 static int prefix_offset;
34
35 static const char *TEXT_NextLine( HDC hdc, const char *str, int *count,
36                                   char *dest, int *len, int width, WORD format)
37 {
38     /* Return next line of text from a string.
39      * 
40      * hdc - handle to DC.
41      * str - string to parse into lines.
42      * count - length of str.
43      * dest - destination in which to return line.
44      * len - length of resultant line in dest in chars.
45      * width - maximum width of line in pixels.
46      * format - format type passed to DrawText.
47      *
48      * Returns pointer to next char in str after end of the line
49      * or NULL if end of str reached.
50      */
51
52     int i = 0, j = 0, k;
53     int plen = 0;
54     int numspaces;
55     SIZE size;
56     int lasttab = 0;
57     int wb_i = 0, wb_j = 0, wb_count = 0;
58
59     while (*count)
60     {
61         switch (str[i])
62         {
63         case CR:
64         case LF:
65             if (!(format & DT_SINGLELINE))
66             {
67                 if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF))
68                 {
69                     (*count)--;
70                     i++;
71                 }
72                 i++;
73                 *len = j;
74                 (*count)--;
75                 return (&str[i]);
76             }
77             dest[j++] = str[i++];
78             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
79                 (format & DT_WORDBREAK))
80             {
81                 if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size))
82                     return NULL;
83                 plen += size.cx;
84             }
85             break;
86             
87         case PREFIX:
88             if (!(format & DT_NOPREFIX) && *count > 1)
89                 {
90                 if (str[++i] == PREFIX)
91                     (*count)--;
92                 else {
93                     prefix_offset = j;
94                     break;
95                 }
96             }
97             dest[j++] = str[i++];
98             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
99                 (format & DT_WORDBREAK))
100             {
101                 if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size))
102                     return NULL;
103                 plen += size.cx;
104             }
105             break;
106             
107         case TAB:
108             if (format & DT_EXPANDTABS)
109             {
110                 wb_i = ++i;
111                 wb_j = j;
112                 wb_count = *count;
113
114                 if (!GetTextExtentPointA(hdc, &dest[lasttab], j - lasttab, &size))
115                     return NULL;
116
117                 numspaces = (tabwidth - size.cx) / spacewidth;
118                 for (k = 0; k < numspaces; k++)
119                     dest[j++] = SPACE;
120                 plen += tabwidth - size.cx;
121                 lasttab = wb_j + numspaces;
122             }
123             else
124             {
125                 dest[j++] = str[i++];
126                 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
127                     (format & DT_WORDBREAK))
128                 {
129                     if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size))
130                         return NULL;
131                     plen += size.cx;
132                 }
133             }
134             break;
135
136         case SPACE:
137             dest[j++] = str[i++];
138             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
139                 (format & DT_WORDBREAK))
140             {
141                 wb_i = i;
142                 wb_j = j - 1;
143                 wb_count = *count;
144                 if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size))
145                     return NULL;
146                 plen += size.cx;
147             }
148             break;
149
150         default:
151             dest[j++] = str[i++];
152             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
153                 (format & DT_WORDBREAK))
154             {
155                 if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size))
156                     return NULL;
157                 plen += size.cx;
158             }
159         }
160
161         (*count)--;
162         if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
163         {
164             if (plen > width)
165             {
166                 if (format & DT_WORDBREAK)
167                 {
168                     if (wb_j)
169                     {
170                         *len = wb_j;
171                         *count = wb_count - 1;
172                         return (&str[wb_i]);
173                     }
174                 }
175                 else
176                 {
177                     *len = j;
178                     return (&str[i]);
179                 }
180             }
181         }
182     }
183     
184     *len = j;
185     return NULL;
186 }
187
188
189 /***********************************************************************
190  *           DrawText16    (USER.85)
191  */
192 INT16 WINAPI DrawText16( HDC16 hdc, LPCSTR str, INT16 count, LPRECT16 rect, UINT16 flags )
193 {
194     INT16 ret;
195
196     if (rect)
197     {
198         RECT rect32;
199         CONV_RECT16TO32( rect, &rect32 );
200         ret = DrawTextA( hdc, str, count, &rect32, flags );
201         CONV_RECT32TO16( &rect32, rect );
202     }
203     else ret = DrawTextA( hdc, str, count, NULL, flags);
204     return ret;
205 }
206
207
208 /***********************************************************************
209  *           DrawTextA    (USER32.164)
210  */
211 INT WINAPI DrawTextA( HDC hdc, LPCSTR str, INT i_count, LPRECT rect, UINT flags )
212 {
213     SIZE size;
214     const char *strPtr;
215     static char line[1024];
216     int len, lh, count=i_count;
217     int prefix_x = 0;
218     int prefix_end = 0;
219     TEXTMETRICA tm;
220     int x = rect->left, y = rect->top;
221     int width = rect->right - rect->left;
222     int max_width = 0;
223
224     TRACE("%s, %d , [(%d,%d),(%d,%d)]\n",
225           debugstr_an (str, count), count,
226           rect->left, rect->top, rect->right, rect->bottom);
227
228     if (!str) return 0;
229     if (count == -1) count = strlen(str);
230     strPtr = str;
231
232     GetTextMetricsA(hdc, &tm);
233     if (flags & DT_EXTERNALLEADING)
234         lh = tm.tmHeight + tm.tmExternalLeading;
235     else
236         lh = tm.tmHeight;
237
238     if (flags & DT_TABSTOP)
239         tabstop = flags >> 8;
240
241     if (flags & DT_EXPANDTABS)
242     {
243         GetTextExtentPointA(hdc, " ", 1, &size);
244         spacewidth = size.cx;
245         GetTextExtentPointA(hdc, "o", 1, &size);
246         tabwidth = size.cx * tabstop;
247     }
248
249     if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
250
251     do
252     {
253         prefix_offset = -1;
254         strPtr = TEXT_NextLine(hdc, strPtr, &count, line, &len, width, flags);
255
256         if (prefix_offset != -1)
257         {
258             GetTextExtentPointA(hdc, line, prefix_offset, &size);
259             prefix_x = size.cx;
260             GetTextExtentPointA(hdc, line, prefix_offset + 1, &size);
261             prefix_end = size.cx - 1;
262         }
263
264         if (!GetTextExtentPointA(hdc, line, len, &size)) return 0;
265         if (flags & DT_CENTER) x = (rect->left + rect->right -
266                                     size.cx) / 2;
267         else if (flags & DT_RIGHT) x = rect->right - size.cx;
268
269         if (flags & DT_SINGLELINE)
270         {
271             if (flags & DT_VCENTER) y = rect->top + 
272                 (rect->bottom - rect->top) / 2 - size.cy / 2;
273             else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
274         }
275         if (!(flags & DT_CALCRECT))
276         {
277             if (!ExtTextOutA(hdc, x, y, (flags & DT_NOCLIP) ? 0 : ETO_CLIPPED,
278                              rect, line, len, NULL )) return 0;
279             if (prefix_offset != -1)
280             {
281                 HPEN hpen = CreatePen( PS_SOLID, 1, GetTextColor(hdc) );
282                 HPEN oldPen = SelectObject( hdc, hpen );
283                 MoveToEx(hdc, x + prefix_x, y + tm.tmAscent + 1, NULL );
284                 LineTo(hdc, x + prefix_end + 1, y + tm.tmAscent + 1 );
285                 SelectObject( hdc, oldPen );
286                 DeleteObject( hpen );
287             }
288         }
289         else if (size.cx > max_width)
290             max_width = size.cx;
291
292         y += lh;
293         if (strPtr)
294         {
295             if (!(flags & DT_NOCLIP))
296             {
297                 if (y > rect->bottom - lh)
298                     break;
299             }
300         }
301     }
302     while (strPtr);
303     if (flags & DT_CALCRECT)
304     {
305         rect->right = rect->left + max_width;
306         rect->bottom = y;
307     }
308     return y - rect->top;
309 }
310
311
312 /***********************************************************************
313  *           DrawTextW    (USER32.167)
314  */
315 INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count,
316                           LPRECT rect, UINT flags )
317 {
318     LPSTR p;
319     INT acount;
320     INT ret;
321     UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */
322         
323     acount = WideCharToMultiByte(codepage,0,str,count,NULL,0,NULL,NULL);
324     p = HeapAlloc( GetProcessHeap(), 0, acount );
325     acount = WideCharToMultiByte(codepage,0,str,count,p,acount,NULL,NULL);
326     if (count == -1) acount = -1;
327     ret = DrawTextA( hdc, p, acount, rect, flags );
328
329     HeapFree( GetProcessHeap(), 0, p );
330     return ret;
331 }
332
333 /***********************************************************************
334  *           DrawTextExA    (USER32.165)
335  */
336 INT WINAPI DrawTextExA( HDC hdc, LPCSTR str, INT count,
337                      LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
338 {
339     TRACE("(%d,'%s',%d,%p,0x%08x,%p)\n",hdc,str,count,rect,flags,dtp);
340     if(dtp) {
341         FIXME("Ignores params:%d,%d,%d,%d\n",dtp->cbSize,
342                    dtp->iTabLength,dtp->iLeftMargin,dtp->iRightMargin);
343     }
344     return DrawTextA(hdc,str,count,rect,flags);
345 }
346
347 /***********************************************************************
348  *           DrawTextExW    (USER32.166)
349  */
350 INT WINAPI DrawTextExW( HDC hdc, LPCWSTR str, INT count,
351                      LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
352 {
353     TRACE("(%d,%p,%d,%p,0x%08x,%p)\n",hdc,str,count,rect,flags,dtp);
354     FIXME("ignores extended functionality\n");
355     return DrawTextW(hdc,str,count,rect,flags);
356 }
357 /***********************************************************************
358  *           TEXT_GrayString
359  *
360  * FIXME: The call to 16-bit code only works because the wine GDI is a 16-bit
361  * heap and we can guarantee that the handles fit in an INT16. We have to
362  * rethink the strategy once the migration to NT handles is complete.
363  * We are going to get a lot of code-duplication once this migration is
364  * completed...
365  * 
366  */
367 static BOOL TEXT_GrayString(HDC hdc, HBRUSH hb, GRAYSTRINGPROC fn, LPARAM lp, INT len,
368                             INT x, INT y, INT cx, INT cy, BOOL unicode, BOOL _32bit)
369 {
370     HBITMAP hbm, hbmsave;
371     HBRUSH hbsave;
372     HFONT hfsave;
373     HDC memdc = CreateCompatibleDC(hdc);
374     int slen = len;
375     BOOL retval = TRUE;
376     COLORREF fg, bg;
377
378     if(!hdc) return FALSE;
379     
380     if(len == 0)
381     {
382         if(unicode)
383             slen = lstrlenW((LPCWSTR)lp);
384         else if(_32bit)
385             slen = strlen((LPCSTR)lp);
386         else
387             slen = strlen((LPCSTR)PTR_SEG_TO_LIN(lp));
388     }
389
390     if((cx == 0 || cy == 0) && slen != -1)
391     {
392         SIZE s;
393         if(unicode)
394             GetTextExtentPoint32W(hdc, (LPCWSTR)lp, slen, &s);
395         else if(_32bit)
396             GetTextExtentPoint32A(hdc, (LPCSTR)lp, slen, &s);
397         else
398             GetTextExtentPoint32A(hdc, (LPCSTR)PTR_SEG_TO_LIN(lp), slen, &s);
399         if(cx == 0) cx = s.cx;
400         if(cy == 0) cy = s.cy;
401     }
402
403     hbm = CreateBitmap(cx, cy, 1, 1, NULL);
404     hbmsave = (HBITMAP)SelectObject(memdc, hbm);
405     hbsave = SelectObject( memdc, GetStockObject(BLACK_BRUSH) );
406     PatBlt( memdc, 0, 0, cx, cy, PATCOPY );
407     SelectObject( memdc, hbsave );
408     SetTextColor(memdc, RGB(255, 255, 255));
409     SetBkColor(memdc, RGB(0, 0, 0));
410     hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
411             
412     if(fn)
413         if(_32bit)
414             retval = fn(memdc, lp, slen);
415         else
416             retval = (BOOL)((BOOL16)((GRAYSTRINGPROC16)fn)((HDC16)memdc, lp, (INT16)slen));
417     else
418         if(unicode)
419             TextOutW(memdc, 0, 0, (LPCWSTR)lp, slen);
420         else if(_32bit)
421             TextOutA(memdc, 0, 0, (LPCSTR)lp, slen);
422         else
423             TextOutA(memdc, 0, 0, (LPCSTR)PTR_SEG_TO_LIN(lp), slen);
424
425     SelectObject(memdc, hfsave);
426
427 /*
428  * Windows doc says that the bitmap isn't grayed when len == -1 and
429  * the callback function returns FALSE. However, testing this on
430  * win95 showed otherwise...
431 */
432 #ifdef GRAYSTRING_USING_DOCUMENTED_BEHAVIOUR
433     if(retval || len != -1)
434 #endif
435     {
436         hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
437         PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
438         SelectObject(memdc, hbsave);
439     }
440
441     if(hb) hbsave = (HBRUSH)SelectObject(hdc, hb);
442     fg = SetTextColor(hdc, RGB(0, 0, 0));
443     bg = SetBkColor(hdc, RGB(255, 255, 255));
444     BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00E20746);
445     SetTextColor(hdc, fg);
446     SetBkColor(hdc, bg);
447     if(hb) SelectObject(hdc, hbsave);
448
449     SelectObject(memdc, hbmsave);
450     DeleteObject(hbm);
451     DeleteDC(memdc);
452     return retval;
453 }
454
455
456 /***********************************************************************
457  *           GrayString16   (USER.185)
458  */
459 BOOL16 WINAPI GrayString16( HDC16 hdc, HBRUSH16 hbr, GRAYSTRINGPROC16 gsprc,
460                             LPARAM lParam, INT16 cch, INT16 x, INT16 y,
461                             INT16 cx, INT16 cy )
462 {
463     return TEXT_GrayString(hdc, hbr, (GRAYSTRINGPROC)gsprc, lParam, cch, x, y, cx, cy, FALSE, FALSE);
464 }
465
466
467 /***********************************************************************
468  *           GrayStringA   (USER32.315)
469  */
470 BOOL WINAPI GrayStringA( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
471                              LPARAM lParam, INT cch, INT x, INT y,
472                              INT cx, INT cy )
473 {
474     return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, FALSE, TRUE);
475 }
476
477
478 /***********************************************************************
479  *           GrayStringW   (USER32.316)
480  */
481 BOOL WINAPI GrayStringW( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
482                              LPARAM lParam, INT cch, INT x, INT y,
483                              INT cx, INT cy )
484 {
485     return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, TRUE, TRUE);
486 }
487
488 /***********************************************************************
489  *           TEXT_TabbedTextOut
490  *
491  * Helper function for TabbedTextOut() and GetTabbedTextExtent().
492  * Note: this doesn't work too well for text-alignment modes other
493  *       than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
494  */
495 static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCSTR lpstr,
496                                 INT count, INT cTabStops, const INT16 *lpTabPos16,
497                                 const INT *lpTabPos32, INT nTabOrg,
498                                 BOOL fDisplayText )
499 {
500     INT defWidth;
501     SIZE extent;
502     int i, tabPos = x;
503     int start = x;
504
505     extent.cx = 0;
506     extent.cy = 0;
507
508     if (cTabStops == 1)
509     {
510         defWidth = lpTabPos32 ? *lpTabPos32 : *lpTabPos16;
511         cTabStops = 0;
512     }
513     else
514     {
515         TEXTMETRICA tm;
516         GetTextMetricsA( hdc, &tm );
517         defWidth = 8 * tm.tmAveCharWidth;
518     }
519
520     while (count > 0)
521     {
522         for (i = 0; i < count; i++)
523             if (lpstr[i] == '\t') break;
524         GetTextExtentPointA( hdc, lpstr, i, &extent );
525         if (lpTabPos32)
526         {
527             while ((cTabStops > 0) &&
528                    (nTabOrg + *lpTabPos32 <= x + extent.cx))
529             {
530                 lpTabPos32++;
531                 cTabStops--;
532             }
533         }
534         else
535         {
536             while ((cTabStops > 0) &&
537                    (nTabOrg + *lpTabPos16 <= x + extent.cx))
538             {
539                 lpTabPos16++;
540                 cTabStops--;
541             }
542         }
543         if (i == count)
544             tabPos = x + extent.cx;
545         else if (cTabStops > 0)
546             tabPos = nTabOrg + (lpTabPos32 ? *lpTabPos32 : *lpTabPos16);
547         else
548             tabPos = nTabOrg + ((x + extent.cx - nTabOrg) / defWidth + 1) * defWidth;
549         if (fDisplayText)
550         {
551             RECT r;
552             r.left   = x;
553             r.top    = y;
554             r.right  = tabPos;
555             r.bottom = y + extent.cy;
556             ExtTextOutA( hdc, x, y,
557                            GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
558                            &r, lpstr, i, NULL );
559         }
560         x = tabPos;
561         count -= i+1;
562         lpstr += i+1;
563     }
564     return MAKELONG(tabPos - start, extent.cy);
565 }
566
567
568 /***********************************************************************
569  *           TabbedTextOut16    (USER.196)
570  */
571 LONG WINAPI TabbedTextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR lpstr,
572                              INT16 count, INT16 cTabStops,
573                              const INT16 *lpTabPos, INT16 nTabOrg )
574 {
575     TRACE("%04x %d,%d '%.*s' %d\n",
576                   hdc, x, y, count, lpstr, count );
577     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
578                                lpTabPos, NULL, nTabOrg, TRUE );
579 }
580
581
582 /***********************************************************************
583  *           TabbedTextOutA    (USER32.542)
584  */
585 LONG WINAPI TabbedTextOutA( HDC hdc, INT x, INT y, LPCSTR lpstr,
586                               INT count, INT cTabStops,
587                               const INT *lpTabPos, INT nTabOrg )
588 {
589     TRACE("%04x %d,%d '%.*s' %d\n",
590                   hdc, x, y, count, lpstr, count );
591     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
592                                NULL, lpTabPos, nTabOrg, TRUE );
593 }
594
595
596 /***********************************************************************
597  *           TabbedTextOutW    (USER32.543)
598  */
599 LONG WINAPI TabbedTextOutW( HDC hdc, INT x, INT y, LPCWSTR str,
600                               INT count, INT cTabStops,
601                               const INT *lpTabPos, INT nTabOrg )
602 {
603     LONG ret;
604     LPSTR p;
605     INT acount;
606     UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */
607
608     acount = WideCharToMultiByte(codepage,0,str,count,NULL,0,NULL,NULL);
609     p = HeapAlloc( GetProcessHeap(), 0, acount );
610     if(p == NULL) return 0; /* FIXME: is this the correct return on failure */ 
611     acount = WideCharToMultiByte(codepage,0,str,count,p,acount,NULL,NULL);
612     ret = TabbedTextOutA( hdc, x, y, p, acount, cTabStops,
613                             lpTabPos, nTabOrg );
614     HeapFree( GetProcessHeap(), 0, p );
615     return ret;
616 }
617
618
619 /***********************************************************************
620  *           GetTabbedTextExtent16    (USER.197)
621  */
622 DWORD WINAPI GetTabbedTextExtent16( HDC16 hdc, LPCSTR lpstr, INT16 count, 
623                                     INT16 cTabStops, const INT16 *lpTabPos )
624 {
625     TRACE("%04x '%.*s' %d\n",
626                   hdc, count, lpstr, count );
627     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
628                                lpTabPos, NULL, 0, FALSE );
629 }
630
631
632 /***********************************************************************
633  *           GetTabbedTextExtentA    (USER32.293)
634  */
635 DWORD WINAPI GetTabbedTextExtentA( HDC hdc, LPCSTR lpstr, INT count, 
636                                      INT cTabStops, const INT *lpTabPos )
637 {
638     TRACE("%04x '%.*s' %d\n",
639                   hdc, count, lpstr, count );
640     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
641                                NULL, lpTabPos, 0, FALSE );
642 }
643
644
645 /***********************************************************************
646  *           GetTabbedTextExtentW    (USER32.294)
647  */
648 DWORD WINAPI GetTabbedTextExtentW( HDC hdc, LPCWSTR lpstr, INT count, 
649                                      INT cTabStops, const INT *lpTabPos )
650 {
651     LONG ret;
652     LPSTR p;
653     INT acount;
654     UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */
655
656     acount = WideCharToMultiByte(codepage,0,lpstr,count,NULL,0,NULL,NULL);
657     p = HeapAlloc( GetProcessHeap(), 0, acount );
658     if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
659     acount = WideCharToMultiByte(codepage,0,lpstr,count,p,acount,NULL,NULL);
660     ret = GetTabbedTextExtentA( hdc, p, acount, cTabStops, lpTabPos );
661     HeapFree( GetProcessHeap(), 0, p );
662     return ret;
663 }