4 * Copyright 1993 Alexandre Julliard
6 * Copyright 2002,2003 Shachar Shemesh
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.
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.
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
24 #include "wine/port.h"
37 #include "gdi_private.h"
38 #include "wine/exception.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(font);
44 /* Device -> World size conversion */
46 /* Performs a device to world transformation on the specified width (which
47 * is in integer format).
49 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
53 /* Perform operation with floating point */
54 floatWidth = (double)width * dc->xformVport2World.eM11;
55 /* Round to integers */
56 return GDI_ROUND(floatWidth);
59 /* Performs a device to world transformation on the specified size (which
60 * is in integer format).
62 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
66 /* Perform operation with floating point */
67 floatHeight = (double)height * dc->xformVport2World.eM22;
68 /* Round to integers */
69 return GDI_ROUND(floatHeight);
72 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
75 pt[0].x = pt[0].y = 0;
78 LPtoDP(dc->hSelf, pt, 2);
79 return pt[1].x - pt[0].x;
82 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
85 pt[0].x = pt[0].y = 0;
88 LPtoDP(dc->hSelf, pt, 2);
89 return pt[1].y - pt[0].y;
92 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
93 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
94 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
95 static BOOL FONT_DeleteObject( HGDIOBJ handle );
97 static const struct gdi_obj_funcs font_funcs =
99 FONT_SelectObject, /* pSelectObject */
100 FONT_GetObjectA, /* pGetObjectA */
101 FONT_GetObjectW, /* pGetObjectW */
102 NULL, /* pUnrealizeObject */
103 FONT_DeleteObject /* pDeleteObject */
113 LPLOGFONTW lpLogFontParam;
114 FONTENUMPROCW lpEnumFunc;
122 * For TranslateCharsetInfo
124 #define MAXTCIINDEX 32
125 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
127 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
128 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
129 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
130 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
131 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
132 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
133 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
134 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
135 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
136 /* reserved by ANSI */
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
145 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
146 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
147 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
148 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
149 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
150 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
151 /* reserved for alternate ANSI and OEM */
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 /* reserved for system */
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
165 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
167 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
168 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
170 fontW->lfFaceName[LF_FACESIZE-1] = 0;
173 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
175 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
176 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
177 LF_FACESIZE, NULL, NULL);
178 fontA->lfFaceName[LF_FACESIZE-1] = 0;
181 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
183 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
185 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
186 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
187 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
188 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
189 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
190 fontA->elfStyle[LF_FACESIZE-1] = '\0';
191 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
192 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
193 fontA->elfScript[LF_FACESIZE-1] = '\0';
196 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
198 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
200 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
201 fontW->elfFullName, LF_FULLFACESIZE );
202 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
203 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
204 fontW->elfStyle, LF_FACESIZE );
205 fontW->elfStyle[LF_FACESIZE-1] = '\0';
206 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
207 fontW->elfScript, LF_FACESIZE );
208 fontW->elfScript[LF_FACESIZE-1] = '\0';
211 /***********************************************************************
212 * TEXTMETRIC conversion functions.
214 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
216 ptmA->tmHeight = ptmW->tmHeight;
217 ptmA->tmAscent = ptmW->tmAscent;
218 ptmA->tmDescent = ptmW->tmDescent;
219 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
220 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
221 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
222 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
223 ptmA->tmWeight = ptmW->tmWeight;
224 ptmA->tmOverhang = ptmW->tmOverhang;
225 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
226 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
227 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
228 if (ptmW->tmCharSet == SYMBOL_CHARSET)
230 ptmA->tmFirstChar = 0x1e;
231 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
233 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
235 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
236 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
240 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
241 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
243 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
244 ptmA->tmBreakChar = ptmW->tmBreakChar;
245 ptmA->tmItalic = ptmW->tmItalic;
246 ptmA->tmUnderlined = ptmW->tmUnderlined;
247 ptmA->tmStruckOut = ptmW->tmStruckOut;
248 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
249 ptmA->tmCharSet = ptmW->tmCharSet;
253 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
255 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
256 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
257 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
258 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
259 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
260 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
263 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
266 DWORD count = sizeof(buf), type, err;
268 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
271 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
272 else *value = atoiW( buf );
277 static UINT get_subpixel_orientation( HKEY key )
279 static const WCHAR smoothing_orientation[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
280 'O','r','i','e','n','t','a','t','i','o','n',0};
283 /* FIXME: handle vertical orientations even though Windows doesn't */
284 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
288 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
289 return WINE_GGO_HBGR_BITMAP;
290 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
291 return WINE_GGO_HRGB_BITMAP;
293 return GGO_GRAY4_BITMAP;
296 static UINT get_default_smoothing( HKEY key )
298 static const WCHAR smoothing[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
299 static const WCHAR smoothing_type[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
302 if (get_key_value( key, smoothing, &enabled )) return 0;
303 if (!enabled) return GGO_BITMAP;
305 if (!get_key_value( key, smoothing_type, &type ) && type == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
306 return get_subpixel_orientation( key );
308 return GGO_GRAY4_BITMAP;
312 /***********************************************************************
313 * GdiGetCodePage (GDI32.@)
315 DWORD WINAPI GdiGetCodePage( HDC hdc )
318 DC *dc = get_dc_ptr( hdc );
322 cp = dc->font_code_page;
323 release_dc_ptr( dc );
328 /***********************************************************************
331 * Returns a Unicode translation of str using the charset of the
332 * currently selected font in hdc. If count is -1 then str is assumed
333 * to be '\0' terminated, otherwise it contains the number of bytes to
334 * convert. If plenW is non-NULL, on return it will point to the
335 * number of WCHARs that have been written. If pCP is non-NULL, on
336 * return it will point to the codepage used in the conversion. The
337 * caller should free the returned LPWSTR from the process heap
340 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
346 cp = GdiGetCodePage( hdc );
348 if(count == -1) count = strlen(str);
349 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
350 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
351 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
352 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
353 if(plenW) *plenW = lenW;
358 /***********************************************************************
359 * CreateFontIndirectExA (GDI32.@)
361 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
363 ENUMLOGFONTEXDVW enumexW;
365 if (!penumexA) return 0;
367 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
368 enumexW.elfDesignVector = penumexA->elfDesignVector;
369 return CreateFontIndirectExW( &enumexW );
372 /***********************************************************************
373 * CreateFontIndirectExW (GDI32.@)
375 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
381 if (!penumex) return 0;
383 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
384 penumex->elfEnumLogfontEx.elfStyle[0] ||
385 penumex->elfEnumLogfontEx.elfScript[0])
387 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
388 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
389 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
390 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
393 plf = &penumex->elfEnumLogfontEx.elfLogFont;
394 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
396 fontPtr->logfont = *plf;
398 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
400 HeapFree( GetProcessHeap(), 0, fontPtr );
404 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
405 plf->lfHeight, plf->lfWidth,
406 plf->lfEscapement, plf->lfOrientation,
407 plf->lfPitchAndFamily,
408 plf->lfOutPrecision, plf->lfClipPrecision,
409 plf->lfQuality, plf->lfCharSet,
410 debugstr_w(plf->lfFaceName),
411 plf->lfWeight > 400 ? "Bold" : "",
412 plf->lfItalic ? "Italic" : "",
413 plf->lfUnderline ? "Underline" : "", hFont);
418 /***********************************************************************
419 * CreateFontIndirectA (GDI32.@)
421 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
427 FONT_LogFontAToW( plfA, &lfW );
428 return CreateFontIndirectW( &lfW );
431 /***********************************************************************
432 * CreateFontIndirectW (GDI32.@)
434 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
436 ENUMLOGFONTEXDVW exdv;
440 exdv.elfEnumLogfontEx.elfLogFont = *plf;
441 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
442 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
443 exdv.elfEnumLogfontEx.elfScript[0] = 0;
444 return CreateFontIndirectExW( &exdv );
447 /*************************************************************************
448 * CreateFontA (GDI32.@)
450 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
451 INT orient, INT weight, DWORD italic,
452 DWORD underline, DWORD strikeout, DWORD charset,
453 DWORD outpres, DWORD clippres, DWORD quality,
454 DWORD pitch, LPCSTR name )
458 logfont.lfHeight = height;
459 logfont.lfWidth = width;
460 logfont.lfEscapement = esc;
461 logfont.lfOrientation = orient;
462 logfont.lfWeight = weight;
463 logfont.lfItalic = italic;
464 logfont.lfUnderline = underline;
465 logfont.lfStrikeOut = strikeout;
466 logfont.lfCharSet = charset;
467 logfont.lfOutPrecision = outpres;
468 logfont.lfClipPrecision = clippres;
469 logfont.lfQuality = quality;
470 logfont.lfPitchAndFamily = pitch;
473 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
475 logfont.lfFaceName[0] = '\0';
477 return CreateFontIndirectA( &logfont );
480 /*************************************************************************
481 * CreateFontW (GDI32.@)
483 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
484 INT orient, INT weight, DWORD italic,
485 DWORD underline, DWORD strikeout, DWORD charset,
486 DWORD outpres, DWORD clippres, DWORD quality,
487 DWORD pitch, LPCWSTR name )
491 logfont.lfHeight = height;
492 logfont.lfWidth = width;
493 logfont.lfEscapement = esc;
494 logfont.lfOrientation = orient;
495 logfont.lfWeight = weight;
496 logfont.lfItalic = italic;
497 logfont.lfUnderline = underline;
498 logfont.lfStrikeOut = strikeout;
499 logfont.lfCharSet = charset;
500 logfont.lfOutPrecision = outpres;
501 logfont.lfClipPrecision = clippres;
502 logfont.lfQuality = quality;
503 logfont.lfPitchAndFamily = pitch;
506 lstrcpynW(logfont.lfFaceName, name,
507 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
509 logfont.lfFaceName[0] = '\0';
511 return CreateFontIndirectW( &logfont );
514 static void update_font_code_page( DC *dc )
517 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
519 /* Hmm, nicely designed api this one! */
520 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
521 dc->font_code_page = csi.ciACP;
525 dc->font_code_page = GetOEMCP();
527 case DEFAULT_CHARSET:
528 dc->font_code_page = GetACP();
538 /* FIXME: These have no place here, but because x11drv
539 enumerates fonts with these (made up) charsets some apps
540 might use them and then the FIXME below would become
541 annoying. Now we could pick the intended codepage for
542 each of these, but since it's broken anyway we'll just
543 use CP_ACP and hope it'll go away...
545 dc->font_code_page = CP_ACP;
549 FIXME("Can't find codepage for charset %d\n", charset);
550 dc->font_code_page = CP_ACP;
555 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
558 /***********************************************************************
561 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
564 DC *dc = get_dc_ptr( hdc );
570 if (!GDI_inc_ref_count( handle ))
572 release_dc_ptr( dc );
576 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
577 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
581 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
582 update_font_code_page( dc );
583 GDI_dec_ref_count( ret );
585 else GDI_dec_ref_count( handle );
587 release_dc_ptr( dc );
592 /***********************************************************************
595 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
597 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
603 FONT_LogFontWToA( &font->logfont, &lfA );
604 if (count > sizeof(lfA)) count = sizeof(lfA);
605 memcpy( buffer, &lfA, count );
607 else count = sizeof(lfA);
608 GDI_ReleaseObj( handle );
612 /***********************************************************************
615 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
617 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
622 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
623 memcpy( buffer, &font->logfont, count );
625 else count = sizeof(LOGFONTW);
626 GDI_ReleaseObj( handle );
631 /***********************************************************************
634 static BOOL FONT_DeleteObject( HGDIOBJ handle )
638 if (!(obj = free_gdi_handle( handle ))) return FALSE;
639 return HeapFree( GetProcessHeap(), 0, obj );
643 /***********************************************************************
646 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
648 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
649 'D','e','s','k','t','o','p',0 };
653 if (*aa_flags) return 0;
655 GetObjectW( font, sizeof(lf), &lf );
656 switch (lf.lfQuality)
658 case NONANTIALIASED_QUALITY:
659 *aa_flags = GGO_BITMAP;
661 case ANTIALIASED_QUALITY:
662 *aa_flags = GGO_GRAY4_BITMAP;
664 case CLEARTYPE_QUALITY:
665 case CLEARTYPE_NATURAL_QUALITY:
666 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
667 *aa_flags = get_subpixel_orientation( key );
671 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
672 *aa_flags = get_default_smoothing( key );
680 /***********************************************************************
683 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
684 * We have to use other types because of the FONTENUMPROCW definition.
686 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
687 DWORD fType, LPARAM lp )
689 struct font_enum *pfe = (struct font_enum *)lp;
692 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
693 if ((!pfe->lpLogFontParam ||
694 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
695 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
696 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
698 /* convert font metrics */
699 ENUMLOGFONTEXA logfont;
700 NEWTEXTMETRICEXA tmA;
704 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
705 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
706 plf = (LOGFONTW *)&logfont.elfLogFont;
707 ptm = (TEXTMETRICW *)&tmA;
709 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
715 /***********************************************************************
716 * FONT_EnumFontFamiliesEx
718 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
719 LPARAM lParam, BOOL unicode )
722 DC *dc = get_dc_ptr( hDC );
727 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
729 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
730 fe.lpLogFontParam = plf;
731 fe.lpEnumFunc = efproc;
733 fe.unicode = unicode;
736 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
737 release_dc_ptr( dc );
739 return ret ? fe.retval : 0;
742 /***********************************************************************
743 * EnumFontFamiliesExW (GDI32.@)
745 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
746 FONTENUMPROCW efproc,
747 LPARAM lParam, DWORD dwFlags )
749 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
752 /***********************************************************************
753 * EnumFontFamiliesExA (GDI32.@)
755 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
756 FONTENUMPROCA efproc,
757 LPARAM lParam, DWORD dwFlags)
763 FONT_LogFontAToW( plf, &lfW );
768 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
771 /***********************************************************************
772 * EnumFontFamiliesA (GDI32.@)
774 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
775 FONTENUMPROCA efproc, LPARAM lpData )
781 if (!*lpFamily) return 1;
782 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
783 lf.lfCharSet = DEFAULT_CHARSET;
784 lf.lfPitchAndFamily = 0;
789 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
792 /***********************************************************************
793 * EnumFontFamiliesW (GDI32.@)
795 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
796 FONTENUMPROCW efproc, LPARAM lpData )
802 if (!*lpFamily) return 1;
803 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
804 lf.lfCharSet = DEFAULT_CHARSET;
805 lf.lfPitchAndFamily = 0;
810 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
813 /***********************************************************************
814 * EnumFontsA (GDI32.@)
816 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
819 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
822 /***********************************************************************
823 * EnumFontsW (GDI32.@)
825 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
828 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
832 /***********************************************************************
833 * GetTextCharacterExtra (GDI32.@)
835 INT WINAPI GetTextCharacterExtra( HDC hdc )
838 DC *dc = get_dc_ptr( hdc );
839 if (!dc) return 0x80000000;
841 release_dc_ptr( dc );
846 /***********************************************************************
847 * SetTextCharacterExtra (GDI32.@)
849 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
851 INT ret = 0x80000000;
852 DC * dc = get_dc_ptr( hdc );
856 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
857 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
858 if (extra != 0x80000000)
861 dc->charExtra = extra;
863 release_dc_ptr( dc );
869 /***********************************************************************
870 * SetTextJustification (GDI32.@)
872 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
876 DC * dc = get_dc_ptr( hdc );
878 if (!dc) return FALSE;
880 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
881 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
884 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
885 if (!extra) breaks = 0;
888 dc->breakExtra = extra / breaks;
889 dc->breakRem = extra - (breaks * dc->breakExtra);
897 release_dc_ptr( dc );
902 /***********************************************************************
903 * GetTextFaceA (GDI32.@)
905 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
907 INT res = GetTextFaceW(hdc, 0, NULL);
908 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
909 GetTextFaceW( hdc, res, nameW );
915 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
919 /* GetTextFaceA does NOT include the nul byte in the return count. */
926 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
927 HeapFree( GetProcessHeap(), 0, nameW );
931 /***********************************************************************
932 * GetTextFaceW (GDI32.@)
934 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
939 DC * dc = get_dc_ptr( hdc );
942 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
943 ret = dev->funcs->pGetTextFace( dev, count, name );
944 release_dc_ptr( dc );
949 /***********************************************************************
950 * GetTextExtentPoint32A (GDI32.@)
952 * See GetTextExtentPoint32W.
954 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
961 if (count < 0) return FALSE;
963 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
967 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
968 HeapFree( GetProcessHeap(), 0, p );
971 TRACE("(%p %s %d %p): returning %d x %d\n",
972 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
977 /***********************************************************************
978 * GetTextExtentPoint32W [GDI32.@]
980 * Computes width/height for a string.
982 * Computes width and height of the specified string.
988 BOOL WINAPI GetTextExtentPoint32W(
989 HDC hdc, /* [in] Handle of device context */
990 LPCWSTR str, /* [in] Address of text string */
991 INT count, /* [in] Number of characters in string */
992 LPSIZE size) /* [out] Address of structure for string size */
994 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
997 /***********************************************************************
998 * GetTextExtentExPointI [GDI32.@]
1000 * Computes width and height of the array of glyph indices.
1003 * hdc [I] Handle of device context.
1004 * indices [I] Glyph index array.
1005 * count [I] Number of glyphs in array.
1006 * max_ext [I] Maximum width in glyphs.
1007 * nfit [O] Maximum number of characters.
1008 * dxs [O] Partial string widths.
1009 * size [O] Returned string size.
1015 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1016 LPINT nfit, LPINT dxs, LPSIZE size )
1022 if (count < 0) return FALSE;
1024 dc = get_dc_ptr( hdc );
1025 if (!dc) return FALSE;
1027 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
1028 ret = dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, nfit, dxs, size );
1029 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1030 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1031 size->cx += count * dc->charExtra;
1032 release_dc_ptr( dc );
1034 TRACE("(%p %p %d %p): returning %d x %d\n",
1035 hdc, indices, count, size, size->cx, size->cy );
1039 /***********************************************************************
1040 * GetTextExtentPointI [GDI32.@]
1042 * Computes width and height of the array of glyph indices.
1045 * hdc [I] Handle of device context.
1046 * indices [I] Glyph index array.
1047 * count [I] Number of glyphs in array.
1048 * size [O] Returned string size.
1054 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1056 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1060 /***********************************************************************
1061 * GetTextExtentPointA (GDI32.@)
1063 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1066 TRACE("not bug compatible.\n");
1067 return GetTextExtentPoint32A( hdc, str, count, size );
1070 /***********************************************************************
1071 * GetTextExtentPointW (GDI32.@)
1073 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1076 TRACE("not bug compatible.\n");
1077 return GetTextExtentPoint32W( hdc, str, count, size );
1081 /***********************************************************************
1082 * GetTextExtentExPointA (GDI32.@)
1084 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1085 INT maxExt, LPINT lpnFit,
1086 LPINT alpDx, LPSIZE size )
1093 if (count < 0) return FALSE;
1097 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1098 if (!walpDx) return FALSE;
1101 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1102 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1105 INT n = lpnFit ? *lpnFit : wlen;
1107 for(i = 0, j = 0; i < n; i++, j++)
1109 alpDx[j] = walpDx[i];
1110 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1113 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1114 HeapFree( GetProcessHeap(), 0, p );
1115 HeapFree( GetProcessHeap(), 0, walpDx );
1120 /***********************************************************************
1121 * GetTextExtentExPointW (GDI32.@)
1123 * Return the size of the string as it would be if it was output properly by
1126 * This should include
1127 * - Intercharacter spacing
1128 * - justification spacing (not yet done)
1129 * - kerning? see below
1131 * Kerning. Since kerning would be carried out by the rendering code it should
1132 * be done by the driver. However they don't support it yet. Also I am not
1133 * yet persuaded that (certainly under Win95) any kerning is actually done.
1135 * str: According to MSDN this should be null-terminated. That is not true; a
1136 * null will not terminate it early.
1137 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1138 * than count. I have seen it be either the size of the full string or
1139 * 1 less than the size of the full string. I have not seen it bear any
1140 * resemblance to the portion that would fit.
1141 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1142 * trailing intercharacter spacing and any trailing justification.
1145 * Currently we do this by measuring each character etc. We should do it by
1146 * passing the request to the driver, perhaps by extending the
1147 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1148 * thinking about kerning issues and rounding issues in the justification.
1151 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1152 INT maxExt, LPINT lpnFit,
1153 LPINT alpDx, LPSIZE size )
1162 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1164 if (count < 0) return FALSE;
1166 dc = get_dc_ptr(hdc);
1167 if (!dc) return FALSE;
1169 GetTextMetricsW(hdc, &tm);
1171 /* If we need to calculate nFit, then we need the partial extents even if
1172 the user hasn't provided us with an array. */
1175 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1179 SetLastError(ERROR_OUTOFMEMORY);
1186 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
1187 ret = dev->funcs->pGetTextExtentExPoint(dev, str, count, 0, NULL, dxs, size);
1189 /* Perform device size to world size transformations. */
1192 INT extra = abs(INTERNAL_XWSTODS(dc, dc->charExtra)),
1193 breakExtra = dc->breakExtra,
1194 breakRem = dc->breakRem,
1199 for (i = 0; i < count; ++i)
1201 dxs[i] += (i+1) * extra;
1202 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1204 dxs[i] += breakExtra;
1211 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1212 if (dxs[i] <= maxExt)
1216 else if (count > 1 && (breakExtra || breakRem))
1218 for (i = 0; i < count; i++)
1220 if (str[i] == tm.tmBreakChar)
1222 size->cx += breakExtra;
1231 size->cx += count * extra;
1232 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1233 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1240 HeapFree(GetProcessHeap(), 0, dxs);
1242 release_dc_ptr( dc );
1244 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1248 /***********************************************************************
1249 * GetTextMetricsA (GDI32.@)
1251 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1255 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1256 FONT_TextMetricWToA( &tm32, metrics );
1260 /***********************************************************************
1261 * GetTextMetricsW (GDI32.@)
1263 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1267 DC * dc = get_dc_ptr( hdc );
1268 if (!dc) return FALSE;
1270 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1271 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1275 /* device layer returns values in device units
1276 * therefore we have to convert them to logical */
1278 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1279 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1281 #define WDPTOLP(x) ((x<0)? \
1282 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1283 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1284 #define HDPTOLP(y) ((y<0)? \
1285 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1286 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1288 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1289 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1290 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1291 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1292 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1293 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1294 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1295 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1299 TRACE("text metrics:\n"
1300 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1301 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1302 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1303 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1304 " PitchAndFamily = %02x\n"
1305 " --------------------\n"
1306 " InternalLeading = %i\n"
1310 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1311 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1312 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1313 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1314 metrics->tmPitchAndFamily,
1315 metrics->tmInternalLeading,
1318 metrics->tmHeight );
1320 release_dc_ptr( dc );
1325 /***********************************************************************
1326 * GetOutlineTextMetricsA (GDI32.@)
1327 * Gets metrics for TrueType fonts.
1330 * If the supplied buffer isn't big enough Windows partially fills it up to
1331 * its given length and returns that length.
1334 * Success: Non-zero or size of required buffer
1337 UINT WINAPI GetOutlineTextMetricsA(
1338 HDC hdc, /* [in] Handle of device context */
1339 UINT cbData, /* [in] Size of metric data array */
1340 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1342 char buf[512], *ptr;
1344 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1345 OUTLINETEXTMETRICA *output = lpOTM;
1348 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1350 if(ret > sizeof(buf))
1351 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1352 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1354 needed = sizeof(OUTLINETEXTMETRICA);
1355 if(lpOTMW->otmpFamilyName)
1356 needed += WideCharToMultiByte(CP_ACP, 0,
1357 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1358 NULL, 0, NULL, NULL);
1359 if(lpOTMW->otmpFaceName)
1360 needed += WideCharToMultiByte(CP_ACP, 0,
1361 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1362 NULL, 0, NULL, NULL);
1363 if(lpOTMW->otmpStyleName)
1364 needed += WideCharToMultiByte(CP_ACP, 0,
1365 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1366 NULL, 0, NULL, NULL);
1367 if(lpOTMW->otmpFullName)
1368 needed += WideCharToMultiByte(CP_ACP, 0,
1369 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1370 NULL, 0, NULL, NULL);
1377 TRACE("needed = %d\n", needed);
1379 /* Since the supplied buffer isn't big enough, we'll alloc one
1380 that is and memcpy the first cbData bytes into the lpOTM at
1382 output = HeapAlloc(GetProcessHeap(), 0, needed);
1384 ret = output->otmSize = min(needed, cbData);
1385 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1386 output->otmFiller = 0;
1387 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1388 output->otmfsSelection = lpOTMW->otmfsSelection;
1389 output->otmfsType = lpOTMW->otmfsType;
1390 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1391 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1392 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1393 output->otmEMSquare = lpOTMW->otmEMSquare;
1394 output->otmAscent = lpOTMW->otmAscent;
1395 output->otmDescent = lpOTMW->otmDescent;
1396 output->otmLineGap = lpOTMW->otmLineGap;
1397 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1398 output->otmsXHeight = lpOTMW->otmsXHeight;
1399 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1400 output->otmMacAscent = lpOTMW->otmMacAscent;
1401 output->otmMacDescent = lpOTMW->otmMacDescent;
1402 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1403 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1404 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1405 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1406 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1407 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1408 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1409 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1410 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1411 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1414 ptr = (char*)(output + 1);
1415 left = needed - sizeof(*output);
1417 if(lpOTMW->otmpFamilyName) {
1418 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1419 len = WideCharToMultiByte(CP_ACP, 0,
1420 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1421 ptr, left, NULL, NULL);
1425 output->otmpFamilyName = 0;
1427 if(lpOTMW->otmpFaceName) {
1428 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1429 len = WideCharToMultiByte(CP_ACP, 0,
1430 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1431 ptr, left, NULL, NULL);
1435 output->otmpFaceName = 0;
1437 if(lpOTMW->otmpStyleName) {
1438 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1439 len = WideCharToMultiByte(CP_ACP, 0,
1440 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1441 ptr, left, NULL, NULL);
1445 output->otmpStyleName = 0;
1447 if(lpOTMW->otmpFullName) {
1448 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1449 len = WideCharToMultiByte(CP_ACP, 0,
1450 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1451 ptr, left, NULL, NULL);
1454 output->otmpFullName = 0;
1458 if(output != lpOTM) {
1459 memcpy(lpOTM, output, cbData);
1460 HeapFree(GetProcessHeap(), 0, output);
1462 /* check if the string offsets really fit into the provided size */
1463 /* FIXME: should we check string length as well? */
1464 /* make sure that we don't read/write beyond the provided buffer */
1465 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1467 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1468 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1471 /* make sure that we don't read/write beyond the provided buffer */
1472 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1474 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1475 lpOTM->otmpFaceName = 0; /* doesn't fit */
1478 /* make sure that we don't read/write beyond the provided buffer */
1479 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1481 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1482 lpOTM->otmpStyleName = 0; /* doesn't fit */
1485 /* make sure that we don't read/write beyond the provided buffer */
1486 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1488 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1489 lpOTM->otmpFullName = 0; /* doesn't fit */
1494 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1495 HeapFree(GetProcessHeap(), 0, lpOTMW);
1501 /***********************************************************************
1502 * GetOutlineTextMetricsW [GDI32.@]
1504 UINT WINAPI GetOutlineTextMetricsW(
1505 HDC hdc, /* [in] Handle of device context */
1506 UINT cbData, /* [in] Size of metric data array */
1507 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1509 DC *dc = get_dc_ptr( hdc );
1510 OUTLINETEXTMETRICW *output = lpOTM;
1514 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1517 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1518 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1520 if (lpOTM && ret > cbData)
1522 output = HeapAlloc(GetProcessHeap(), 0, ret);
1523 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1528 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1529 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1531 #define WDPTOLP(x) ((x<0)? \
1532 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1533 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1534 #define HDPTOLP(y) ((y<0)? \
1535 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1536 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1538 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1539 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1540 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1541 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1542 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1543 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1544 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1545 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1546 output->otmAscent = HDPTOLP(output->otmAscent);
1547 output->otmDescent = HDPTOLP(output->otmDescent);
1548 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1549 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1550 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1551 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1552 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1553 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1554 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1555 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1556 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1557 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1558 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1559 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1560 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1561 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1562 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1563 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1564 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1565 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1566 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1567 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1568 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1569 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1574 memcpy(lpOTM, output, cbData);
1575 HeapFree(GetProcessHeap(), 0, output);
1583 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1585 INT i, count = lastChar - firstChar + 1;
1593 mbcp = GdiGetCodePage(hdc);
1601 if (lastChar > 0xffff)
1603 if ((firstChar ^ lastChar) > 0xff)
1607 if (lastChar > 0xff)
1613 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1617 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1621 str[i++] = (BYTE)(c >> 8);
1622 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1623 str[i] = 0x1f; /* FIXME: use default character */
1637 /***********************************************************************
1638 * GetCharWidthW (GDI32.@)
1639 * GetCharWidth32W (GDI32.@)
1641 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1647 DC * dc = get_dc_ptr( hdc );
1649 if (!dc) return FALSE;
1651 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1652 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1656 /* convert device units to logical */
1657 for( i = firstChar; i <= lastChar; i++, buffer++ )
1658 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1660 release_dc_ptr( dc );
1665 /***********************************************************************
1666 * GetCharWidthA (GDI32.@)
1667 * GetCharWidth32A (GDI32.@)
1669 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1677 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1681 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1683 for(i = 0; i < wlen; i++)
1685 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1693 HeapFree(GetProcessHeap(), 0, str);
1694 HeapFree(GetProcessHeap(), 0, wstr);
1700 /* helper for nulldrv_ExtTextOut */
1701 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1702 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1704 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1705 UINT indices[3] = {0, 0, 0x20};
1711 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1713 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1716 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1717 if (ret != GDI_ERROR) break;
1720 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1721 if (!image) return ERROR_SUCCESS;
1725 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1727 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1728 size = metrics->gmBlackBoxY * stride;
1730 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1731 image->is_copy = TRUE;
1732 image->free = free_heap_bits;
1734 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1735 if (ret == GDI_ERROR)
1737 HeapFree( GetProcessHeap(), 0, image->ptr );
1738 return ERROR_NOT_FOUND;
1740 return ERROR_SUCCESS;
1743 /* helper for nulldrv_ExtTextOut */
1744 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1745 LPCWSTR str, UINT count, const INT *dx )
1750 reset_bounds( &bounds );
1751 for (i = 0; i < count; i++)
1753 GLYPHMETRICS metrics;
1755 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1757 rect.left = x + metrics.gmptGlyphOrigin.x;
1758 rect.top = y - metrics.gmptGlyphOrigin.y;
1759 rect.right = rect.left + metrics.gmBlackBoxX;
1760 rect.bottom = rect.top + metrics.gmBlackBoxY;
1761 add_bounds_rect( &bounds, &rect );
1765 if (flags & ETO_PDY)
1768 y += dx[ i * 2 + 1];
1774 x += metrics.gmCellIncX;
1775 y += metrics.gmCellIncY;
1781 /* helper for nulldrv_ExtTextOut */
1782 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1783 const struct gdi_image_bits *image, const RECT *clip )
1785 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1786 UINT x, y, i, count, max_count;
1787 BYTE *ptr = image->ptr;
1788 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1790 RECT rect, clipped_rect;
1792 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1793 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1794 rect.right = rect.left + metrics->gmBlackBoxX;
1795 rect.bottom = rect.top + metrics->gmBlackBoxY;
1796 if (!clip) clipped_rect = rect;
1797 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1799 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1800 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1804 ptr += (clipped_rect.top - rect.top) * stride;
1805 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1807 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1809 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1810 pts[count].x = rect.left + x;
1811 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1812 pts[count + 1].x = rect.left + x;
1813 if (pts[count + 1].x > pts[count].x)
1815 pts[count].y = pts[count + 1].y = y;
1820 assert( count <= max_count );
1821 DPtoLP( hdc, pts, count );
1822 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1823 HeapFree( GetProcessHeap(), 0, pts );
1826 /***********************************************************************
1827 * nulldrv_ExtTextOut
1829 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1830 LPCWSTR str, UINT count, const INT *dx )
1832 DC *dc = get_nulldrv_dc( dev );
1838 if (flags & ETO_OPAQUE)
1841 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1845 orig = SelectObject( dev->hdc, brush );
1846 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1847 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1848 SelectObject( dev->hdc, orig );
1849 DeleteObject( brush );
1853 if (!count) return TRUE;
1855 if (dc->aa_flags != GGO_BITMAP)
1857 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1858 BITMAPINFO *info = (BITMAPINFO *)buffer;
1859 struct gdi_image_bits bits;
1860 struct bitblt_coords src, dst;
1862 /* FIXME Subpixel modes */
1863 UINT aa_flags = GGO_GRAY4_BITMAP;
1865 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1866 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1867 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1868 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1870 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1871 src.x = src.visrect.left;
1872 src.y = src.visrect.top;
1873 src.width = src.visrect.right - src.visrect.left;
1874 src.height = src.visrect.bottom - src.visrect.top;
1876 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1877 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1879 /* we can avoid the GetImage, just query the needed format */
1880 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1881 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1882 info->bmiHeader.biWidth = src.width;
1883 info->bmiHeader.biHeight = -src.height;
1884 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1885 if (!err || err == ERROR_BAD_FORMAT)
1887 /* make the source rectangle relative to the source bits */
1889 src.visrect.left = src.visrect.top = 0;
1890 src.visrect.right = src.width;
1891 src.visrect.bottom = src.height;
1893 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1894 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1895 bits.is_copy = TRUE;
1896 bits.free = free_heap_bits;
1897 err = ERROR_SUCCESS;
1902 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1903 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1904 if (!err && !bits.is_copy)
1906 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1909 if (bits.free) bits.free( &bits );
1910 return ERROR_OUTOFMEMORY;
1912 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1913 if (bits.free) bits.free( &bits );
1915 bits.is_copy = TRUE;
1916 bits.free = free_heap_bits;
1921 /* make x,y relative to the image bits */
1922 x += src.visrect.left - dst.visrect.left;
1923 y += src.visrect.top - dst.visrect.top;
1924 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1925 aa_flags, str, count, dx );
1926 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
1927 if (bits.free) bits.free( &bits );
1932 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1933 orig = SelectObject( dev->hdc, pen );
1935 for (i = 0; i < count; i++)
1937 GLYPHMETRICS metrics;
1938 struct gdi_image_bits image;
1940 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
1943 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1944 if (image.free) image.free( &image );
1948 if (flags & ETO_PDY)
1951 y += dx[ i * 2 + 1];
1957 x += metrics.gmCellIncX;
1958 y += metrics.gmCellIncY;
1962 SelectObject( dev->hdc, orig );
1963 DeleteObject( pen );
1968 /***********************************************************************
1969 * ExtTextOutA (GDI32.@)
1973 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1974 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1982 if (flags & ETO_GLYPH_INDEX)
1983 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1985 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1988 unsigned int i = 0, j = 0;
1990 /* allocate enough for a ETO_PDY */
1991 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
1993 if(IsDBCSLeadByteEx(codepage, str[i]))
1997 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
1998 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2001 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2008 lpDxW[j++] = lpDx[i * 2];
2009 lpDxW[j++] = lpDx[i * 2 + 1];
2012 lpDxW[j++] = lpDx[i];
2018 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2020 HeapFree( GetProcessHeap(), 0, p );
2021 HeapFree( GetProcessHeap(), 0, lpDxW );
2026 /***********************************************************************
2027 * ExtTextOutW (GDI32.@)
2029 * Draws text using the currently selected font, background color, and text color.
2033 * x,y [I] coordinates of string
2035 * ETO_GRAYED - undocumented on MSDN
2036 * ETO_OPAQUE - use background color for fill the rectangle
2037 * ETO_CLIPPED - clipping text to the rectangle
2038 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2039 * than encoded characters. Implies ETO_IGNORELANGUAGE
2040 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2041 * Affects BiDi ordering
2042 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2043 * ETO_PDY - unimplemented
2044 * ETO_NUMERICSLATIN - unimplemented always assumed -
2045 * do not translate numbers into locale representations
2046 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2047 * lprect [I] dimensions for clipping or/and opaquing
2048 * str [I] text string
2049 * count [I] number of symbols in string
2050 * lpDx [I] optional parameter with distance between drawing characters
2056 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2057 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2060 LPWSTR reordered_str = (LPWSTR)str;
2061 WORD *glyphs = NULL;
2062 UINT align = GetTextAlign( hdc );
2063 DWORD layout = GetLayout( hdc );
2067 double cosEsc, sinEsc;
2071 BOOL done_extents = FALSE;
2072 POINT *deltas = NULL, width = {0, 0};
2074 DC * dc = get_dc_ptr( hdc );
2077 static int quietfixme = 0;
2079 if (!dc) return FALSE;
2081 breakRem = dc->breakRem;
2083 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2085 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2090 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2091 type = GetObjectType(hdc);
2092 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2094 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2095 release_dc_ptr( dc );
2100 flags &= ~ETO_CLIPPED;
2102 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2103 if (layout & LAYOUT_RTL)
2105 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2106 align ^= TA_RTLREADING;
2109 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2112 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2114 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2115 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2116 reordered_str, count, NULL, &glyphs, &cGlyphs);
2118 flags |= ETO_IGNORELANGUAGE;
2121 flags |= ETO_GLYPH_INDEX;
2122 if (cGlyphs != count)
2126 else if(flags & ETO_GLYPH_INDEX)
2127 glyphs = reordered_str;
2129 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2130 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2131 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2133 if(align & TA_UPDATECP)
2135 GetCurrentPositionEx( hdc, &pt );
2140 GetTextMetricsW(hdc, &tm);
2141 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2143 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2144 lf.lfEscapement = 0;
2146 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2147 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2149 lf.lfEscapement = -lf.lfEscapement;
2152 if(lf.lfEscapement != 0)
2154 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2155 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2163 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
2167 if(flags & ETO_GLYPH_INDEX)
2168 GetTextExtentPointI(hdc, glyphs, count, &sz);
2170 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2172 done_extents = TRUE;
2175 rc.right = x + sz.cx;
2176 rc.bottom = y + sz.cy;
2183 LPtoDP(hdc, (POINT*)&rc, 2);
2185 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
2186 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
2189 if (lprect && (flags & ETO_OPAQUE))
2190 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2200 LPtoDP(hdc, &pt, 1);
2204 char_extra = GetTextCharacterExtra(hdc);
2205 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2209 POINT total = {0, 0}, desired[2];
2211 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2212 for(i = 0; i < count; i++)
2218 deltas[i].x = lpDx[i * 2] + char_extra;
2219 deltas[i].y = -lpDx[i * 2 + 1];
2223 deltas[i].x = lpDx[i] + char_extra;
2230 if(flags & ETO_GLYPH_INDEX)
2231 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2233 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2235 deltas[i].x = tmpsz.cx;
2239 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2241 deltas[i].x = deltas[i].x + dc->breakExtra;
2248 total.x += deltas[i].x;
2249 total.y += deltas[i].y;
2251 desired[0].x = desired[0].y = 0;
2253 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2254 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2256 LPtoDP(hdc, desired, 2);
2257 desired[1].x -= desired[0].x;
2258 desired[1].y -= desired[0].y;
2260 if (dc->GraphicsMode == GM_COMPATIBLE)
2262 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2263 desired[1].x = -desired[1].x;
2264 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2265 desired[1].y = -desired[1].y;
2268 deltas[i].x = desired[1].x - width.x;
2269 deltas[i].y = desired[1].y - width.y;
2281 if(flags & ETO_GLYPH_INDEX)
2282 GetTextExtentPointI(hdc, glyphs, count, &sz);
2284 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2285 done_extents = TRUE;
2287 desired[0].x = desired[0].y = 0;
2288 desired[1].x = sz.cx;
2290 LPtoDP(hdc, desired, 2);
2291 desired[1].x -= desired[0].x;
2292 desired[1].y -= desired[0].y;
2294 if (dc->GraphicsMode == GM_COMPATIBLE)
2296 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2297 desired[1].x = -desired[1].x;
2298 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2299 desired[1].y = -desired[1].y;
2304 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2305 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2306 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2309 if (align & TA_UPDATECP)
2313 DPtoLP(hdc, &pt, 1);
2314 MoveToEx(hdc, pt.x, pt.y, NULL);
2326 if (align & TA_UPDATECP)
2330 DPtoLP(hdc, &pt, 1);
2331 MoveToEx(hdc, pt.x, pt.y, NULL);
2336 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2339 y += tm.tmAscent * cosEsc;
2340 x += tm.tmAscent * sinEsc;
2344 y -= tm.tmDescent * cosEsc;
2345 x -= tm.tmDescent * sinEsc;
2352 if (GetBkMode(hdc) != TRANSPARENT)
2354 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2356 if(!(flags & ETO_OPAQUE) || !lprect ||
2357 x < rc.left || x + width.x >= rc.right ||
2358 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2362 text_box.right = x + width.x;
2363 text_box.top = y - tm.tmAscent;
2364 text_box.bottom = y + tm.tmDescent;
2366 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2367 if (!is_rect_empty( &text_box ))
2368 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2373 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2374 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2377 HeapFree(GetProcessHeap(), 0, deltas);
2378 if(glyphs != reordered_str)
2379 HeapFree(GetProcessHeap(), 0, glyphs);
2380 if(reordered_str != str)
2381 HeapFree(GetProcessHeap(), 0, reordered_str);
2383 release_dc_ptr( dc );
2385 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2387 int underlinePos, strikeoutPos;
2388 int underlineWidth, strikeoutWidth;
2389 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2390 OUTLINETEXTMETRICW* otm = NULL;
2392 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2393 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2395 hbrush = SelectObject(hdc, hbrush);
2400 underlineWidth = tm.tmAscent / 20 + 1;
2401 strikeoutPos = tm.tmAscent / 2;
2402 strikeoutWidth = underlineWidth;
2406 otm = HeapAlloc(GetProcessHeap(), 0, size);
2407 GetOutlineTextMetricsW(hdc, size, otm);
2408 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2409 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2410 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2411 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2412 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2413 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2414 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2415 HeapFree(GetProcessHeap(), 0, otm);
2421 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2422 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2423 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2424 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2425 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2426 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2427 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2428 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2429 pts[4].x = pts[0].x;
2430 pts[4].y = pts[0].y;
2431 DPtoLP(hdc, pts, 5);
2432 Polygon(hdc, pts, 5);
2437 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2438 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2439 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2440 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2441 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2442 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2443 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2444 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2445 pts[4].x = pts[0].x;
2446 pts[4].y = pts[0].y;
2447 DPtoLP(hdc, pts, 5);
2448 Polygon(hdc, pts, 5);
2451 SelectObject(hdc, hpen);
2452 hbrush = SelectObject(hdc, hbrush);
2453 DeleteObject(hbrush);
2460 /***********************************************************************
2461 * TextOutA (GDI32.@)
2463 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2465 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2469 /***********************************************************************
2470 * TextOutW (GDI32.@)
2472 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2474 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2478 /***********************************************************************
2479 * PolyTextOutA (GDI32.@)
2483 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2485 for (; cStrings>0; cStrings--, pptxt++)
2486 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2493 /***********************************************************************
2494 * PolyTextOutW (GDI32.@)
2496 * Draw several Strings
2502 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2504 for (; cStrings>0; cStrings--, pptxt++)
2505 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2511 /***********************************************************************
2512 * SetMapperFlags (GDI32.@)
2514 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2516 DC *dc = get_dc_ptr( hdc );
2517 DWORD ret = GDI_ERROR;
2521 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2522 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2523 if (flags != GDI_ERROR)
2525 ret = dc->mapperFlags;
2526 dc->mapperFlags = flags;
2528 release_dc_ptr( dc );
2533 /***********************************************************************
2534 * GetAspectRatioFilterEx (GDI32.@)
2536 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2538 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2543 /***********************************************************************
2544 * GetCharABCWidthsA (GDI32.@)
2546 * See GetCharABCWidthsW.
2548 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2556 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2560 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2563 HeapFree(GetProcessHeap(), 0, str);
2567 for(i = 0; i < wlen; i++)
2569 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2577 HeapFree(GetProcessHeap(), 0, str);
2578 HeapFree(GetProcessHeap(), 0, wstr);
2584 /******************************************************************************
2585 * GetCharABCWidthsW [GDI32.@]
2587 * Retrieves widths of characters in range.
2590 * hdc [I] Handle of device context
2591 * firstChar [I] First character in range to query
2592 * lastChar [I] Last character in range to query
2593 * abc [O] Address of character-width structure
2596 * Only works with TrueType fonts
2602 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2605 DC *dc = get_dc_ptr(hdc);
2611 if (!dc) return FALSE;
2615 release_dc_ptr( dc );
2619 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2620 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2621 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2623 release_dc_ptr( dc );
2627 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2628 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2631 /* convert device units to logical */
2632 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2633 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2634 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2635 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2639 release_dc_ptr( dc );
2644 /******************************************************************************
2645 * GetCharABCWidthsI [GDI32.@]
2647 * Retrieves widths of characters in range.
2650 * hdc [I] Handle of device context
2651 * firstChar [I] First glyphs in range to query
2652 * count [I] Last glyphs in range to query
2653 * pgi [i] Array of glyphs to query
2654 * abc [O] Address of character-width structure
2657 * Only works with TrueType fonts
2663 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2664 LPWORD pgi, LPABC abc)
2666 DC *dc = get_dc_ptr(hdc);
2671 if (!dc) return FALSE;
2675 release_dc_ptr( dc );
2679 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2680 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2683 /* convert device units to logical */
2684 for( i = 0; i < count; i++, abc++ ) {
2685 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2686 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2687 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2691 release_dc_ptr( dc );
2696 /***********************************************************************
2697 * GetGlyphOutlineA (GDI32.@)
2699 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2700 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2701 LPVOID lpBuffer, const MAT2 *lpmat2 )
2703 if (!lpmat2) return GDI_ERROR;
2705 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2710 cp = GdiGetCodePage(hdc);
2711 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2713 mbchs[0] = (uChar & 0xff00) >> 8;
2714 mbchs[1] = (uChar & 0xff);
2717 mbchs[0] = (uChar & 0xff);
2720 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2723 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2727 /***********************************************************************
2728 * GetGlyphOutlineW (GDI32.@)
2730 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2731 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2732 LPVOID lpBuffer, const MAT2 *lpmat2 )
2738 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2739 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2741 if (!lpmat2) return GDI_ERROR;
2743 dc = get_dc_ptr(hdc);
2744 if(!dc) return GDI_ERROR;
2746 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2747 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2748 release_dc_ptr( dc );
2753 /***********************************************************************
2754 * CreateScalableFontResourceA (GDI32.@)
2756 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2757 LPCSTR lpszResourceFile,
2758 LPCSTR lpszFontFile,
2759 LPCSTR lpszCurrentPath )
2761 LPWSTR lpszResourceFileW = NULL;
2762 LPWSTR lpszFontFileW = NULL;
2763 LPWSTR lpszCurrentPathW = NULL;
2767 if (lpszResourceFile)
2769 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2770 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2771 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2776 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2777 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2778 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2781 if (lpszCurrentPath)
2783 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2784 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2785 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2788 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2789 lpszFontFileW, lpszCurrentPathW);
2791 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2792 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2793 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2798 /***********************************************************************
2799 * CreateScalableFontResourceW (GDI32.@)
2801 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2802 LPCWSTR font_file, LPCWSTR font_path )
2804 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2805 debugstr_w(font_file), debugstr_w(font_path) );
2807 return WineEngCreateScalableFontResource( hidden, resource_file,
2808 font_file, font_path );
2811 /*************************************************************************
2812 * GetKerningPairsA (GDI32.@)
2814 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2815 LPKERNINGPAIR kern_pairA )
2819 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2820 KERNINGPAIR *kern_pairW;
2822 if (!cPairs && kern_pairA)
2824 SetLastError(ERROR_INVALID_PARAMETER);
2828 cp = GdiGetCodePage(hDC);
2830 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2831 * to fail on an invalid character for CP_SYMBOL.
2833 cpi.DefaultChar[0] = 0;
2834 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2836 FIXME("Can't find codepage %u info\n", cp);
2840 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2841 if (!total_kern_pairs) return 0;
2843 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2844 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2846 for (i = 0; i < total_kern_pairs; i++)
2850 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2853 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2856 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2861 if (kern_pairs_copied >= cPairs) break;
2863 kern_pairA->wFirst = (BYTE)first;
2864 kern_pairA->wSecond = (BYTE)second;
2865 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2868 kern_pairs_copied++;
2871 HeapFree(GetProcessHeap(), 0, kern_pairW);
2873 return kern_pairs_copied;
2876 /*************************************************************************
2877 * GetKerningPairsW (GDI32.@)
2879 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2880 LPKERNINGPAIR lpKerningPairs )
2886 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2888 if (!cPairs && lpKerningPairs)
2890 SetLastError(ERROR_INVALID_PARAMETER);
2894 dc = get_dc_ptr(hDC);
2897 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2898 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2899 release_dc_ptr( dc );
2903 /*************************************************************************
2904 * TranslateCharsetInfo [GDI32.@]
2906 * Fills a CHARSETINFO structure for a character set, code page, or
2907 * font. This allows making the correspondence between different labels
2908 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2909 * of the same encoding.
2911 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2912 * only one codepage should be set in *lpSrc.
2915 * TRUE on success, FALSE on failure.
2918 BOOL WINAPI TranslateCharsetInfo(
2919 LPDWORD lpSrc, /* [in]
2920 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2921 if flags == TCI_SRCCHARSET: a character set value
2922 if flags == TCI_SRCCODEPAGE: a code page value
2924 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2925 DWORD flags /* [in] determines interpretation of lpSrc */)
2929 case TCI_SRCFONTSIG:
2930 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2932 case TCI_SRCCODEPAGE:
2933 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2935 case TCI_SRCCHARSET:
2936 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2941 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2942 *lpCs = FONT_tci[index];
2946 /*************************************************************************
2947 * GetFontLanguageInfo (GDI32.@)
2949 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2951 FONTSIGNATURE fontsig;
2952 static const DWORD GCP_DBCS_MASK=0x003F0000,
2953 GCP_DIACRITIC_MASK=0x00000000,
2954 FLI_GLYPHS_MASK=0x00000000,
2955 GCP_GLYPHSHAPE_MASK=0x00000040,
2956 GCP_KASHIDA_MASK=0x00000000,
2957 GCP_LIGATE_MASK=0x00000000,
2958 GCP_USEKERNING_MASK=0x00000000,
2959 GCP_REORDER_MASK=0x00000060;
2963 GetTextCharsetInfo( hdc, &fontsig, 0 );
2964 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2966 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2969 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2970 result|=GCP_DIACRITIC;
2972 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2975 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2976 result|=GCP_GLYPHSHAPE;
2978 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2979 result|=GCP_KASHIDA;
2981 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2984 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2985 result|=GCP_USEKERNING;
2987 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2988 if( GetTextAlign( hdc) & TA_RTLREADING )
2989 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2990 result|=GCP_REORDER;
2996 /*************************************************************************
2997 * GetFontData [GDI32.@]
2999 * Retrieve data for TrueType font.
3003 * success: Number of bytes returned
3004 * failure: GDI_ERROR
3008 * Calls SetLastError()
3011 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3012 LPVOID buffer, DWORD length)
3014 DC *dc = get_dc_ptr(hdc);
3018 if(!dc) return GDI_ERROR;
3020 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3021 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3022 release_dc_ptr( dc );
3026 /*************************************************************************
3027 * GetGlyphIndicesA [GDI32.@]
3029 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3030 LPWORD pgi, DWORD flags)
3036 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3037 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3039 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3040 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3041 HeapFree(GetProcessHeap(), 0, lpstrW);
3046 /*************************************************************************
3047 * GetGlyphIndicesW [GDI32.@]
3049 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3050 LPWORD pgi, DWORD flags)
3052 DC *dc = get_dc_ptr(hdc);
3056 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3057 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3059 if(!dc) return GDI_ERROR;
3061 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3062 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3063 release_dc_ptr( dc );
3067 /*************************************************************************
3068 * GetCharacterPlacementA [GDI32.@]
3070 * See GetCharacterPlacementW.
3073 * the web browser control of ie4 calls this with dwFlags=0
3076 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3077 INT nMaxExtent, GCP_RESULTSA *lpResults,
3082 GCP_RESULTSW resultsW;
3086 TRACE("%s, %d, %d, 0x%08x\n",
3087 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3089 /* both structs are equal in size */
3090 memcpy(&resultsW, lpResults, sizeof(resultsW));
3092 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3093 if(lpResults->lpOutString)
3094 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3096 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3098 lpResults->nGlyphs = resultsW.nGlyphs;
3099 lpResults->nMaxFit = resultsW.nMaxFit;
3101 if(lpResults->lpOutString) {
3102 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3103 lpResults->lpOutString, uCount, NULL, NULL );
3106 HeapFree(GetProcessHeap(), 0, lpStringW);
3107 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3112 /*************************************************************************
3113 * GetCharacterPlacementW [GDI32.@]
3115 * Retrieve information about a string. This includes the width, reordering,
3116 * Glyphing and so on.
3120 * The width and height of the string if successful, 0 if failed.
3124 * All flags except GCP_REORDER are not yet implemented.
3125 * Reordering is not 100% compliant to the Windows BiDi method.
3126 * Caret positioning is not yet implemented for BiDi.
3127 * Classes are not yet implemented.
3131 GetCharacterPlacementW(
3132 HDC hdc, /* [in] Device context for which the rendering is to be done */
3133 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3134 INT uCount, /* [in] Number of WORDS in string. */
3135 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3136 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
3137 DWORD dwFlags /* [in] Flags specifying how to process the string */
3144 TRACE("%s, %d, %d, 0x%08x\n",
3145 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3147 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3148 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3149 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3150 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3151 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3153 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
3154 if(lpResults->lpClass) FIXME("classes not implemented\n");
3155 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3156 FIXME("Caret positions for complex scripts not implemented\n");
3158 nSet = (UINT)uCount;
3159 if(nSet > lpResults->nGlyphs)
3160 nSet = lpResults->nGlyphs;
3162 /* return number of initialized fields */
3163 lpResults->nGlyphs = nSet;
3165 if((dwFlags&GCP_REORDER)==0 )
3167 /* Treat the case where no special handling was requested in a fastpath way */
3168 /* copy will do if the GCP_REORDER flag is not set */
3169 if(lpResults->lpOutString)
3170 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3172 if(lpResults->lpOrder)
3174 for(i = 0; i < nSet; i++)
3175 lpResults->lpOrder[i] = i;
3179 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3180 nSet, lpResults->lpOrder, NULL, NULL );
3183 /* FIXME: Will use the placement chars */
3184 if (lpResults->lpDx)
3187 for (i = 0; i < nSet; i++)
3189 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3190 lpResults->lpDx[i]= c;
3194 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3198 lpResults->lpCaretPos[0] = 0;
3199 for (i = 1; i < nSet; i++)
3200 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3201 lpResults->lpCaretPos[i] = (pos += size.cx);
3204 if(lpResults->lpGlyphs)
3205 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3207 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3208 ret = MAKELONG(size.cx, size.cy);
3213 /*************************************************************************
3214 * GetCharABCWidthsFloatA [GDI32.@]
3216 * See GetCharABCWidthsFloatW.
3218 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3225 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3229 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3231 for (i = 0; i < wlen; i++)
3233 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3241 HeapFree( GetProcessHeap(), 0, str );
3242 HeapFree( GetProcessHeap(), 0, wstr );
3247 /*************************************************************************
3248 * GetCharABCWidthsFloatW [GDI32.@]
3250 * Retrieves widths of a range of characters.
3253 * hdc [I] Handle to device context.
3254 * first [I] First character in range to query.
3255 * last [I] Last character in range to query.
3256 * abcf [O] Array of LPABCFLOAT structures.
3262 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3268 DC *dc = get_dc_ptr( hdc );
3270 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3272 if (!dc) return FALSE;
3274 if (!abcf) goto done;
3275 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3277 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3278 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3281 /* convert device units to logical */
3282 for (i = first; i <= last; i++, abcf++)
3284 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3285 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3286 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3289 HeapFree( GetProcessHeap(), 0, abc );
3292 release_dc_ptr( dc );
3296 /*************************************************************************
3297 * GetCharWidthFloatA [GDI32.@]
3299 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3300 UINT iLastChar, PFLOAT pxBuffer)
3302 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3306 /*************************************************************************
3307 * GetCharWidthFloatW [GDI32.@]
3309 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3310 UINT iLastChar, PFLOAT pxBuffer)
3312 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3317 /***********************************************************************
3319 * Font Resource API *
3321 ***********************************************************************/
3323 /***********************************************************************
3324 * AddFontResourceA (GDI32.@)
3326 INT WINAPI AddFontResourceA( LPCSTR str )
3328 return AddFontResourceExA( str, 0, NULL);
3331 /***********************************************************************
3332 * AddFontResourceW (GDI32.@)
3334 INT WINAPI AddFontResourceW( LPCWSTR str )
3336 return AddFontResourceExW(str, 0, NULL);
3340 /***********************************************************************
3341 * AddFontResourceExA (GDI32.@)
3343 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3345 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3346 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3349 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3350 ret = AddFontResourceExW(strW, fl, pdv);
3351 HeapFree(GetProcessHeap(), 0, strW);
3355 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3357 HRSRC rsrc = FindResourceW(hModule, name, type);
3358 HGLOBAL hMem = LoadResource(hModule, rsrc);
3359 LPVOID *pMem = LockResource(hMem);
3360 int *num_total = (int *)lParam;
3363 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3364 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3366 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3370 *num_total += num_in_res;
3374 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3376 HANDLE file, mapping;
3379 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3380 if (file == INVALID_HANDLE_VALUE) return NULL;
3382 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3384 CloseHandle( file );
3388 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3389 CloseHandle( file );
3390 if (!mapping) return NULL;
3392 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3393 CloseHandle( mapping );
3398 static WCHAR *get_scalable_filename( const WCHAR *res )
3401 BYTE *ptr = map_file( res, &size );
3402 const IMAGE_DOS_HEADER *dos;
3403 const IMAGE_OS2_HEADER *ne;
3405 WORD rsrc_off, align, type_id, count;
3406 DWORD res_off, res_len, i;
3409 if (!ptr) return NULL;
3411 if (size.u.LowPart < sizeof( *dos )) goto fail;
3412 dos = (const IMAGE_DOS_HEADER *)ptr;
3413 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3414 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3415 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3416 rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
3417 if (size.u.LowPart < rsrc_off + 10) goto fail;
3418 align = *(WORD *)(ptr + rsrc_off);
3420 type_id = *(WORD *)(ptr + rsrc_off);
3421 while (type_id && type_id != 0x80cc)
3423 count = *(WORD *)(ptr + rsrc_off + 2);
3424 rsrc_off += 8 + count * 12;
3425 if (size.u.LowPart < rsrc_off + 8) goto fail;
3426 type_id = *(WORD *)(ptr + rsrc_off);
3428 if (!type_id) goto fail;
3429 count = *(WORD *)(ptr + rsrc_off + 2);
3430 if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;
3432 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3433 res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
3434 if (size.u.LowPart < res_off + res_len) goto fail;
3436 for (i = 0; i < res_len; i++)
3437 if (ptr[ res_off + i ] == 0) break;
3438 if (i == res_len) goto fail;
3440 len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
3441 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3442 if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );
3445 UnmapViewOfFile( ptr );
3449 /***********************************************************************
3450 * AddFontResourceExW (GDI32.@)
3452 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3454 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3459 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3460 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3461 if (hModule != NULL)
3463 int num_resources = 0;
3464 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3466 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3467 wine_dbgstr_w(str));
3468 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3469 ret = num_resources;
3470 FreeLibrary(hModule);
3472 else if ((filename = get_scalable_filename( str )) != NULL)
3474 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3475 HeapFree( GetProcessHeap(), 0, filename );
3481 /***********************************************************************
3482 * RemoveFontResourceA (GDI32.@)
3484 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3486 return RemoveFontResourceExA(str, 0, 0);
3489 /***********************************************************************
3490 * RemoveFontResourceW (GDI32.@)
3492 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3494 return RemoveFontResourceExW(str, 0, 0);
3497 /***********************************************************************
3498 * AddFontMemResourceEx (GDI32.@)
3500 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3505 if (!pbFont || !cbFont || !pcFonts)
3507 SetLastError(ERROR_INVALID_PARAMETER);
3511 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3516 *pcFonts = num_fonts;
3520 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3521 RemoveFontMemResourceEx(ret);
3529 /***********************************************************************
3530 * RemoveFontMemResourceEx (GDI32.@)
3532 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3534 FIXME("(%p) stub\n", fh);
3538 /***********************************************************************
3539 * RemoveFontResourceExA (GDI32.@)
3541 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3543 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3544 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3547 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3548 ret = RemoveFontResourceExW(strW, fl, pdv);
3549 HeapFree(GetProcessHeap(), 0, strW);
3553 /***********************************************************************
3554 * RemoveFontResourceExW (GDI32.@)
3556 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3558 return WineEngRemoveFontResourceEx(str, fl, pdv);
3561 /***********************************************************************
3562 * GetTextCharset (GDI32.@)
3564 UINT WINAPI GetTextCharset(HDC hdc)
3566 /* MSDN docs say this is equivalent */
3567 return GetTextCharsetInfo(hdc, NULL, 0);
3570 /***********************************************************************
3571 * GetTextCharsetInfo (GDI32.@)
3573 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3575 UINT ret = DEFAULT_CHARSET;
3576 DC *dc = get_dc_ptr(hdc);
3581 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3582 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3583 release_dc_ptr( dc );
3586 if (ret == DEFAULT_CHARSET && fs)
3587 memset(fs, 0, sizeof(FONTSIGNATURE));
3591 /***********************************************************************
3592 * GdiGetCharDimensions (GDI32.@)
3594 * Gets the average width of the characters in the English alphabet.
3597 * hdc [I] Handle to the device context to measure on.
3598 * lptm [O] Pointer to memory to store the text metrics into.
3599 * height [O] On exit, the maximum height of characters in the English alphabet.
3602 * The average width of characters in the English alphabet.
3605 * This function is used by the dialog manager to get the size of a dialog
3606 * unit. It should also be used by other pieces of code that need to know
3607 * the size of a dialog unit in logical units without having access to the
3608 * window handle of the dialog.
3609 * Windows caches the font metrics from this function, but we don't and
3610 * there doesn't appear to be an immediate advantage to do so.
3613 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3615 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3618 static const WCHAR alphabet[] = {
3619 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3620 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3621 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3623 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3625 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3627 if (height) *height = sz.cy;
3628 return (sz.cx / 26 + 1) / 2;
3631 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3633 FIXME("(%d): stub\n", fEnableEUDC);
3637 /***********************************************************************
3638 * GetCharWidthI (GDI32.@)
3640 * Retrieve widths of characters.
3643 * hdc [I] Handle to a device context.
3644 * first [I] First glyph in range to query.
3645 * count [I] Number of glyph indices to query.
3646 * glyphs [I] Array of glyphs to query.
3647 * buffer [O] Buffer to receive character widths.
3650 * Only works with TrueType fonts.
3656 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3661 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3663 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3666 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3668 HeapFree(GetProcessHeap(), 0, abc);
3672 for (i = 0; i < count; i++)
3673 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3675 HeapFree(GetProcessHeap(), 0, abc);
3679 /***********************************************************************
3680 * GetFontUnicodeRanges (GDI32.@)
3682 * Retrieve a list of supported Unicode characters in a font.
3685 * hdc [I] Handle to a device context.
3686 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3689 * Success: Number of bytes written to the buffer pointed to by lpgs.
3693 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3697 DC *dc = get_dc_ptr(hdc);
3699 TRACE("(%p, %p)\n", hdc, lpgs);
3703 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3704 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3710 /*************************************************************
3711 * FontIsLinked (GDI32.@)
3713 BOOL WINAPI FontIsLinked(HDC hdc)
3715 DC *dc = get_dc_ptr(hdc);
3719 if (!dc) return FALSE;
3720 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3721 ret = dev->funcs->pFontIsLinked( dev );
3723 TRACE("returning %d\n", ret);
3727 /*************************************************************
3728 * GdiRealizationInfo (GDI32.@)
3730 * Returns a structure that contains some font information.
3732 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3734 DC *dc = get_dc_ptr(hdc);
3738 if (!dc) return FALSE;
3739 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3740 ret = dev->funcs->pGdiRealizationInfo( dev, info );