Move DCFuncs ExtTextOut and GetTextExtentPoint to Unicode.
[wine] / objects / text.c
1 /*
2  * text functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  */
7
8 #include <string.h>
9
10 #include "wine/winuser16.h"
11 #include "winbase.h"
12 #include "winuser.h"
13 #include "winerror.h"
14 #include "dc.h"
15 #include "gdi.h"
16 #include "heap.h"
17 #include "debugtools.h"
18 #include "cache.h"
19 #include "debugstr.h"
20
21 DEFAULT_DEBUG_CHANNEL(text)
22
23 #define TAB     9
24 #define LF     10
25 #define CR     13
26 #define SPACE  32
27 #define PREFIX 38
28
29 #define SWAP_INT(a,b)  { int t = a; a = b; b = t; }
30
31 static int tabstop = 8;
32 static int tabwidth;
33 static int spacewidth;
34 static int prefix_offset;
35
36 static const char *TEXT_NextLine( HDC16 hdc, const char *str, int *count,
37                                   char *dest, int *len, int width, WORD format)
38 {
39     /* Return next line of text from a string.
40      * 
41      * hdc - handle to DC.
42      * str - string to parse into lines.
43      * count - length of str.
44      * dest - destination in which to return line.
45      * len - length of resultant line in dest in chars.
46      * width - maximum width of line in pixels.
47      * format - format type passed to DrawText.
48      *
49      * Returns pointer to next char in str after end of the line
50      * or NULL if end of str reached.
51      */
52
53     int i = 0, j = 0, k;
54     int plen = 0;
55     int numspaces;
56     SIZE16 size;
57     int lasttab = 0;
58     int wb_i = 0, wb_j = 0, wb_count = 0;
59
60     while (*count)
61     {
62         switch (str[i])
63         {
64         case CR:
65         case LF:
66             if (!(format & DT_SINGLELINE))
67             {
68                 if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF))
69                 {
70                     (*count)--;
71                     i++;
72                 }
73                 i++;
74                 *len = j;
75                 (*count)--;
76                 return (&str[i]);
77             }
78             dest[j++] = str[i++];
79             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
80                 (format & DT_WORDBREAK))
81             {
82                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
83                     return NULL;
84                 plen += size.cx;
85             }
86             break;
87             
88         case PREFIX:
89             if (!(format & DT_NOPREFIX) && *count > 1)
90                 {
91                 if (str[++i] == PREFIX)
92                     (*count)--;
93                 else {
94                     prefix_offset = j;
95                     break;
96                 }
97             }
98             dest[j++] = str[i++];
99             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
100                 (format & DT_WORDBREAK))
101             {
102                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
103                     return NULL;
104                 plen += size.cx;
105             }
106             break;
107             
108         case TAB:
109             if (format & DT_EXPANDTABS)
110             {
111                 wb_i = ++i;
112                 wb_j = j;
113                 wb_count = *count;
114
115                 if (!GetTextExtentPoint16(hdc, &dest[lasttab], j - lasttab,
116                                                                  &size))
117                     return NULL;
118
119                 numspaces = (tabwidth - size.cx) / spacewidth;
120                 for (k = 0; k < numspaces; k++)
121                     dest[j++] = SPACE;
122                 plen += tabwidth - size.cx;
123                 lasttab = wb_j + numspaces;
124             }
125             else
126             {
127                 dest[j++] = str[i++];
128                 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
129                     (format & DT_WORDBREAK))
130                 {
131                     if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
132                         return NULL;
133                     plen += size.cx;
134                 }
135             }
136             break;
137
138         case SPACE:
139             dest[j++] = str[i++];
140             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
141                 (format & DT_WORDBREAK))
142             {
143                 wb_i = i;
144                 wb_j = j - 1;
145                 wb_count = *count;
146                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
147                     return NULL;
148                 plen += size.cx;
149             }
150             break;
151
152         default:
153             dest[j++] = str[i++];
154             if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
155                 (format & DT_WORDBREAK))
156             {
157                 if (!GetTextExtentPoint16(hdc, &dest[j-1], 1, &size))
158                     return NULL;
159                 plen += size.cx;
160             }
161         }
162
163         (*count)--;
164         if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
165         {
166             if (plen > width)
167             {
168                 if (format & DT_WORDBREAK)
169                 {
170                     if (wb_j)
171                     {
172                         *len = wb_j;
173                         *count = wb_count - 1;
174                         return (&str[wb_i]);
175                     }
176                 }
177                 else
178                 {
179                     *len = j;
180                     return (&str[i]);
181                 }
182             }
183         }
184     }
185     
186     *len = j;
187     return NULL;
188 }
189
190
191 /***********************************************************************
192  *           DrawText16    (USER.85)
193  */
194 INT16 WINAPI DrawText16( HDC16 hdc, LPCSTR str, INT16 i_count,
195                          LPRECT16 rect, UINT16 flags )
196 {
197     SIZE16 size;
198     const char *strPtr;
199     static char line[1024];
200     int len, lh, count=i_count;
201     int prefix_x = 0;
202     int prefix_end = 0;
203     TEXTMETRIC16 tm;
204     int x = rect->left, y = rect->top;
205     int width = rect->right - rect->left;
206     int max_width = 0;
207
208     TRACE("%s, %d , [(%d,%d),(%d,%d)]\n",
209           debugstr_an (str, count), count,
210           rect->left, rect->top, rect->right, rect->bottom);
211
212     if (!str) return 0;
213     if (count == -1) count = strlen(str);
214     strPtr = str;
215
216     GetTextMetrics16(hdc, &tm);
217     if (flags & DT_EXTERNALLEADING)
218         lh = tm.tmHeight + tm.tmExternalLeading;
219     else
220         lh = tm.tmHeight;
221
222     if (flags & DT_TABSTOP)
223         tabstop = flags >> 8;
224
225     if (flags & DT_EXPANDTABS)
226     {
227         GetTextExtentPoint16(hdc, " ", 1, &size);
228         spacewidth = size.cx;
229         GetTextExtentPoint16(hdc, "o", 1, &size);
230         tabwidth = size.cx * tabstop;
231     }
232
233     if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
234
235     do
236     {
237         prefix_offset = -1;
238         strPtr = TEXT_NextLine(hdc, strPtr, &count, line, &len, width, flags);
239
240         if (prefix_offset != -1)
241         {
242             GetTextExtentPoint16(hdc, line, prefix_offset, &size);
243             prefix_x = size.cx;
244             GetTextExtentPoint16(hdc, line, prefix_offset + 1, &size);
245             prefix_end = size.cx - 1;
246         }
247
248         if (!GetTextExtentPoint16(hdc, line, len, &size)) return 0;
249         if (flags & DT_CENTER) x = (rect->left + rect->right -
250                                     size.cx) / 2;
251         else if (flags & DT_RIGHT) x = rect->right - size.cx;
252
253         if (flags & DT_SINGLELINE)
254         {
255             if (flags & DT_VCENTER) y = rect->top + 
256                 (rect->bottom - rect->top) / 2 - size.cy / 2;
257             else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
258         }
259         if (!(flags & DT_CALCRECT))
260         {
261             if (!ExtTextOut16(hdc, x, y, (flags & DT_NOCLIP) ? 0 : ETO_CLIPPED,
262                               rect, line, len, NULL )) return 0;
263             if (prefix_offset != -1)
264             {
265                 HPEN hpen = CreatePen( PS_SOLID, 1, GetTextColor(hdc) );
266                 HPEN oldPen = SelectObject( hdc, hpen );
267                 MoveTo16(hdc, x + prefix_x, y + tm.tmAscent + 1 );
268                 LineTo(hdc, x + prefix_end + 1, y + tm.tmAscent + 1 );
269                 SelectObject( hdc, oldPen );
270                 DeleteObject( hpen );
271             }
272         }
273         else if (size.cx > max_width)
274             max_width = size.cx;
275
276         y += lh;
277         if (strPtr)
278         {
279             if (!(flags & DT_NOCLIP))
280             {
281                 if (y > rect->bottom - lh)
282                     break;
283             }
284         }
285     }
286     while (strPtr);
287     if (flags & DT_CALCRECT)
288     {
289         rect->right = rect->left + max_width;
290         rect->bottom = y;
291     }
292     return y - rect->top;
293 }
294
295
296 /***********************************************************************
297  *           DrawText32A    (USER32.164)
298  */
299 INT WINAPI DrawTextA( HDC hdc, LPCSTR str, INT count,
300                           LPRECT rect, UINT flags )
301 {
302     RECT16 rect16;
303     INT16 ret;
304
305     if (!rect)
306         return DrawText16( (HDC16)hdc, str, (INT16)count, NULL, (UINT16)flags);
307     CONV_RECT32TO16( rect, &rect16 );
308     ret = DrawText16( (HDC16)hdc, str, (INT16)count, &rect16, (UINT16)flags );
309     CONV_RECT16TO32( &rect16, rect );
310     return ret;
311 }
312
313
314 /***********************************************************************
315  *           DrawText32W    (USER32.167)
316  */
317 INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count,
318                           LPRECT rect, UINT flags )
319 {
320     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
321     INT ret = DrawTextA( hdc, p, count, rect, flags );
322     HeapFree( GetProcessHeap(), 0, p );
323     return ret;
324 }
325
326 /***********************************************************************
327  *           DrawTextEx32A    (USER32.165)
328  */
329 INT WINAPI DrawTextExA( HDC hdc, LPCSTR str, INT count,
330                      LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
331 {
332     TRACE("(%d,'%s',%d,%p,0x%08x,%p)\n",hdc,str,count,rect,flags,dtp);
333     if(dtp) {
334         FIXME("Ignores params:%d,%d,%d,%d,%d\n",dtp->cbSize,
335                    dtp->iTabLength,dtp->iLeftMargin,dtp->iRightMargin,
336                    dtp->uiLengthDrawn);
337     }
338     return DrawTextA(hdc,str,count,rect,flags);
339 }
340
341 /***********************************************************************
342  *           DrawTextEx32W    (USER32.166)
343  */
344 INT WINAPI DrawTextExW( HDC hdc, LPCWSTR str, INT count,
345                      LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
346 {
347     TRACE("(%d,%p,%d,%p,0x%08x,%p)\n",hdc,str,count,rect,flags,dtp);
348     FIXME("ignores extended functionality\n");
349     return DrawTextW(hdc,str,count,rect,flags);
350 }
351
352 /***********************************************************************
353  *           ExtTextOut16    (GDI.351)
354  */
355 BOOL16 WINAPI ExtTextOut16( HDC16 hdc, INT16 x, INT16 y, UINT16 flags,
356                             const RECT16 *lprect, LPCSTR str, UINT16 count,
357                             const INT16 *lpDx )
358 {
359     BOOL        ret;
360     int         i;
361     RECT        rect32;
362     LPINT       lpdx32 = NULL;
363
364     if (lpDx) lpdx32 = (LPINT)HEAP_xalloc( GetProcessHeap(), 0,
365                                              sizeof(INT)*count );
366     if (lprect) CONV_RECT16TO32(lprect,&rect32);
367     if (lpdx32) for (i=count;i--;) lpdx32[i]=lpDx[i];
368     ret = ExtTextOutA(hdc,x,y,flags,lprect?&rect32:NULL,str,count,lpdx32);
369     if (lpdx32) HeapFree( GetProcessHeap(), 0, lpdx32 );
370     return ret;
371
372
373 }
374
375
376 /***********************************************************************
377  *           ExtTextOutA    (GDI32.98)
378  */
379 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
380                              const RECT *lprect, LPCSTR str, UINT count,
381                              const INT *lpDx )
382 {
383     /* str need not be \0 terminated but lstrcpynAtoW adds \0 so we allocate one
384        more byte */
385     LPWSTR p = HeapAlloc( GetProcessHeap(), 0, (count+1) * sizeof(WCHAR) );
386     INT ret;
387     lstrcpynAtoW( p, str, count+1 );
388     ret = ExtTextOutW( hdc, x, y, flags, lprect, p, count, lpDx );
389     HeapFree( GetProcessHeap(), 0, p );
390     return ret;
391 }
392
393
394 /***********************************************************************
395  *           ExtTextOutW    (GDI32.99)
396  */
397 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
398                              const RECT *lprect, LPCWSTR str, UINT count,
399                              const INT *lpDx )
400 {
401     DC * dc = DC_GetDCPtr( hdc );
402     return dc && dc->funcs->pExtTextOut && 
403         dc->funcs->pExtTextOut(dc,x,y,flags,lprect,str,count,lpDx);
404 }
405
406
407 /***********************************************************************
408  *           TextOut16    (GDI.33)
409  */
410 BOOL16 WINAPI TextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR str, INT16 count )
411 {
412     return ExtTextOut16( hdc, x, y, 0, NULL, str, count, NULL );
413 }
414
415
416 /***********************************************************************
417  *           TextOut32A    (GDI32.355)
418  */
419 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
420 {
421     return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
422 }
423
424
425 /***********************************************************************
426  *           TextOut32W    (GDI32.356)
427  */
428 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
429 {
430     return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
431 }
432
433
434 /***********************************************************************
435  *           TEXT_GrayString
436  *
437  * FIXME: The call to 16-bit code only works because the wine GDI is a 16-bit
438  * heap and we can guarantee that the handles fit in an INT16. We have to
439  * rethink the strategy once the migration to NT handles is complete.
440  * We are going to get a lot of code-duplication once this migration is
441  * completed...
442  * 
443  */
444 static BOOL TEXT_GrayString(HDC hdc, HBRUSH hb, 
445                               GRAYSTRINGPROC fn, LPARAM lp, INT len,
446                               INT x, INT y, INT cx, INT cy, 
447                               BOOL unicode, BOOL _32bit)
448 {
449     HBITMAP hbm, hbmsave;
450     HBRUSH hbsave;
451     HFONT hfsave;
452     HDC memdc = CreateCompatibleDC(hdc);
453     int slen = len;
454     BOOL retval = TRUE;
455     RECT r;
456     COLORREF fg, bg;
457
458     if(!hdc) return FALSE;
459     
460     if(len == 0)
461     {
462         if(unicode)
463             slen = lstrlenW((LPCWSTR)lp);
464         else if(_32bit)
465             slen = lstrlenA((LPCSTR)lp);
466         else
467             slen = lstrlenA((LPCSTR)PTR_SEG_TO_LIN(lp));
468     }
469
470     if((cx == 0 || cy == 0) && slen != -1)
471     {
472         SIZE s;
473         if(unicode)
474             GetTextExtentPoint32W(hdc, (LPCWSTR)lp, slen, &s);
475         else if(_32bit)
476             GetTextExtentPoint32A(hdc, (LPCSTR)lp, slen, &s);
477         else
478             GetTextExtentPoint32A(hdc, (LPCSTR)PTR_SEG_TO_LIN(lp), slen, &s);
479         if(cx == 0) cx = s.cx;
480         if(cy == 0) cy = s.cy;
481     }
482
483     r.left = r.top = 0;
484     r.right = cx;
485     r.bottom = cy;
486
487     hbm = CreateBitmap(cx, cy, 1, 1, NULL);
488     hbmsave = (HBITMAP)SelectObject(memdc, hbm);
489     FillRect(memdc, &r, (HBRUSH)GetStockObject(BLACK_BRUSH));
490     SetTextColor(memdc, RGB(255, 255, 255));
491     SetBkColor(memdc, RGB(0, 0, 0));
492     hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
493             
494     if(fn)
495         if(_32bit)
496             retval = fn(memdc, lp, slen);
497         else
498             retval = (BOOL)((BOOL16)((GRAYSTRINGPROC16)fn)((HDC16)memdc, lp, (INT16)slen));
499     else
500         if(unicode)
501             TextOutW(memdc, 0, 0, (LPCWSTR)lp, slen);
502         else if(_32bit)
503             TextOutA(memdc, 0, 0, (LPCSTR)lp, slen);
504         else
505             TextOutA(memdc, 0, 0, (LPCSTR)PTR_SEG_TO_LIN(lp), slen);
506
507     SelectObject(memdc, hfsave);
508
509 /*
510  * Windows doc says that the bitmap isn't grayed when len == -1 and
511  * the callback function returns FALSE. However, testing this on
512  * win95 showed otherwise...
513 */
514 #ifdef GRAYSTRING_USING_DOCUMENTED_BEHAVIOUR
515     if(retval || len != -1)
516 #endif
517     {
518         hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
519         PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
520         SelectObject(memdc, hbsave);
521     }
522
523     if(hb) hbsave = (HBRUSH)SelectObject(hdc, hb);
524     fg = SetTextColor(hdc, RGB(0, 0, 0));
525     bg = SetBkColor(hdc, RGB(255, 255, 255));
526     BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00E20746);
527     SetTextColor(hdc, fg);
528     SetBkColor(hdc, bg);
529     if(hb) SelectObject(hdc, hbsave);
530
531     SelectObject(memdc, hbmsave);
532     DeleteObject(hbm);
533     DeleteDC(memdc);
534     return retval;
535 }
536
537
538 /***********************************************************************
539  *           GrayString16   (USER.185)
540  */
541 BOOL16 WINAPI GrayString16( HDC16 hdc, HBRUSH16 hbr, GRAYSTRINGPROC16 gsprc,
542                             LPARAM lParam, INT16 cch, INT16 x, INT16 y,
543                             INT16 cx, INT16 cy )
544 {
545     return TEXT_GrayString(hdc, hbr, (GRAYSTRINGPROC)gsprc, lParam, cch, x, y, cx, cy, FALSE, FALSE);
546 }
547
548
549 /***********************************************************************
550  *           GrayString32A   (USER32.315)
551  */
552 BOOL WINAPI GrayStringA( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
553                              LPARAM lParam, INT cch, INT x, INT y,
554                              INT cx, INT cy )
555 {
556     return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, FALSE, TRUE);
557 }
558
559
560 /***********************************************************************
561  *           GrayString32W   (USER32.316)
562  */
563 BOOL WINAPI GrayStringW( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
564                              LPARAM lParam, INT cch, INT x, INT y,
565                              INT cx, INT cy )
566 {
567     return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, TRUE, TRUE);
568 }
569
570
571 /***********************************************************************
572  *           TEXT_TabbedTextOut
573  *
574  * Helper function for TabbedTextOut() and GetTabbedTextExtent().
575  * Note: this doesn't work too well for text-alignment modes other
576  *       than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
577  */
578 LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCSTR lpstr,
579                          INT count, INT cTabStops, const INT16 *lpTabPos16,
580                          const INT *lpTabPos32, INT nTabOrg,
581                          BOOL fDisplayText )
582 {
583     INT defWidth;
584     DWORD extent = 0;
585     int i, tabPos = x;
586     int start = x;
587
588     if (cTabStops == 1)
589     {
590         defWidth = lpTabPos32 ? *lpTabPos32 : *lpTabPos16;
591         cTabStops = 0;
592     }
593     else
594     {
595         TEXTMETRIC16 tm;
596         GetTextMetrics16( hdc, &tm );
597         defWidth = 8 * tm.tmAveCharWidth;
598     }
599     
600     while (count > 0)
601     {
602         for (i = 0; i < count; i++)
603             if (lpstr[i] == '\t') break;
604         extent = GetTextExtent16( hdc, lpstr, i );
605         if (lpTabPos32)
606         {
607             while ((cTabStops > 0) &&
608                    (nTabOrg + *lpTabPos32 <= x + LOWORD(extent)))
609             {
610                 lpTabPos32++;
611                 cTabStops--;
612             }
613         }
614         else
615         {
616             while ((cTabStops > 0) &&
617                    (nTabOrg + *lpTabPos16 <= x + LOWORD(extent)))
618             {
619                 lpTabPos16++;
620                 cTabStops--;
621             }
622         }
623         if (i == count)
624             tabPos = x + LOWORD(extent);
625         else if (cTabStops > 0)
626             tabPos = nTabOrg + (lpTabPos32 ? *lpTabPos32 : *lpTabPos16);
627         else
628             tabPos = nTabOrg + ((x + LOWORD(extent) - nTabOrg) / defWidth + 1) * defWidth;
629         if (fDisplayText)
630         {
631             RECT r;
632             SetRect( &r, x, y, tabPos, y+HIWORD(extent) );
633             ExtTextOutA( hdc, x, y,
634                            GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
635                            &r, lpstr, i, NULL );
636         }
637         x = tabPos;
638         count -= i+1;
639         lpstr += i+1;
640     }
641     return MAKELONG(tabPos - start, HIWORD(extent));
642 }
643
644
645 /***********************************************************************
646  *           TabbedTextOut16    (USER.196)
647  */
648 LONG WINAPI TabbedTextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR lpstr,
649                              INT16 count, INT16 cTabStops,
650                              const INT16 *lpTabPos, INT16 nTabOrg )
651 {
652     TRACE("%04x %d,%d '%.*s' %d\n",
653                   hdc, x, y, count, lpstr, count );
654     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
655                                lpTabPos, NULL, nTabOrg, TRUE );
656 }
657
658
659 /***********************************************************************
660  *           TabbedTextOut32A    (USER32.542)
661  */
662 LONG WINAPI TabbedTextOutA( HDC hdc, INT x, INT y, LPCSTR lpstr,
663                               INT count, INT cTabStops,
664                               const INT *lpTabPos, INT nTabOrg )
665 {
666     TRACE("%04x %d,%d '%.*s' %d\n",
667                   hdc, x, y, count, lpstr, count );
668     return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
669                                NULL, lpTabPos, nTabOrg, TRUE );
670 }
671
672
673 /***********************************************************************
674  *           TabbedTextOut32W    (USER32.543)
675  */
676 LONG WINAPI TabbedTextOutW( HDC hdc, INT x, INT y, LPCWSTR str,
677                               INT count, INT cTabStops,
678                               const INT *lpTabPos, INT nTabOrg )
679 {
680     LONG ret;
681     LPSTR p = HEAP_xalloc( GetProcessHeap(), 0, count + 1 );
682     lstrcpynWtoA( p, str, count + 1 );
683     ret = TabbedTextOutA( hdc, x, y, p, count, cTabStops,
684                             lpTabPos, nTabOrg );
685     HeapFree( GetProcessHeap(), 0, p );
686     return ret;
687 }
688
689
690 /***********************************************************************
691  *           GetTabbedTextExtent16    (USER.197)
692  */
693 DWORD WINAPI GetTabbedTextExtent16( HDC16 hdc, LPCSTR lpstr, INT16 count, 
694                                     INT16 cTabStops, const INT16 *lpTabPos )
695 {
696     TRACE("%04x '%.*s' %d\n",
697                   hdc, count, lpstr, count );
698     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
699                                lpTabPos, NULL, 0, FALSE );
700 }
701
702
703 /***********************************************************************
704  *           GetTabbedTextExtent32A    (USER32.293)
705  */
706 DWORD WINAPI GetTabbedTextExtentA( HDC hdc, LPCSTR lpstr, INT count, 
707                                      INT cTabStops, const INT *lpTabPos )
708 {
709     TRACE("%04x '%.*s' %d\n",
710                   hdc, count, lpstr, count );
711     return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
712                                NULL, lpTabPos, 0, FALSE );
713 }
714
715
716 /***********************************************************************
717  *           GetTabbedTextExtent32W    (USER32.294)
718  */
719 DWORD WINAPI GetTabbedTextExtentW( HDC hdc, LPCWSTR lpstr, INT count, 
720                                      INT cTabStops, const INT *lpTabPos )
721 {
722     LONG ret;
723     LPSTR p = HEAP_xalloc( GetProcessHeap(), 0, count + 1 );
724     lstrcpynWtoA( p, lpstr, count + 1 );
725     ret = GetTabbedTextExtentA( hdc, p, count, cTabStops, lpTabPos );
726     HeapFree( GetProcessHeap(), 0, p );
727     return ret;
728 }
729
730 /***********************************************************************
731  * GetTextCharset32 [GDI32.226]  Gets character set for font in DC
732  *
733  * NOTES
734  *    Should it return a UINT32 instead of an INT32?
735  *    => YES, as GetTextCharsetInfo returns UINT32
736  *
737  * RETURNS
738  *    Success: Character set identifier
739  *    Failure: DEFAULT_CHARSET
740  */
741 UINT WINAPI GetTextCharset(
742     HDC hdc) /* [in] Handle to device context */
743 {
744     /* MSDN docs say this is equivalent */
745     return GetTextCharsetInfo(hdc, NULL, 0);
746 }
747
748 /***********************************************************************
749  * GetTextCharset16 [GDI.612]
750  */
751 UINT16 WINAPI GetTextCharset16(HDC16 hdc)
752 {
753     return (UINT16)GetTextCharset(hdc);
754 }
755
756 /***********************************************************************
757  * GetTextCharsetInfo [GDI32.381]  Gets character set for font
758  *
759  * NOTES
760  *    Should csi be an LPFONTSIGNATURE instead of an LPCHARSETINFO?
761  *    Should it return a UINT32 instead of an INT32?
762  *    => YES and YES, from win32.hlp from Borland
763  *
764  * RETURNS
765  *    Success: Character set identifier
766  *    Failure: DEFAULT_CHARSET
767  */
768 UINT WINAPI GetTextCharsetInfo(
769     HDC hdc,          /* [in]  Handle to device context */
770     LPFONTSIGNATURE fs, /* [out] Pointer to struct to receive data */
771     DWORD flags)        /* [in]  Reserved - must be 0 */
772 {
773     HGDIOBJ hFont;
774     UINT charSet = DEFAULT_CHARSET;
775     LOGFONTW lf;
776     CHARSETINFO csinfo;
777
778     hFont = GetCurrentObject(hdc, OBJ_FONT);
779     if (hFont == 0)
780         return(DEFAULT_CHARSET);
781     if ( GetObjectW(hFont, sizeof(LOGFONTW), &lf) != 0 )
782         charSet = lf.lfCharSet;
783
784     if (fs != NULL) {
785       if (!TranslateCharsetInfo((LPDWORD)charSet, &csinfo, TCI_SRCCHARSET))
786            return  (DEFAULT_CHARSET);
787       memcpy(fs, &csinfo.fs, sizeof(FONTSIGNATURE));
788     }
789     return charSet;
790 }
791
792 /***********************************************************************
793  * PolyTextOutA [GDI.402]  Draw several Strings
794  */
795 BOOL WINAPI PolyTextOutA (
796                           HDC hdc,               /* Handle to device context */                   
797                           PPOLYTEXTA pptxt,      /* array of strings */
798                           INT cStrings           /* Number of strings in array */
799                           )
800 {
801   FIXME("stub!\n");
802   SetLastError ( ERROR_CALL_NOT_IMPLEMENTED );
803   return 0;
804 }
805
806
807
808 /***********************************************************************
809  * PolyTextOutW [GDI.403] Draw several Strings
810  */
811 BOOL WINAPI PolyTextOutW ( 
812                           HDC hdc,               /* Handle to device context */                   
813                           PPOLYTEXTW pptxt,      /* array of strings */
814                           INT cStrings           /* Number of strings in array */
815                           )
816 {
817   FIXME("stub!\n");
818   SetLastError ( ERROR_CALL_NOT_IMPLEMENTED );
819   return 0;
820 }