Bugfix: SetDCState did not reset clipping region to empty.
[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 "debug.h"
14 #include "cache.h"
15 #include "debugstr.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     TRACE(text,"%s, %d , [(%d,%d),(%d,%d)]\n",
203           debugstr_an (str, count), count,
204           rect->left, rect->top, rect->right, rect->bottom);
205     
206     if (count == -1) count = strlen(str);
207     strPtr = str;
208
209     GetTextMetrics16(hdc, &tm);
210     if (flags & DT_EXTERNALLEADING)
211         lh = tm.tmHeight + tm.tmExternalLeading;
212     else
213         lh = tm.tmHeight;
214
215     if (flags & DT_TABSTOP)
216         tabstop = flags >> 8;
217
218     if (flags & DT_EXPANDTABS)
219     {
220         GetTextExtentPoint16(hdc, " ", 1, &size);
221         spacewidth = size.cx;
222         GetTextExtentPoint16(hdc, "o", 1, &size);
223         tabwidth = size.cx * tabstop;
224     }
225
226     if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
227
228     do
229     {
230         prefix_offset = -1;
231         strPtr = TEXT_NextLine(hdc, strPtr, &count, line, &len, width, flags);
232
233         if (prefix_offset != -1)
234         {
235             GetTextExtentPoint16(hdc, line, prefix_offset, &size);
236             prefix_x = size.cx;
237             GetTextExtentPoint16(hdc, line, prefix_offset + 1, &size);
238             prefix_end = size.cx - 1;
239         }
240
241         if (!GetTextExtentPoint16(hdc, line, len, &size)) return 0;
242         if (flags & DT_CENTER) x = (rect->left + rect->right -
243                                     size.cx) / 2;
244         else if (flags & DT_RIGHT) x = rect->right - size.cx;
245
246         if (flags & DT_SINGLELINE)
247         {
248             if (flags & DT_VCENTER) y = rect->top + 
249                 (rect->bottom - rect->top) / 2 - size.cy / 2;
250             else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
251         }
252         if (!(flags & DT_CALCRECT))
253         {
254             if (!ExtTextOut16(hdc, x, y, (flags & DT_NOCLIP) ? 0 : ETO_CLIPPED,
255                               rect, line, len, NULL )) return 0;
256             if (prefix_offset != -1)
257             {
258                 HPEN32 hpen = CreatePen32( PS_SOLID, 1, GetTextColor32(hdc) );
259                 HPEN32 oldPen = SelectObject32( hdc, hpen );
260                 MoveTo(hdc, x + prefix_x, y + tm.tmAscent + 1 );
261                 LineTo32(hdc, x + prefix_end + 1, y + tm.tmAscent + 1 );
262                 SelectObject32( hdc, oldPen );
263                 DeleteObject32( hpen );
264             }
265         }
266         else if (size.cx > max_width)
267             max_width = size.cx;
268
269         y += lh;
270         if (strPtr)
271         {
272             if (!(flags & DT_NOCLIP))
273             {
274                 if (y > rect->bottom - lh)
275                     break;
276             }
277         }
278     }
279     while (strPtr);
280     if (flags & DT_CALCRECT)
281     {
282         rect->right = rect->left + max_width;
283         rect->bottom = y;
284     }
285     return y - rect->top;
286 }
287
288
289 /***********************************************************************
290  *           DrawText32A    (USER32.164)
291  */
292 INT32 WINAPI DrawText32A( HDC32 hdc, LPCSTR str, INT32 count,
293                           LPRECT32 rect, UINT32 flags )
294 {
295     RECT16 rect16;
296     INT16 ret;
297
298     if (!rect)
299         return DrawText16( (HDC16)hdc, str, (INT16)count, NULL, (UINT16)flags);
300     CONV_RECT32TO16( rect, &rect16 );
301     ret = DrawText16( (HDC16)hdc, str, (INT16)count, &rect16, (UINT16)flags );
302     CONV_RECT16TO32( &rect16, rect );
303     return ret;
304 }
305
306
307 /***********************************************************************
308  *           DrawText32W    (USER32.167)
309  */
310 INT32 WINAPI DrawText32W( HDC32 hdc, LPCWSTR str, INT32 count,
311                           LPRECT32 rect, UINT32 flags )
312 {
313     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
314     INT32 ret = DrawText32A( hdc, p, count, rect, flags );
315     HeapFree( GetProcessHeap(), 0, p );
316     return ret;
317 }
318
319 /***********************************************************************
320  *           DrawTextEx32A    (USER32.165)
321  */
322 INT32 WINAPI DrawTextEx32A( HDC32 hdc, LPCSTR str, INT32 count,
323                      LPRECT32 rect, UINT32 flags, LPDRAWTEXTPARAMS dtp )
324 {
325     TRACE(text,"(%d,'%s',%d,%p,0x%08x,%p)\n",hdc,str,count,rect,flags,dtp);
326     if(dtp) {
327         FIXME(text,"Ignores params:%d,%d,%d,%d,%d\n",dtp->cbSize,
328                    dtp->iTabLength,dtp->iLeftMargin,dtp->iRightMargin,
329                    dtp->uiLengthDrawn);
330     }
331     return DrawText32A(hdc,str,count,rect,flags);
332 }
333
334 /***********************************************************************
335  *           DrawTextEx32W    (USER32.166)
336  */
337 INT32 WINAPI DrawTextEx32W( HDC32 hdc, LPCWSTR str, INT32 count,
338                      LPRECT32 rect, UINT32 flags, LPDRAWTEXTPARAMS dtp )
339 {
340     TRACE(text,"(%d,%p,%d,%p,0x%08x,%p)\n",hdc,str,count,rect,flags,dtp);
341     FIXME(text,"ignores extended functionality\n");
342     return DrawText32W(hdc,str,count,rect,flags);
343 }
344
345 /***********************************************************************
346  *           ExtTextOut16    (GDI.351)
347  */
348 BOOL16 WINAPI ExtTextOut16( HDC16 hdc, INT16 x, INT16 y, UINT16 flags,
349                             const RECT16 *lprect, LPCSTR str, UINT16 count,
350                             const INT16 *lpDx )
351 {
352     BOOL32      ret;
353     int         i;
354     RECT32      rect32;
355     LPINT32     lpdx32 = NULL;
356
357     if (lpDx) lpdx32 = (LPINT32)HEAP_xalloc( GetProcessHeap(), 0,
358                                              sizeof(INT32)*count );
359     if (lprect) CONV_RECT16TO32(lprect,&rect32);
360     if (lpdx32) for (i=count;i--;) lpdx32[i]=lpDx[i];
361     ret = ExtTextOut32A(hdc,x,y,flags,lprect?&rect32:NULL,str,count,lpdx32);
362     if (lpdx32) HeapFree( GetProcessHeap(), 0, lpdx32 );
363     return ret;
364
365
366 }
367
368
369 /***********************************************************************
370  *           ExtTextOut32A    (GDI32.98)
371  */
372 BOOL32 WINAPI ExtTextOut32A( HDC32 hdc, INT32 x, INT32 y, UINT32 flags,
373                              const RECT32 *lprect, LPCSTR str, UINT32 count,
374                              const INT32 *lpDx )
375 {
376     DC * dc = DC_GetDCPtr( hdc );
377     return dc && dc->funcs->pExtTextOut && 
378            dc->funcs->pExtTextOut(dc,x,y,flags,lprect,str,count,lpDx);
379 }
380
381
382 /***********************************************************************
383  *           ExtTextOut32W    (GDI32.99)
384  */
385 BOOL32 WINAPI ExtTextOut32W( HDC32 hdc, INT32 x, INT32 y, UINT32 flags,
386                              const RECT32 *lprect, LPCWSTR str, UINT32 count,
387                              const INT32 *lpDx )
388 {
389     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
390     INT32 ret = ExtTextOut32A( hdc, x, y, flags, lprect, p, count, lpDx );
391     HeapFree( GetProcessHeap(), 0, p );
392     return ret;
393 }
394
395
396 /***********************************************************************
397  *           TextOut16    (GDI.33)
398  */
399 BOOL16 WINAPI TextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR str, INT16 count )
400 {
401     return ExtTextOut16( hdc, x, y, 0, NULL, str, count, NULL );
402 }
403
404
405 /***********************************************************************
406  *           TextOut32A    (GDI32.355)
407  */
408 BOOL32 WINAPI TextOut32A( HDC32 hdc, INT32 x, INT32 y, LPCSTR str, INT32 count )
409 {
410     return ExtTextOut32A( hdc, x, y, 0, NULL, str, count, NULL );
411 }
412
413
414 /***********************************************************************
415  *           TextOut32W    (GDI32.356)
416  */
417 BOOL32 WINAPI TextOut32W(HDC32 hdc, INT32 x, INT32 y, LPCWSTR str, INT32 count)
418 {
419     return ExtTextOut32W( hdc, x, y, 0, NULL, str, count, NULL );
420 }
421
422
423 /***********************************************************************
424  *           TEXT_GrayString
425  *
426  * FIXME: The call to 16-bit code only works because the wine GDI is a 16-bit
427  * heap and we can guarantee that the handles fit in an INT16. We have to
428  * rethink the strategy once the migration to NT handles is complete.
429  * We are going to get a lot of code-duplication once this migration is
430  * completed...
431  * 
432  */
433 static BOOL32 TEXT_GrayString(HDC32 hdc, HBRUSH32 hb, 
434                               GRAYSTRINGPROC32 fn, LPARAM lp, INT32 len,
435                               INT32 x, INT32 y, INT32 cx, INT32 cy, 
436                               BOOL32 unicode, BOOL32 _32bit)
437 {
438     HBITMAP32 hbm, hbmsave;
439     HBRUSH32 hbsave;
440     HFONT32 hfsave;
441     HDC32 memdc = CreateCompatibleDC32(hdc);
442     int slen = len;
443     BOOL32 retval = TRUE;
444     RECT32 r;
445     COLORREF fg, bg;
446
447     if(!hdc) return FALSE;
448     
449     if(len == 0)
450     {
451         if(unicode)
452             slen = lstrlen32W((LPCWSTR)lp);
453         else if(_32bit)
454             slen = lstrlen32A((LPCSTR)lp);
455         else
456             slen = lstrlen32A((LPCSTR)PTR_SEG_TO_LIN(lp));
457     }
458
459     if((cx == 0 || cy == 0) && slen != -1)
460     {
461         SIZE32 s;
462         if(unicode)
463             GetTextExtentPoint32W(hdc, (LPCWSTR)lp, slen, &s);
464         else if(_32bit)
465             GetTextExtentPoint32A(hdc, (LPCSTR)lp, slen, &s);
466         else
467             GetTextExtentPoint32A(hdc, (LPCSTR)PTR_SEG_TO_LIN(lp), slen, &s);
468         if(cx == 0) cx = s.cx;
469         if(cy == 0) cy = s.cy;
470     }
471
472     r.left = r.top = 0;
473     r.right = cx;
474     r.bottom = cy;
475
476     hbm = CreateBitmap32(cx, cy, 1, 1, NULL);
477     hbmsave = (HBITMAP32)SelectObject32(memdc, hbm);
478     FillRect32(memdc, &r, (HBRUSH32)GetStockObject32(BLACK_BRUSH));
479     SetTextColor32(memdc, RGB(255, 255, 255));
480     SetBkColor32(memdc, RGB(0, 0, 0));
481     hfsave = (HFONT32)SelectObject32(memdc, GetCurrentObject(hdc, OBJ_FONT));
482             
483     if(fn)
484         if(_32bit)
485             retval = fn(memdc, lp, slen);
486         else
487             retval = (BOOL32)((BOOL16)((GRAYSTRINGPROC16)fn)((HDC16)memdc, lp, (INT16)slen));
488     else
489         if(unicode)
490             TextOut32W(memdc, 0, 0, (LPCWSTR)lp, slen);
491         else if(_32bit)
492             TextOut32A(memdc, 0, 0, (LPCSTR)lp, slen);
493         else
494             TextOut32A(memdc, 0, 0, (LPCSTR)PTR_SEG_TO_LIN(lp), slen);
495
496     SelectObject32(memdc, hfsave);
497
498 /*
499  * Windows doc says that the bitmap isn't grayed when len == -1 and
500  * the callback function returns FALSE. However, testing this on
501  * win95 showed otherwise...
502 */
503 #ifdef GRAYSTRING_USING_DOCUMENTED_BEHAVIOUR
504     if(retval || len != -1)
505 #endif
506     {
507         hbsave = (HBRUSH32)SelectObject32(memdc, CACHE_GetPattern55AABrush());
508         PatBlt32(memdc, 0, 0, cx, cy, 0x000A0329);
509         SelectObject32(memdc, hbsave);
510     }
511
512     if(hb) hbsave = (HBRUSH32)SelectObject32(hdc, hb);
513     fg = SetTextColor32(hdc, RGB(0, 0, 0));
514     bg = SetBkColor32(hdc, RGB(255, 255, 255));
515     BitBlt32(hdc, x, y, cx, cy, memdc, 0, 0, 0x00E20746);
516     SetTextColor32(hdc, fg);
517     SetBkColor32(hdc, bg);
518     if(hb) SelectObject32(hdc, hbsave);
519
520     SelectObject32(memdc, hbmsave);
521     DeleteObject32(hbm);
522     DeleteDC32(memdc);
523     return retval;
524 }
525
526
527 /***********************************************************************
528  *           GrayString16   (USER.185)
529  */
530 BOOL16 WINAPI GrayString16( HDC16 hdc, HBRUSH16 hbr, GRAYSTRINGPROC16 gsprc,
531                             LPARAM lParam, INT16 cch, INT16 x, INT16 y,
532                             INT16 cx, INT16 cy )
533 {
534     return TEXT_GrayString(hdc, hbr, (GRAYSTRINGPROC32)gsprc, lParam, cch, x, y, cx, cy, FALSE, FALSE);
535 }
536
537
538 /***********************************************************************
539  *           GrayString32A   (USER32.315)
540  */
541 BOOL32 WINAPI GrayString32A( HDC32 hdc, HBRUSH32 hbr, GRAYSTRINGPROC32 gsprc,
542                              LPARAM lParam, INT32 cch, INT32 x, INT32 y,
543                              INT32 cx, INT32 cy )
544 {
545     return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, FALSE, TRUE);
546 }
547
548
549 /***********************************************************************
550  *           GrayString32W   (USER32.316)
551  */
552 BOOL32 WINAPI GrayString32W( HDC32 hdc, HBRUSH32 hbr, GRAYSTRINGPROC32 gsprc,
553                              LPARAM lParam, INT32 cch, INT32 x, INT32 y,
554                              INT32 cx, INT32 cy )
555 {
556     return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, TRUE, TRUE);
557 }
558
559
560 /***********************************************************************
561  *           TEXT_TabbedTextOut
562  *
563  * Helper function for TabbedTextOut() and GetTabbedTextExtent().
564  * Note: this doesn't work too well for text-alignment modes other
565  *       than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
566  */
567 LONG TEXT_TabbedTextOut( HDC32 hdc, INT32 x, INT32 y, LPCSTR lpstr,
568                          INT32 count, INT32 cTabStops, const INT16 *lpTabPos16,
569                          const INT32 *lpTabPos32, INT32 nTabOrg,
570                          BOOL32 fDisplayText )
571 {
572     INT32 defWidth;
573     DWORD extent = 0;
574     int i, tabPos = x;
575     int start = x;
576
577     if (cTabStops == 1)
578     {
579         defWidth = lpTabPos32 ? *lpTabPos32 : *lpTabPos16;
580         cTabStops = 0;
581     }
582     else
583     {
584         TEXTMETRIC16 tm;
585         GetTextMetrics16( hdc, &tm );
586         defWidth = 8 * tm.tmAveCharWidth;
587     }
588     
589     while (count > 0)
590     {
591         for (i = 0; i < count; i++)
592             if (lpstr[i] == '\t') break;
593         extent = GetTextExtent( hdc, lpstr, i );
594         if (lpTabPos32)
595         {
596             while ((cTabStops > 0) &&
597                    (nTabOrg + *lpTabPos32 <= x + LOWORD(extent)))
598             {
599                 lpTabPos32++;
600                 cTabStops--;
601             }
602         }
603         else
604         {
605             while ((cTabStops > 0) &&
606                    (nTabOrg + *lpTabPos16 <= x + LOWORD(extent)))
607             {
608                 lpTabPos16++;
609                 cTabStops--;
610             }
611         }
612         if (i == count)
613             tabPos = x + LOWORD(extent);
614         else if (cTabStops > 0)
615             tabPos = nTabOrg + (lpTabPos32 ? *lpTabPos32 : *lpTabPos16);
616         else
617             tabPos = nTabOrg + ((x + LOWORD(extent) - nTabOrg) / defWidth + 1) * defWidth;
618         if (fDisplayText)
619         {
620             RECT32 r;
621             SetRect32( &r, x, y, tabPos, y+HIWORD(extent) );
622             ExtTextOut32A( hdc, x, y,
623                            GetBkMode32(hdc) == OPAQUE ? ETO_OPAQUE : 0,
624                            &r, lpstr, i, NULL );
625         }
626         x = tabPos;
627         count -= i+1;
628         lpstr += i+1;
629     }
630     return MAKELONG(tabPos - start, HIWORD(extent));
631 }
632
633
634 /***********************************************************************
635  *           TabbedTextOut16    (USER.196)
636  */
637 LONG WINAPI TabbedTextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR lpstr,
638                              INT16 count, INT16 cTabStops,
639                              const INT16 *lpTabPos, INT16 nTabOrg )
640 {
641     TRACE(text, "%04x %d,%d '%.*s' %d\n",
642                   hdc, x, y, count, lpstr, count );
643     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
644                                lpTabPos, NULL, nTabOrg, TRUE );
645 }
646
647
648 /***********************************************************************
649  *           TabbedTextOut32A    (USER32.542)
650  */
651 LONG WINAPI TabbedTextOut32A( HDC32 hdc, INT32 x, INT32 y, LPCSTR lpstr,
652                               INT32 count, INT32 cTabStops,
653                               const INT32 *lpTabPos, INT32 nTabOrg )
654 {
655     TRACE(text, "%04x %d,%d '%.*s' %d\n",
656                   hdc, x, y, count, lpstr, count );
657     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
658                                NULL, lpTabPos, nTabOrg, TRUE );
659 }
660
661
662 /***********************************************************************
663  *           TabbedTextOut32W    (USER32.543)
664  */
665 LONG WINAPI TabbedTextOut32W( HDC32 hdc, INT32 x, INT32 y, LPCWSTR str,
666                               INT32 count, INT32 cTabStops,
667                               const INT32 *lpTabPos, INT32 nTabOrg )
668 {
669     LONG ret;
670     LPSTR p = HEAP_xalloc( GetProcessHeap(), 0, count + 1 );
671     lstrcpynWtoA( p, str, count + 1 );
672     ret = TabbedTextOut32A( hdc, x, y, p, count, cTabStops,
673                             lpTabPos, nTabOrg );
674     HeapFree( GetProcessHeap(), 0, p );
675     return ret;
676 }
677
678
679 /***********************************************************************
680  *           GetTabbedTextExtent16    (USER.197)
681  */
682 DWORD WINAPI GetTabbedTextExtent16( HDC16 hdc, LPCSTR lpstr, INT16 count, 
683                                     INT16 cTabStops, const INT16 *lpTabPos )
684 {
685     TRACE(text, "%04x '%.*s' %d\n",
686                   hdc, count, lpstr, count );
687     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
688                                lpTabPos, NULL, 0, FALSE );
689 }
690
691
692 /***********************************************************************
693  *           GetTabbedTextExtent32A    (USER32.293)
694  */
695 DWORD WINAPI GetTabbedTextExtent32A( HDC32 hdc, LPCSTR lpstr, INT32 count, 
696                                      INT32 cTabStops, const INT32 *lpTabPos )
697 {
698     TRACE(text, "%04x '%.*s' %d\n",
699                   hdc, count, lpstr, count );
700     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
701                                NULL, lpTabPos, 0, FALSE );
702 }
703
704
705 /***********************************************************************
706  *           GetTabbedTextExtent32W    (USER32.294)
707  */
708 DWORD WINAPI GetTabbedTextExtent32W( HDC32 hdc, LPCWSTR lpstr, INT32 count, 
709                                      INT32 cTabStops, const INT32 *lpTabPos )
710 {
711     LONG ret;
712     LPSTR p = HEAP_xalloc( GetProcessHeap(), 0, count + 1 );
713     lstrcpynWtoA( p, lpstr, count + 1 );
714     ret = GetTabbedTextExtent32A( hdc, p, count, cTabStops, lpTabPos );
715     HeapFree( GetProcessHeap(), 0, p );
716     return ret;
717 }
718
719 /***********************************************************************
720  * GetTextCharset32 [GDI32.226]  Gets character set for font in DC
721  *
722  * NOTES
723  *    Should it return a UINT32 instead of an INT32?
724  *
725  * RETURNS
726  *    Success: Character set identifier
727  *    Failure: DEFAULT_CHARSET
728  */
729 INT32 WINAPI GetTextCharset32(
730     HDC32 hdc) /* [in] Handle to device context */
731 {
732     /* MSDN docs say this is equivalent */
733     return GetTextCharsetInfo(hdc, NULL, 0);
734 }
735
736 /***********************************************************************
737  * GetTextCharset16 [GDI.612]
738  */
739 INT16 WINAPI GetTextCharset16(HDC16 hdc)
740 {
741     return GetTextCharset32(hdc);
742 }
743
744 /***********************************************************************
745  * GetTextCharsetInfo [GDI32.381]  Gets character set for font
746  *
747  * NOTES
748  *    Should csi be an LPFONTSIGNATURE instead of an LPCHARSETINFO?
749  *    Should it return a UINT32 instead of an INT32?
750  *
751  * RETURNS
752  *    Success: Character set identifier
753  *    Failure: DEFAULT_CHARSET
754  */
755 INT32 WINAPI GetTextCharsetInfo(
756     HDC32 hdc,         /* [in]  Handle to device context */
757     LPCHARSETINFO csi, /* [out] Pointer to struct to receive data */
758     DWORD flags)       /* [in]  Reserved - must be 0 */
759 {
760     FIXME(text,"(0x%x,%p,%08lx): stub\n",hdc,csi,flags);
761     if (csi) {
762         csi->ciCharset = DEFAULT_CHARSET;
763         csi->ciACP = GetACP();
764     }
765     /* ... fill fontstruct too ... */
766     return DEFAULT_CHARSET;
767 }