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