mshtml: Added IHTMLStyleSheet::get_rules implementation.
[wine] / dlls / gdi32 / font.c
1 /*
2  * GDI font objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1997 Alex Korobka
6  * Copyright 2002,2003 Shachar Shemesh
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include "winerror.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "wownt32.h"
35 #include "gdi_private.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(font);
40
41   /* Device -> World size conversion */
42
43 /* Performs a device to world transformation on the specified width (which
44  * is in integer format).
45  */
46 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
47 {
48     FLOAT floatWidth;
49
50     /* Perform operation with floating point */
51     floatWidth = (FLOAT)width * dc->xformVport2World.eM11;
52     /* Round to integers */
53     return GDI_ROUND(floatWidth);
54 }
55
56 /* Performs a device to world transformation on the specified size (which
57  * is in integer format).
58  */
59 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
60 {
61     FLOAT floatHeight;
62
63     /* Perform operation with floating point */
64     floatHeight = (FLOAT)height * dc->xformVport2World.eM22;
65     /* Round to integers */
66     return GDI_ROUND(floatHeight);
67 }
68
69 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
70 {
71     POINT pt[2];
72     pt[0].x = pt[0].y = 0;
73     pt[1].x = width;
74     pt[1].y = 0;
75     LPtoDP(dc->hSelf, pt, 2);
76     return pt[1].x - pt[0].x;
77 }
78
79 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
80 {
81     POINT pt[2];
82     pt[0].x = pt[0].y = 0;
83     pt[1].x = 0;
84     pt[1].y = height;
85     LPtoDP(dc->hSelf, pt, 2);
86     return pt[1].y - pt[0].y;
87 }
88
89 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
90 static INT FONT_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
91 static INT FONT_GetObjectA( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
92 static INT FONT_GetObjectW( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
93 static BOOL FONT_DeleteObject( HGDIOBJ handle, void *obj );
94
95 static const struct gdi_obj_funcs font_funcs =
96 {
97     FONT_SelectObject,  /* pSelectObject */
98     FONT_GetObject16,   /* pGetObject16 */
99     FONT_GetObjectA,    /* pGetObjectA */
100     FONT_GetObjectW,    /* pGetObjectW */
101     NULL,               /* pUnrealizeObject */
102     FONT_DeleteObject   /* pDeleteObject */
103 };
104
105 #define ENUM_UNICODE    0x00000001
106 #define ENUM_CALLED     0x00000002
107
108 typedef struct
109 {
110     GDIOBJHDR   header;
111     LOGFONTW    logfont;
112 } FONTOBJ;
113
114 typedef struct
115 {
116   LPLOGFONT16           lpLogFontParam;
117   FONTENUMPROC16        lpEnumFunc;
118   LPARAM                lpData;
119
120   LPNEWTEXTMETRICEX16   lpTextMetric;
121   LPENUMLOGFONTEX16     lpLogFont;
122   SEGPTR                segTextMetric;
123   SEGPTR                segLogFont;
124   DWORD                 dwFlags;
125   HDC                   hdc;
126   DC                   *dc;
127   PHYSDEV               physDev;
128 } fontEnum16;
129
130 typedef struct
131 {
132   LPLOGFONTW          lpLogFontParam;
133   FONTENUMPROCW       lpEnumFunc;
134   LPARAM              lpData;
135   DWORD               dwFlags;
136   HDC                 hdc;
137   DC                 *dc;
138   PHYSDEV             physDev;
139 } fontEnum32;
140
141 /*
142  *  For TranslateCharsetInfo
143  */
144 #define FS(x) {{0,0,0,0},{0x1<<(x),0}}
145 #define MAXTCIINDEX 32
146 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
147   /* ANSI */
148   { ANSI_CHARSET, 1252, FS(0)},
149   { EASTEUROPE_CHARSET, 1250, FS(1)},
150   { RUSSIAN_CHARSET, 1251, FS(2)},
151   { GREEK_CHARSET, 1253, FS(3)},
152   { TURKISH_CHARSET, 1254, FS(4)},
153   { HEBREW_CHARSET, 1255, FS(5)},
154   { ARABIC_CHARSET, 1256, FS(6)},
155   { BALTIC_CHARSET, 1257, FS(7)},
156   { VIETNAMESE_CHARSET, 1258, FS(8)},
157   /* reserved by ANSI */
158   { DEFAULT_CHARSET, 0, FS(0)},
159   { DEFAULT_CHARSET, 0, FS(0)},
160   { DEFAULT_CHARSET, 0, FS(0)},
161   { DEFAULT_CHARSET, 0, FS(0)},
162   { DEFAULT_CHARSET, 0, FS(0)},
163   { DEFAULT_CHARSET, 0, FS(0)},
164   { DEFAULT_CHARSET, 0, FS(0)},
165   /* ANSI and OEM */
166   { THAI_CHARSET,  874,  FS(16)},
167   { SHIFTJIS_CHARSET, 932, FS(17)},
168   { GB2312_CHARSET, 936, FS(18)},
169   { HANGEUL_CHARSET, 949, FS(19)},
170   { CHINESEBIG5_CHARSET, 950, FS(20)},
171   { JOHAB_CHARSET, 1361, FS(21)},
172   /* reserved for alternate ANSI and OEM */
173   { DEFAULT_CHARSET, 0, FS(0)},
174   { DEFAULT_CHARSET, 0, FS(0)},
175   { DEFAULT_CHARSET, 0, FS(0)},
176   { DEFAULT_CHARSET, 0, FS(0)},
177   { DEFAULT_CHARSET, 0, FS(0)},
178   { DEFAULT_CHARSET, 0, FS(0)},
179   { DEFAULT_CHARSET, 0, FS(0)},
180   { DEFAULT_CHARSET, 0, FS(0)},
181   /* reserved for system */
182   { DEFAULT_CHARSET, 0, FS(0)},
183   { SYMBOL_CHARSET, CP_SYMBOL, FS(31)},
184 };
185
186 /***********************************************************************
187  *              LOGFONT conversion functions.
188  */
189 static void FONT_LogFontWTo16( const LOGFONTW* font32, LPLOGFONT16 font16 )
190 {
191     font16->lfHeight = font32->lfHeight;
192     font16->lfWidth = font32->lfWidth;
193     font16->lfEscapement = font32->lfEscapement;
194     font16->lfOrientation = font32->lfOrientation;
195     font16->lfWeight = font32->lfWeight;
196     font16->lfItalic = font32->lfItalic;
197     font16->lfUnderline = font32->lfUnderline;
198     font16->lfStrikeOut = font32->lfStrikeOut;
199     font16->lfCharSet = font32->lfCharSet;
200     font16->lfOutPrecision = font32->lfOutPrecision;
201     font16->lfClipPrecision = font32->lfClipPrecision;
202     font16->lfQuality = font32->lfQuality;
203     font16->lfPitchAndFamily = font32->lfPitchAndFamily;
204     WideCharToMultiByte( CP_ACP, 0, font32->lfFaceName, -1,
205                          font16->lfFaceName, LF_FACESIZE, NULL, NULL );
206     font16->lfFaceName[LF_FACESIZE-1] = 0;
207 }
208
209 static void FONT_LogFont16ToW( const LOGFONT16 *font16, LPLOGFONTW font32 )
210 {
211     font32->lfHeight = font16->lfHeight;
212     font32->lfWidth = font16->lfWidth;
213     font32->lfEscapement = font16->lfEscapement;
214     font32->lfOrientation = font16->lfOrientation;
215     font32->lfWeight = font16->lfWeight;
216     font32->lfItalic = font16->lfItalic;
217     font32->lfUnderline = font16->lfUnderline;
218     font32->lfStrikeOut = font16->lfStrikeOut;
219     font32->lfCharSet = font16->lfCharSet;
220     font32->lfOutPrecision = font16->lfOutPrecision;
221     font32->lfClipPrecision = font16->lfClipPrecision;
222     font32->lfQuality = font16->lfQuality;
223     font32->lfPitchAndFamily = font16->lfPitchAndFamily;
224     MultiByteToWideChar( CP_ACP, 0, font16->lfFaceName, -1, font32->lfFaceName, LF_FACESIZE );
225     font32->lfFaceName[LF_FACESIZE-1] = 0;
226 }
227
228 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
229 {
230     memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
231     MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
232                         LF_FACESIZE);
233     fontW->lfFaceName[LF_FACESIZE-1] = 0;
234 }
235
236 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
237 {
238     memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
239     WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
240                         LF_FACESIZE, NULL, NULL);
241     fontA->lfFaceName[LF_FACESIZE-1] = 0;
242 }
243
244 static void FONT_EnumLogFontExWTo16( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEX16 font16 )
245 {
246     FONT_LogFontWTo16( (const LOGFONTW *)fontW, (LPLOGFONT16)font16);
247
248     WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
249                          (LPSTR) font16->elfFullName, LF_FULLFACESIZE, NULL, NULL );
250     font16->elfFullName[LF_FULLFACESIZE-1] = '\0';
251     WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
252                          (LPSTR) font16->elfStyle, LF_FACESIZE, NULL, NULL );
253     font16->elfStyle[LF_FACESIZE-1] = '\0';
254     WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
255                          (LPSTR) font16->elfScript, LF_FACESIZE, NULL, NULL );
256     font16->elfScript[LF_FACESIZE-1] = '\0';
257 }
258
259 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
260 {
261     FONT_LogFontWToA( (const LOGFONTW *)fontW, (LPLOGFONTA)fontA);
262
263     WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
264                          (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
265     fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
266     WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
267                          (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
268     fontA->elfStyle[LF_FACESIZE-1] = '\0';
269     WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
270                          (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
271     fontA->elfScript[LF_FACESIZE-1] = '\0';
272 }
273
274 /***********************************************************************
275  *              TEXTMETRIC conversion functions.
276  */
277 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
278 {
279     ptmA->tmHeight = ptmW->tmHeight;
280     ptmA->tmAscent = ptmW->tmAscent;
281     ptmA->tmDescent = ptmW->tmDescent;
282     ptmA->tmInternalLeading = ptmW->tmInternalLeading;
283     ptmA->tmExternalLeading = ptmW->tmExternalLeading;
284     ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
285     ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
286     ptmA->tmWeight = ptmW->tmWeight;
287     ptmA->tmOverhang = ptmW->tmOverhang;
288     ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
289     ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
290     ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
291     if (ptmW->tmCharSet == SYMBOL_CHARSET)
292     {
293         UINT last_char = ptmW->tmLastChar;
294         if (last_char > 0xf000) last_char -= 0xf000;
295         ptmA->tmLastChar = min(last_char, 255);
296     }
297     else
298         ptmA->tmLastChar = min(ptmW->tmLastChar, 255);
299     ptmA->tmDefaultChar = min(ptmW->tmDefaultChar, 255);
300     ptmA->tmBreakChar = min(ptmW->tmBreakChar, 255);
301     ptmA->tmItalic = ptmW->tmItalic;
302     ptmA->tmUnderlined = ptmW->tmUnderlined;
303     ptmA->tmStruckOut = ptmW->tmStruckOut;
304     ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
305     ptmA->tmCharSet = ptmW->tmCharSet;
306 }
307
308
309 static void FONT_NewTextMetricExWTo16(const NEWTEXTMETRICEXW *ptmW, LPNEWTEXTMETRICEX16 ptm16 )
310 {
311     ptm16->ntmTm.tmHeight = ptmW->ntmTm.tmHeight;
312     ptm16->ntmTm.tmAscent = ptmW->ntmTm.tmAscent;
313     ptm16->ntmTm.tmDescent = ptmW->ntmTm.tmDescent;
314     ptm16->ntmTm.tmInternalLeading = ptmW->ntmTm.tmInternalLeading;
315     ptm16->ntmTm.tmExternalLeading = ptmW->ntmTm.tmExternalLeading;
316     ptm16->ntmTm.tmAveCharWidth = ptmW->ntmTm.tmAveCharWidth;
317     ptm16->ntmTm.tmMaxCharWidth = ptmW->ntmTm.tmMaxCharWidth;
318     ptm16->ntmTm.tmWeight = ptmW->ntmTm.tmWeight;
319     ptm16->ntmTm.tmOverhang = ptmW->ntmTm.tmOverhang;
320     ptm16->ntmTm.tmDigitizedAspectX = ptmW->ntmTm.tmDigitizedAspectX;
321     ptm16->ntmTm.tmDigitizedAspectY = ptmW->ntmTm.tmDigitizedAspectY;
322     ptm16->ntmTm.tmFirstChar = ptmW->ntmTm.tmFirstChar > 255 ? 255 : ptmW->ntmTm.tmFirstChar;
323     ptm16->ntmTm.tmLastChar = ptmW->ntmTm.tmLastChar > 255 ? 255 : ptmW->ntmTm.tmLastChar;
324     ptm16->ntmTm.tmDefaultChar = ptmW->ntmTm.tmDefaultChar > 255 ? 255 : ptmW->ntmTm.tmDefaultChar;
325     ptm16->ntmTm.tmBreakChar = ptmW->ntmTm.tmBreakChar > 255 ? 255 : ptmW->ntmTm.tmBreakChar;
326     ptm16->ntmTm.tmItalic = ptmW->ntmTm.tmItalic;
327     ptm16->ntmTm.tmUnderlined = ptmW->ntmTm.tmUnderlined;
328     ptm16->ntmTm.tmStruckOut = ptmW->ntmTm.tmStruckOut;
329     ptm16->ntmTm.tmPitchAndFamily = ptmW->ntmTm.tmPitchAndFamily;
330     ptm16->ntmTm.tmCharSet = ptmW->ntmTm.tmCharSet;
331     ptm16->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
332     ptm16->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
333     ptm16->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
334     ptm16->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
335     memcpy(&ptm16->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
336 }
337
338 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
339 {
340     FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
341     ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
342     ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
343     ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
344     ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
345     memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
346 }
347
348
349 /***********************************************************************
350  *           GdiGetCodePage   (GDI32.@)
351  */
352 DWORD WINAPI GdiGetCodePage( HDC hdc )
353 {
354     UINT cp = CP_ACP;
355     CHARSETINFO csi;
356     int charset = GetTextCharset(hdc);
357
358     /* Hmm, nicely designed api this one! */
359     if(TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
360         cp = csi.ciACP;
361     else {
362         switch(charset) {
363         case OEM_CHARSET:
364             cp = GetOEMCP();
365             break;
366         case DEFAULT_CHARSET:
367             cp = GetACP();
368             break;
369
370         case VISCII_CHARSET:
371         case TCVN_CHARSET:
372         case KOI8_CHARSET:
373         case ISO3_CHARSET:
374         case ISO4_CHARSET:
375         case ISO10_CHARSET:
376         case CELTIC_CHARSET:
377             /* FIXME: These have no place here, but because x11drv
378                enumerates fonts with these (made up) charsets some apps
379                might use them and then the FIXME below would become
380                annoying.  Now we could pick the intended codepage for
381                each of these, but since it's broken anyway we'll just
382                use CP_ACP and hope it'll go away...
383             */
384             cp = CP_ACP;
385             break;
386
387         default:
388             FIXME("Can't find codepage for charset %d\n", charset);
389             break;
390         }
391     }
392
393     TRACE("charset %d => cp %d\n", charset, cp);
394     return cp;
395 }
396
397 /***********************************************************************
398  *           FONT_mbtowc
399  *
400  * Returns a Unicode translation of str using the charset of the
401  * currently selected font in hdc.  If count is -1 then str is assumed
402  * to be '\0' terminated, otherwise it contains the number of bytes to
403  * convert.  If plenW is non-NULL, on return it will point to the
404  * number of WCHARs that have been written.  If pCP is non-NULL, on
405  * return it will point to the codepage used in the conversion.  The
406  * caller should free the returned LPWSTR from the process heap
407  * itself.
408  */
409 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
410 {
411     UINT cp;
412     INT lenW;
413     LPWSTR strW;
414
415     cp = GdiGetCodePage( hdc );
416
417     if(count == -1) count = strlen(str);
418     lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
419     strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
420     MultiByteToWideChar(cp, 0, str, count, strW, lenW);
421     TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
422     if(plenW) *plenW = lenW;
423     if(pCP) *pCP = cp;
424     return strW;
425 }
426
427
428 /***********************************************************************
429  *           CreateFontIndirectA   (GDI32.@)
430  */
431 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
432 {
433     LOGFONTW lfW;
434
435     if (plfA) {
436         FONT_LogFontAToW( plfA, &lfW );
437         return CreateFontIndirectW( &lfW );
438      } else
439         return CreateFontIndirectW( NULL );
440
441 }
442
443 /***********************************************************************
444  *           CreateFontIndirectW   (GDI32.@)
445  */
446 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
447 {
448     HFONT hFont = 0;
449
450     if (plf)
451     {
452         FONTOBJ* fontPtr;
453         if ((fontPtr = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC,
454                                         (HGDIOBJ *)&hFont, &font_funcs )))
455         {
456             static const WCHAR ItalicW[] = {' ','I','t','a','l','i','c','\0'};
457             static const WCHAR BoldW[]   = {' ','B','o','l','d','\0'};
458             WCHAR *pFaceNameItalicSuffix, *pFaceNameBoldSuffix;
459             WCHAR* pFaceNameSuffix = NULL;
460
461             memcpy( &fontPtr->logfont, plf, sizeof(LOGFONTW) );
462
463             TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
464                   plf->lfHeight, plf->lfWidth,
465                   plf->lfEscapement, plf->lfOrientation,
466                   plf->lfPitchAndFamily,
467                   plf->lfOutPrecision, plf->lfClipPrecision,
468                   plf->lfQuality, plf->lfCharSet,
469                   debugstr_w(plf->lfFaceName),
470                   plf->lfWeight > 400 ? "Bold" : "",
471                   plf->lfItalic ? "Italic" : "",
472                   plf->lfUnderline ? "Underline" : "", hFont);
473
474             if (plf->lfEscapement != plf->lfOrientation) {
475               /* this should really depend on whether GM_ADVANCED is set */
476               fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
477               WARN("orientation angle %f set to "
478                    "escapement angle %f for new font %p\n",
479                    plf->lfOrientation/10., plf->lfEscapement/10., hFont);
480             }
481
482             pFaceNameItalicSuffix = strstrW(fontPtr->logfont.lfFaceName, ItalicW);
483             if (pFaceNameItalicSuffix) {
484                 fontPtr->logfont.lfItalic = TRUE;
485                 pFaceNameSuffix = pFaceNameItalicSuffix;
486             }
487
488             pFaceNameBoldSuffix = strstrW(fontPtr->logfont.lfFaceName, BoldW);
489             if (pFaceNameBoldSuffix) {
490                 if (fontPtr->logfont.lfWeight < FW_BOLD) {
491                     fontPtr->logfont.lfWeight = FW_BOLD;
492                 }
493                 if (!pFaceNameSuffix ||
494                     (pFaceNameBoldSuffix < pFaceNameSuffix)) {
495                     pFaceNameSuffix = pFaceNameBoldSuffix;
496                 }
497             }
498
499             if (pFaceNameSuffix) *pFaceNameSuffix = 0;
500
501             GDI_ReleaseObj( hFont );
502         }
503     }
504     else WARN("(NULL) => NULL\n");
505
506     return hFont;
507 }
508
509 /*************************************************************************
510  *           CreateFontA    (GDI32.@)
511  */
512 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
513                               INT orient, INT weight, DWORD italic,
514                               DWORD underline, DWORD strikeout, DWORD charset,
515                               DWORD outpres, DWORD clippres, DWORD quality,
516                               DWORD pitch, LPCSTR name )
517 {
518     LOGFONTA logfont;
519
520     logfont.lfHeight = height;
521     logfont.lfWidth = width;
522     logfont.lfEscapement = esc;
523     logfont.lfOrientation = orient;
524     logfont.lfWeight = weight;
525     logfont.lfItalic = italic;
526     logfont.lfUnderline = underline;
527     logfont.lfStrikeOut = strikeout;
528     logfont.lfCharSet = charset;
529     logfont.lfOutPrecision = outpres;
530     logfont.lfClipPrecision = clippres;
531     logfont.lfQuality = quality;
532     logfont.lfPitchAndFamily = pitch;
533
534     if (name)
535         lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
536     else
537         logfont.lfFaceName[0] = '\0';
538
539     return CreateFontIndirectA( &logfont );
540 }
541
542 /*************************************************************************
543  *           CreateFontW    (GDI32.@)
544  */
545 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
546                               INT orient, INT weight, DWORD italic,
547                               DWORD underline, DWORD strikeout, DWORD charset,
548                               DWORD outpres, DWORD clippres, DWORD quality,
549                               DWORD pitch, LPCWSTR name )
550 {
551     LOGFONTW logfont;
552
553     logfont.lfHeight = height;
554     logfont.lfWidth = width;
555     logfont.lfEscapement = esc;
556     logfont.lfOrientation = orient;
557     logfont.lfWeight = weight;
558     logfont.lfItalic = italic;
559     logfont.lfUnderline = underline;
560     logfont.lfStrikeOut = strikeout;
561     logfont.lfCharSet = charset;
562     logfont.lfOutPrecision = outpres;
563     logfont.lfClipPrecision = clippres;
564     logfont.lfQuality = quality;
565     logfont.lfPitchAndFamily = pitch;
566
567     if (name)
568         lstrcpynW(logfont.lfFaceName, name,
569                   sizeof(logfont.lfFaceName) / sizeof(WCHAR));
570     else
571         logfont.lfFaceName[0] = '\0';
572
573     return CreateFontIndirectW( &logfont );
574 }
575
576
577 /***********************************************************************
578  *           FONT_SelectObject
579  *
580  * If the driver supports vector fonts we create a gdi font first and
581  * then call the driver to give it a chance to supply its own device
582  * font.  If the driver wants to do this it returns TRUE and we can
583  * delete the gdi font, if the driver wants to use the gdi font it
584  * should return FALSE, to signal an error return GDI_ERROR.  For
585  * drivers that don't support vector fonts they must supply their own
586  * font.
587  */
588 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
589 {
590     HGDIOBJ ret = 0;
591     DC *dc = get_dc_ptr( hdc );
592
593     if (!dc) return 0;
594
595     if (!GDI_inc_ref_count( handle ))
596     {
597         release_dc_ptr( dc );
598         return 0;
599     }
600
601     if (dc->hFont != handle || dc->gdiFont == NULL)
602     {
603         if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE)
604         {
605             FONTOBJ *font = GDI_GetObjPtr( handle, FONT_MAGIC );  /* to grab the GDI lock (FIXME) */
606             dc->gdiFont = WineEngCreateFontInstance(dc, handle);
607             if (font) GDI_ReleaseObj( handle );
608         }
609     }
610
611     if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont );
612
613     if (ret && dc->gdiFont) dc->gdiFont = 0;
614
615     if (ret == HGDI_ERROR)
616     {
617         GDI_dec_ref_count( handle );
618         ret = 0; /* SelectObject returns 0 on error */
619     }
620     else
621     {
622         ret = dc->hFont;
623         dc->hFont = handle;
624         GDI_dec_ref_count( ret );
625     }
626     release_dc_ptr( dc );
627     return ret;
628 }
629
630
631 /***********************************************************************
632  *           FONT_GetObject16
633  */
634 static INT FONT_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
635 {
636     FONTOBJ *font = obj;
637     LOGFONT16 lf16;
638
639     FONT_LogFontWTo16( &font->logfont, &lf16 );
640
641     if (count > sizeof(LOGFONT16)) count = sizeof(LOGFONT16);
642     memcpy( buffer, &lf16, count );
643     return count;
644 }
645
646 /***********************************************************************
647  *           FONT_GetObjectA
648  */
649 static INT FONT_GetObjectA( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
650 {
651     FONTOBJ *font = obj;
652     LOGFONTA lfA;
653
654     if(!buffer)
655         return sizeof(lfA);
656     FONT_LogFontWToA( &font->logfont, &lfA );
657
658     if (count > sizeof(lfA)) count = sizeof(lfA);
659     memcpy( buffer, &lfA, count );
660     return count;
661 }
662
663 /***********************************************************************
664  *           FONT_GetObjectW
665  */
666 static INT FONT_GetObjectW( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
667 {
668     FONTOBJ *font = obj;
669     if(!buffer)
670         return sizeof(LOGFONTW);
671     if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
672     memcpy( buffer, &font->logfont, count );
673     return count;
674 }
675
676
677 /***********************************************************************
678  *           FONT_DeleteObject
679  */
680 static BOOL FONT_DeleteObject( HGDIOBJ handle, void *obj )
681 {
682     WineEngDestroyFontInstance( handle );
683     return GDI_FreeObject( handle, obj );
684 }
685
686
687 /***********************************************************************
688  *              FONT_EnumInstance16
689  *
690  * Called by the device driver layer to pass font info
691  * down to the application.
692  *
693  * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
694  *       We have to use other types because of the FONTENUMPROCW definition.
695  */
696 static INT CALLBACK FONT_EnumInstance16( const LOGFONTW *plf, const TEXTMETRICW *ptm,
697                                          DWORD fType, LPARAM lp )
698 {
699     fontEnum16 *pfe = (fontEnum16*)lp;
700     INT ret = 1;
701     DC *dc;
702
703     if( pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
704         pfe->lpLogFontParam->lfCharSet == plf->lfCharSet )
705     {
706         WORD args[7];
707         DWORD result;
708
709         FONT_EnumLogFontExWTo16((const ENUMLOGFONTEXW *)plf, pfe->lpLogFont);
710         FONT_NewTextMetricExWTo16((const NEWTEXTMETRICEXW *)ptm, pfe->lpTextMetric);
711         pfe->dwFlags |= ENUM_CALLED;
712         DC_ReleaseDCPtr( pfe->dc );  /* release the GDI lock */
713
714         args[6] = SELECTOROF(pfe->segLogFont);
715         args[5] = OFFSETOF(pfe->segLogFont);
716         args[4] = SELECTOROF(pfe->segTextMetric);
717         args[3] = OFFSETOF(pfe->segTextMetric);
718         args[2] = fType;
719         args[1] = HIWORD(pfe->lpData);
720         args[0] = LOWORD(pfe->lpData);
721         WOWCallback16Ex( (DWORD)pfe->lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &result );
722         ret = LOWORD(result);
723
724         /* get the lock again and make sure the DC is still valid */
725         dc = DC_GetDCPtr( pfe->hdc );
726         if (!dc || dc != pfe->dc || dc->physDev != pfe->physDev)
727         {
728             if (dc) DC_ReleaseDCPtr( dc );
729             pfe->hdc = 0;  /* make sure we don't try to release it later on */
730             pfe->dc = NULL;
731             ret = 0;
732         }
733     }
734     return ret;
735 }
736
737 /***********************************************************************
738  *              FONT_EnumInstance
739  *
740  * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
741  *       We have to use other types because of the FONTENUMPROCW definition.
742  */
743 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
744                                        DWORD fType, LPARAM lp )
745 {
746     fontEnum32 *pfe = (fontEnum32*)lp;
747     INT ret = 1;
748     DC *dc;
749
750     /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
751     if((pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
752         pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
753        (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
754     {
755         /* convert font metrics */
756         ENUMLOGFONTEXA logfont;
757         NEWTEXTMETRICEXA tmA;
758
759         pfe->dwFlags |= ENUM_CALLED;
760         if (!(pfe->dwFlags & ENUM_UNICODE))
761         {
762             FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
763             FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
764             plf = (LOGFONTW *)&logfont.elfLogFont;
765             ptm = (TEXTMETRICW *)&tmA;
766         }
767         DC_ReleaseDCPtr( pfe->dc );  /* release the GDI lock */
768
769         ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
770
771         /* get the lock again and make sure the DC is still valid */
772         dc = DC_GetDCPtr( pfe->hdc );
773         if (!dc || dc != pfe->dc || dc->physDev != pfe->physDev)
774         {
775             if (dc) DC_ReleaseDCPtr( dc );
776             pfe->hdc = 0;  /* make sure we don't try to release it later on */
777             pfe->dc = NULL;
778             ret = 0;
779         }
780     }
781     return ret;
782 }
783
784 /***********************************************************************
785  *              EnumFontFamiliesEx      (GDI.613)
786  */
787 INT16 WINAPI EnumFontFamiliesEx16( HDC16 hDC, LPLOGFONT16 plf,
788                                    FONTENUMPROC16 efproc, LPARAM lParam,
789                                    DWORD dwFlags)
790 {
791     fontEnum16 fe16;
792     INT16       ret = 1, ret2;
793     DC*         dc = DC_GetDCPtr( HDC_32(hDC) );
794     NEWTEXTMETRICEX16 tm16;
795     ENUMLOGFONTEX16 lf16;
796     LOGFONTW lfW;
797     BOOL enum_gdi_fonts;
798
799     if (!dc) return 0;
800     FONT_LogFont16ToW(plf, &lfW);
801
802     fe16.hdc = HDC_32(hDC);
803     fe16.dc = dc;
804     fe16.physDev = dc->physDev;
805     fe16.lpLogFontParam = plf;
806     fe16.lpEnumFunc = efproc;
807     fe16.lpData = lParam;
808     fe16.lpTextMetric = &tm16;
809     fe16.lpLogFont = &lf16;
810     fe16.segTextMetric = MapLS( &tm16 );
811     fe16.segLogFont = MapLS( &lf16 );
812     fe16.dwFlags = 0;
813
814     enum_gdi_fonts = GetDeviceCaps(fe16.hdc, TEXTCAPS) & TC_VA_ABLE;
815
816     if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
817     {
818         ret = 0;
819         goto done;
820     }
821
822     if (enum_gdi_fonts)
823         ret = WineEngEnumFonts( &lfW, FONT_EnumInstance16, (LPARAM)&fe16 );
824     fe16.dwFlags &= ~ENUM_CALLED;
825     if (ret && dc->funcs->pEnumDeviceFonts) {
826         ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, &lfW, FONT_EnumInstance16, (LPARAM)&fe16 );
827         if(fe16.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
828             ret = ret2;
829     }
830 done:
831     UnMapLS( fe16.segTextMetric );
832     UnMapLS( fe16.segLogFont );
833     if (fe16.dc) DC_ReleaseDCPtr( fe16.dc );
834     return ret;
835 }
836
837 /***********************************************************************
838  *              FONT_EnumFontFamiliesEx
839  */
840 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf,
841                                     FONTENUMPROCW efproc,
842                                     LPARAM lParam, DWORD dwUnicode)
843 {
844     INT ret = 1, ret2;
845     DC *dc = DC_GetDCPtr( hDC );
846     fontEnum32 fe32;
847     BOOL enum_gdi_fonts;
848
849     if (!dc) return 0;
850
851     TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName),
852           plf->lfCharSet);
853     fe32.lpLogFontParam = plf;
854     fe32.lpEnumFunc = efproc;
855     fe32.lpData = lParam;
856     fe32.dwFlags = dwUnicode;
857     fe32.hdc = hDC;
858     fe32.dc = dc;
859     fe32.physDev = dc->physDev;
860
861     enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE;
862
863     if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
864     {
865         ret = 0;
866         goto done;
867     }
868
869     if (enum_gdi_fonts)
870         ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 );
871     fe32.dwFlags &= ~ENUM_CALLED;
872     if (ret && dc->funcs->pEnumDeviceFonts) {
873         ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 );
874         if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
875             ret = ret2;
876     }
877  done:
878     if (fe32.dc) DC_ReleaseDCPtr( fe32.dc );
879     return ret;
880 }
881
882 /***********************************************************************
883  *              EnumFontFamiliesExW     (GDI32.@)
884  */
885 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
886                                     FONTENUMPROCW efproc,
887                                     LPARAM lParam, DWORD dwFlags )
888 {
889     return  FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE );
890 }
891
892 /***********************************************************************
893  *              EnumFontFamiliesExA     (GDI32.@)
894  */
895 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
896                                     FONTENUMPROCA efproc,
897                                     LPARAM lParam, DWORD dwFlags)
898 {
899     LOGFONTW lfW;
900     FONT_LogFontAToW( plf, &lfW );
901
902     return FONT_EnumFontFamiliesEx( hDC, &lfW, (FONTENUMPROCW)efproc, lParam, 0);
903 }
904
905 /***********************************************************************
906  *              EnumFontFamilies        (GDI.330)
907  */
908 INT16 WINAPI EnumFontFamilies16( HDC16 hDC, LPCSTR lpFamily,
909                                  FONTENUMPROC16 efproc, LPARAM lpData )
910 {
911     LOGFONT16   lf;
912
913     lf.lfCharSet = DEFAULT_CHARSET;
914     if (lpFamily)
915     {
916         if (!*lpFamily) return 1;
917         lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
918     }
919     else lf.lfFaceName[0] = '\0';
920
921     return EnumFontFamiliesEx16( hDC, &lf, efproc, lpData, 0 );
922 }
923
924 /***********************************************************************
925  *              EnumFontFamiliesA       (GDI32.@)
926  */
927 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
928                                   FONTENUMPROCA efproc, LPARAM lpData )
929 {
930     LOGFONTA    lf;
931
932     lf.lfCharSet = DEFAULT_CHARSET;
933     if (lpFamily)
934     {
935         if (!*lpFamily) return 1;
936         lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
937     }
938     else lf.lfFaceName[0] = lf.lfFaceName[1] = '\0';
939
940     return EnumFontFamiliesExA( hDC, &lf, efproc, lpData, 0 );
941 }
942
943 /***********************************************************************
944  *              EnumFontFamiliesW       (GDI32.@)
945  */
946 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
947                                   FONTENUMPROCW efproc, LPARAM lpData )
948 {
949     LOGFONTW  lf;
950
951     lf.lfCharSet = DEFAULT_CHARSET;
952     if (lpFamily)
953     {
954         if (!*lpFamily) return 1;
955         lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
956     }
957     else lf.lfFaceName[0] = 0;
958
959     return EnumFontFamiliesExW( hDC, &lf, efproc, lpData, 0 );
960 }
961
962 /***********************************************************************
963  *              EnumFonts               (GDI.70)
964  */
965 INT16 WINAPI EnumFonts16( HDC16 hDC, LPCSTR lpName, FONTENUMPROC16 efproc,
966                           LPARAM lpData )
967 {
968     return EnumFontFamilies16( hDC, lpName, efproc, lpData );
969 }
970
971 /***********************************************************************
972  *              EnumFontsA              (GDI32.@)
973  */
974 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
975                            LPARAM lpData )
976 {
977     return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
978 }
979
980 /***********************************************************************
981  *              EnumFontsW              (GDI32.@)
982  */
983 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
984                            LPARAM lpData )
985 {
986     return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
987 }
988
989
990 /***********************************************************************
991  *           GetTextCharacterExtra    (GDI32.@)
992  */
993 INT WINAPI GetTextCharacterExtra( HDC hdc )
994 {
995     INT ret;
996     DC *dc = DC_GetDCPtr( hdc );
997     if (!dc) return 0x80000000;
998     ret = dc->charExtra;
999     DC_ReleaseDCPtr( dc );
1000     return ret;
1001 }
1002
1003
1004 /***********************************************************************
1005  *           SetTextCharacterExtra    (GDI32.@)
1006  */
1007 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
1008 {
1009     INT prev;
1010     DC * dc = DC_GetDCPtr( hdc );
1011     if (!dc) return 0x80000000;
1012     if (dc->funcs->pSetTextCharacterExtra)
1013         prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra );
1014     else
1015     {
1016         prev = dc->charExtra;
1017         dc->charExtra = extra;
1018     }
1019     DC_ReleaseDCPtr( dc );
1020     return prev;
1021 }
1022
1023
1024 /***********************************************************************
1025  *           SetTextJustification    (GDI32.@)
1026  */
1027 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1028 {
1029     BOOL ret = TRUE;
1030     DC * dc = DC_GetDCPtr( hdc );
1031     if (!dc) return FALSE;
1032     if (dc->funcs->pSetTextJustification)
1033         ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks );
1034     else
1035     {
1036         extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
1037         if (!extra) breaks = 0;
1038         if (breaks)
1039         {
1040             dc->breakExtra = extra / breaks;
1041             dc->breakRem   = extra - (breaks * dc->breakExtra);
1042         }
1043         else
1044         {
1045             dc->breakExtra = 0;
1046             dc->breakRem   = 0;
1047         }
1048     }
1049     DC_ReleaseDCPtr( dc );
1050     return ret;
1051 }
1052
1053
1054 /***********************************************************************
1055  *           GetTextFaceA    (GDI32.@)
1056  */
1057 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1058 {
1059     INT res = GetTextFaceW(hdc, 0, NULL);
1060     LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1061     GetTextFaceW( hdc, res, nameW );
1062
1063     if (name)
1064     {
1065         if (count && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, count, NULL, NULL))
1066             name[count-1] = 0;
1067         res = strlen(name);
1068     }
1069     else
1070         res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1071     HeapFree( GetProcessHeap(), 0, nameW );
1072     return res;
1073 }
1074
1075 /***********************************************************************
1076  *           GetTextFaceW    (GDI32.@)
1077  */
1078 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1079 {
1080     FONTOBJ *font;
1081     INT     ret = 0;
1082
1083     DC * dc = DC_GetDCPtr( hdc );
1084     if (!dc) return 0;
1085
1086     if(dc->gdiFont)
1087         ret = WineEngGetTextFace(dc->gdiFont, count, name);
1088     else if ((font = (FONTOBJ *) GDI_GetObjPtr( dc->hFont, FONT_MAGIC )))
1089     {
1090         if (name)
1091         {
1092             lstrcpynW( name, font->logfont.lfFaceName, count );
1093             ret = strlenW(name);
1094         }
1095         else ret = strlenW(font->logfont.lfFaceName) + 1;
1096         GDI_ReleaseObj( dc->hFont );
1097     }
1098     DC_ReleaseDCPtr( dc );
1099     return ret;
1100 }
1101
1102
1103 /***********************************************************************
1104  *           GetTextExtentPoint32A    (GDI32.@)
1105  *
1106  * See GetTextExtentPoint32W.
1107  */
1108 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1109                                      LPSIZE size )
1110 {
1111     BOOL ret = FALSE;
1112     INT wlen;
1113     LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1114
1115     if (p) {
1116         ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1117         HeapFree( GetProcessHeap(), 0, p );
1118     }
1119
1120     TRACE("(%p %s %d %p): returning %d x %d\n",
1121           hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1122     return ret;
1123 }
1124
1125
1126 /***********************************************************************
1127  * GetTextExtentPoint32W [GDI32.@]
1128  *
1129  * Computes width/height for a string.
1130  *
1131  * Computes width and height of the specified string.
1132  *
1133  * RETURNS
1134  *    Success: TRUE
1135  *    Failure: FALSE
1136  */
1137 BOOL WINAPI GetTextExtentPoint32W(
1138     HDC hdc,     /* [in]  Handle of device context */
1139     LPCWSTR str,   /* [in]  Address of text string */
1140     INT count,   /* [in]  Number of characters in string */
1141     LPSIZE size) /* [out] Address of structure for string size */
1142 {
1143     return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1144 }
1145
1146 /***********************************************************************
1147  * GetTextExtentExPointI [GDI32.@]
1148  *
1149  * Computes width and height of the array of glyph indices.
1150  *
1151  * PARAMS
1152  *    hdc     [I] Handle of device context.
1153  *    indices [I] Glyph index array.
1154  *    count   [I] Number of glyphs in array.
1155  *    max_ext [I] Maximum width in glyphs.
1156  *    nfit    [O] Maximum number of characters.
1157  *    dxs     [O] Partial string widths.
1158  *    size    [O] Returned string size.
1159  *
1160  * RETURNS
1161  *    Success: TRUE
1162  *    Failure: FALSE
1163  */
1164 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1165                                    LPINT nfit, LPINT dxs, LPSIZE size )
1166 {
1167     BOOL ret = FALSE;
1168     DC * dc = DC_GetDCPtr( hdc );
1169     if (!dc) return FALSE;
1170
1171     if(dc->gdiFont) {
1172         ret = WineEngGetTextExtentExPointI(dc->gdiFont, indices, count, max_ext, nfit, dxs, size);
1173         size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1174         size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1175         size->cx += count * dc->charExtra;
1176     }
1177     else if(dc->funcs->pGetTextExtentExPoint) {
1178         FIXME("calling GetTextExtentExPoint\n");
1179         ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, (LPCWSTR)indices,
1180                                                 count, max_ext, nfit, dxs, size );
1181     }
1182
1183     DC_ReleaseDCPtr( dc );
1184
1185     TRACE("(%p %p %d %p): returning %d x %d\n",
1186           hdc, indices, count, size, size->cx, size->cy );
1187     return ret;
1188 }
1189
1190 /***********************************************************************
1191  * GetTextExtentPointI [GDI32.@]
1192  *
1193  * Computes width and height of the array of glyph indices.
1194  *
1195  * PARAMS
1196  *    hdc     [I] Handle of device context.
1197  *    indices [I] Glyph index array.
1198  *    count   [I] Number of glyphs in array.
1199  *    size    [O] Returned string size.
1200  *
1201  * RETURNS
1202  *    Success: TRUE
1203  *    Failure: FALSE
1204  */
1205 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1206 {
1207     return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1208 }
1209
1210
1211 /***********************************************************************
1212  *           GetTextExtentPointA    (GDI32.@)
1213  */
1214 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1215                                           LPSIZE size )
1216 {
1217     TRACE("not bug compatible.\n");
1218     return GetTextExtentPoint32A( hdc, str, count, size );
1219 }
1220
1221 /***********************************************************************
1222  *           GetTextExtentPointW   (GDI32.@)
1223  */
1224 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1225                                           LPSIZE size )
1226 {
1227     TRACE("not bug compatible.\n");
1228     return GetTextExtentPoint32W( hdc, str, count, size );
1229 }
1230
1231
1232 /***********************************************************************
1233  *           GetTextExtentExPointA    (GDI32.@)
1234  */
1235 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1236                                    INT maxExt, LPINT lpnFit,
1237                                    LPINT alpDx, LPSIZE size )
1238 {
1239     BOOL ret;
1240     INT wlen;
1241     INT *walpDx = NULL;
1242     LPWSTR p = NULL;
1243     
1244     if (alpDx &&
1245        NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
1246        return FALSE;
1247     
1248     p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1249     ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1250     if (walpDx)
1251     {
1252         INT n = lpnFit ? *lpnFit : wlen;
1253         INT i, j;
1254         for(i = 0, j = 0; i < n; i++, j++)
1255         {
1256             alpDx[j] = walpDx[i];
1257             if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1258         }
1259     }
1260     if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1261     HeapFree( GetProcessHeap(), 0, p );
1262     HeapFree( GetProcessHeap(), 0, walpDx );
1263     return ret;
1264 }
1265
1266
1267 /***********************************************************************
1268  *           GetTextExtentExPointW    (GDI32.@)
1269  *
1270  * Return the size of the string as it would be if it was output properly by
1271  * e.g. TextOut.
1272  *
1273  * This should include
1274  * - Intercharacter spacing
1275  * - justification spacing (not yet done)
1276  * - kerning? see below
1277  *
1278  * Kerning.  Since kerning would be carried out by the rendering code it should
1279  * be done by the driver.  However they don't support it yet.  Also I am not
1280  * yet persuaded that (certainly under Win95) any kerning is actually done.
1281  *
1282  * str: According to MSDN this should be null-terminated.  That is not true; a
1283  *      null will not terminate it early.
1284  * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1285  *       than count.  I have seen it be either the size of the full string or
1286  *       1 less than the size of the full string.  I have not seen it bear any
1287  *       resemblance to the portion that would fit.
1288  * lpnFit: What exactly is fitting?  Stupidly, in my opinion, it includes the
1289  *         trailing intercharacter spacing and any trailing justification.
1290  *
1291  * FIXME
1292  * Currently we do this by measuring each character etc.  We should do it by
1293  * passing the request to the driver, perhaps by extending the
1294  * pGetTextExtentPoint function to take the alpDx argument.  That would avoid
1295  * thinking about kerning issues and rounding issues in the justification.
1296  */
1297
1298 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1299                                    INT maxExt, LPINT lpnFit,
1300                                    LPINT alpDx, LPSIZE size )
1301 {
1302     INT nFit = 0;
1303     LPINT dxs = NULL;
1304     DC *dc;
1305     BOOL ret = FALSE;
1306     TEXTMETRICW tm;
1307
1308     TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1309
1310     dc = DC_GetDCPtr(hdc);
1311     if (! dc)
1312         return FALSE;
1313
1314     GetTextMetricsW(hdc, &tm);
1315
1316     /* If we need to calculate nFit, then we need the partial extents even if
1317        the user hasn't provided us with an array.  */
1318     if (lpnFit)
1319     {
1320         dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1321         if (! dxs)
1322         {
1323             DC_ReleaseDCPtr(dc);
1324             SetLastError(ERROR_OUTOFMEMORY);
1325             return FALSE;
1326         }
1327     }
1328     else
1329         dxs = alpDx;
1330
1331     if (dc->gdiFont)
1332         ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
1333                                           0, NULL, dxs, size);
1334     else if (dc->funcs->pGetTextExtentExPoint)
1335         ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
1336                                                0, NULL, dxs, size);
1337
1338     /* Perform device size to world size transformations.  */
1339     if (ret)
1340     {
1341         INT extra      = dc->charExtra,
1342         breakExtra = dc->breakExtra,
1343         breakRem   = dc->breakRem,
1344         i;
1345
1346         if (dxs)
1347         {
1348             for (i = 0; i < count; ++i)
1349             {
1350                 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1351                 dxs[i] += (i+1) * extra;
1352                 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1353                 {
1354                     dxs[i] += breakExtra;
1355                     if (breakRem > 0)
1356                     {
1357                         breakRem--;
1358                         dxs[i]++;
1359                     }
1360                 }
1361                 if (dxs[i] <= maxExt)
1362                     ++nFit;
1363             }
1364             breakRem = dc->breakRem;
1365         }
1366         size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1367         size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1368
1369         if (!dxs && count > 1 && (breakExtra || breakRem))
1370         {
1371             for (i = 0; i < count; i++)
1372             {
1373                 if (str[i] == tm.tmBreakChar)
1374                 {
1375                     size->cx += breakExtra;
1376                     if (breakRem > 0)
1377                     {
1378                         breakRem--;
1379                         (size->cx)++;
1380                     }
1381                 }
1382             }
1383         }
1384     }
1385
1386     if (lpnFit)
1387         *lpnFit = nFit;
1388
1389     if (! alpDx)
1390         HeapFree(GetProcessHeap(), 0, dxs);
1391
1392     DC_ReleaseDCPtr( dc );
1393
1394     TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1395     return ret;
1396 }
1397
1398 /***********************************************************************
1399  *           GetTextMetricsA    (GDI32.@)
1400  */
1401 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1402 {
1403     TEXTMETRICW tm32;
1404
1405     if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1406     FONT_TextMetricWToA( &tm32, metrics );
1407     return TRUE;
1408 }
1409
1410 /***********************************************************************
1411  *           GetTextMetricsW    (GDI32.@)
1412  */
1413 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1414 {
1415     BOOL ret = FALSE;
1416     DC * dc = DC_GetDCPtr( hdc );
1417     if (!dc) return FALSE;
1418
1419     if (dc->gdiFont)
1420         ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1421     else if (dc->funcs->pGetTextMetrics)
1422         ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1423
1424     if (ret)
1425     {
1426     /* device layer returns values in device units
1427      * therefore we have to convert them to logical */
1428
1429         metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1430         metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1431
1432 #define WDPTOLP(x) ((x<0)?                                      \
1433                 (-abs(INTERNAL_XDSTOWS(dc, (x)))):              \
1434                 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1435 #define HDPTOLP(y) ((y<0)?                                      \
1436                 (-abs(INTERNAL_YDSTOWS(dc, (y)))):              \
1437                 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1438
1439     metrics->tmHeight           = HDPTOLP(metrics->tmHeight);
1440     metrics->tmAscent           = HDPTOLP(metrics->tmAscent);
1441     metrics->tmDescent          = HDPTOLP(metrics->tmDescent);
1442     metrics->tmInternalLeading  = HDPTOLP(metrics->tmInternalLeading);
1443     metrics->tmExternalLeading  = HDPTOLP(metrics->tmExternalLeading);
1444     metrics->tmAveCharWidth     = WDPTOLP(metrics->tmAveCharWidth);
1445     metrics->tmMaxCharWidth     = WDPTOLP(metrics->tmMaxCharWidth);
1446     metrics->tmOverhang         = WDPTOLP(metrics->tmOverhang);
1447         ret = TRUE;
1448 #undef WDPTOLP
1449 #undef HDPTOLP
1450     TRACE("text metrics:\n"
1451           "    Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1452           "    Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1453           "    UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1454           "    StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1455           "    PitchAndFamily = %02x\n"
1456           "    --------------------\n"
1457           "    InternalLeading = %i\n"
1458           "    Ascent = %i\n"
1459           "    Descent = %i\n"
1460           "    Height = %i\n",
1461           metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1462           metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1463           metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1464           metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1465           metrics->tmPitchAndFamily,
1466           metrics->tmInternalLeading,
1467           metrics->tmAscent,
1468           metrics->tmDescent,
1469           metrics->tmHeight );
1470     }
1471     DC_ReleaseDCPtr( dc );
1472     return ret;
1473 }
1474
1475
1476 /***********************************************************************
1477  * GetOutlineTextMetrics [GDI.308]  Gets metrics for TrueType fonts.
1478  *
1479  * NOTES
1480  *    lpOTM should be LPOUTLINETEXTMETRIC
1481  *
1482  * RETURNS
1483  *    Success: Non-zero or size of required buffer
1484  *    Failure: 0
1485  */
1486 UINT16 WINAPI GetOutlineTextMetrics16(
1487     HDC16 hdc,    /* [in]  Handle of device context */
1488     UINT16 cbData, /* [in]  Size of metric data array */
1489     LPOUTLINETEXTMETRIC16 lpOTM)  /* [out] Address of metric data array */
1490 {
1491     FIXME("(%04x,%04x,%p): stub\n", hdc,cbData,lpOTM);
1492     return 0;
1493 }
1494
1495
1496 /***********************************************************************
1497  *              GetOutlineTextMetricsA (GDI32.@)
1498  * Gets metrics for TrueType fonts.
1499  *
1500  * NOTES
1501  *    If the supplied buffer isn't big enough Windows partially fills it up to
1502  *    its given length and returns that length.
1503  *
1504  * RETURNS
1505  *    Success: Non-zero or size of required buffer
1506  *    Failure: 0
1507  */
1508 UINT WINAPI GetOutlineTextMetricsA(
1509     HDC hdc,    /* [in]  Handle of device context */
1510     UINT cbData, /* [in]  Size of metric data array */
1511     LPOUTLINETEXTMETRICA lpOTM)  /* [out] Address of metric data array */
1512 {
1513     char buf[512], *ptr;
1514     UINT ret, needed;
1515     OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1516     OUTLINETEXTMETRICA *output = lpOTM;
1517     INT left, len;
1518
1519     if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1520         return 0;
1521     if(ret > sizeof(buf))
1522         lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1523     GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1524
1525     needed = sizeof(OUTLINETEXTMETRICA);
1526     if(lpOTMW->otmpFamilyName)
1527         needed += WideCharToMultiByte(CP_ACP, 0,
1528            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1529                                       NULL, 0, NULL, NULL);
1530     if(lpOTMW->otmpFaceName)
1531         needed += WideCharToMultiByte(CP_ACP, 0,
1532            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1533                                       NULL, 0, NULL, NULL);
1534     if(lpOTMW->otmpStyleName)
1535         needed += WideCharToMultiByte(CP_ACP, 0,
1536            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1537                                       NULL, 0, NULL, NULL);
1538     if(lpOTMW->otmpFullName)
1539         needed += WideCharToMultiByte(CP_ACP, 0,
1540            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1541                                       NULL, 0, NULL, NULL);
1542
1543     if(!lpOTM) {
1544         ret = needed;
1545         goto end;
1546     }
1547
1548     TRACE("needed = %d\n", needed);
1549     if(needed > cbData)
1550         /* Since the supplied buffer isn't big enough, we'll alloc one
1551            that is and memcpy the first cbData bytes into the lpOTM at
1552            the end. */
1553         output = HeapAlloc(GetProcessHeap(), 0, needed);
1554
1555     ret = output->otmSize = min(needed, cbData);
1556     FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1557     output->otmFiller = 0;
1558     output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1559     output->otmfsSelection = lpOTMW->otmfsSelection;
1560     output->otmfsType = lpOTMW->otmfsType;
1561     output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1562     output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1563     output->otmItalicAngle = lpOTMW->otmItalicAngle;
1564     output->otmEMSquare = lpOTMW->otmEMSquare;
1565     output->otmAscent = lpOTMW->otmAscent;
1566     output->otmDescent = lpOTMW->otmDescent;
1567     output->otmLineGap = lpOTMW->otmLineGap;
1568     output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1569     output->otmsXHeight = lpOTMW->otmsXHeight;
1570     output->otmrcFontBox = lpOTMW->otmrcFontBox;
1571     output->otmMacAscent = lpOTMW->otmMacAscent;
1572     output->otmMacDescent = lpOTMW->otmMacDescent;
1573     output->otmMacLineGap = lpOTMW->otmMacLineGap;
1574     output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1575     output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1576     output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1577     output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1578     output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1579     output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1580     output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1581     output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1582     output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1583
1584
1585     ptr = (char*)(output + 1);
1586     left = needed - sizeof(*output);
1587
1588     if(lpOTMW->otmpFamilyName) {
1589         output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1590         len = WideCharToMultiByte(CP_ACP, 0,
1591              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1592                                   ptr, left, NULL, NULL);
1593         left -= len;
1594         ptr += len;
1595     } else
1596         output->otmpFamilyName = 0;
1597
1598     if(lpOTMW->otmpFaceName) {
1599         output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1600         len = WideCharToMultiByte(CP_ACP, 0,
1601              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1602                                   ptr, left, NULL, NULL);
1603         left -= len;
1604         ptr += len;
1605     } else
1606         output->otmpFaceName = 0;
1607
1608     if(lpOTMW->otmpStyleName) {
1609         output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1610         len = WideCharToMultiByte(CP_ACP, 0,
1611              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1612                                   ptr, left, NULL, NULL);
1613         left -= len;
1614         ptr += len;
1615     } else
1616         output->otmpStyleName = 0;
1617
1618     if(lpOTMW->otmpFullName) {
1619         output->otmpFullName = (LPSTR)(ptr - (char*)output);
1620         len = WideCharToMultiByte(CP_ACP, 0,
1621              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1622                                   ptr, left, NULL, NULL);
1623         left -= len;
1624     } else
1625         output->otmpFullName = 0;
1626
1627     assert(left == 0);
1628
1629     if(output != lpOTM) {
1630         memcpy(lpOTM, output, cbData);
1631         HeapFree(GetProcessHeap(), 0, output);
1632
1633         /* check if the string offsets really fit into the provided size */
1634         /* FIXME: should we check string length as well? */
1635         /* make sure that we don't read/write beyond the provided buffer */
1636         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1637         {
1638             if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1639                 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1640         }
1641
1642         /* make sure that we don't read/write beyond the provided buffer */
1643         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1644         {
1645             if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1646                 lpOTM->otmpFaceName = 0; /* doesn't fit */
1647         }
1648
1649             /* make sure that we don't read/write beyond the provided buffer */
1650         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1651         {
1652             if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1653                 lpOTM->otmpStyleName = 0; /* doesn't fit */
1654         }
1655
1656         /* make sure that we don't read/write beyond the provided buffer */
1657         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1658         {
1659             if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1660                 lpOTM->otmpFullName = 0; /* doesn't fit */
1661         }
1662     }
1663
1664 end:
1665     if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1666         HeapFree(GetProcessHeap(), 0, lpOTMW);
1667
1668     return ret;
1669 }
1670
1671
1672 /***********************************************************************
1673  *           GetOutlineTextMetricsW [GDI32.@]
1674  */
1675 UINT WINAPI GetOutlineTextMetricsW(
1676     HDC hdc,    /* [in]  Handle of device context */
1677     UINT cbData, /* [in]  Size of metric data array */
1678     LPOUTLINETEXTMETRICW lpOTM)  /* [out] Address of metric data array */
1679 {
1680     DC *dc = DC_GetDCPtr( hdc );
1681     OUTLINETEXTMETRICW *output = lpOTM;
1682     UINT ret;
1683
1684     TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1685     if(!dc) return 0;
1686
1687     if(dc->gdiFont) {
1688         ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1689         if(lpOTM && ret) {
1690             if(ret > cbData) {
1691                 output = HeapAlloc(GetProcessHeap(), 0, ret);
1692                 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1693             }
1694
1695 #define WDPTOLP(x) ((x<0)?                                      \
1696                 (-abs(INTERNAL_XDSTOWS(dc, (x)))):              \
1697                 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1698 #define HDPTOLP(y) ((y<0)?                                      \
1699                 (-abs(INTERNAL_YDSTOWS(dc, (y)))):              \
1700                 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1701
1702             output->otmTextMetrics.tmHeight           = HDPTOLP(output->otmTextMetrics.tmHeight);
1703             output->otmTextMetrics.tmAscent           = HDPTOLP(output->otmTextMetrics.tmAscent);
1704             output->otmTextMetrics.tmDescent          = HDPTOLP(output->otmTextMetrics.tmDescent);
1705             output->otmTextMetrics.tmInternalLeading  = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1706             output->otmTextMetrics.tmExternalLeading  = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1707             output->otmTextMetrics.tmAveCharWidth     = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1708             output->otmTextMetrics.tmMaxCharWidth     = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1709             output->otmTextMetrics.tmOverhang         = WDPTOLP(output->otmTextMetrics.tmOverhang);
1710             output->otmAscent = HDPTOLP(output->otmAscent);
1711             output->otmDescent = HDPTOLP(output->otmDescent);
1712             output->otmLineGap = HDPTOLP(output->otmLineGap);
1713             output->otmsCapEmHeight = HDPTOLP(output->otmsCapEmHeight);
1714             output->otmsXHeight = HDPTOLP(output->otmsXHeight);
1715             output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1716             output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1717             output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1718             output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1719             output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1720             output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1721             output->otmMacLineGap = HDPTOLP(output->otmMacLineGap);
1722             output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1723             output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1724             output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1725             output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1726             output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1727             output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1728             output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1729             output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1730             output->otmsStrikeoutSize = HDPTOLP(output->otmsStrikeoutSize);
1731             output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1732             output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1733             output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1734 #undef WDPTOLP
1735 #undef HDPTOLP
1736             if(output != lpOTM) {
1737                 memcpy(lpOTM, output, cbData);
1738                 HeapFree(GetProcessHeap(), 0, output);
1739                 ret = cbData;
1740             }
1741         }
1742     }
1743
1744     else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1745               but really this should just be a return 0. */
1746
1747         ret = sizeof(*lpOTM);
1748         if (lpOTM) {
1749             if(cbData < ret)
1750                 ret = 0;
1751             else {
1752                 memset(lpOTM, 0, ret);
1753                 lpOTM->otmSize = sizeof(*lpOTM);
1754                 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1755                 /*
1756                   Further fill of the structure not implemented,
1757                   Needs real values for the structure members
1758                 */
1759             }
1760         }
1761     }
1762     DC_ReleaseDCPtr(dc);
1763     return ret;
1764 }
1765
1766
1767 /***********************************************************************
1768  *           GetCharWidthW      (GDI32.@)
1769  *           GetCharWidth32W    (GDI32.@)
1770  */
1771 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1772                                LPINT buffer )
1773 {
1774     UINT i;
1775     BOOL ret = FALSE;
1776     DC * dc = DC_GetDCPtr( hdc );
1777     if (!dc) return FALSE;
1778
1779     if (dc->gdiFont)
1780         ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1781     else if (dc->funcs->pGetCharWidth)
1782         ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1783
1784     if (ret)
1785     {
1786         /* convert device units to logical */
1787         for( i = firstChar; i <= lastChar; i++, buffer++ )
1788             *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1789         ret = TRUE;
1790     }
1791     DC_ReleaseDCPtr( dc );
1792     return ret;
1793 }
1794
1795
1796 /***********************************************************************
1797  *           GetCharWidthA      (GDI32.@)
1798  *           GetCharWidth32A    (GDI32.@)
1799  */
1800 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1801                                LPINT buffer )
1802 {
1803     INT i, wlen, count = (INT)(lastChar - firstChar + 1);
1804     LPSTR str;
1805     LPWSTR wstr;
1806     BOOL ret = TRUE;
1807
1808     if(count <= 0) return FALSE;
1809
1810     str = HeapAlloc(GetProcessHeap(), 0, count);
1811     for(i = 0; i < count; i++)
1812         str[i] = (BYTE)(firstChar + i);
1813
1814     wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1815
1816     for(i = 0; i < wlen; i++)
1817     {
1818         if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1819         {
1820             ret = FALSE;
1821             break;
1822         }
1823         buffer++;
1824     }
1825
1826     HeapFree(GetProcessHeap(), 0, str);
1827     HeapFree(GetProcessHeap(), 0, wstr);
1828
1829     return ret;
1830 }
1831
1832
1833 /***********************************************************************
1834  *           ExtTextOutA    (GDI32.@)
1835  *
1836  * See ExtTextOutW.
1837  */
1838 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1839                          const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1840 {
1841     INT wlen;
1842     UINT codepage;
1843     LPWSTR p;
1844     BOOL ret;
1845     LPINT lpDxW = NULL;
1846
1847     if (flags & ETO_GLYPH_INDEX)
1848         return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1849
1850     p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1851
1852     if (lpDx) {
1853         unsigned int i = 0, j = 0;
1854
1855         lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT));
1856         while(i < count) {
1857             if(IsDBCSLeadByteEx(codepage, str[i])) {
1858                 lpDxW[j++] = lpDx[i] + lpDx[i+1];
1859                 i = i + 2;
1860             } else {
1861                 lpDxW[j++] = lpDx[i];
1862                 i = i + 1;
1863             }
1864         }
1865     }
1866
1867     ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1868
1869     HeapFree( GetProcessHeap(), 0, p );
1870     HeapFree( GetProcessHeap(), 0, lpDxW );
1871     return ret;
1872 }
1873
1874
1875 /***********************************************************************
1876  *           ExtTextOutW    (GDI32.@)
1877  *
1878  * Draws text using the currently selected font, background color, and text color.
1879  * 
1880  * 
1881  * PARAMS
1882  *    x,y    [I] coordinates of string
1883  *    flags  [I]
1884  *        ETO_GRAYED - undocumented on MSDN
1885  *        ETO_OPAQUE - use background color for fill the rectangle
1886  *        ETO_CLIPPED - clipping text to the rectangle
1887  *        ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1888  *                          than encoded characters. Implies ETO_IGNORELANGUAGE
1889  *        ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1890  *                         Affects BiDi ordering
1891  *        ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1892  *        ETO_PDY - unimplemented
1893  *        ETO_NUMERICSLATIN - unimplemented always assumed -
1894  *                            do not translate numbers into locale representations
1895  *        ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1896  *    lprect [I] dimensions for clipping or/and opaquing
1897  *    str    [I] text string
1898  *    count  [I] number of symbols in string
1899  *    lpDx   [I] optional parameter with distance between drawing characters
1900  *
1901  * RETURNS
1902  *    Success: TRUE
1903  *    Failure: FALSE
1904  */
1905 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1906                          const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1907 {
1908     BOOL ret = FALSE;
1909     LPWSTR reordered_str = (LPWSTR)str;
1910     WORD *glyphs = NULL;
1911     UINT align = GetTextAlign( hdc );
1912     POINT pt;
1913     TEXTMETRICW tm;
1914     LOGFONTW lf;
1915     double cosEsc, sinEsc;
1916     INT *deltas = NULL, char_extra;
1917     SIZE sz;
1918     RECT rc;
1919     BOOL done_extents = FALSE;
1920     INT width = 0, xwidth = 0, ywidth = 0;
1921     DWORD type;
1922     DC * dc = get_dc_ptr( hdc );
1923     INT breakRem;
1924
1925     if (!dc) return FALSE;
1926
1927     breakRem = dc->breakRem;
1928
1929     if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
1930         FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
1931
1932     if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1933     {
1934         release_dc_ptr( dc );
1935         return ret;
1936     }
1937
1938     update_dc( dc );
1939     type = GetObjectType(hdc);
1940     if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1941     {
1942         ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1943         release_dc_ptr( dc );
1944         return ret;
1945     }
1946
1947     if (!lprect)
1948         flags &= ~ETO_CLIPPED;
1949         
1950     if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
1951     {
1952         reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1953
1954         BIDI_Reorder( str, count, GCP_REORDER,
1955                       ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
1956                       WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
1957                       reordered_str, count, NULL );
1958     
1959         flags |= ETO_IGNORELANGUAGE;
1960     }
1961
1962     TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
1963           lprect, debugstr_wn(str, count), count, lpDx);
1964
1965     if(flags & ETO_GLYPH_INDEX)
1966         glyphs = reordered_str;
1967
1968     if(lprect)
1969         TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
1970               lprect->bottom);
1971     TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1972
1973     if(align & TA_UPDATECP)
1974     {
1975         GetCurrentPositionEx( hdc, &pt );
1976         x = pt.x;
1977         y = pt.y;
1978     }
1979
1980     GetTextMetricsW(hdc, &tm);
1981     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1982
1983     if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1984         lf.lfEscapement = 0;
1985
1986     if(lf.lfEscapement != 0)
1987     {
1988         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1989         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1990     }
1991     else
1992     {
1993         cosEsc = 1;
1994         sinEsc = 0;
1995     }
1996
1997     if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1998     {
1999         if(!lprect)
2000         {
2001             if(flags & ETO_GLYPH_INDEX)
2002                 GetTextExtentPointI(hdc, glyphs, count, &sz);
2003             else
2004                 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2005
2006             done_extents = TRUE;
2007             rc.left = x;
2008             rc.top = y;
2009             rc.right = x + sz.cx;
2010             rc.bottom = y + sz.cy;
2011         }
2012         else
2013         {
2014             rc = *lprect;
2015         }
2016
2017         LPtoDP(hdc, (POINT*)&rc, 2);
2018
2019         if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
2020         if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
2021     }
2022
2023     if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
2024         dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
2025
2026     if(count == 0)
2027     {
2028         ret = TRUE;
2029         goto done;
2030     }
2031
2032     pt.x = x;
2033     pt.y = y;
2034     LPtoDP(hdc, &pt, 1);
2035     x = pt.x;
2036     y = pt.y;
2037
2038     char_extra = GetTextCharacterExtra(hdc);
2039     if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2040     {
2041         UINT i;
2042         SIZE tmpsz;
2043         deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
2044         for(i = 0; i < count; i++)
2045         {
2046             if(lpDx && (flags & ETO_PDY))
2047                 deltas[i] = lpDx[i*2] + char_extra;
2048             else if(lpDx)
2049                 deltas[i] = lpDx[i] + char_extra;
2050             else
2051             {
2052                 if(flags & ETO_GLYPH_INDEX)
2053                     GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2054                 else
2055                     GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2056
2057                 deltas[i] = tmpsz.cx;
2058             }
2059             
2060             if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2061             {
2062                 deltas[i] = deltas[i] + dc->breakExtra;
2063                 if (breakRem > 0)
2064                 {
2065                     breakRem--;
2066                     deltas[i]++;
2067                 }
2068             }
2069             deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
2070             width += deltas[i];
2071         }
2072     }
2073     else
2074     {
2075         if(!done_extents)
2076         {
2077             if(flags & ETO_GLYPH_INDEX)
2078                 GetTextExtentPointI(hdc, glyphs, count, &sz);
2079             else
2080                 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2081             done_extents = TRUE;
2082         }
2083         width = INTERNAL_XWSTODS(dc, sz.cx);
2084     }
2085     xwidth = width * cosEsc;
2086     ywidth = width * sinEsc;
2087
2088     tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2089     tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2090     switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2091     {
2092     case TA_LEFT:
2093         if (align & TA_UPDATECP)
2094         {
2095             pt.x = x + xwidth;
2096             pt.y = y - ywidth;
2097             DPtoLP(hdc, &pt, 1);
2098             MoveToEx(hdc, pt.x, pt.y, NULL);
2099         }
2100         break;
2101
2102     case TA_CENTER:
2103         x -= xwidth / 2;
2104         y += ywidth / 2;
2105         break;
2106
2107     case TA_RIGHT:
2108         x -= xwidth;
2109         y += ywidth;
2110         if (align & TA_UPDATECP)
2111         {
2112             pt.x = x;
2113             pt.y = y;
2114             DPtoLP(hdc, &pt, 1);
2115             MoveToEx(hdc, pt.x, pt.y, NULL);
2116         }
2117         break;
2118     }
2119
2120     switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2121     {
2122     case TA_TOP:
2123         y += tm.tmAscent * cosEsc;
2124         x += tm.tmAscent * sinEsc;
2125         break;
2126
2127     case TA_BOTTOM:
2128         y -= tm.tmDescent * cosEsc;
2129         x -= tm.tmDescent * sinEsc;
2130         break;
2131
2132     case TA_BASELINE:
2133         break;
2134     }
2135
2136     if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
2137     {
2138         if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2139         {
2140             if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
2141                y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2142             {
2143                 RECT rc;
2144                 rc.left = x;
2145                 rc.right = x + width;
2146                 rc.top = y - tm.tmAscent;
2147                 rc.bottom = y + tm.tmDescent;
2148                 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
2149             }
2150         }
2151     }
2152
2153     if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
2154     {
2155         HFONT orig_font = dc->hFont, cur_font;
2156         UINT glyph;
2157         INT span = 0, *offsets = NULL;
2158         unsigned int i;
2159
2160         glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2161         for(i = 0; i < count; i++)
2162         {
2163             WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
2164             if(cur_font != dc->hFont)
2165             {
2166                 if(!offsets)
2167                 {
2168                     unsigned int j;
2169                     offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2170                     offsets[0] = 0;
2171                     if(!deltas)
2172                     {
2173                         SIZE tmpsz;
2174                         for(j = 1; j < count; j++)
2175                         {
2176                             GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
2177                             offsets[j] = offsets[j-1] + INTERNAL_XWSTODS(dc, tmpsz.cx);
2178                         }
2179                     }
2180                     else
2181                     {
2182                         for(j = 1; j < count; j++)
2183                             offsets[j] = offsets[j-1] + deltas[j];
2184                     }
2185                 }
2186                 if(span)
2187                 {
2188                     if (PATH_IsPathOpen(dc->path))
2189                         ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
2190                                               (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2191                                               glyphs, span, deltas ? deltas + i - span : NULL);
2192                     else
2193                         dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
2194                                            (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2195                                            glyphs, span, deltas ? deltas + i - span : NULL);
2196                     span = 0;
2197                 }
2198                 SelectObject(hdc, cur_font);
2199             }
2200             glyphs[span++] = glyph;
2201
2202             if(i == count - 1)
2203             {
2204                 if (PATH_IsPathOpen(dc->path))
2205                     ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
2206                                           y - (offsets ? offsets[count - span] * sinEsc : 0),
2207                                           (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2208                                           glyphs, span, deltas ? deltas + count - span : NULL);
2209                 else
2210                     ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
2211                                              y - (offsets ? offsets[count - span] * sinEsc : 0),
2212                                              (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2213                                              glyphs, span, deltas ? deltas + count - span : NULL);
2214                 SelectObject(hdc, orig_font);
2215                 HeapFree(GetProcessHeap(), 0, offsets);
2216            }
2217         }
2218     }
2219     else
2220     {
2221         if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2222         {
2223             glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2224             GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2225             flags |= ETO_GLYPH_INDEX;
2226         }
2227
2228         if (PATH_IsPathOpen(dc->path))
2229             ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
2230                                   glyphs ? glyphs : reordered_str, count, deltas);
2231         else
2232             ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
2233                                      glyphs ? glyphs : reordered_str, count, deltas);
2234     }
2235
2236 done:
2237     HeapFree(GetProcessHeap(), 0, deltas);
2238     if(glyphs != reordered_str)
2239         HeapFree(GetProcessHeap(), 0, glyphs);
2240     if(reordered_str != str)
2241         HeapFree(GetProcessHeap(), 0, reordered_str);
2242
2243     release_dc_ptr( dc );
2244
2245     if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2246     {
2247         int underlinePos, strikeoutPos;
2248         int underlineWidth, strikeoutWidth;
2249         UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2250         OUTLINETEXTMETRICW* otm = NULL;
2251
2252         if(!size)
2253         {
2254             underlinePos = 0;
2255             underlineWidth = tm.tmAscent / 20 + 1;
2256             strikeoutPos = tm.tmAscent / 2;
2257             strikeoutWidth = underlineWidth;
2258         }
2259         else
2260         {
2261             otm = HeapAlloc(GetProcessHeap(), 0, size);
2262             GetOutlineTextMetricsW(hdc, size, otm);
2263             underlinePos = otm->otmsUnderscorePosition;
2264             underlineWidth = otm->otmsUnderscoreSize;
2265             strikeoutPos = otm->otmsStrikeoutPosition;
2266             strikeoutWidth = otm->otmsStrikeoutSize;
2267             HeapFree(GetProcessHeap(), 0, otm);
2268         }
2269
2270         if (PATH_IsPathOpen(dc->path))
2271         {
2272             POINT pts[5];
2273             HPEN hpen;
2274             HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2275
2276             hbrush = SelectObject(hdc, hbrush);
2277             hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2278
2279             if (lf.lfUnderline)
2280             {
2281                 pts[0].x = x - underlinePos * sinEsc;
2282                 pts[0].y = y - underlinePos * cosEsc;
2283                 pts[1].x = x + xwidth - underlinePos * sinEsc;
2284                 pts[1].y = y - ywidth - underlinePos * cosEsc;
2285                 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2286                 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2287                 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2288                 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2289                 pts[4].x = pts[0].x;
2290                 pts[4].y = pts[0].y;
2291                 DPtoLP(hdc, pts, 5);
2292                 Polygon(hdc, pts, 5);
2293             }
2294
2295             if (lf.lfStrikeOut)
2296             {
2297                 pts[0].x = x - strikeoutPos * sinEsc;
2298                 pts[0].y = y - strikeoutPos * cosEsc;
2299                 pts[1].x = x + xwidth - strikeoutPos * sinEsc;
2300                 pts[1].y = y - ywidth - strikeoutPos * cosEsc;
2301                 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2302                 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2303                 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2304                 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2305                 pts[4].x = pts[0].x;
2306                 pts[4].y = pts[0].y;
2307                 DPtoLP(hdc, pts, 5);
2308                 Polygon(hdc, pts, 5);
2309             }
2310
2311             SelectObject(hdc, hpen);
2312             hbrush = SelectObject(hdc, hbrush);
2313             DeleteObject(hbrush);
2314         }
2315         else
2316         {
2317             POINT pts[2], oldpt;
2318             HPEN hpen;
2319
2320             if (lf.lfUnderline)
2321             {
2322                 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2323                 hpen = SelectObject(hdc, hpen);
2324                 pts[0].x = x;
2325                 pts[0].y = y;
2326                 pts[1].x = x + xwidth;
2327                 pts[1].y = y - ywidth;
2328                 DPtoLP(hdc, pts, 2);
2329                 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2330                 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2331                 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2332                 DeleteObject(SelectObject(hdc, hpen));
2333             }
2334
2335             if (lf.lfStrikeOut)
2336             {
2337                 hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
2338                 hpen = SelectObject(hdc, hpen);
2339                 pts[0].x = x;
2340                 pts[0].y = y;
2341                 pts[1].x = x + xwidth;
2342                 pts[1].y = y - ywidth;
2343                 DPtoLP(hdc, pts, 2);
2344                 MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2345                 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2346                 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2347                 DeleteObject(SelectObject(hdc, hpen));
2348             }
2349         }
2350     }
2351
2352     return ret;
2353 }
2354
2355
2356 /***********************************************************************
2357  *           TextOutA    (GDI32.@)
2358  */
2359 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2360 {
2361     return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2362 }
2363
2364
2365 /***********************************************************************
2366  *           TextOutW    (GDI32.@)
2367  */
2368 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2369 {
2370     return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2371 }
2372
2373
2374 /***********************************************************************
2375  *              PolyTextOutA (GDI32.@)
2376  *
2377  * See PolyTextOutW.
2378  */
2379 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2380 {
2381     for (; cStrings>0; cStrings--, pptxt++)
2382         if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2383             return FALSE;
2384     return TRUE;
2385 }
2386
2387
2388
2389 /***********************************************************************
2390  *              PolyTextOutW (GDI32.@)
2391  *
2392  * Draw several Strings
2393  *
2394  * RETURNS
2395  *  TRUE:  Success.
2396  *  FALSE: Failure.
2397  */
2398 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2399 {
2400     for (; cStrings>0; cStrings--, pptxt++)
2401         if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2402             return FALSE;
2403     return TRUE;
2404 }
2405
2406
2407 /* FIXME: all following APIs ******************************************/
2408
2409
2410 /***********************************************************************
2411  *           SetMapperFlags    (GDI32.@)
2412  */
2413 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2414 {
2415     DC *dc = DC_GetDCPtr( hDC );
2416     DWORD ret = 0;
2417     if(!dc) return 0;
2418     if(dc->funcs->pSetMapperFlags)
2419     {
2420         ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2421         /* FIXME: ret is just a success flag, we should return a proper value */
2422     }
2423     else
2424         FIXME("(%p, 0x%08x): stub - harmless\n", hDC, dwFlag);
2425     DC_ReleaseDCPtr( dc );
2426     return ret;
2427 }
2428
2429 /***********************************************************************
2430  *          GetAspectRatioFilterEx  (GDI.486)
2431  */
2432 BOOL16 WINAPI GetAspectRatioFilterEx16( HDC16 hdc, LPSIZE16 pAspectRatio )
2433 {
2434   FIXME("(%04x, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2435   return FALSE;
2436 }
2437
2438 /***********************************************************************
2439  *          GetAspectRatioFilterEx  (GDI32.@)
2440  */
2441 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2442 {
2443   FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2444   return FALSE;
2445 }
2446
2447
2448 /***********************************************************************
2449  *           GetCharABCWidthsA   (GDI32.@)
2450  *
2451  * See GetCharABCWidthsW.
2452  */
2453 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2454                                   LPABC abc )
2455 {
2456     INT i, wlen, count = (INT)(lastChar - firstChar + 1);
2457     LPSTR str;
2458     LPWSTR wstr;
2459     BOOL ret = TRUE;
2460
2461     if(count <= 0) return FALSE;
2462
2463     str = HeapAlloc(GetProcessHeap(), 0, count);
2464     for(i = 0; i < count; i++)
2465         str[i] = (BYTE)(firstChar + i);
2466
2467     wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
2468
2469     for(i = 0; i < wlen; i++)
2470     {
2471         if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2472         {
2473             ret = FALSE;
2474             break;
2475         }
2476         abc++;
2477     }
2478
2479     HeapFree(GetProcessHeap(), 0, str);
2480     HeapFree(GetProcessHeap(), 0, wstr);
2481
2482     return ret;
2483 }
2484
2485
2486 /******************************************************************************
2487  * GetCharABCWidthsW [GDI32.@]
2488  *
2489  * Retrieves widths of characters in range.
2490  *
2491  * PARAMS
2492  *    hdc       [I] Handle of device context
2493  *    firstChar [I] First character in range to query
2494  *    lastChar  [I] Last character in range to query
2495  *    abc       [O] Address of character-width structure
2496  *
2497  * NOTES
2498  *    Only works with TrueType fonts
2499  *
2500  * RETURNS
2501  *    Success: TRUE
2502  *    Failure: FALSE
2503  */
2504 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2505                                    LPABC abc )
2506 {
2507     DC *dc = DC_GetDCPtr(hdc);
2508     unsigned int i;
2509     BOOL ret = FALSE;
2510
2511     if (!dc) return FALSE;
2512
2513     if(dc->gdiFont)
2514         ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2515     else
2516         FIXME(": stub\n");
2517
2518     if (ret)
2519     {
2520         /* convert device units to logical */
2521         for( i = firstChar; i <= lastChar; i++, abc++ ) {
2522             abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2523             abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2524             abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2525         }
2526         ret = TRUE;
2527     }
2528
2529     DC_ReleaseDCPtr( dc );
2530     return ret;
2531 }
2532
2533
2534 /******************************************************************************
2535  * GetCharABCWidthsI [GDI32.@]
2536  *
2537  * Retrieves widths of characters in range.
2538  *
2539  * PARAMS
2540  *    hdc       [I] Handle of device context
2541  *    firstChar [I] First glyphs in range to query
2542  *    count     [I] Last glyphs in range to query
2543  *    pgi       [i] Array of glyphs to query
2544  *    abc       [O] Address of character-width structure
2545  *
2546  * NOTES
2547  *    Only works with TrueType fonts
2548  *
2549  * RETURNS
2550  *    Success: TRUE
2551  *    Failure: FALSE
2552  */
2553 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2554                                LPWORD pgi, LPABC abc)
2555 {
2556     DC *dc = DC_GetDCPtr(hdc);
2557     unsigned int i;
2558     BOOL ret = FALSE;
2559
2560     if (!dc) return FALSE;
2561
2562     if(dc->gdiFont)
2563         ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2564     else
2565         FIXME(": stub\n");
2566
2567     if (ret)
2568     {
2569         /* convert device units to logical */
2570         for( i = 0; i < count; i++, abc++ ) {
2571             abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2572             abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2573             abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2574         }
2575         ret = TRUE;
2576     }
2577
2578     DC_ReleaseDCPtr( dc );
2579     return ret;
2580 }
2581
2582
2583 /***********************************************************************
2584  *           GetGlyphOutlineA    (GDI32.@)
2585  */
2586 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2587                                  LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2588                                  LPVOID lpBuffer, const MAT2 *lpmat2 )
2589 {
2590     LPWSTR p = NULL;
2591     DWORD ret;
2592     UINT c;
2593
2594     if(!(fuFormat & GGO_GLYPH_INDEX)) {
2595         int len;
2596         char mbchs[2];
2597         if(uChar > 0xff) { /* but, 2 bytes character only */
2598             len = 2;
2599             mbchs[0] = (uChar & 0xff00) >> 8;
2600             mbchs[1] = (uChar & 0xff);
2601         } else {
2602             len = 1;
2603             mbchs[0] = (uChar & 0xff);
2604         }
2605         p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
2606         c = p[0];
2607     } else
2608         c = uChar;
2609     ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
2610                            lpmat2);
2611     HeapFree(GetProcessHeap(), 0, p);
2612     return ret;
2613 }
2614
2615 /***********************************************************************
2616  *           GetGlyphOutlineW    (GDI32.@)
2617  */
2618 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2619                                  LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2620                                  LPVOID lpBuffer, const MAT2 *lpmat2 )
2621 {
2622     DC *dc = DC_GetDCPtr(hdc);
2623     DWORD ret;
2624
2625     TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2626           hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2627
2628     if(!dc) return GDI_ERROR;
2629
2630     if(dc->gdiFont)
2631       ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2632                                    cbBuffer, lpBuffer, lpmat2);
2633     else
2634       ret = GDI_ERROR;
2635
2636     DC_ReleaseDCPtr( dc );
2637     return ret;
2638 }
2639
2640
2641 /***********************************************************************
2642  *           CreateScalableFontResourceA   (GDI32.@)
2643  */
2644 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2645                                              LPCSTR lpszResourceFile,
2646                                              LPCSTR lpszFontFile,
2647                                              LPCSTR lpszCurrentPath )
2648 {
2649     HANDLE f;
2650
2651     /* fHidden=1 - only visible for the calling app, read-only, not
2652      * enumbered with EnumFonts/EnumFontFamilies
2653      * lpszCurrentPath can be NULL
2654      */
2655     FIXME("(%d,%s,%s,%s): stub\n",
2656           fHidden, debugstr_a(lpszResourceFile), debugstr_a(lpszFontFile),
2657           debugstr_a(lpszCurrentPath) );
2658
2659     /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2660     if ((f = CreateFileA(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2661         CloseHandle(f);
2662         SetLastError(ERROR_FILE_EXISTS);
2663         return FALSE;
2664     }
2665     return FALSE; /* create failed */
2666 }
2667
2668 /***********************************************************************
2669  *           CreateScalableFontResourceW   (GDI32.@)
2670  */
2671 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2672                                              LPCWSTR lpszResourceFile,
2673                                              LPCWSTR lpszFontFile,
2674                                              LPCWSTR lpszCurrentPath )
2675 {
2676     FIXME("(%d,%p,%p,%p): stub\n",
2677           fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath );
2678     return FALSE; /* create failed */
2679 }
2680
2681 /*************************************************************************
2682  *             GetKerningPairsA   (GDI32.@)
2683  */
2684 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2685                                LPKERNINGPAIR kern_pairA )
2686 {
2687     INT charset;
2688     CHARSETINFO csi;
2689     CPINFO cpi;
2690     DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2691     KERNINGPAIR *kern_pairW;
2692
2693     if (!cPairs && kern_pairA)
2694     {
2695         SetLastError(ERROR_INVALID_PARAMETER);
2696         return 0;
2697     }
2698
2699     charset = GetTextCharset(hDC);
2700     if (!TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
2701     {
2702         FIXME("Can't find codepage for charset %d\n", charset);
2703         return 0;
2704     }
2705     /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2706      * to fail on an invalid character for CP_SYMBOL.
2707      */
2708     cpi.DefaultChar[0] = 0;
2709     if (csi.ciACP != CP_SYMBOL && !GetCPInfo(csi.ciACP, &cpi))
2710     {
2711         FIXME("Can't find codepage %u info\n", csi.ciACP);
2712         return 0;
2713     }
2714     TRACE("charset %d => codepage %u\n", charset, csi.ciACP);
2715
2716     total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2717     if (!total_kern_pairs) return 0;
2718
2719     kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2720     GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2721
2722     for (i = 0; i < total_kern_pairs; i++)
2723     {
2724         char first, second;
2725
2726         if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2727             continue;
2728
2729         if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2730             continue;
2731
2732         if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2733             continue;
2734
2735         if (kern_pairA)
2736         {
2737             if (kern_pairs_copied >= cPairs) break;
2738
2739             kern_pairA->wFirst = (BYTE)first;
2740             kern_pairA->wSecond = (BYTE)second;
2741             kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2742             kern_pairA++;
2743         }
2744         kern_pairs_copied++;
2745     }
2746
2747     HeapFree(GetProcessHeap(), 0, kern_pairW);
2748
2749     return kern_pairs_copied;
2750 }
2751
2752 /*************************************************************************
2753  *             GetKerningPairsW   (GDI32.@)
2754  */
2755 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2756                                  LPKERNINGPAIR lpKerningPairs )
2757 {
2758     DC *dc;
2759     DWORD ret = 0;
2760
2761     TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2762
2763     if (!cPairs && lpKerningPairs)
2764     {
2765         SetLastError(ERROR_INVALID_PARAMETER);
2766         return 0;
2767     }
2768
2769     dc = DC_GetDCPtr(hDC);
2770     if (!dc) return 0;
2771
2772     if (dc->gdiFont)
2773         ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
2774
2775     DC_ReleaseDCPtr( dc );
2776     return ret;
2777 }
2778
2779 /*************************************************************************
2780  * TranslateCharsetInfo [GDI32.@]
2781  *
2782  * Fills a CHARSETINFO structure for a character set, code page, or
2783  * font. This allows making the correspondance between different labelings
2784  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2785  * of the same encoding.
2786  *
2787  * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2788  * only one codepage should be set in *lpSrc.
2789  *
2790  * RETURNS
2791  *   TRUE on success, FALSE on failure.
2792  *
2793  */
2794 BOOL WINAPI TranslateCharsetInfo(
2795   LPDWORD lpSrc, /* [in]
2796        if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2797        if flags == TCI_SRCCHARSET: a character set value
2798        if flags == TCI_SRCCODEPAGE: a code page value
2799                  */
2800   LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2801   DWORD flags /* [in] determines interpretation of lpSrc */)
2802 {
2803     int index = 0;
2804     switch (flags) {
2805     case TCI_SRCFONTSIG:
2806         while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
2807       break;
2808     case TCI_SRCCODEPAGE:
2809       while (PtrToUlong(lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
2810       break;
2811     case TCI_SRCCHARSET:
2812       while (PtrToUlong(lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
2813       break;
2814     default:
2815       return FALSE;
2816     }
2817     if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2818     memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO));
2819     return TRUE;
2820 }
2821
2822 /*************************************************************************
2823  *             GetFontLanguageInfo   (GDI32.@)
2824  */
2825 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2826 {
2827         FONTSIGNATURE fontsig;
2828         static const DWORD GCP_DBCS_MASK=0x003F0000,
2829                 GCP_DIACRITIC_MASK=0x00000000,
2830                 FLI_GLYPHS_MASK=0x00000000,
2831                 GCP_GLYPHSHAPE_MASK=0x00000040,
2832                 GCP_KASHIDA_MASK=0x00000000,
2833                 GCP_LIGATE_MASK=0x00000000,
2834                 GCP_USEKERNING_MASK=0x00000000,
2835                 GCP_REORDER_MASK=0x00000060;
2836
2837         DWORD result=0;
2838
2839         GetTextCharsetInfo( hdc, &fontsig, 0 );
2840         /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2841
2842         if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2843                 result|=GCP_DBCS;
2844
2845         if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2846                 result|=GCP_DIACRITIC;
2847
2848         if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2849                 result|=FLI_GLYPHS;
2850
2851         if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2852                 result|=GCP_GLYPHSHAPE;
2853
2854         if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2855                 result|=GCP_KASHIDA;
2856
2857         if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2858                 result|=GCP_LIGATE;
2859
2860         if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2861                 result|=GCP_USEKERNING;
2862
2863         /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2864         if( GetTextAlign( hdc) & TA_RTLREADING )
2865             if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2866                     result|=GCP_REORDER;
2867
2868         return result;
2869 }
2870
2871
2872 /*************************************************************************
2873  * GetFontData [GDI32.@]
2874  *
2875  * Retrieve data for TrueType font.
2876  *
2877  * RETURNS
2878  *
2879  * success: Number of bytes returned
2880  * failure: GDI_ERROR
2881  *
2882  * NOTES
2883  *
2884  * Calls SetLastError()
2885  *
2886  */
2887 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2888     LPVOID buffer, DWORD length)
2889 {
2890     DC *dc = DC_GetDCPtr(hdc);
2891     DWORD ret = GDI_ERROR;
2892
2893     if(!dc) return GDI_ERROR;
2894
2895     if(dc->gdiFont)
2896       ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2897
2898     DC_ReleaseDCPtr( dc );
2899     return ret;
2900 }
2901
2902 /*************************************************************************
2903  * GetGlyphIndicesA [GDI32.@]
2904  */
2905 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2906                               LPWORD pgi, DWORD flags)
2907 {
2908     DWORD ret;
2909     WCHAR *lpstrW;
2910     INT countW;
2911
2912     TRACE("(%p, %s, %d, %p, 0x%x)\n",
2913           hdc, debugstr_an(lpstr, count), count, pgi, flags);
2914
2915     lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
2916     ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2917     HeapFree(GetProcessHeap(), 0, lpstrW);
2918
2919     return ret;
2920 }
2921
2922 /*************************************************************************
2923  * GetGlyphIndicesW [GDI32.@]
2924  */
2925 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2926                               LPWORD pgi, DWORD flags)
2927 {
2928     DC *dc = DC_GetDCPtr(hdc);
2929     DWORD ret = GDI_ERROR;
2930
2931     TRACE("(%p, %s, %d, %p, 0x%x)\n",
2932           hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2933
2934     if(!dc) return GDI_ERROR;
2935
2936     if(dc->gdiFont)
2937         ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2938
2939     DC_ReleaseDCPtr( dc );
2940     return ret;
2941 }
2942
2943 /*************************************************************************
2944  * GetCharacterPlacementA [GDI32.@]
2945  *
2946  * See GetCharacterPlacementW.
2947  *
2948  * NOTES:
2949  *  the web browser control of ie4 calls this with dwFlags=0
2950  */
2951 DWORD WINAPI
2952 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2953                          INT nMaxExtent, GCP_RESULTSA *lpResults,
2954                          DWORD dwFlags)
2955 {
2956     WCHAR *lpStringW;
2957     INT uCountW;
2958     GCP_RESULTSW resultsW;
2959     DWORD ret;
2960     UINT font_cp;
2961
2962     TRACE("%s, %d, %d, 0x%08x\n",
2963           debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2964
2965     /* both structs are equal in size */
2966     memcpy(&resultsW, lpResults, sizeof(resultsW));
2967
2968     lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
2969     if(lpResults->lpOutString)
2970         resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2971
2972     ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2973
2974     lpResults->nGlyphs = resultsW.nGlyphs;
2975     lpResults->nMaxFit = resultsW.nMaxFit;
2976
2977     if(lpResults->lpOutString) {
2978         WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
2979                             lpResults->lpOutString, uCount, NULL, NULL );
2980     }
2981
2982     HeapFree(GetProcessHeap(), 0, lpStringW);
2983     HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2984
2985     return ret;
2986 }
2987
2988 /*************************************************************************
2989  * GetCharacterPlacementW [GDI32.@]
2990  *
2991  *   Retrieve information about a string. This includes the width, reordering,
2992  *   Glyphing and so on.
2993  *
2994  * RETURNS
2995  *
2996  *   The width and height of the string if successful, 0 if failed.
2997  *
2998  * BUGS
2999  *
3000  *   All flags except GCP_REORDER are not yet implemented.
3001  *   Reordering is not 100% complient to the Windows BiDi method.
3002  *   Caret positioning is not yet implemented for BiDi.
3003  *   Classes are not yet implemented.
3004  *
3005  */
3006 DWORD WINAPI
3007 GetCharacterPlacementW(
3008                 HDC hdc,                /* [in] Device context for which the rendering is to be done */
3009                 LPCWSTR lpString,       /* [in] The string for which information is to be returned */
3010                 INT uCount,             /* [in] Number of WORDS in string. */
3011                 INT nMaxExtent,         /* [in] Maximum extent the string is to take (in HDC logical units) */
3012                 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
3013                 DWORD dwFlags           /* [in] Flags specifying how to process the string */
3014                 )
3015 {
3016     DWORD ret=0;
3017     SIZE size;
3018     UINT i, nSet;
3019
3020     TRACE("%s, %d, %d, 0x%08x\n",
3021           debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3022
3023     TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3024           "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3025             lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3026             lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3027             lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3028
3029     if(dwFlags&(~GCP_REORDER))                  FIXME("flags 0x%08x ignored\n", dwFlags);
3030     if(lpResults->lpClass)      FIXME("classes not implemented\n");
3031     if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3032         FIXME("Caret positions for complex scripts not implemented\n");
3033
3034         nSet = (UINT)uCount;
3035         if(nSet > lpResults->nGlyphs)
3036                 nSet = lpResults->nGlyphs;
3037
3038         /* return number of initialized fields */
3039         lpResults->nGlyphs = nSet;
3040
3041         if((dwFlags&GCP_REORDER)==0 )
3042         {
3043                 /* Treat the case where no special handling was requested in a fastpath way */
3044                 /* copy will do if the GCP_REORDER flag is not set */
3045                 if(lpResults->lpOutString)
3046                     memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3047
3048                 if(lpResults->lpOrder)
3049                 {
3050                         for(i = 0; i < nSet; i++)
3051                                 lpResults->lpOrder[i] = i;
3052                 }
3053         } else
3054         {
3055             BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3056                           nSet, lpResults->lpOrder );
3057         }
3058
3059         /* FIXME: Will use the placement chars */
3060         if (lpResults->lpDx)
3061         {
3062                 int c;
3063                 for (i = 0; i < nSet; i++)
3064                 {
3065                         if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3066                                 lpResults->lpDx[i]= c;
3067                 }
3068         }
3069
3070     if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3071     {
3072         int pos = 0;
3073        
3074         lpResults->lpCaretPos[0] = 0;
3075         for (i = 1; i < nSet; i++)
3076             if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3077                 lpResults->lpCaretPos[i] = (pos += size.cx);
3078     }
3079    
3080     if(lpResults->lpGlyphs)
3081         GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3082
3083     if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3084       ret = MAKELONG(size.cx, size.cy);
3085
3086     return ret;
3087 }
3088
3089 /*************************************************************************
3090  *      GetCharABCWidthsFloatA [GDI32.@]
3091  *
3092  * See GetCharABCWidthsFloatW.
3093  */
3094 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3095 {
3096     INT i, wlen, count = (INT)(last - first + 1);
3097     LPSTR str;
3098     LPWSTR wstr;
3099     BOOL ret = TRUE;
3100
3101     if (count <= 0) return FALSE;
3102
3103     str = HeapAlloc(GetProcessHeap(), 0, count);
3104
3105     for(i = 0; i < count; i++)
3106         str[i] = (BYTE)(first + i);
3107
3108     wstr = FONT_mbtowc( hdc, str, count, &wlen, NULL );
3109
3110     for (i = 0; i < wlen; i++)
3111     {
3112         if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3113         {
3114             ret = FALSE;
3115             break;
3116         }
3117         abcf++;
3118     }
3119
3120     HeapFree( GetProcessHeap(), 0, str );
3121     HeapFree( GetProcessHeap(), 0, wstr );
3122
3123     return ret;
3124 }
3125
3126 /*************************************************************************
3127  *      GetCharABCWidthsFloatW [GDI32.@]
3128  *
3129  * Retrieves widths of a range of characters.
3130  *
3131  * PARAMS
3132  *    hdc   [I] Handle to device context.
3133  *    first [I] First character in range to query.
3134  *    last  [I] Last character in range to query.
3135  *    abcf  [O] Array of LPABCFLOAT structures.
3136  *
3137  * RETURNS
3138  *    Success: TRUE
3139  *    Failure: FALSE
3140  *
3141  * BUGS
3142  *    Only works with TrueType fonts. It also doesn't return real
3143  *    floats but converted integers because it's implemented on
3144  *    top of GetCharABCWidthsW.
3145  */
3146 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3147 {
3148     ABC *abc;
3149     unsigned int i, size = sizeof(ABC) * (last - first + 1);
3150     BOOL ret;
3151
3152     TRACE("%p, %d, %d, %p - partial stub\n", hdc, first, last, abcf);
3153
3154     abc = HeapAlloc( GetProcessHeap(), 0, size );
3155     if (!abc) return FALSE;
3156
3157     ret = GetCharABCWidthsW( hdc, first, last, abc );
3158     if (ret)
3159     {
3160         for (i = first; i <= last; i++, abc++, abcf++)
3161         {
3162             abcf->abcfA = abc->abcA;
3163             abcf->abcfB = abc->abcB;
3164             abcf->abcfC = abc->abcC;
3165         }
3166     }
3167     HeapFree( GetProcessHeap(), 0, abc );
3168     return ret;
3169 }
3170
3171 /*************************************************************************
3172  *      GetCharWidthFloatA [GDI32.@]
3173  */
3174 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3175                                     UINT iLastChar, PFLOAT pxBuffer)
3176 {
3177     FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3178     return 0;
3179 }
3180
3181 /*************************************************************************
3182  *      GetCharWidthFloatW [GDI32.@]
3183  */
3184 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3185                                     UINT iLastChar, PFLOAT pxBuffer)
3186 {
3187     FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3188     return 0;
3189 }
3190
3191
3192 /***********************************************************************
3193  *                                                                     *
3194  *           Font Resource API                                         *
3195  *                                                                     *
3196  ***********************************************************************/
3197
3198 /***********************************************************************
3199  *           AddFontResourceA    (GDI32.@)
3200  */
3201 INT WINAPI AddFontResourceA( LPCSTR str )
3202 {
3203     return AddFontResourceExA( str, 0, NULL);
3204 }
3205
3206 /***********************************************************************
3207  *           AddFontResourceW    (GDI32.@)
3208  */
3209 INT WINAPI AddFontResourceW( LPCWSTR str )
3210 {
3211     return AddFontResourceExW(str, 0, NULL);
3212 }
3213
3214
3215 /***********************************************************************
3216  *           AddFontResourceExA    (GDI32.@)
3217  */
3218 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3219 {
3220     DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3221     LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3222     INT ret;
3223
3224     MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3225     ret = AddFontResourceExW(strW, fl, pdv);
3226     HeapFree(GetProcessHeap(), 0, strW);
3227     return ret;
3228 }
3229
3230 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3231 {
3232     HRSRC rsrc = FindResourceW(hModule, name, type);
3233     HGLOBAL hMem = LoadResource(hModule, rsrc);
3234     LPVOID *pMem = LockResource(hMem);
3235     int *num_total = (int *)lParam;
3236     DWORD num_in_res;
3237
3238     TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3239     if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3240     {
3241         ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3242         return FALSE;
3243     }
3244
3245     *num_total += num_in_res;
3246     return TRUE;
3247 }
3248
3249 /***********************************************************************
3250  *           AddFontResourceExW    (GDI32.@)
3251  */
3252 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3253 {
3254     int ret = WineEngAddFontResourceEx(str, fl, pdv);
3255     if (ret == 0)
3256     {
3257         /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3258         HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3259         if (hModule != NULL)
3260         {
3261             int num_resources = 0;
3262             LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8);  /* we don't want to include winuser.h */
3263
3264             TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3265                 wine_dbgstr_w(str));
3266             if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3267                 ret = num_resources;
3268             FreeLibrary(hModule);
3269         }
3270     }
3271     return ret;
3272 }
3273
3274 /***********************************************************************
3275  *           RemoveFontResourceA    (GDI32.@)
3276  */
3277 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3278 {
3279     return RemoveFontResourceExA(str, 0, 0);
3280 }
3281
3282 /***********************************************************************
3283  *           RemoveFontResourceW    (GDI32.@)
3284  */
3285 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3286 {
3287     return RemoveFontResourceExW(str, 0, 0);
3288 }
3289
3290 /***********************************************************************
3291  *           AddFontMemResourceEx    (GDI32.@)
3292  */
3293 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3294 {
3295     return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts);
3296 }
3297
3298 /***********************************************************************
3299  *           RemoveFontResourceExA    (GDI32.@)
3300  */
3301 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3302 {
3303     DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3304     LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3305     INT ret;
3306
3307     MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3308     ret = RemoveFontResourceExW(strW, fl, pdv);
3309     HeapFree(GetProcessHeap(), 0, strW);
3310     return ret;
3311 }
3312
3313 /***********************************************************************
3314  *           RemoveFontResourceExW    (GDI32.@)
3315  */
3316 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3317 {
3318     return WineEngRemoveFontResourceEx(str, fl, pdv);
3319 }
3320
3321 /***********************************************************************
3322  *           GetTextCharset    (GDI32.@)
3323  */
3324 UINT WINAPI GetTextCharset(HDC hdc)
3325 {
3326     /* MSDN docs say this is equivalent */
3327     return GetTextCharsetInfo(hdc, NULL, 0);
3328 }
3329
3330 /***********************************************************************
3331  *           GetTextCharsetInfo    (GDI32.@)
3332  */
3333 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3334 {
3335     UINT ret = DEFAULT_CHARSET;
3336     DC *dc = DC_GetDCPtr(hdc);
3337
3338     if (dc)
3339     {
3340         if (dc->gdiFont)
3341             ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3342
3343         DC_ReleaseDCPtr( dc );
3344     }
3345
3346     if (ret == DEFAULT_CHARSET && fs)
3347         memset(fs, 0, sizeof(FONTSIGNATURE));
3348     return ret;
3349 }
3350
3351 /***********************************************************************
3352  *           GdiGetCharDimensions    (GDI32.@)
3353  *
3354  * Gets the average width of the characters in the English alphabet.
3355  *
3356  * PARAMS
3357  *  hdc    [I] Handle to the device context to measure on.
3358  *  lptm   [O] Pointer to memory to store the text metrics into.
3359  *  height [O] On exit, the maximum height of characters in the English alphabet.
3360  *
3361  * RETURNS
3362  *  The average width of characters in the English alphabet.
3363  *
3364  * NOTES
3365  *  This function is used by the dialog manager to get the size of a dialog
3366  *  unit. It should also be used by other pieces of code that need to know
3367  *  the size of a dialog unit in logical units without having access to the
3368  *  window handle of the dialog.
3369  *  Windows caches the font metrics from this function, but we don't and
3370  *  there doesn't appear to be an immediate advantage to do so.
3371  *
3372  * SEE ALSO
3373  *  GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3374  */
3375 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3376 {
3377     SIZE sz;
3378     static const WCHAR alphabet[] = {
3379         'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3380         'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3381         'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3382
3383     if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3384
3385     if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3386
3387     if (height) *height = sz.cy;
3388     return (sz.cx / 26 + 1) / 2;
3389 }
3390
3391 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3392 {
3393     FIXME("(%d): stub\n", fEnableEUDC);
3394     return FALSE;
3395 }
3396
3397 /***********************************************************************
3398  *           GetCharWidthI    (GDI32.@)
3399  *
3400  * Retrieve widths of characters.
3401  *
3402  * PARAMS
3403  *  hdc    [I] Handle to a device context.
3404  *  first  [I] First glyph in range to query.
3405  *  count  [I] Number of glyph indices to query.
3406  *  glyphs [I] Array of glyphs to query.
3407  *  buffer [O] Buffer to receive character widths.
3408  *
3409  * NOTES
3410  *  Only works with TrueType fonts.
3411  *
3412  * RETURNS
3413  *  Success: TRUE
3414  *  Failure: FALSE
3415  */
3416 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3417 {
3418     ABC *abc;
3419     unsigned int i;
3420
3421     TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3422
3423     if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3424         return FALSE;
3425
3426     if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3427     {
3428         HeapFree(GetProcessHeap(), 0, abc);
3429         return FALSE;
3430     }
3431
3432     for (i = 0; i < count; i++)
3433         buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3434
3435     HeapFree(GetProcessHeap(), 0, abc);
3436     return TRUE;
3437 }
3438
3439 /***********************************************************************
3440  *           GetFontUnicodeRanges    (GDI32.@)
3441  *
3442  *  Retrieve a list of supported Unicode characters in a font.
3443  *
3444  *  PARAMS
3445  *   hdc  [I] Handle to a device context.
3446  *   lpgs [O] GLYPHSET structure specifying supported character ranges.
3447  *
3448  *  RETURNS
3449  *   Success: Number of bytes written to the buffer pointed to by lpgs.
3450  *   Failure: 0
3451  *
3452  */
3453 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3454 {
3455     DWORD ret = 0;
3456     DC *dc = DC_GetDCPtr(hdc);
3457
3458     TRACE("(%p, %p)\n", hdc, lpgs);
3459
3460     if (!dc) return 0;
3461
3462     if (dc->gdiFont) ret = WineEngGetFontUnicodeRanges(dc->gdiFont, lpgs);
3463     DC_ReleaseDCPtr(dc);
3464     return ret;
3465 }
3466
3467
3468 /*************************************************************
3469  *           FontIsLinked    (GDI32.@)
3470  */
3471 BOOL WINAPI FontIsLinked(HDC hdc)
3472 {
3473     DC *dc = DC_GetDCPtr(hdc);
3474     BOOL ret = FALSE;
3475
3476     if (!dc) return FALSE;
3477     if (dc->gdiFont) ret = WineEngFontIsLinked(dc->gdiFont);
3478     DC_ReleaseDCPtr(dc);
3479     TRACE("returning %d\n", ret);
3480     return ret;
3481 }