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