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