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);
2187 if (lprect && (flags & ETO_OPAQUE))
2188 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2198 LPtoDP(hdc, &pt, 1);
2202 char_extra = GetTextCharacterExtra(hdc);
2203 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2207 POINT total = {0, 0}, desired[2];
2209 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2210 for(i = 0; i < count; i++)
2216 deltas[i].x = lpDx[i * 2] + char_extra;
2217 deltas[i].y = -lpDx[i * 2 + 1];
2221 deltas[i].x = lpDx[i] + char_extra;
2228 if(flags & ETO_GLYPH_INDEX)
2229 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2231 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2233 deltas[i].x = tmpsz.cx;
2237 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2239 deltas[i].x = deltas[i].x + dc->breakExtra;
2246 total.x += deltas[i].x;
2247 total.y += deltas[i].y;
2249 desired[0].x = desired[0].y = 0;
2251 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2252 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2254 LPtoDP(hdc, desired, 2);
2255 desired[1].x -= desired[0].x;
2256 desired[1].y -= desired[0].y;
2258 if (dc->GraphicsMode == GM_COMPATIBLE)
2260 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2261 desired[1].x = -desired[1].x;
2262 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2263 desired[1].y = -desired[1].y;
2266 deltas[i].x = desired[1].x - width.x;
2267 deltas[i].y = desired[1].y - width.y;
2279 if(flags & ETO_GLYPH_INDEX)
2280 GetTextExtentPointI(hdc, glyphs, count, &sz);
2282 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2283 done_extents = TRUE;
2285 desired[0].x = desired[0].y = 0;
2286 desired[1].x = sz.cx;
2288 LPtoDP(hdc, desired, 2);
2289 desired[1].x -= desired[0].x;
2290 desired[1].y -= desired[0].y;
2292 if (dc->GraphicsMode == GM_COMPATIBLE)
2294 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2295 desired[1].x = -desired[1].x;
2296 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2297 desired[1].y = -desired[1].y;
2302 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2303 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2304 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2307 if (align & TA_UPDATECP)
2311 DPtoLP(hdc, &pt, 1);
2312 MoveToEx(hdc, pt.x, pt.y, NULL);
2324 if (align & TA_UPDATECP)
2328 DPtoLP(hdc, &pt, 1);
2329 MoveToEx(hdc, pt.x, pt.y, NULL);
2334 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2337 y += tm.tmAscent * cosEsc;
2338 x += tm.tmAscent * sinEsc;
2342 y -= tm.tmDescent * cosEsc;
2343 x -= tm.tmDescent * sinEsc;
2350 if (GetBkMode(hdc) != TRANSPARENT)
2352 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2354 if(!(flags & ETO_OPAQUE) || !lprect ||
2355 x < rc.left || x + width.x >= rc.right ||
2356 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2360 text_box.right = x + width.x;
2361 text_box.top = y - tm.tmAscent;
2362 text_box.bottom = y + tm.tmDescent;
2364 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2365 if (!is_rect_empty( &text_box ))
2366 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2371 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2372 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2375 HeapFree(GetProcessHeap(), 0, deltas);
2376 if(glyphs != reordered_str)
2377 HeapFree(GetProcessHeap(), 0, glyphs);
2378 if(reordered_str != str)
2379 HeapFree(GetProcessHeap(), 0, reordered_str);
2381 release_dc_ptr( dc );
2383 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2385 int underlinePos, strikeoutPos;
2386 int underlineWidth, strikeoutWidth;
2387 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2388 OUTLINETEXTMETRICW* otm = NULL;
2390 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2391 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2393 hbrush = SelectObject(hdc, hbrush);
2398 underlineWidth = tm.tmAscent / 20 + 1;
2399 strikeoutPos = tm.tmAscent / 2;
2400 strikeoutWidth = underlineWidth;
2404 otm = HeapAlloc(GetProcessHeap(), 0, size);
2405 GetOutlineTextMetricsW(hdc, size, otm);
2406 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2407 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2408 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2409 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2410 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2411 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2412 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2413 HeapFree(GetProcessHeap(), 0, otm);
2419 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2420 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2421 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2422 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2423 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2424 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2425 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2426 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2427 pts[4].x = pts[0].x;
2428 pts[4].y = pts[0].y;
2429 DPtoLP(hdc, pts, 5);
2430 Polygon(hdc, pts, 5);
2435 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2436 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2437 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2438 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2439 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2440 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2441 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2442 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2443 pts[4].x = pts[0].x;
2444 pts[4].y = pts[0].y;
2445 DPtoLP(hdc, pts, 5);
2446 Polygon(hdc, pts, 5);
2449 SelectObject(hdc, hpen);
2450 hbrush = SelectObject(hdc, hbrush);
2451 DeleteObject(hbrush);
2458 /***********************************************************************
2459 * TextOutA (GDI32.@)
2461 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2463 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2467 /***********************************************************************
2468 * TextOutW (GDI32.@)
2470 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2472 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2476 /***********************************************************************
2477 * PolyTextOutA (GDI32.@)
2481 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2483 for (; cStrings>0; cStrings--, pptxt++)
2484 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2491 /***********************************************************************
2492 * PolyTextOutW (GDI32.@)
2494 * Draw several Strings
2500 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2502 for (; cStrings>0; cStrings--, pptxt++)
2503 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2509 /***********************************************************************
2510 * SetMapperFlags (GDI32.@)
2512 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2514 DC *dc = get_dc_ptr( hdc );
2515 DWORD ret = GDI_ERROR;
2519 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2520 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2521 if (flags != GDI_ERROR)
2523 ret = dc->mapperFlags;
2524 dc->mapperFlags = flags;
2526 release_dc_ptr( dc );
2531 /***********************************************************************
2532 * GetAspectRatioFilterEx (GDI32.@)
2534 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2536 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2541 /***********************************************************************
2542 * GetCharABCWidthsA (GDI32.@)
2544 * See GetCharABCWidthsW.
2546 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2554 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2558 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2561 HeapFree(GetProcessHeap(), 0, str);
2565 for(i = 0; i < wlen; i++)
2567 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2575 HeapFree(GetProcessHeap(), 0, str);
2576 HeapFree(GetProcessHeap(), 0, wstr);
2582 /******************************************************************************
2583 * GetCharABCWidthsW [GDI32.@]
2585 * Retrieves widths of characters in range.
2588 * hdc [I] Handle of device context
2589 * firstChar [I] First character in range to query
2590 * lastChar [I] Last character in range to query
2591 * abc [O] Address of character-width structure
2594 * Only works with TrueType fonts
2600 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2603 DC *dc = get_dc_ptr(hdc);
2609 if (!dc) return FALSE;
2613 release_dc_ptr( dc );
2617 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2618 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2619 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2621 release_dc_ptr( dc );
2625 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2626 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2629 /* convert device units to logical */
2630 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2631 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2632 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2633 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2637 release_dc_ptr( dc );
2642 /******************************************************************************
2643 * GetCharABCWidthsI [GDI32.@]
2645 * Retrieves widths of characters in range.
2648 * hdc [I] Handle of device context
2649 * firstChar [I] First glyphs in range to query
2650 * count [I] Last glyphs in range to query
2651 * pgi [i] Array of glyphs to query
2652 * abc [O] Address of character-width structure
2655 * Only works with TrueType fonts
2661 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2662 LPWORD pgi, LPABC abc)
2664 DC *dc = get_dc_ptr(hdc);
2669 if (!dc) return FALSE;
2673 release_dc_ptr( dc );
2677 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2678 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2681 /* convert device units to logical */
2682 for( i = 0; i < count; i++, abc++ ) {
2683 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2684 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2685 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2689 release_dc_ptr( dc );
2694 /***********************************************************************
2695 * GetGlyphOutlineA (GDI32.@)
2697 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2698 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2699 LPVOID lpBuffer, const MAT2 *lpmat2 )
2701 if (!lpmat2) return GDI_ERROR;
2703 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2708 cp = GdiGetCodePage(hdc);
2709 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2711 mbchs[0] = (uChar & 0xff00) >> 8;
2712 mbchs[1] = (uChar & 0xff);
2715 mbchs[0] = (uChar & 0xff);
2718 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2721 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2725 /***********************************************************************
2726 * GetGlyphOutlineW (GDI32.@)
2728 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2729 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2730 LPVOID lpBuffer, const MAT2 *lpmat2 )
2736 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2737 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2739 if (!lpmat2) return GDI_ERROR;
2741 dc = get_dc_ptr(hdc);
2742 if(!dc) return GDI_ERROR;
2744 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2745 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2746 release_dc_ptr( dc );
2751 /***********************************************************************
2752 * CreateScalableFontResourceA (GDI32.@)
2754 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2755 LPCSTR lpszResourceFile,
2756 LPCSTR lpszFontFile,
2757 LPCSTR lpszCurrentPath )
2759 LPWSTR lpszResourceFileW = NULL;
2760 LPWSTR lpszFontFileW = NULL;
2761 LPWSTR lpszCurrentPathW = NULL;
2765 if (lpszResourceFile)
2767 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2768 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2769 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2774 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2775 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2776 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2779 if (lpszCurrentPath)
2781 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2782 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2783 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2786 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2787 lpszFontFileW, lpszCurrentPathW);
2789 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2790 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2791 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2796 /***********************************************************************
2797 * CreateScalableFontResourceW (GDI32.@)
2799 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2800 LPCWSTR font_file, LPCWSTR font_path )
2802 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2803 debugstr_w(font_file), debugstr_w(font_path) );
2805 return WineEngCreateScalableFontResource( hidden, resource_file,
2806 font_file, font_path );
2809 /*************************************************************************
2810 * GetKerningPairsA (GDI32.@)
2812 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2813 LPKERNINGPAIR kern_pairA )
2817 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2818 KERNINGPAIR *kern_pairW;
2820 if (!cPairs && kern_pairA)
2822 SetLastError(ERROR_INVALID_PARAMETER);
2826 cp = GdiGetCodePage(hDC);
2828 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2829 * to fail on an invalid character for CP_SYMBOL.
2831 cpi.DefaultChar[0] = 0;
2832 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2834 FIXME("Can't find codepage %u info\n", cp);
2838 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2839 if (!total_kern_pairs) return 0;
2841 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2842 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2844 for (i = 0; i < total_kern_pairs; i++)
2848 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2851 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2854 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2859 if (kern_pairs_copied >= cPairs) break;
2861 kern_pairA->wFirst = (BYTE)first;
2862 kern_pairA->wSecond = (BYTE)second;
2863 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2866 kern_pairs_copied++;
2869 HeapFree(GetProcessHeap(), 0, kern_pairW);
2871 return kern_pairs_copied;
2874 /*************************************************************************
2875 * GetKerningPairsW (GDI32.@)
2877 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2878 LPKERNINGPAIR lpKerningPairs )
2884 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2886 if (!cPairs && lpKerningPairs)
2888 SetLastError(ERROR_INVALID_PARAMETER);
2892 dc = get_dc_ptr(hDC);
2895 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2896 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2897 release_dc_ptr( dc );
2901 /*************************************************************************
2902 * TranslateCharsetInfo [GDI32.@]
2904 * Fills a CHARSETINFO structure for a character set, code page, or
2905 * font. This allows making the correspondence between different labels
2906 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2907 * of the same encoding.
2909 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2910 * only one codepage should be set in *lpSrc.
2913 * TRUE on success, FALSE on failure.
2916 BOOL WINAPI TranslateCharsetInfo(
2917 LPDWORD lpSrc, /* [in]
2918 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2919 if flags == TCI_SRCCHARSET: a character set value
2920 if flags == TCI_SRCCODEPAGE: a code page value
2922 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2923 DWORD flags /* [in] determines interpretation of lpSrc */)
2927 case TCI_SRCFONTSIG:
2928 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2930 case TCI_SRCCODEPAGE:
2931 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2933 case TCI_SRCCHARSET:
2934 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2939 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2940 *lpCs = FONT_tci[index];
2944 /*************************************************************************
2945 * GetFontLanguageInfo (GDI32.@)
2947 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2949 FONTSIGNATURE fontsig;
2950 static const DWORD GCP_DBCS_MASK=0x003F0000,
2951 GCP_DIACRITIC_MASK=0x00000000,
2952 FLI_GLYPHS_MASK=0x00000000,
2953 GCP_GLYPHSHAPE_MASK=0x00000040,
2954 GCP_KASHIDA_MASK=0x00000000,
2955 GCP_LIGATE_MASK=0x00000000,
2956 GCP_USEKERNING_MASK=0x00000000,
2957 GCP_REORDER_MASK=0x00000060;
2961 GetTextCharsetInfo( hdc, &fontsig, 0 );
2962 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2964 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2967 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2968 result|=GCP_DIACRITIC;
2970 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2973 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2974 result|=GCP_GLYPHSHAPE;
2976 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2977 result|=GCP_KASHIDA;
2979 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2982 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2983 result|=GCP_USEKERNING;
2985 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2986 if( GetTextAlign( hdc) & TA_RTLREADING )
2987 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2988 result|=GCP_REORDER;
2994 /*************************************************************************
2995 * GetFontData [GDI32.@]
2997 * Retrieve data for TrueType font.
3001 * success: Number of bytes returned
3002 * failure: GDI_ERROR
3006 * Calls SetLastError()
3009 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3010 LPVOID buffer, DWORD length)
3012 DC *dc = get_dc_ptr(hdc);
3016 if(!dc) return GDI_ERROR;
3018 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3019 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3020 release_dc_ptr( dc );
3024 /*************************************************************************
3025 * GetGlyphIndicesA [GDI32.@]
3027 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3028 LPWORD pgi, DWORD flags)
3034 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3035 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3037 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3038 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3039 HeapFree(GetProcessHeap(), 0, lpstrW);
3044 /*************************************************************************
3045 * GetGlyphIndicesW [GDI32.@]
3047 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3048 LPWORD pgi, DWORD flags)
3050 DC *dc = get_dc_ptr(hdc);
3054 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3055 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3057 if(!dc) return GDI_ERROR;
3059 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3060 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3061 release_dc_ptr( dc );
3065 /*************************************************************************
3066 * GetCharacterPlacementA [GDI32.@]
3068 * See GetCharacterPlacementW.
3071 * the web browser control of ie4 calls this with dwFlags=0
3074 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3075 INT nMaxExtent, GCP_RESULTSA *lpResults,
3080 GCP_RESULTSW resultsW;
3084 TRACE("%s, %d, %d, 0x%08x\n",
3085 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3087 /* both structs are equal in size */
3088 memcpy(&resultsW, lpResults, sizeof(resultsW));
3090 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3091 if(lpResults->lpOutString)
3092 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3094 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3096 lpResults->nGlyphs = resultsW.nGlyphs;
3097 lpResults->nMaxFit = resultsW.nMaxFit;
3099 if(lpResults->lpOutString) {
3100 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3101 lpResults->lpOutString, uCount, NULL, NULL );
3104 HeapFree(GetProcessHeap(), 0, lpStringW);
3105 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3110 /*************************************************************************
3111 * GetCharacterPlacementW [GDI32.@]
3113 * Retrieve information about a string. This includes the width, reordering,
3114 * Glyphing and so on.
3118 * The width and height of the string if successful, 0 if failed.
3122 * All flags except GCP_REORDER are not yet implemented.
3123 * Reordering is not 100% compliant to the Windows BiDi method.
3124 * Caret positioning is not yet implemented for BiDi.
3125 * Classes are not yet implemented.
3129 GetCharacterPlacementW(
3130 HDC hdc, /* [in] Device context for which the rendering is to be done */
3131 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3132 INT uCount, /* [in] Number of WORDS in string. */
3133 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3134 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
3135 DWORD dwFlags /* [in] Flags specifying how to process the string */
3142 TRACE("%s, %d, %d, 0x%08x\n",
3143 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3145 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3146 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3147 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3148 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3149 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3151 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
3152 if(lpResults->lpClass) FIXME("classes not implemented\n");
3153 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3154 FIXME("Caret positions for complex scripts not implemented\n");
3156 nSet = (UINT)uCount;
3157 if(nSet > lpResults->nGlyphs)
3158 nSet = lpResults->nGlyphs;
3160 /* return number of initialized fields */
3161 lpResults->nGlyphs = nSet;
3163 if((dwFlags&GCP_REORDER)==0 )
3165 /* Treat the case where no special handling was requested in a fastpath way */
3166 /* copy will do if the GCP_REORDER flag is not set */
3167 if(lpResults->lpOutString)
3168 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3170 if(lpResults->lpOrder)
3172 for(i = 0; i < nSet; i++)
3173 lpResults->lpOrder[i] = i;
3177 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3178 nSet, lpResults->lpOrder, NULL, NULL );
3181 /* FIXME: Will use the placement chars */
3182 if (lpResults->lpDx)
3185 for (i = 0; i < nSet; i++)
3187 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3188 lpResults->lpDx[i]= c;
3192 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3196 lpResults->lpCaretPos[0] = 0;
3197 for (i = 1; i < nSet; i++)
3198 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3199 lpResults->lpCaretPos[i] = (pos += size.cx);
3202 if(lpResults->lpGlyphs)
3203 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3205 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3206 ret = MAKELONG(size.cx, size.cy);
3211 /*************************************************************************
3212 * GetCharABCWidthsFloatA [GDI32.@]
3214 * See GetCharABCWidthsFloatW.
3216 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3223 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3227 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3229 for (i = 0; i < wlen; i++)
3231 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3239 HeapFree( GetProcessHeap(), 0, str );
3240 HeapFree( GetProcessHeap(), 0, wstr );
3245 /*************************************************************************
3246 * GetCharABCWidthsFloatW [GDI32.@]
3248 * Retrieves widths of a range of characters.
3251 * hdc [I] Handle to device context.
3252 * first [I] First character in range to query.
3253 * last [I] Last character in range to query.
3254 * abcf [O] Array of LPABCFLOAT structures.
3260 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3266 DC *dc = get_dc_ptr( hdc );
3268 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3270 if (!dc) return FALSE;
3272 if (!abcf) goto done;
3273 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3275 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3276 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3279 /* convert device units to logical */
3280 for (i = first; i <= last; i++, abcf++)
3282 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3283 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3284 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3287 HeapFree( GetProcessHeap(), 0, abc );
3290 release_dc_ptr( dc );
3294 /*************************************************************************
3295 * GetCharWidthFloatA [GDI32.@]
3297 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3298 UINT iLastChar, PFLOAT pxBuffer)
3300 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3304 /*************************************************************************
3305 * GetCharWidthFloatW [GDI32.@]
3307 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3308 UINT iLastChar, PFLOAT pxBuffer)
3310 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3315 /***********************************************************************
3317 * Font Resource API *
3319 ***********************************************************************/
3321 /***********************************************************************
3322 * AddFontResourceA (GDI32.@)
3324 INT WINAPI AddFontResourceA( LPCSTR str )
3326 return AddFontResourceExA( str, 0, NULL);
3329 /***********************************************************************
3330 * AddFontResourceW (GDI32.@)
3332 INT WINAPI AddFontResourceW( LPCWSTR str )
3334 return AddFontResourceExW(str, 0, NULL);
3338 /***********************************************************************
3339 * AddFontResourceExA (GDI32.@)
3341 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3343 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3344 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3347 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3348 ret = AddFontResourceExW(strW, fl, pdv);
3349 HeapFree(GetProcessHeap(), 0, strW);
3353 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3355 HRSRC rsrc = FindResourceW(hModule, name, type);
3356 HGLOBAL hMem = LoadResource(hModule, rsrc);
3357 LPVOID *pMem = LockResource(hMem);
3358 int *num_total = (int *)lParam;
3361 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3362 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3364 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3368 *num_total += num_in_res;
3372 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3374 HANDLE file, mapping;
3377 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3378 if (file == INVALID_HANDLE_VALUE) return NULL;
3380 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3382 CloseHandle( file );
3386 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3387 CloseHandle( file );
3388 if (!mapping) return NULL;
3390 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3391 CloseHandle( mapping );
3396 static WCHAR *get_scalable_filename( const WCHAR *res )
3399 BYTE *ptr = map_file( res, &size );
3400 const IMAGE_DOS_HEADER *dos;
3401 const IMAGE_OS2_HEADER *ne;
3403 WORD rsrc_off, align, type_id, count;
3404 DWORD res_off, res_len, i;
3407 if (!ptr) return NULL;
3409 if (size.u.LowPart < sizeof( *dos )) goto fail;
3410 dos = (const IMAGE_DOS_HEADER *)ptr;
3411 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3412 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3413 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3414 rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
3415 if (size.u.LowPart < rsrc_off + 10) goto fail;
3416 align = *(WORD *)(ptr + rsrc_off);
3418 type_id = *(WORD *)(ptr + rsrc_off);
3419 while (type_id && type_id != 0x80cc)
3421 count = *(WORD *)(ptr + rsrc_off + 2);
3422 rsrc_off += 8 + count * 12;
3423 if (size.u.LowPart < rsrc_off + 8) goto fail;
3424 type_id = *(WORD *)(ptr + rsrc_off);
3426 if (!type_id) goto fail;
3427 count = *(WORD *)(ptr + rsrc_off + 2);
3428 if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;
3430 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3431 res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
3432 if (size.u.LowPart < res_off + res_len) goto fail;
3434 for (i = 0; i < res_len; i++)
3435 if (ptr[ res_off + i ] == 0) break;
3436 if (i == res_len) goto fail;
3438 len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
3439 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3440 if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );
3443 UnmapViewOfFile( ptr );
3447 /***********************************************************************
3448 * AddFontResourceExW (GDI32.@)
3450 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3452 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3457 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3458 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3459 if (hModule != NULL)
3461 int num_resources = 0;
3462 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3464 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3465 wine_dbgstr_w(str));
3466 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3467 ret = num_resources;
3468 FreeLibrary(hModule);
3470 else if ((filename = get_scalable_filename( str )) != NULL)
3472 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3473 HeapFree( GetProcessHeap(), 0, filename );
3479 /***********************************************************************
3480 * RemoveFontResourceA (GDI32.@)
3482 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3484 return RemoveFontResourceExA(str, 0, 0);
3487 /***********************************************************************
3488 * RemoveFontResourceW (GDI32.@)
3490 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3492 return RemoveFontResourceExW(str, 0, 0);
3495 /***********************************************************************
3496 * AddFontMemResourceEx (GDI32.@)
3498 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3503 if (!pbFont || !cbFont || !pcFonts)
3505 SetLastError(ERROR_INVALID_PARAMETER);
3509 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3514 *pcFonts = num_fonts;
3518 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3519 RemoveFontMemResourceEx(ret);
3527 /***********************************************************************
3528 * RemoveFontMemResourceEx (GDI32.@)
3530 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3532 FIXME("(%p) stub\n", fh);
3536 /***********************************************************************
3537 * RemoveFontResourceExA (GDI32.@)
3539 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3541 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3542 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3545 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3546 ret = RemoveFontResourceExW(strW, fl, pdv);
3547 HeapFree(GetProcessHeap(), 0, strW);
3551 /***********************************************************************
3552 * RemoveFontResourceExW (GDI32.@)
3554 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3556 return WineEngRemoveFontResourceEx(str, fl, pdv);
3559 /***********************************************************************
3560 * GetTextCharset (GDI32.@)
3562 UINT WINAPI GetTextCharset(HDC hdc)
3564 /* MSDN docs say this is equivalent */
3565 return GetTextCharsetInfo(hdc, NULL, 0);
3568 /***********************************************************************
3569 * GetTextCharsetInfo (GDI32.@)
3571 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3573 UINT ret = DEFAULT_CHARSET;
3574 DC *dc = get_dc_ptr(hdc);
3579 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3580 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3581 release_dc_ptr( dc );
3584 if (ret == DEFAULT_CHARSET && fs)
3585 memset(fs, 0, sizeof(FONTSIGNATURE));
3589 /***********************************************************************
3590 * GdiGetCharDimensions (GDI32.@)
3592 * Gets the average width of the characters in the English alphabet.
3595 * hdc [I] Handle to the device context to measure on.
3596 * lptm [O] Pointer to memory to store the text metrics into.
3597 * height [O] On exit, the maximum height of characters in the English alphabet.
3600 * The average width of characters in the English alphabet.
3603 * This function is used by the dialog manager to get the size of a dialog
3604 * unit. It should also be used by other pieces of code that need to know
3605 * the size of a dialog unit in logical units without having access to the
3606 * window handle of the dialog.
3607 * Windows caches the font metrics from this function, but we don't and
3608 * there doesn't appear to be an immediate advantage to do so.
3611 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3613 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3616 static const WCHAR alphabet[] = {
3617 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3618 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3619 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3621 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3623 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3625 if (height) *height = sz.cy;
3626 return (sz.cx / 26 + 1) / 2;
3629 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3631 FIXME("(%d): stub\n", fEnableEUDC);
3635 /***********************************************************************
3636 * GetCharWidthI (GDI32.@)
3638 * Retrieve widths of characters.
3641 * hdc [I] Handle to a device context.
3642 * first [I] First glyph in range to query.
3643 * count [I] Number of glyph indices to query.
3644 * glyphs [I] Array of glyphs to query.
3645 * buffer [O] Buffer to receive character widths.
3648 * Only works with TrueType fonts.
3654 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3659 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3661 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3664 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3666 HeapFree(GetProcessHeap(), 0, abc);
3670 for (i = 0; i < count; i++)
3671 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3673 HeapFree(GetProcessHeap(), 0, abc);
3677 /***********************************************************************
3678 * GetFontUnicodeRanges (GDI32.@)
3680 * Retrieve a list of supported Unicode characters in a font.
3683 * hdc [I] Handle to a device context.
3684 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3687 * Success: Number of bytes written to the buffer pointed to by lpgs.
3691 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3695 DC *dc = get_dc_ptr(hdc);
3697 TRACE("(%p, %p)\n", hdc, lpgs);
3701 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3702 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3708 /*************************************************************
3709 * FontIsLinked (GDI32.@)
3711 BOOL WINAPI FontIsLinked(HDC hdc)
3713 DC *dc = get_dc_ptr(hdc);
3717 if (!dc) return FALSE;
3718 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3719 ret = dev->funcs->pFontIsLinked( dev );
3721 TRACE("returning %d\n", ret);
3725 /*************************************************************
3726 * GdiRealizationInfo (GDI32.@)
3728 * Returns a structure that contains some font information.
3730 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3732 DC *dc = get_dc_ptr(hdc);
3736 if (!dc) return FALSE;
3737 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3738 ret = dev->funcs->pGdiRealizationInfo( dev, info );