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