setupapi: Don't abort key enumeration early.
[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  * GetTextExtentPointI [GDI32.@]
1148  *
1149  * Computes width and height of the array of glyph indices.
1150  *
1151  * RETURNS
1152  *    Success: TRUE
1153  *    Failure: FALSE
1154  */
1155 BOOL WINAPI GetTextExtentPointI(
1156     HDC hdc,     /* [in]  Handle of device context */
1157     const WORD *indices,   /* [in]  Address of glyph index array */
1158     INT count,   /* [in]  Number of glyphs in array */
1159     LPSIZE size) /* [out] Address of structure for string size */
1160 {
1161     BOOL ret = FALSE;
1162     DC * dc = DC_GetDCPtr( hdc );
1163     if (!dc) return FALSE;
1164
1165     if(dc->gdiFont) {
1166         ret = WineEngGetTextExtentPointI(dc->gdiFont, indices, count, size);
1167         size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1168         size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1169         size->cx += count * dc->charExtra;
1170     }
1171     else if(dc->funcs->pGetTextExtentExPoint) {
1172         FIXME("calling GetTextExtentExPoint\n");
1173         ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, (LPCWSTR)indices,
1174                                                 count, 0, NULL, NULL, size );
1175     }
1176
1177     DC_ReleaseDCPtr( dc );
1178
1179     TRACE("(%p %p %d %p): returning %d x %d\n",
1180           hdc, indices, count, size, size->cx, size->cy );
1181     return ret;
1182 }
1183
1184
1185 /***********************************************************************
1186  *           GetTextExtentPointA    (GDI32.@)
1187  */
1188 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1189                                           LPSIZE size )
1190 {
1191     TRACE("not bug compatible.\n");
1192     return GetTextExtentPoint32A( hdc, str, count, size );
1193 }
1194
1195 /***********************************************************************
1196  *           GetTextExtentPointW   (GDI32.@)
1197  */
1198 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1199                                           LPSIZE size )
1200 {
1201     TRACE("not bug compatible.\n");
1202     return GetTextExtentPoint32W( hdc, str, count, size );
1203 }
1204
1205
1206 /***********************************************************************
1207  *           GetTextExtentExPointA    (GDI32.@)
1208  */
1209 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1210                                    INT maxExt, LPINT lpnFit,
1211                                    LPINT alpDx, LPSIZE size )
1212 {
1213     BOOL ret;
1214     INT wlen;
1215     INT *walpDx = NULL;
1216     LPWSTR p = NULL;
1217     
1218     if (alpDx &&
1219        NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
1220        return FALSE;
1221     
1222     p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1223     ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1224     if (walpDx)
1225     {
1226         INT n = lpnFit ? *lpnFit : wlen;
1227         INT i, j;
1228         for(i = 0, j = 0; i < n; i++, j++)
1229         {
1230             alpDx[j] = walpDx[i];
1231             if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1232         }
1233     }
1234     if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1235     HeapFree( GetProcessHeap(), 0, p );
1236     HeapFree( GetProcessHeap(), 0, walpDx );
1237     return ret;
1238 }
1239
1240
1241 /***********************************************************************
1242  *           GetTextExtentExPointW    (GDI32.@)
1243  *
1244  * Return the size of the string as it would be if it was output properly by
1245  * e.g. TextOut.
1246  *
1247  * This should include
1248  * - Intercharacter spacing
1249  * - justification spacing (not yet done)
1250  * - kerning? see below
1251  *
1252  * Kerning.  Since kerning would be carried out by the rendering code it should
1253  * be done by the driver.  However they don't support it yet.  Also I am not
1254  * yet persuaded that (certainly under Win95) any kerning is actually done.
1255  *
1256  * str: According to MSDN this should be null-terminated.  That is not true; a
1257  *      null will not terminate it early.
1258  * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1259  *       than count.  I have seen it be either the size of the full string or
1260  *       1 less than the size of the full string.  I have not seen it bear any
1261  *       resemblance to the portion that would fit.
1262  * lpnFit: What exactly is fitting?  Stupidly, in my opinion, it includes the
1263  *         trailing intercharacter spacing and any trailing justification.
1264  *
1265  * FIXME
1266  * Currently we do this by measuring each character etc.  We should do it by
1267  * passing the request to the driver, perhaps by extending the
1268  * pGetTextExtentPoint function to take the alpDx argument.  That would avoid
1269  * thinking about kerning issues and rounding issues in the justification.
1270  */
1271
1272 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1273                                    INT maxExt, LPINT lpnFit,
1274                                    LPINT alpDx, LPSIZE size )
1275 {
1276     INT nFit = 0;
1277     LPINT dxs = NULL;
1278     DC *dc;
1279     BOOL ret = FALSE;
1280     TEXTMETRICW tm;
1281
1282     TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1283
1284     dc = DC_GetDCPtr(hdc);
1285     if (! dc)
1286         return FALSE;
1287
1288     GetTextMetricsW(hdc, &tm);
1289
1290     /* If we need to calculate nFit, then we need the partial extents even if
1291        the user hasn't provided us with an array.  */
1292     if (lpnFit)
1293     {
1294         dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1295         if (! dxs)
1296         {
1297             DC_ReleaseDCPtr(dc);
1298             SetLastError(ERROR_OUTOFMEMORY);
1299             return FALSE;
1300         }
1301     }
1302     else
1303         dxs = alpDx;
1304
1305     if (dc->gdiFont)
1306         ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
1307                                           0, NULL, dxs, size);
1308     else if (dc->funcs->pGetTextExtentExPoint)
1309         ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
1310                                                0, NULL, dxs, size);
1311
1312     /* Perform device size to world size transformations.  */
1313     if (ret)
1314     {
1315         INT extra      = dc->charExtra,
1316         breakExtra = dc->breakExtra,
1317         breakRem   = dc->breakRem,
1318         i;
1319
1320         if (dxs)
1321         {
1322             for (i = 0; i < count; ++i)
1323             {
1324                 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1325                 dxs[i] += (i+1) * extra;
1326                 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1327                 {
1328                     dxs[i] += breakExtra;
1329                     if (breakRem > 0)
1330                     {
1331                         breakRem--;
1332                         dxs[i]++;
1333                     }
1334                 }
1335                 if (dxs[i] <= maxExt)
1336                     ++nFit;
1337             }
1338             breakRem = dc->breakRem;
1339         }
1340         size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1341         size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1342
1343         if (!dxs && count > 1 && (breakExtra || breakRem))
1344         {
1345             for (i = 0; i < count; i++)
1346             {
1347                 if (str[i] == tm.tmBreakChar)
1348                 {
1349                     size->cx += breakExtra;
1350                     if (breakRem > 0)
1351                     {
1352                         breakRem--;
1353                         (size->cx)++;
1354                     }
1355                 }
1356             }
1357         }
1358     }
1359
1360     if (lpnFit)
1361         *lpnFit = nFit;
1362
1363     if (! alpDx)
1364         HeapFree(GetProcessHeap(), 0, dxs);
1365
1366     DC_ReleaseDCPtr( dc );
1367
1368     TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1369     return ret;
1370 }
1371
1372 /***********************************************************************
1373  *           GetTextMetricsA    (GDI32.@)
1374  */
1375 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1376 {
1377     TEXTMETRICW tm32;
1378
1379     if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1380     FONT_TextMetricWToA( &tm32, metrics );
1381     return TRUE;
1382 }
1383
1384 /***********************************************************************
1385  *           GetTextMetricsW    (GDI32.@)
1386  */
1387 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1388 {
1389     BOOL ret = FALSE;
1390     DC * dc = DC_GetDCPtr( hdc );
1391     if (!dc) return FALSE;
1392
1393     if (dc->gdiFont)
1394         ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1395     else if (dc->funcs->pGetTextMetrics)
1396         ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1397
1398     if (ret)
1399     {
1400     /* device layer returns values in device units
1401      * therefore we have to convert them to logical */
1402
1403         metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1404         metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1405
1406 #define WDPTOLP(x) ((x<0)?                                      \
1407                 (-abs(INTERNAL_XDSTOWS(dc, (x)))):              \
1408                 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1409 #define HDPTOLP(y) ((y<0)?                                      \
1410                 (-abs(INTERNAL_YDSTOWS(dc, (y)))):              \
1411                 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1412
1413     metrics->tmHeight           = HDPTOLP(metrics->tmHeight);
1414     metrics->tmAscent           = HDPTOLP(metrics->tmAscent);
1415     metrics->tmDescent          = HDPTOLP(metrics->tmDescent);
1416     metrics->tmInternalLeading  = HDPTOLP(metrics->tmInternalLeading);
1417     metrics->tmExternalLeading  = HDPTOLP(metrics->tmExternalLeading);
1418     metrics->tmAveCharWidth     = WDPTOLP(metrics->tmAveCharWidth);
1419     metrics->tmMaxCharWidth     = WDPTOLP(metrics->tmMaxCharWidth);
1420     metrics->tmOverhang         = WDPTOLP(metrics->tmOverhang);
1421         ret = TRUE;
1422 #undef WDPTOLP
1423 #undef HDPTOLP
1424     TRACE("text metrics:\n"
1425           "    Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1426           "    Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1427           "    UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1428           "    StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1429           "    PitchAndFamily = %02x\n"
1430           "    --------------------\n"
1431           "    InternalLeading = %i\n"
1432           "    Ascent = %i\n"
1433           "    Descent = %i\n"
1434           "    Height = %i\n",
1435           metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1436           metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1437           metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1438           metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1439           metrics->tmPitchAndFamily,
1440           metrics->tmInternalLeading,
1441           metrics->tmAscent,
1442           metrics->tmDescent,
1443           metrics->tmHeight );
1444     }
1445     DC_ReleaseDCPtr( dc );
1446     return ret;
1447 }
1448
1449
1450 /***********************************************************************
1451  * GetOutlineTextMetrics [GDI.308]  Gets metrics for TrueType fonts.
1452  *
1453  * NOTES
1454  *    lpOTM should be LPOUTLINETEXTMETRIC
1455  *
1456  * RETURNS
1457  *    Success: Non-zero or size of required buffer
1458  *    Failure: 0
1459  */
1460 UINT16 WINAPI GetOutlineTextMetrics16(
1461     HDC16 hdc,    /* [in]  Handle of device context */
1462     UINT16 cbData, /* [in]  Size of metric data array */
1463     LPOUTLINETEXTMETRIC16 lpOTM)  /* [out] Address of metric data array */
1464 {
1465     FIXME("(%04x,%04x,%p): stub\n", hdc,cbData,lpOTM);
1466     return 0;
1467 }
1468
1469
1470 /***********************************************************************
1471  *              GetOutlineTextMetricsA (GDI32.@)
1472  * Gets metrics for TrueType fonts.
1473  *
1474  * NOTES
1475  *    If the supplied buffer isn't big enough Windows partially fills it up to
1476  *    its given length and returns that length.
1477  *
1478  * RETURNS
1479  *    Success: Non-zero or size of required buffer
1480  *    Failure: 0
1481  */
1482 UINT WINAPI GetOutlineTextMetricsA(
1483     HDC hdc,    /* [in]  Handle of device context */
1484     UINT cbData, /* [in]  Size of metric data array */
1485     LPOUTLINETEXTMETRICA lpOTM)  /* [out] Address of metric data array */
1486 {
1487     char buf[512], *ptr;
1488     UINT ret, needed;
1489     OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1490     OUTLINETEXTMETRICA *output = lpOTM;
1491     INT left, len;
1492
1493     if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1494         return 0;
1495     if(ret > sizeof(buf))
1496         lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1497     GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1498
1499     needed = sizeof(OUTLINETEXTMETRICA);
1500     if(lpOTMW->otmpFamilyName)
1501         needed += WideCharToMultiByte(CP_ACP, 0,
1502            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1503                                       NULL, 0, NULL, NULL);
1504     if(lpOTMW->otmpFaceName)
1505         needed += WideCharToMultiByte(CP_ACP, 0,
1506            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1507                                       NULL, 0, NULL, NULL);
1508     if(lpOTMW->otmpStyleName)
1509         needed += WideCharToMultiByte(CP_ACP, 0,
1510            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1511                                       NULL, 0, NULL, NULL);
1512     if(lpOTMW->otmpFullName)
1513         needed += WideCharToMultiByte(CP_ACP, 0,
1514            (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1515                                       NULL, 0, NULL, NULL);
1516
1517     if(!lpOTM) {
1518         ret = needed;
1519         goto end;
1520     }
1521
1522     TRACE("needed = %d\n", needed);
1523     if(needed > cbData)
1524         /* Since the supplied buffer isn't big enough, we'll alloc one
1525            that is and memcpy the first cbData bytes into the lpOTM at
1526            the end. */
1527         output = HeapAlloc(GetProcessHeap(), 0, needed);
1528
1529     ret = output->otmSize = min(needed, cbData);
1530     FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1531     output->otmFiller = 0;
1532     output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1533     output->otmfsSelection = lpOTMW->otmfsSelection;
1534     output->otmfsType = lpOTMW->otmfsType;
1535     output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1536     output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1537     output->otmItalicAngle = lpOTMW->otmItalicAngle;
1538     output->otmEMSquare = lpOTMW->otmEMSquare;
1539     output->otmAscent = lpOTMW->otmAscent;
1540     output->otmDescent = lpOTMW->otmDescent;
1541     output->otmLineGap = lpOTMW->otmLineGap;
1542     output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1543     output->otmsXHeight = lpOTMW->otmsXHeight;
1544     output->otmrcFontBox = lpOTMW->otmrcFontBox;
1545     output->otmMacAscent = lpOTMW->otmMacAscent;
1546     output->otmMacDescent = lpOTMW->otmMacDescent;
1547     output->otmMacLineGap = lpOTMW->otmMacLineGap;
1548     output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1549     output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1550     output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1551     output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1552     output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1553     output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1554     output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1555     output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1556     output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1557
1558
1559     ptr = (char*)(output + 1);
1560     left = needed - sizeof(*output);
1561
1562     if(lpOTMW->otmpFamilyName) {
1563         output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1564         len = WideCharToMultiByte(CP_ACP, 0,
1565              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1566                                   ptr, left, NULL, NULL);
1567         left -= len;
1568         ptr += len;
1569     } else
1570         output->otmpFamilyName = 0;
1571
1572     if(lpOTMW->otmpFaceName) {
1573         output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1574         len = WideCharToMultiByte(CP_ACP, 0,
1575              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1576                                   ptr, left, NULL, NULL);
1577         left -= len;
1578         ptr += len;
1579     } else
1580         output->otmpFaceName = 0;
1581
1582     if(lpOTMW->otmpStyleName) {
1583         output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1584         len = WideCharToMultiByte(CP_ACP, 0,
1585              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1586                                   ptr, left, NULL, NULL);
1587         left -= len;
1588         ptr += len;
1589     } else
1590         output->otmpStyleName = 0;
1591
1592     if(lpOTMW->otmpFullName) {
1593         output->otmpFullName = (LPSTR)(ptr - (char*)output);
1594         len = WideCharToMultiByte(CP_ACP, 0,
1595              (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1596                                   ptr, left, NULL, NULL);
1597         left -= len;
1598     } else
1599         output->otmpFullName = 0;
1600
1601     assert(left == 0);
1602
1603     if(output != lpOTM) {
1604         memcpy(lpOTM, output, cbData);
1605         HeapFree(GetProcessHeap(), 0, output);
1606
1607         /* check if the string offsets really fit into the provided size */
1608         /* FIXME: should we check string length as well? */
1609         /* make sure that we don't read/write beyond the provided buffer */
1610         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1611         {
1612             if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1613                 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1614         }
1615
1616         /* make sure that we don't read/write beyond the provided buffer */
1617         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1618         {
1619             if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1620                 lpOTM->otmpFaceName = 0; /* doesn't fit */
1621         }
1622
1623             /* make sure that we don't read/write beyond the provided buffer */
1624         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1625         {
1626             if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1627                 lpOTM->otmpStyleName = 0; /* doesn't fit */
1628         }
1629
1630         /* make sure that we don't read/write beyond the provided buffer */
1631         if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1632         {
1633             if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1634                 lpOTM->otmpFullName = 0; /* doesn't fit */
1635         }
1636     }
1637
1638 end:
1639     if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1640         HeapFree(GetProcessHeap(), 0, lpOTMW);
1641
1642     return ret;
1643 }
1644
1645
1646 /***********************************************************************
1647  *           GetOutlineTextMetricsW [GDI32.@]
1648  */
1649 UINT WINAPI GetOutlineTextMetricsW(
1650     HDC hdc,    /* [in]  Handle of device context */
1651     UINT cbData, /* [in]  Size of metric data array */
1652     LPOUTLINETEXTMETRICW lpOTM)  /* [out] Address of metric data array */
1653 {
1654     DC *dc = DC_GetDCPtr( hdc );
1655     OUTLINETEXTMETRICW *output = lpOTM;
1656     UINT ret;
1657
1658     TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1659     if(!dc) return 0;
1660
1661     if(dc->gdiFont) {
1662         ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1663         if(lpOTM && ret) {
1664             if(ret > cbData) {
1665                 output = HeapAlloc(GetProcessHeap(), 0, ret);
1666                 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1667             }
1668
1669 #define WDPTOLP(x) ((x<0)?                                      \
1670                 (-abs(INTERNAL_XDSTOWS(dc, (x)))):              \
1671                 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1672 #define HDPTOLP(y) ((y<0)?                                      \
1673                 (-abs(INTERNAL_YDSTOWS(dc, (y)))):              \
1674                 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1675
1676             output->otmTextMetrics.tmHeight           = HDPTOLP(output->otmTextMetrics.tmHeight);
1677             output->otmTextMetrics.tmAscent           = HDPTOLP(output->otmTextMetrics.tmAscent);
1678             output->otmTextMetrics.tmDescent          = HDPTOLP(output->otmTextMetrics.tmDescent);
1679             output->otmTextMetrics.tmInternalLeading  = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1680             output->otmTextMetrics.tmExternalLeading  = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1681             output->otmTextMetrics.tmAveCharWidth     = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1682             output->otmTextMetrics.tmMaxCharWidth     = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1683             output->otmTextMetrics.tmOverhang         = WDPTOLP(output->otmTextMetrics.tmOverhang);
1684             output->otmAscent = HDPTOLP(output->otmAscent);
1685             output->otmDescent = HDPTOLP(output->otmDescent);
1686             output->otmLineGap = HDPTOLP(output->otmLineGap);
1687             output->otmsCapEmHeight = HDPTOLP(output->otmsCapEmHeight);
1688             output->otmsXHeight = HDPTOLP(output->otmsXHeight);
1689             output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1690             output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1691             output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1692             output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1693             output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1694             output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1695             output->otmMacLineGap = HDPTOLP(output->otmMacLineGap);
1696             output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1697             output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1698             output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1699             output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1700             output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1701             output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1702             output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1703             output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1704             output->otmsStrikeoutSize = HDPTOLP(output->otmsStrikeoutSize);
1705             output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1706             output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1707             output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1708 #undef WDPTOLP
1709 #undef HDPTOLP
1710             if(output != lpOTM) {
1711                 memcpy(lpOTM, output, cbData);
1712                 HeapFree(GetProcessHeap(), 0, output);
1713                 ret = cbData;
1714             }
1715         }
1716     }
1717
1718     else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1719               but really this should just be a return 0. */
1720
1721         ret = sizeof(*lpOTM);
1722         if (lpOTM) {
1723             if(cbData < ret)
1724                 ret = 0;
1725             else {
1726                 memset(lpOTM, 0, ret);
1727                 lpOTM->otmSize = sizeof(*lpOTM);
1728                 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1729                 /*
1730                   Further fill of the structure not implemented,
1731                   Needs real values for the structure members
1732                 */
1733             }
1734         }
1735     }
1736     DC_ReleaseDCPtr(dc);
1737     return ret;
1738 }
1739
1740
1741 /***********************************************************************
1742  *           GetCharWidthW      (GDI32.@)
1743  *           GetCharWidth32W    (GDI32.@)
1744  */
1745 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1746                                LPINT buffer )
1747 {
1748     UINT i;
1749     BOOL ret = FALSE;
1750     DC * dc = DC_GetDCPtr( hdc );
1751     if (!dc) return FALSE;
1752
1753     if (dc->gdiFont)
1754         ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1755     else if (dc->funcs->pGetCharWidth)
1756         ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1757
1758     if (ret)
1759     {
1760         /* convert device units to logical */
1761         for( i = firstChar; i <= lastChar; i++, buffer++ )
1762             *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1763         ret = TRUE;
1764     }
1765     DC_ReleaseDCPtr( dc );
1766     return ret;
1767 }
1768
1769
1770 /***********************************************************************
1771  *           GetCharWidthA      (GDI32.@)
1772  *           GetCharWidth32A    (GDI32.@)
1773  */
1774 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1775                                LPINT buffer )
1776 {
1777     INT i, wlen, count = (INT)(lastChar - firstChar + 1);
1778     LPSTR str;
1779     LPWSTR wstr;
1780     BOOL ret = TRUE;
1781
1782     if(count <= 0) return FALSE;
1783
1784     str = HeapAlloc(GetProcessHeap(), 0, count);
1785     for(i = 0; i < count; i++)
1786         str[i] = (BYTE)(firstChar + i);
1787
1788     wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1789
1790     for(i = 0; i < wlen; i++)
1791     {
1792         if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1793         {
1794             ret = FALSE;
1795             break;
1796         }
1797         buffer++;
1798     }
1799
1800     HeapFree(GetProcessHeap(), 0, str);
1801     HeapFree(GetProcessHeap(), 0, wstr);
1802
1803     return ret;
1804 }
1805
1806
1807 /***********************************************************************
1808  *           ExtTextOutA    (GDI32.@)
1809  *
1810  * See ExtTextOutW.
1811  */
1812 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1813                          const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1814 {
1815     INT wlen;
1816     UINT codepage;
1817     LPWSTR p;
1818     BOOL ret;
1819     LPINT lpDxW = NULL;
1820
1821     if (flags & ETO_GLYPH_INDEX)
1822         return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1823
1824     p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1825
1826     if (lpDx) {
1827         unsigned int i = 0, j = 0;
1828
1829         lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT));
1830         while(i < count) {
1831             if(IsDBCSLeadByteEx(codepage, str[i])) {
1832                 lpDxW[j++] = lpDx[i] + lpDx[i+1];
1833                 i = i + 2;
1834             } else {
1835                 lpDxW[j++] = lpDx[i];
1836                 i = i + 1;
1837             }
1838         }
1839     }
1840
1841     ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1842
1843     HeapFree( GetProcessHeap(), 0, p );
1844     HeapFree( GetProcessHeap(), 0, lpDxW );
1845     return ret;
1846 }
1847
1848
1849 /***********************************************************************
1850  *           ExtTextOutW    (GDI32.@)
1851  *
1852  * Draws text using the currently selected font, background color, and text color.
1853  * 
1854  * 
1855  * PARAMS
1856  *    x,y    [I] coordinates of string
1857  *    flags  [I]
1858  *        ETO_GRAYED - undocumented on MSDN
1859  *        ETO_OPAQUE - use background color for fill the rectangle
1860  *        ETO_CLIPPED - clipping text to the rectangle
1861  *        ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1862  *                          than encoded characters. Implies ETO_IGNORELANGUAGE
1863  *        ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1864  *                         Affects BiDi ordering
1865  *        ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1866  *        ETO_PDY - unimplemented
1867  *        ETO_NUMERICSLATIN - unimplemented always assumed -
1868  *                            do not translate numbers into locale representations
1869  *        ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1870  *    lprect [I] dimensions for clipping or/and opaquing
1871  *    str    [I] text string
1872  *    count  [I] number of symbols in string
1873  *    lpDx   [I] optional parameter with distance between drawing characters
1874  *
1875  * RETURNS
1876  *    Success: TRUE
1877  *    Failure: FALSE
1878  */
1879 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1880                          const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1881 {
1882     BOOL ret = FALSE;
1883     LPWSTR reordered_str = (LPWSTR)str;
1884     WORD *glyphs = NULL;
1885     UINT align = GetTextAlign( hdc );
1886     POINT pt;
1887     TEXTMETRICW tm;
1888     LOGFONTW lf;
1889     double cosEsc, sinEsc;
1890     INT *deltas = NULL, char_extra;
1891     SIZE sz;
1892     RECT rc;
1893     BOOL done_extents = FALSE;
1894     INT width = 0, xwidth = 0, ywidth = 0;
1895     DWORD type;
1896     DC * dc = get_dc_ptr( hdc );
1897     INT breakRem;
1898
1899     if (!dc) return FALSE;
1900
1901     breakRem = dc->breakRem;
1902
1903     if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
1904         FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
1905
1906     if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1907     {
1908         release_dc_ptr( dc );
1909         return ret;
1910     }
1911
1912     update_dc( dc );
1913     type = GetObjectType(hdc);
1914     if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1915     {
1916         ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1917         release_dc_ptr( dc );
1918         return ret;
1919     }
1920
1921     if (!lprect)
1922         flags &= ~ETO_CLIPPED;
1923         
1924     if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
1925     {
1926         reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1927
1928         BIDI_Reorder( str, count, GCP_REORDER,
1929                       ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
1930                       WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
1931                       reordered_str, count, NULL );
1932     
1933         flags |= ETO_IGNORELANGUAGE;
1934     }
1935
1936     TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
1937           lprect, debugstr_wn(str, count), count, lpDx);
1938
1939     if(flags & ETO_GLYPH_INDEX)
1940         glyphs = reordered_str;
1941
1942     if(lprect)
1943         TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
1944               lprect->bottom);
1945     TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1946
1947     if(align & TA_UPDATECP)
1948     {
1949         GetCurrentPositionEx( hdc, &pt );
1950         x = pt.x;
1951         y = pt.y;
1952     }
1953
1954     GetTextMetricsW(hdc, &tm);
1955     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1956
1957     if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1958         lf.lfEscapement = 0;
1959
1960     if(lf.lfEscapement != 0)
1961     {
1962         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1963         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1964     }
1965     else
1966     {
1967         cosEsc = 1;
1968         sinEsc = 0;
1969     }
1970
1971     if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1972     {
1973         if(!lprect)
1974         {
1975             if(flags & ETO_GLYPH_INDEX)
1976                 GetTextExtentPointI(hdc, glyphs, count, &sz);
1977             else
1978                 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1979
1980             done_extents = TRUE;
1981             rc.left = x;
1982             rc.top = y;
1983             rc.right = x + sz.cx;
1984             rc.bottom = y + sz.cy;
1985         }
1986         else
1987         {
1988             rc = *lprect;
1989         }
1990
1991         LPtoDP(hdc, (POINT*)&rc, 2);
1992
1993         if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1994         if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1995     }
1996
1997     if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1998         dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1999
2000     if(count == 0)
2001     {
2002         ret = TRUE;
2003         goto done;
2004     }
2005
2006     pt.x = x;
2007     pt.y = y;
2008     LPtoDP(hdc, &pt, 1);
2009     x = pt.x;
2010     y = pt.y;
2011
2012     char_extra = GetTextCharacterExtra(hdc);
2013     if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2014     {
2015         UINT i;
2016         SIZE tmpsz;
2017         deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
2018         for(i = 0; i < count; i++)
2019         {
2020             if(lpDx && (flags & ETO_PDY))
2021                 deltas[i] = lpDx[i*2] + char_extra;
2022             else if(lpDx)
2023                 deltas[i] = lpDx[i] + char_extra;
2024             else
2025             {
2026                 if(flags & ETO_GLYPH_INDEX)
2027                     GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2028                 else
2029                     GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2030
2031                 deltas[i] = tmpsz.cx;
2032             }
2033             
2034             if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2035             {
2036                 deltas[i] = deltas[i] + dc->breakExtra;
2037                 if (breakRem > 0)
2038                 {
2039                     breakRem--;
2040                     deltas[i]++;
2041                 }
2042             }
2043             deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
2044             width += deltas[i];
2045         }
2046     }
2047     else
2048     {
2049         if(!done_extents)
2050         {
2051             if(flags & ETO_GLYPH_INDEX)
2052                 GetTextExtentPointI(hdc, glyphs, count, &sz);
2053             else
2054                 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2055             done_extents = TRUE;
2056         }
2057         width = INTERNAL_XWSTODS(dc, sz.cx);
2058     }
2059     xwidth = width * cosEsc;
2060     ywidth = width * sinEsc;
2061
2062     tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2063     tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2064     switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2065     {
2066     case TA_LEFT:
2067         if (align & TA_UPDATECP)
2068         {
2069             pt.x = x + xwidth;
2070             pt.y = y - ywidth;
2071             DPtoLP(hdc, &pt, 1);
2072             MoveToEx(hdc, pt.x, pt.y, NULL);
2073         }
2074         break;
2075
2076     case TA_CENTER:
2077         x -= xwidth / 2;
2078         y += ywidth / 2;
2079         break;
2080
2081     case TA_RIGHT:
2082         x -= xwidth;
2083         y += ywidth;
2084         if (align & TA_UPDATECP)
2085         {
2086             pt.x = x;
2087             pt.y = y;
2088             DPtoLP(hdc, &pt, 1);
2089             MoveToEx(hdc, pt.x, pt.y, NULL);
2090         }
2091         break;
2092     }
2093
2094     switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2095     {
2096     case TA_TOP:
2097         y += tm.tmAscent * cosEsc;
2098         x += tm.tmAscent * sinEsc;
2099         break;
2100
2101     case TA_BOTTOM:
2102         y -= tm.tmDescent * cosEsc;
2103         x -= tm.tmDescent * sinEsc;
2104         break;
2105
2106     case TA_BASELINE:
2107         break;
2108     }
2109
2110     if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
2111     {
2112         if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2113         {
2114             if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
2115                y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2116             {
2117                 RECT rc;
2118                 rc.left = x;
2119                 rc.right = x + width;
2120                 rc.top = y - tm.tmAscent;
2121                 rc.bottom = y + tm.tmDescent;
2122                 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
2123             }
2124         }
2125     }
2126
2127     if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
2128     {
2129         HFONT orig_font = dc->hFont, cur_font;
2130         UINT glyph;
2131         INT span = 0, *offsets = NULL, i;
2132
2133         glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2134         for(i = 0; i < count; i++)
2135         {
2136             WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
2137             if(cur_font != dc->hFont)
2138             {
2139                 if(!offsets)
2140                 {
2141                     int j;
2142                     offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2143                     offsets[0] = 0;
2144                     if(!deltas)
2145                     {
2146                         SIZE tmpsz;
2147                         for(j = 1; j < count; j++)
2148                         {
2149                             GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
2150                             offsets[j] = offsets[j-1] + INTERNAL_XWSTODS(dc, tmpsz.cx);
2151                         }
2152                     }
2153                     else
2154                     {
2155                         for(j = 1; j < count; j++)
2156                             offsets[j] = offsets[j-1] + deltas[j];
2157                     }
2158                 }
2159                 if(span)
2160                 {
2161                     if (PATH_IsPathOpen(dc->path))
2162                         ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
2163                                               (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2164                                               glyphs, span, deltas ? deltas + i - span : NULL);
2165                     else
2166                         dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
2167                                            (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2168                                            glyphs, span, deltas ? deltas + i - span : NULL);
2169                     span = 0;
2170                 }
2171                 SelectObject(hdc, cur_font);
2172             }
2173             glyphs[span++] = glyph;
2174
2175             if(i == count - 1)
2176             {
2177                 if (PATH_IsPathOpen(dc->path))
2178                     ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
2179                                           y - (offsets ? offsets[count - span] * sinEsc : 0),
2180                                           (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2181                                           glyphs, span, deltas ? deltas + count - span : NULL);
2182                 else
2183                     ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
2184                                              y - (offsets ? offsets[count - span] * sinEsc : 0),
2185                                              (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2186                                              glyphs, span, deltas ? deltas + count - span : NULL);
2187                 SelectObject(hdc, orig_font);
2188                 HeapFree(GetProcessHeap(), 0, offsets);
2189            }
2190         }
2191     }
2192     else
2193     {
2194         if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2195         {
2196             glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2197             GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2198             flags |= ETO_GLYPH_INDEX;
2199         }
2200
2201         if (PATH_IsPathOpen(dc->path))
2202             ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
2203                                   glyphs ? glyphs : reordered_str, count, deltas);
2204         else
2205             ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
2206                                      glyphs ? glyphs : reordered_str, count, deltas);
2207     }
2208
2209 done:
2210     HeapFree(GetProcessHeap(), 0, deltas);
2211     if(glyphs != reordered_str)
2212         HeapFree(GetProcessHeap(), 0, glyphs);
2213     if(reordered_str != str)
2214         HeapFree(GetProcessHeap(), 0, reordered_str);
2215
2216     release_dc_ptr( dc );
2217
2218     if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2219     {
2220         int underlinePos, strikeoutPos;
2221         int underlineWidth, strikeoutWidth;
2222         UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2223         OUTLINETEXTMETRICW* otm = NULL;
2224
2225         if(!size)
2226         {
2227             underlinePos = 0;
2228             underlineWidth = tm.tmAscent / 20 + 1;
2229             strikeoutPos = tm.tmAscent / 2;
2230             strikeoutWidth = underlineWidth;
2231         }
2232         else
2233         {
2234             otm = HeapAlloc(GetProcessHeap(), 0, size);
2235             GetOutlineTextMetricsW(hdc, size, otm);
2236             underlinePos = otm->otmsUnderscorePosition;
2237             underlineWidth = otm->otmsUnderscoreSize;
2238             strikeoutPos = otm->otmsStrikeoutPosition;
2239             strikeoutWidth = otm->otmsStrikeoutSize;
2240             HeapFree(GetProcessHeap(), 0, otm);
2241         }
2242
2243         if (PATH_IsPathOpen(dc->path))
2244         {
2245             POINT pts[5];
2246             HPEN hpen;
2247             HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2248
2249             hbrush = SelectObject(hdc, hbrush);
2250             hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2251
2252             if (lf.lfUnderline)
2253             {
2254                 pts[0].x = x - underlinePos * sinEsc;
2255                 pts[0].y = y - underlinePos * cosEsc;
2256                 pts[1].x = x + xwidth - underlinePos * sinEsc;
2257                 pts[1].y = y - ywidth - underlinePos * cosEsc;
2258                 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2259                 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2260                 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2261                 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2262                 pts[4].x = pts[0].x;
2263                 pts[4].y = pts[0].y;
2264                 DPtoLP(hdc, pts, 5);
2265                 Polygon(hdc, pts, 5);
2266             }
2267
2268             if (lf.lfStrikeOut)
2269             {
2270                 pts[0].x = x - strikeoutPos * sinEsc;
2271                 pts[0].y = y - strikeoutPos * cosEsc;
2272                 pts[1].x = x + xwidth - strikeoutPos * sinEsc;
2273                 pts[1].y = y - ywidth - strikeoutPos * cosEsc;
2274                 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2275                 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2276                 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2277                 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2278                 pts[4].x = pts[0].x;
2279                 pts[4].y = pts[0].y;
2280                 DPtoLP(hdc, pts, 5);
2281                 Polygon(hdc, pts, 5);
2282             }
2283
2284             SelectObject(hdc, hpen);
2285             hbrush = SelectObject(hdc, hbrush);
2286             DeleteObject(hbrush);
2287         }
2288         else
2289         {
2290             POINT pts[2], oldpt;
2291             HPEN hpen;
2292
2293             if (lf.lfUnderline)
2294             {
2295                 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2296                 hpen = SelectObject(hdc, hpen);
2297                 pts[0].x = x;
2298                 pts[0].y = y;
2299                 pts[1].x = x + xwidth;
2300                 pts[1].y = y - ywidth;
2301                 DPtoLP(hdc, pts, 2);
2302                 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2303                 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2304                 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2305                 DeleteObject(SelectObject(hdc, hpen));
2306             }
2307
2308             if (lf.lfStrikeOut)
2309             {
2310                 hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
2311                 hpen = SelectObject(hdc, hpen);
2312                 pts[0].x = x;
2313                 pts[0].y = y;
2314                 pts[1].x = x + xwidth;
2315                 pts[1].y = y - ywidth;
2316                 DPtoLP(hdc, pts, 2);
2317                 MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2318                 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2319                 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2320                 DeleteObject(SelectObject(hdc, hpen));
2321             }
2322         }
2323     }
2324
2325     return ret;
2326 }
2327
2328
2329 /***********************************************************************
2330  *           TextOutA    (GDI32.@)
2331  */
2332 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2333 {
2334     return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2335 }
2336
2337
2338 /***********************************************************************
2339  *           TextOutW    (GDI32.@)
2340  */
2341 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2342 {
2343     return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2344 }
2345
2346
2347 /***********************************************************************
2348  *              PolyTextOutA (GDI32.@)
2349  *
2350  * See PolyTextOutW.
2351  */
2352 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2353 {
2354     for (; cStrings>0; cStrings--, pptxt++)
2355         if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2356             return FALSE;
2357     return TRUE;
2358 }
2359
2360
2361
2362 /***********************************************************************
2363  *              PolyTextOutW (GDI32.@)
2364  *
2365  * Draw several Strings
2366  *
2367  * RETURNS
2368  *  TRUE:  Success.
2369  *  FALSE: Failure.
2370  */
2371 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2372 {
2373     for (; cStrings>0; cStrings--, pptxt++)
2374         if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2375             return FALSE;
2376     return TRUE;
2377 }
2378
2379
2380 /* FIXME: all following APIs ******************************************/
2381
2382
2383 /***********************************************************************
2384  *           SetMapperFlags    (GDI32.@)
2385  */
2386 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2387 {
2388     DC *dc = DC_GetDCPtr( hDC );
2389     DWORD ret = 0;
2390     if(!dc) return 0;
2391     if(dc->funcs->pSetMapperFlags)
2392     {
2393         ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2394         /* FIXME: ret is just a success flag, we should return a proper value */
2395     }
2396     else
2397         FIXME("(%p, 0x%08x): stub - harmless\n", hDC, dwFlag);
2398     DC_ReleaseDCPtr( dc );
2399     return ret;
2400 }
2401
2402 /***********************************************************************
2403  *          GetAspectRatioFilterEx  (GDI.486)
2404  */
2405 BOOL16 WINAPI GetAspectRatioFilterEx16( HDC16 hdc, LPSIZE16 pAspectRatio )
2406 {
2407   FIXME("(%04x, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2408   return FALSE;
2409 }
2410
2411 /***********************************************************************
2412  *          GetAspectRatioFilterEx  (GDI32.@)
2413  */
2414 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2415 {
2416   FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2417   return FALSE;
2418 }
2419
2420
2421 /***********************************************************************
2422  *           GetCharABCWidthsA   (GDI32.@)
2423  *
2424  * See GetCharABCWidthsW.
2425  */
2426 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2427                                   LPABC abc )
2428 {
2429     INT i, wlen, count = (INT)(lastChar - firstChar + 1);
2430     LPSTR str;
2431     LPWSTR wstr;
2432     BOOL ret = TRUE;
2433
2434     if(count <= 0) return FALSE;
2435
2436     str = HeapAlloc(GetProcessHeap(), 0, count);
2437     for(i = 0; i < count; i++)
2438         str[i] = (BYTE)(firstChar + i);
2439
2440     wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
2441
2442     for(i = 0; i < wlen; i++)
2443     {
2444         if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2445         {
2446             ret = FALSE;
2447             break;
2448         }
2449         abc++;
2450     }
2451
2452     HeapFree(GetProcessHeap(), 0, str);
2453     HeapFree(GetProcessHeap(), 0, wstr);
2454
2455     return ret;
2456 }
2457
2458
2459 /******************************************************************************
2460  * GetCharABCWidthsW [GDI32.@]
2461  *
2462  * Retrieves widths of characters in range.
2463  *
2464  * PARAMS
2465  *    hdc       [I] Handle of device context
2466  *    firstChar [I] First character in range to query
2467  *    lastChar  [I] Last character in range to query
2468  *    abc       [O] Address of character-width structure
2469  *
2470  * NOTES
2471  *    Only works with TrueType fonts
2472  *
2473  * RETURNS
2474  *    Success: TRUE
2475  *    Failure: FALSE
2476  */
2477 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2478                                    LPABC abc )
2479 {
2480     DC *dc = DC_GetDCPtr(hdc);
2481     unsigned int i;
2482     BOOL ret = FALSE;
2483
2484     if (!dc) return FALSE;
2485
2486     if(dc->gdiFont)
2487         ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2488     else
2489         FIXME(": stub\n");
2490
2491     if (ret)
2492     {
2493         /* convert device units to logical */
2494         for( i = firstChar; i <= lastChar; i++, abc++ ) {
2495             abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2496             abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2497             abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2498         }
2499         ret = TRUE;
2500     }
2501
2502     DC_ReleaseDCPtr( dc );
2503     return ret;
2504 }
2505
2506
2507 /******************************************************************************
2508  * GetCharABCWidthsI [GDI32.@]
2509  *
2510  * Retrieves widths of characters in range.
2511  *
2512  * PARAMS
2513  *    hdc       [I] Handle of device context
2514  *    firstChar [I] First glyphs in range to query
2515  *    count     [I] Last glyphs in range to query
2516  *    pgi       [i] Array of glyphs to query
2517  *    abc       [O] Address of character-width structure
2518  *
2519  * NOTES
2520  *    Only works with TrueType fonts
2521  *
2522  * RETURNS
2523  *    Success: TRUE
2524  *    Failure: FALSE
2525  */
2526 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2527                                LPWORD pgi, LPABC abc)
2528 {
2529     DC *dc = DC_GetDCPtr(hdc);
2530     unsigned int i;
2531     BOOL ret = FALSE;
2532
2533     if (!dc) return FALSE;
2534
2535     if(dc->gdiFont)
2536         ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2537     else
2538         FIXME(": stub\n");
2539
2540     if (ret)
2541     {
2542         /* convert device units to logical */
2543         for( i = 0; i < count; i++, abc++ ) {
2544             abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2545             abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2546             abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2547         }
2548         ret = TRUE;
2549     }
2550
2551     DC_ReleaseDCPtr( dc );
2552     return ret;
2553 }
2554
2555
2556 /***********************************************************************
2557  *           GetGlyphOutlineA    (GDI32.@)
2558  */
2559 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2560                                  LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2561                                  LPVOID lpBuffer, const MAT2 *lpmat2 )
2562 {
2563     LPWSTR p = NULL;
2564     DWORD ret;
2565     UINT c;
2566
2567     if(!(fuFormat & GGO_GLYPH_INDEX)) {
2568         int len;
2569         char mbchs[2];
2570         if(uChar > 0xff) { /* but, 2 bytes character only */
2571             len = 2;
2572             mbchs[0] = (uChar & 0xff00) >> 8;
2573             mbchs[1] = (uChar & 0xff);
2574         } else {
2575             len = 1;
2576             mbchs[0] = (uChar & 0xff);
2577         }
2578         p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
2579         c = p[0];
2580     } else
2581         c = uChar;
2582     ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
2583                            lpmat2);
2584     HeapFree(GetProcessHeap(), 0, p);
2585     return ret;
2586 }
2587
2588 /***********************************************************************
2589  *           GetGlyphOutlineW    (GDI32.@)
2590  */
2591 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2592                                  LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2593                                  LPVOID lpBuffer, const MAT2 *lpmat2 )
2594 {
2595     DC *dc = DC_GetDCPtr(hdc);
2596     DWORD ret;
2597
2598     TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2599           hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2600
2601     if(!dc) return GDI_ERROR;
2602
2603     if(dc->gdiFont)
2604       ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2605                                    cbBuffer, lpBuffer, lpmat2);
2606     else
2607       ret = GDI_ERROR;
2608
2609     DC_ReleaseDCPtr( dc );
2610     return ret;
2611 }
2612
2613
2614 /***********************************************************************
2615  *           CreateScalableFontResourceA   (GDI32.@)
2616  */
2617 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2618                                              LPCSTR lpszResourceFile,
2619                                              LPCSTR lpszFontFile,
2620                                              LPCSTR lpszCurrentPath )
2621 {
2622     HANDLE f;
2623
2624     /* fHidden=1 - only visible for the calling app, read-only, not
2625      * enumbered with EnumFonts/EnumFontFamilies
2626      * lpszCurrentPath can be NULL
2627      */
2628     FIXME("(%d,%s,%s,%s): stub\n",
2629           fHidden, debugstr_a(lpszResourceFile), debugstr_a(lpszFontFile),
2630           debugstr_a(lpszCurrentPath) );
2631
2632     /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2633     if ((f = CreateFileA(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2634         CloseHandle(f);
2635         SetLastError(ERROR_FILE_EXISTS);
2636         return FALSE;
2637     }
2638     return FALSE; /* create failed */
2639 }
2640
2641 /***********************************************************************
2642  *           CreateScalableFontResourceW   (GDI32.@)
2643  */
2644 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2645                                              LPCWSTR lpszResourceFile,
2646                                              LPCWSTR lpszFontFile,
2647                                              LPCWSTR lpszCurrentPath )
2648 {
2649     FIXME("(%d,%p,%p,%p): stub\n",
2650           fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath );
2651     return FALSE; /* create failed */
2652 }
2653
2654 /*************************************************************************
2655  *             GetKerningPairsA   (GDI32.@)
2656  */
2657 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2658                                LPKERNINGPAIR kern_pairA )
2659 {
2660     INT charset;
2661     CHARSETINFO csi;
2662     CPINFO cpi;
2663     DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2664     KERNINGPAIR *kern_pairW;
2665
2666     if (!cPairs && kern_pairA)
2667     {
2668         SetLastError(ERROR_INVALID_PARAMETER);
2669         return 0;
2670     }
2671
2672     charset = GetTextCharset(hDC);
2673     if (!TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
2674     {
2675         FIXME("Can't find codepage for charset %d\n", charset);
2676         return 0;
2677     }
2678     /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2679      * to fail on an invalid character for CP_SYMBOL.
2680      */
2681     cpi.DefaultChar[0] = 0;
2682     if (csi.ciACP != CP_SYMBOL && !GetCPInfo(csi.ciACP, &cpi))
2683     {
2684         FIXME("Can't find codepage %u info\n", csi.ciACP);
2685         return 0;
2686     }
2687     TRACE("charset %d => codepage %u\n", charset, csi.ciACP);
2688
2689     total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2690     if (!total_kern_pairs) return 0;
2691
2692     kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2693     GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2694
2695     for (i = 0; i < total_kern_pairs; i++)
2696     {
2697         char first, second;
2698
2699         if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2700             continue;
2701
2702         if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2703             continue;
2704
2705         if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2706             continue;
2707
2708         if (kern_pairA)
2709         {
2710             if (kern_pairs_copied >= cPairs) break;
2711
2712             kern_pairA->wFirst = (BYTE)first;
2713             kern_pairA->wSecond = (BYTE)second;
2714             kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2715             kern_pairA++;
2716         }
2717         kern_pairs_copied++;
2718     }
2719
2720     HeapFree(GetProcessHeap(), 0, kern_pairW);
2721
2722     return kern_pairs_copied;
2723 }
2724
2725 /*************************************************************************
2726  *             GetKerningPairsW   (GDI32.@)
2727  */
2728 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2729                                  LPKERNINGPAIR lpKerningPairs )
2730 {
2731     DC *dc;
2732     DWORD ret = 0;
2733
2734     TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2735
2736     if (!cPairs && lpKerningPairs)
2737     {
2738         SetLastError(ERROR_INVALID_PARAMETER);
2739         return 0;
2740     }
2741
2742     dc = DC_GetDCPtr(hDC);
2743     if (!dc) return 0;
2744
2745     if (dc->gdiFont)
2746         ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
2747
2748     DC_ReleaseDCPtr( dc );
2749     return ret;
2750 }
2751
2752 /*************************************************************************
2753  * TranslateCharsetInfo [GDI32.@]
2754  *
2755  * Fills a CHARSETINFO structure for a character set, code page, or
2756  * font. This allows making the correspondance between different labelings
2757  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2758  * of the same encoding.
2759  *
2760  * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2761  * only one codepage should be set in *lpSrc.
2762  *
2763  * RETURNS
2764  *   TRUE on success, FALSE on failure.
2765  *
2766  */
2767 BOOL WINAPI TranslateCharsetInfo(
2768   LPDWORD lpSrc, /* [in]
2769        if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2770        if flags == TCI_SRCCHARSET: a character set value
2771        if flags == TCI_SRCCODEPAGE: a code page value
2772                  */
2773   LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2774   DWORD flags /* [in] determines interpretation of lpSrc */)
2775 {
2776     int index = 0;
2777     switch (flags) {
2778     case TCI_SRCFONTSIG:
2779         while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
2780       break;
2781     case TCI_SRCCODEPAGE:
2782       while (PtrToUlong(lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
2783       break;
2784     case TCI_SRCCHARSET:
2785       while (PtrToUlong(lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
2786       break;
2787     default:
2788       return FALSE;
2789     }
2790     if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2791     memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO));
2792     return TRUE;
2793 }
2794
2795 /*************************************************************************
2796  *             GetFontLanguageInfo   (GDI32.@)
2797  */
2798 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2799 {
2800         FONTSIGNATURE fontsig;
2801         static const DWORD GCP_DBCS_MASK=0x003F0000,
2802                 GCP_DIACRITIC_MASK=0x00000000,
2803                 FLI_GLYPHS_MASK=0x00000000,
2804                 GCP_GLYPHSHAPE_MASK=0x00000040,
2805                 GCP_KASHIDA_MASK=0x00000000,
2806                 GCP_LIGATE_MASK=0x00000000,
2807                 GCP_USEKERNING_MASK=0x00000000,
2808                 GCP_REORDER_MASK=0x00000060;
2809
2810         DWORD result=0;
2811
2812         GetTextCharsetInfo( hdc, &fontsig, 0 );
2813         /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2814
2815         if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2816                 result|=GCP_DBCS;
2817
2818         if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2819                 result|=GCP_DIACRITIC;
2820
2821         if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2822                 result|=FLI_GLYPHS;
2823
2824         if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2825                 result|=GCP_GLYPHSHAPE;
2826
2827         if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2828                 result|=GCP_KASHIDA;
2829
2830         if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2831                 result|=GCP_LIGATE;
2832
2833         if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2834                 result|=GCP_USEKERNING;
2835
2836         /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2837         if( GetTextAlign( hdc) & TA_RTLREADING )
2838             if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2839                     result|=GCP_REORDER;
2840
2841         return result;
2842 }
2843
2844
2845 /*************************************************************************
2846  * GetFontData [GDI32.@]
2847  *
2848  * Retrieve data for TrueType font.
2849  *
2850  * RETURNS
2851  *
2852  * success: Number of bytes returned
2853  * failure: GDI_ERROR
2854  *
2855  * NOTES
2856  *
2857  * Calls SetLastError()
2858  *
2859  */
2860 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2861     LPVOID buffer, DWORD length)
2862 {
2863     DC *dc = DC_GetDCPtr(hdc);
2864     DWORD ret = GDI_ERROR;
2865
2866     if(!dc) return GDI_ERROR;
2867
2868     if(dc->gdiFont)
2869       ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2870
2871     DC_ReleaseDCPtr( dc );
2872     return ret;
2873 }
2874
2875 /*************************************************************************
2876  * GetGlyphIndicesA [GDI32.@]
2877  */
2878 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2879                               LPWORD pgi, DWORD flags)
2880 {
2881     DWORD ret;
2882     WCHAR *lpstrW;
2883     INT countW;
2884
2885     TRACE("(%p, %s, %d, %p, 0x%x)\n",
2886           hdc, debugstr_an(lpstr, count), count, pgi, flags);
2887
2888     lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
2889     ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2890     HeapFree(GetProcessHeap(), 0, lpstrW);
2891
2892     return ret;
2893 }
2894
2895 /*************************************************************************
2896  * GetGlyphIndicesW [GDI32.@]
2897  */
2898 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2899                               LPWORD pgi, DWORD flags)
2900 {
2901     DC *dc = DC_GetDCPtr(hdc);
2902     DWORD ret = GDI_ERROR;
2903
2904     TRACE("(%p, %s, %d, %p, 0x%x)\n",
2905           hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2906
2907     if(!dc) return GDI_ERROR;
2908
2909     if(dc->gdiFont)
2910         ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2911
2912     DC_ReleaseDCPtr( dc );
2913     return ret;
2914 }
2915
2916 /*************************************************************************
2917  * GetCharacterPlacementA [GDI32.@]
2918  *
2919  * See GetCharacterPlacementW.
2920  *
2921  * NOTES:
2922  *  the web browser control of ie4 calls this with dwFlags=0
2923  */
2924 DWORD WINAPI
2925 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2926                          INT nMaxExtent, GCP_RESULTSA *lpResults,
2927                          DWORD dwFlags)
2928 {
2929     WCHAR *lpStringW;
2930     INT uCountW;
2931     GCP_RESULTSW resultsW;
2932     DWORD ret;
2933     UINT font_cp;
2934
2935     TRACE("%s, %d, %d, 0x%08x\n",
2936           debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2937
2938     /* both structs are equal in size */
2939     memcpy(&resultsW, lpResults, sizeof(resultsW));
2940
2941     lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
2942     if(lpResults->lpOutString)
2943         resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2944
2945     ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2946
2947     lpResults->nGlyphs = resultsW.nGlyphs;
2948     lpResults->nMaxFit = resultsW.nMaxFit;
2949
2950     if(lpResults->lpOutString) {
2951         WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
2952                             lpResults->lpOutString, uCount, NULL, NULL );
2953     }
2954
2955     HeapFree(GetProcessHeap(), 0, lpStringW);
2956     HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2957
2958     return ret;
2959 }
2960
2961 /*************************************************************************
2962  * GetCharacterPlacementW [GDI32.@]
2963  *
2964  *   Retrieve information about a string. This includes the width, reordering,
2965  *   Glyphing and so on.
2966  *
2967  * RETURNS
2968  *
2969  *   The width and height of the string if successful, 0 if failed.
2970  *
2971  * BUGS
2972  *
2973  *   All flags except GCP_REORDER are not yet implemented.
2974  *   Reordering is not 100% complient to the Windows BiDi method.
2975  *   Caret positioning is not yet implemented for BiDi.
2976  *   Classes are not yet implemented.
2977  *
2978  */
2979 DWORD WINAPI
2980 GetCharacterPlacementW(
2981                 HDC hdc,                /* [in] Device context for which the rendering is to be done */
2982                 LPCWSTR lpString,       /* [in] The string for which information is to be returned */
2983                 INT uCount,             /* [in] Number of WORDS in string. */
2984                 INT nMaxExtent,         /* [in] Maximum extent the string is to take (in HDC logical units) */
2985                 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
2986                 DWORD dwFlags           /* [in] Flags specifying how to process the string */
2987                 )
2988 {
2989     DWORD ret=0;
2990     SIZE size;
2991     UINT i, nSet;
2992
2993     TRACE("%s, %d, %d, 0x%08x\n",
2994           debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2995
2996     TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
2997           "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2998             lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
2999             lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3000             lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3001
3002     if(dwFlags&(~GCP_REORDER))                  FIXME("flags 0x%08x ignored\n", dwFlags);
3003     if(lpResults->lpClass)      FIXME("classes not implemented\n");
3004     if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3005         FIXME("Caret positions for complex scripts not implemented\n");
3006
3007         nSet = (UINT)uCount;
3008         if(nSet > lpResults->nGlyphs)
3009                 nSet = lpResults->nGlyphs;
3010
3011         /* return number of initialized fields */
3012         lpResults->nGlyphs = nSet;
3013
3014         if((dwFlags&GCP_REORDER)==0 )
3015         {
3016                 /* Treat the case where no special handling was requested in a fastpath way */
3017                 /* copy will do if the GCP_REORDER flag is not set */
3018                 if(lpResults->lpOutString)
3019                     memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3020
3021                 if(lpResults->lpOrder)
3022                 {
3023                         for(i = 0; i < nSet; i++)
3024                                 lpResults->lpOrder[i] = i;
3025                 }
3026         } else
3027         {
3028             BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3029                           nSet, lpResults->lpOrder );
3030         }
3031
3032         /* FIXME: Will use the placement chars */
3033         if (lpResults->lpDx)
3034         {
3035                 int c;
3036                 for (i = 0; i < nSet; i++)
3037                 {
3038                         if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3039                                 lpResults->lpDx[i]= c;
3040                 }
3041         }
3042
3043     if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3044     {
3045         int pos = 0;
3046        
3047         lpResults->lpCaretPos[0] = 0;
3048         for (i = 1; i < nSet; i++)
3049             if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3050                 lpResults->lpCaretPos[i] = (pos += size.cx);
3051     }
3052    
3053     if(lpResults->lpGlyphs)
3054         GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3055
3056     if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3057       ret = MAKELONG(size.cx, size.cy);
3058
3059     return ret;
3060 }
3061
3062 /*************************************************************************
3063  *      GetCharABCWidthsFloatA [GDI32.@]
3064  *
3065  * See GetCharABCWidthsFloatW.
3066  */
3067 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3068 {
3069     INT i, wlen, count = (INT)(last - first + 1);
3070     LPSTR str;
3071     LPWSTR wstr;
3072     BOOL ret = TRUE;
3073
3074     if (count <= 0) return FALSE;
3075
3076     str = HeapAlloc(GetProcessHeap(), 0, count);
3077
3078     for(i = 0; i < count; i++)
3079         str[i] = (BYTE)(first + i);
3080
3081     wstr = FONT_mbtowc( hdc, str, count, &wlen, NULL );
3082
3083     for (i = 0; i < wlen; i++)
3084     {
3085         if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3086         {
3087             ret = FALSE;
3088             break;
3089         }
3090         abcf++;
3091     }
3092
3093     HeapFree( GetProcessHeap(), 0, str );
3094     HeapFree( GetProcessHeap(), 0, wstr );
3095
3096     return ret;
3097 }
3098
3099 /*************************************************************************
3100  *      GetCharABCWidthsFloatW [GDI32.@]
3101  *
3102  * Retrieves widths of a range of characters.
3103  *
3104  * PARAMS
3105  *    hdc   [I] Handle to device context.
3106  *    first [I] First character in range to query.
3107  *    last  [I] Last character in range to query.
3108  *    abcf  [O] Array of LPABCFLOAT structures.
3109  *
3110  * RETURNS
3111  *    Success: TRUE
3112  *    Failure: FALSE
3113  *
3114  * BUGS
3115  *    Only works with TrueType fonts. It also doesn't return real
3116  *    floats but converted integers because it's implemented on
3117  *    top of GetCharABCWidthsW.
3118  */
3119 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3120 {
3121     ABC *abc;
3122     unsigned int i, size = sizeof(ABC) * (last - first + 1);
3123     BOOL ret;
3124
3125     TRACE("%p, %d, %d, %p - partial stub\n", hdc, first, last, abcf);
3126
3127     abc = HeapAlloc( GetProcessHeap(), 0, size );
3128     if (!abc) return FALSE;
3129
3130     ret = GetCharABCWidthsW( hdc, first, last, abc );
3131     if (ret)
3132     {
3133         for (i = first; i <= last; i++, abc++, abcf++)
3134         {
3135             abcf->abcfA = abc->abcA;
3136             abcf->abcfB = abc->abcB;
3137             abcf->abcfC = abc->abcC;
3138         }
3139     }
3140     HeapFree( GetProcessHeap(), 0, abc );
3141     return ret;
3142 }
3143
3144 /*************************************************************************
3145  *      GetCharWidthFloatA [GDI32.@]
3146  */
3147 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3148                                     UINT iLastChar, PFLOAT pxBuffer)
3149 {
3150     FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3151     return 0;
3152 }
3153
3154 /*************************************************************************
3155  *      GetCharWidthFloatW [GDI32.@]
3156  */
3157 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3158                                     UINT iLastChar, PFLOAT pxBuffer)
3159 {
3160     FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3161     return 0;
3162 }
3163
3164
3165 /***********************************************************************
3166  *                                                                     *
3167  *           Font Resource API                                         *
3168  *                                                                     *
3169  ***********************************************************************/
3170
3171 /***********************************************************************
3172  *           AddFontResourceA    (GDI32.@)
3173  */
3174 INT WINAPI AddFontResourceA( LPCSTR str )
3175 {
3176     return AddFontResourceExA( str, 0, NULL);
3177 }
3178
3179 /***********************************************************************
3180  *           AddFontResourceW    (GDI32.@)
3181  */
3182 INT WINAPI AddFontResourceW( LPCWSTR str )
3183 {
3184     return AddFontResourceExW(str, 0, NULL);
3185 }
3186
3187
3188 /***********************************************************************
3189  *           AddFontResourceExA    (GDI32.@)
3190  */
3191 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3192 {
3193     DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3194     LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3195     INT ret;
3196
3197     MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3198     ret = AddFontResourceExW(strW, fl, pdv);
3199     HeapFree(GetProcessHeap(), 0, strW);
3200     return ret;
3201 }
3202
3203 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3204 {
3205     HRSRC rsrc = FindResourceW(hModule, name, type);
3206     HGLOBAL hMem = LoadResource(hModule, rsrc);
3207     LPVOID *pMem = LockResource(hMem);
3208     int *num_total = (int *)lParam;
3209     DWORD num_in_res;
3210
3211     TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3212     if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3213     {
3214         ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3215         return FALSE;
3216     }
3217
3218     *num_total += num_in_res;
3219     return TRUE;
3220 }
3221
3222 /***********************************************************************
3223  *           AddFontResourceExW    (GDI32.@)
3224  */
3225 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3226 {
3227     int ret = WineEngAddFontResourceEx(str, fl, pdv);
3228     if (ret == 0)
3229     {
3230         /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3231         HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3232         if (hModule != NULL)
3233         {
3234             int num_resources = 0;
3235             LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8);  /* we don't want to include winuser.h */
3236
3237             TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3238                 wine_dbgstr_w(str));
3239             if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3240                 ret = num_resources;
3241             FreeLibrary(hModule);
3242         }
3243     }
3244     return ret;
3245 }
3246
3247 /***********************************************************************
3248  *           RemoveFontResourceA    (GDI32.@)
3249  */
3250 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3251 {
3252     return RemoveFontResourceExA(str, 0, 0);
3253 }
3254
3255 /***********************************************************************
3256  *           RemoveFontResourceW    (GDI32.@)
3257  */
3258 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3259 {
3260     return RemoveFontResourceExW(str, 0, 0);
3261 }
3262
3263 /***********************************************************************
3264  *           AddFontMemResourceEx    (GDI32.@)
3265  */
3266 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3267 {
3268     return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts);
3269 }
3270
3271 /***********************************************************************
3272  *           RemoveFontResourceExA    (GDI32.@)
3273  */
3274 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3275 {
3276     DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3277     LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3278     INT ret;
3279
3280     MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3281     ret = RemoveFontResourceExW(strW, fl, pdv);
3282     HeapFree(GetProcessHeap(), 0, strW);
3283     return ret;
3284 }
3285
3286 /***********************************************************************
3287  *           RemoveFontResourceExW    (GDI32.@)
3288  */
3289 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3290 {
3291     return WineEngRemoveFontResourceEx(str, fl, pdv);
3292 }
3293
3294 /***********************************************************************
3295  *           GetTextCharset    (GDI32.@)
3296  */
3297 UINT WINAPI GetTextCharset(HDC hdc)
3298 {
3299     /* MSDN docs say this is equivalent */
3300     return GetTextCharsetInfo(hdc, NULL, 0);
3301 }
3302
3303 /***********************************************************************
3304  *           GetTextCharsetInfo    (GDI32.@)
3305  */
3306 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3307 {
3308     UINT ret = DEFAULT_CHARSET;
3309     DC *dc = DC_GetDCPtr(hdc);
3310
3311     if (dc)
3312     {
3313         if (dc->gdiFont)
3314             ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3315
3316         DC_ReleaseDCPtr( dc );
3317     }
3318
3319     if (ret == DEFAULT_CHARSET && fs)
3320         memset(fs, 0, sizeof(FONTSIGNATURE));
3321     return ret;
3322 }
3323
3324 /***********************************************************************
3325  *           GdiGetCharDimensions    (GDI32.@)
3326  *
3327  * Gets the average width of the characters in the English alphabet.
3328  *
3329  * PARAMS
3330  *  hdc    [I] Handle to the device context to measure on.
3331  *  lptm   [O] Pointer to memory to store the text metrics into.
3332  *  height [O] On exit, the maximum height of characters in the English alphabet.
3333  *
3334  * RETURNS
3335  *  The average width of characters in the English alphabet.
3336  *
3337  * NOTES
3338  *  This function is used by the dialog manager to get the size of a dialog
3339  *  unit. It should also be used by other pieces of code that need to know
3340  *  the size of a dialog unit in logical units without having access to the
3341  *  window handle of the dialog.
3342  *  Windows caches the font metrics from this function, but we don't and
3343  *  there doesn't appear to be an immediate advantage to do so.
3344  *
3345  * SEE ALSO
3346  *  GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3347  */
3348 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3349 {
3350     SIZE sz;
3351     static const WCHAR alphabet[] = {
3352         'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3353         'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3354         'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3355
3356     if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3357
3358     if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3359
3360     if (height) *height = sz.cy;
3361     return (sz.cx / 26 + 1) / 2;
3362 }
3363
3364 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3365 {
3366     FIXME("(%d): stub\n", fEnableEUDC);
3367     return FALSE;
3368 }
3369
3370 /***********************************************************************
3371  *           GetCharWidthI    (GDI32.@)
3372  *
3373  * Retrieve widths of characters.
3374  *
3375  * PARAMS
3376  *  hdc    [I] Handle to a device context.
3377  *  first  [I] First glyph in range to query.
3378  *  count  [I] Number of glyph indices to query.
3379  *  glyphs [I] Array of glyphs to query.
3380  *  buffer [O] Buffer to receive character widths.
3381  *
3382  * NOTES
3383  *  Only works with TrueType fonts.
3384  *
3385  * RETURNS
3386  *  Success: TRUE
3387  *  Failure: FALSE
3388  */
3389 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3390 {
3391     ABC *abc;
3392     unsigned int i;
3393
3394     TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3395
3396     if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3397         return FALSE;
3398
3399     if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3400     {
3401         HeapFree(GetProcessHeap(), 0, abc);
3402         return FALSE;
3403     }
3404
3405     for (i = 0; i < count; i++)
3406         buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3407
3408     HeapFree(GetProcessHeap(), 0, abc);
3409     return TRUE;
3410 }
3411
3412 /***********************************************************************
3413  *           GetFontUnicodeRanges    (GDI32.@)
3414  *
3415  *  Retrieve a list of supported Unicode characters in a font.
3416  *
3417  *  PARAMS
3418  *   hdc  [I] Handle to a device context.
3419  *   lpgs [O] GLYPHSET structure specifying supported character ranges.
3420  *
3421  *  RETURNS
3422  *   Success: Number of bytes written to the buffer pointed to by lpgs.
3423  *   Failure: 0
3424  *
3425  */
3426 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3427 {
3428     DWORD ret = 0;
3429     DC *dc = DC_GetDCPtr(hdc);
3430
3431     TRACE("(%p, %p)\n", hdc, lpgs);
3432
3433     if (!dc) return 0;
3434
3435     if (dc->gdiFont) ret = WineEngGetFontUnicodeRanges(dc->gdiFont, lpgs);
3436     DC_ReleaseDCPtr(dc);
3437     return ret;
3438 }
3439
3440
3441 /*************************************************************
3442  *           FontIsLinked    (GDI32.@)
3443  */
3444 BOOL WINAPI FontIsLinked(HDC hdc)
3445 {
3446     DC *dc = DC_GetDCPtr(hdc);
3447     BOOL ret = FALSE;
3448
3449     if (!dc) return FALSE;
3450     if (dc->gdiFont) ret = WineEngFontIsLinked(dc->gdiFont);
3451     DC_ReleaseDCPtr(dc);
3452     TRACE("returning %d\n", ret);
3453     return ret;
3454 }