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