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 (plf->lfEscapement != plf->lfOrientation)
400 /* this should really depend on whether GM_ADVANCED is set */
401 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
402 WARN("orientation angle %f set to "
403 "escapement angle %f for new font %p\n",
404 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
407 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
409 HeapFree( GetProcessHeap(), 0, fontPtr );
413 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
414 plf->lfHeight, plf->lfWidth,
415 plf->lfEscapement, plf->lfOrientation,
416 plf->lfPitchAndFamily,
417 plf->lfOutPrecision, plf->lfClipPrecision,
418 plf->lfQuality, plf->lfCharSet,
419 debugstr_w(plf->lfFaceName),
420 plf->lfWeight > 400 ? "Bold" : "",
421 plf->lfItalic ? "Italic" : "",
422 plf->lfUnderline ? "Underline" : "", hFont);
427 /***********************************************************************
428 * CreateFontIndirectA (GDI32.@)
430 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
436 FONT_LogFontAToW( plfA, &lfW );
437 return CreateFontIndirectW( &lfW );
440 /***********************************************************************
441 * CreateFontIndirectW (GDI32.@)
443 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
445 ENUMLOGFONTEXDVW exdv;
449 exdv.elfEnumLogfontEx.elfLogFont = *plf;
450 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
451 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
452 exdv.elfEnumLogfontEx.elfScript[0] = 0;
453 return CreateFontIndirectExW( &exdv );
456 /*************************************************************************
457 * CreateFontA (GDI32.@)
459 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
460 INT orient, INT weight, DWORD italic,
461 DWORD underline, DWORD strikeout, DWORD charset,
462 DWORD outpres, DWORD clippres, DWORD quality,
463 DWORD pitch, LPCSTR name )
467 logfont.lfHeight = height;
468 logfont.lfWidth = width;
469 logfont.lfEscapement = esc;
470 logfont.lfOrientation = orient;
471 logfont.lfWeight = weight;
472 logfont.lfItalic = italic;
473 logfont.lfUnderline = underline;
474 logfont.lfStrikeOut = strikeout;
475 logfont.lfCharSet = charset;
476 logfont.lfOutPrecision = outpres;
477 logfont.lfClipPrecision = clippres;
478 logfont.lfQuality = quality;
479 logfont.lfPitchAndFamily = pitch;
482 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
484 logfont.lfFaceName[0] = '\0';
486 return CreateFontIndirectA( &logfont );
489 /*************************************************************************
490 * CreateFontW (GDI32.@)
492 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
493 INT orient, INT weight, DWORD italic,
494 DWORD underline, DWORD strikeout, DWORD charset,
495 DWORD outpres, DWORD clippres, DWORD quality,
496 DWORD pitch, LPCWSTR name )
500 logfont.lfHeight = height;
501 logfont.lfWidth = width;
502 logfont.lfEscapement = esc;
503 logfont.lfOrientation = orient;
504 logfont.lfWeight = weight;
505 logfont.lfItalic = italic;
506 logfont.lfUnderline = underline;
507 logfont.lfStrikeOut = strikeout;
508 logfont.lfCharSet = charset;
509 logfont.lfOutPrecision = outpres;
510 logfont.lfClipPrecision = clippres;
511 logfont.lfQuality = quality;
512 logfont.lfPitchAndFamily = pitch;
515 lstrcpynW(logfont.lfFaceName, name,
516 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
518 logfont.lfFaceName[0] = '\0';
520 return CreateFontIndirectW( &logfont );
523 static void update_font_code_page( DC *dc )
526 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
528 /* Hmm, nicely designed api this one! */
529 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
530 dc->font_code_page = csi.ciACP;
534 dc->font_code_page = GetOEMCP();
536 case DEFAULT_CHARSET:
537 dc->font_code_page = GetACP();
547 /* FIXME: These have no place here, but because x11drv
548 enumerates fonts with these (made up) charsets some apps
549 might use them and then the FIXME below would become
550 annoying. Now we could pick the intended codepage for
551 each of these, but since it's broken anyway we'll just
552 use CP_ACP and hope it'll go away...
554 dc->font_code_page = CP_ACP;
558 FIXME("Can't find codepage for charset %d\n", charset);
559 dc->font_code_page = CP_ACP;
564 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
567 /***********************************************************************
570 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
573 DC *dc = get_dc_ptr( hdc );
579 if (!GDI_inc_ref_count( handle ))
581 release_dc_ptr( dc );
585 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
586 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
590 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
591 update_font_code_page( dc );
592 GDI_dec_ref_count( ret );
594 else GDI_dec_ref_count( handle );
596 release_dc_ptr( dc );
601 /***********************************************************************
604 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
606 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
612 FONT_LogFontWToA( &font->logfont, &lfA );
613 if (count > sizeof(lfA)) count = sizeof(lfA);
614 memcpy( buffer, &lfA, count );
616 else count = sizeof(lfA);
617 GDI_ReleaseObj( handle );
621 /***********************************************************************
624 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
626 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
631 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
632 memcpy( buffer, &font->logfont, count );
634 else count = sizeof(LOGFONTW);
635 GDI_ReleaseObj( handle );
640 /***********************************************************************
643 static BOOL FONT_DeleteObject( HGDIOBJ handle )
647 WineEngDestroyFontInstance( handle );
649 if (!(obj = free_gdi_handle( handle ))) return FALSE;
650 return HeapFree( GetProcessHeap(), 0, obj );
654 /***********************************************************************
657 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
659 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
660 'D','e','s','k','t','o','p',0 };
664 if (*aa_flags) return 0;
666 GetObjectW( font, sizeof(lf), &lf );
667 switch (lf.lfQuality)
669 case NONANTIALIASED_QUALITY:
670 *aa_flags = GGO_BITMAP;
672 case ANTIALIASED_QUALITY:
673 *aa_flags = GGO_GRAY4_BITMAP;
675 case CLEARTYPE_QUALITY:
676 case CLEARTYPE_NATURAL_QUALITY:
677 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
678 *aa_flags = get_subpixel_orientation( key );
682 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
683 *aa_flags = get_default_smoothing( key );
691 /***********************************************************************
694 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
695 * We have to use other types because of the FONTENUMPROCW definition.
697 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
698 DWORD fType, LPARAM lp )
700 struct font_enum *pfe = (struct font_enum *)lp;
703 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
704 if ((!pfe->lpLogFontParam ||
705 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
706 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
707 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
709 /* convert font metrics */
710 ENUMLOGFONTEXA logfont;
711 NEWTEXTMETRICEXA tmA;
715 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
716 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
717 plf = (LOGFONTW *)&logfont.elfLogFont;
718 ptm = (TEXTMETRICW *)&tmA;
720 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
726 /***********************************************************************
727 * FONT_EnumFontFamiliesEx
729 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
730 LPARAM lParam, BOOL unicode )
733 DC *dc = get_dc_ptr( hDC );
738 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
740 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
741 fe.lpLogFontParam = plf;
742 fe.lpEnumFunc = efproc;
744 fe.unicode = unicode;
747 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
748 release_dc_ptr( dc );
750 return ret ? fe.retval : 0;
753 /***********************************************************************
754 * EnumFontFamiliesExW (GDI32.@)
756 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
757 FONTENUMPROCW efproc,
758 LPARAM lParam, DWORD dwFlags )
760 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
763 /***********************************************************************
764 * EnumFontFamiliesExA (GDI32.@)
766 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
767 FONTENUMPROCA efproc,
768 LPARAM lParam, DWORD dwFlags)
774 FONT_LogFontAToW( plf, &lfW );
779 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
782 /***********************************************************************
783 * EnumFontFamiliesA (GDI32.@)
785 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
786 FONTENUMPROCA efproc, LPARAM lpData )
792 if (!*lpFamily) return 1;
793 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
794 lf.lfCharSet = DEFAULT_CHARSET;
795 lf.lfPitchAndFamily = 0;
800 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
803 /***********************************************************************
804 * EnumFontFamiliesW (GDI32.@)
806 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
807 FONTENUMPROCW efproc, LPARAM lpData )
813 if (!*lpFamily) return 1;
814 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
815 lf.lfCharSet = DEFAULT_CHARSET;
816 lf.lfPitchAndFamily = 0;
821 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
824 /***********************************************************************
825 * EnumFontsA (GDI32.@)
827 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
830 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
833 /***********************************************************************
834 * EnumFontsW (GDI32.@)
836 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
839 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
843 /***********************************************************************
844 * GetTextCharacterExtra (GDI32.@)
846 INT WINAPI GetTextCharacterExtra( HDC hdc )
849 DC *dc = get_dc_ptr( hdc );
850 if (!dc) return 0x80000000;
852 release_dc_ptr( dc );
857 /***********************************************************************
858 * SetTextCharacterExtra (GDI32.@)
860 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
862 INT ret = 0x80000000;
863 DC * dc = get_dc_ptr( hdc );
867 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
868 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
869 if (extra != 0x80000000)
872 dc->charExtra = extra;
874 release_dc_ptr( dc );
880 /***********************************************************************
881 * SetTextJustification (GDI32.@)
883 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
887 DC * dc = get_dc_ptr( hdc );
889 if (!dc) return FALSE;
891 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
892 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
895 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
896 if (!extra) breaks = 0;
899 dc->breakExtra = extra / breaks;
900 dc->breakRem = extra - (breaks * dc->breakExtra);
908 release_dc_ptr( dc );
913 /***********************************************************************
914 * GetTextFaceA (GDI32.@)
916 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
918 INT res = GetTextFaceW(hdc, 0, NULL);
919 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
920 GetTextFaceW( hdc, res, nameW );
926 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
930 /* GetTextFaceA does NOT include the nul byte in the return count. */
937 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
938 HeapFree( GetProcessHeap(), 0, nameW );
942 /***********************************************************************
943 * GetTextFaceW (GDI32.@)
945 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
950 DC * dc = get_dc_ptr( hdc );
953 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
954 ret = dev->funcs->pGetTextFace( dev, count, name );
955 release_dc_ptr( dc );
960 /***********************************************************************
961 * GetTextExtentPoint32A (GDI32.@)
963 * See GetTextExtentPoint32W.
965 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
972 if (count < 0) return FALSE;
974 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
978 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
979 HeapFree( GetProcessHeap(), 0, p );
982 TRACE("(%p %s %d %p): returning %d x %d\n",
983 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
988 /***********************************************************************
989 * GetTextExtentPoint32W [GDI32.@]
991 * Computes width/height for a string.
993 * Computes width and height of the specified string.
999 BOOL WINAPI GetTextExtentPoint32W(
1000 HDC hdc, /* [in] Handle of device context */
1001 LPCWSTR str, /* [in] Address of text string */
1002 INT count, /* [in] Number of characters in string */
1003 LPSIZE size) /* [out] Address of structure for string size */
1005 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1008 /***********************************************************************
1009 * GetTextExtentExPointI [GDI32.@]
1011 * Computes width and height of the array of glyph indices.
1014 * hdc [I] Handle of device context.
1015 * indices [I] Glyph index array.
1016 * count [I] Number of glyphs in array.
1017 * max_ext [I] Maximum width in glyphs.
1018 * nfit [O] Maximum number of characters.
1019 * dxs [O] Partial string widths.
1020 * size [O] Returned string size.
1026 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1027 LPINT nfit, LPINT dxs, LPSIZE size )
1033 if (count < 0) return FALSE;
1035 dc = get_dc_ptr( hdc );
1036 if (!dc) return FALSE;
1038 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
1039 ret = dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, nfit, dxs, size );
1040 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1041 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1042 size->cx += count * dc->charExtra;
1043 release_dc_ptr( dc );
1045 TRACE("(%p %p %d %p): returning %d x %d\n",
1046 hdc, indices, count, size, size->cx, size->cy );
1050 /***********************************************************************
1051 * GetTextExtentPointI [GDI32.@]
1053 * Computes width and height of the array of glyph indices.
1056 * hdc [I] Handle of device context.
1057 * indices [I] Glyph index array.
1058 * count [I] Number of glyphs in array.
1059 * size [O] Returned string size.
1065 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1067 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1071 /***********************************************************************
1072 * GetTextExtentPointA (GDI32.@)
1074 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1077 TRACE("not bug compatible.\n");
1078 return GetTextExtentPoint32A( hdc, str, count, size );
1081 /***********************************************************************
1082 * GetTextExtentPointW (GDI32.@)
1084 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1087 TRACE("not bug compatible.\n");
1088 return GetTextExtentPoint32W( hdc, str, count, size );
1092 /***********************************************************************
1093 * GetTextExtentExPointA (GDI32.@)
1095 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1096 INT maxExt, LPINT lpnFit,
1097 LPINT alpDx, LPSIZE size )
1104 if (count < 0) return FALSE;
1108 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1109 if (!walpDx) return FALSE;
1112 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1113 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1116 INT n = lpnFit ? *lpnFit : wlen;
1118 for(i = 0, j = 0; i < n; i++, j++)
1120 alpDx[j] = walpDx[i];
1121 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1124 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1125 HeapFree( GetProcessHeap(), 0, p );
1126 HeapFree( GetProcessHeap(), 0, walpDx );
1131 /***********************************************************************
1132 * GetTextExtentExPointW (GDI32.@)
1134 * Return the size of the string as it would be if it was output properly by
1137 * This should include
1138 * - Intercharacter spacing
1139 * - justification spacing (not yet done)
1140 * - kerning? see below
1142 * Kerning. Since kerning would be carried out by the rendering code it should
1143 * be done by the driver. However they don't support it yet. Also I am not
1144 * yet persuaded that (certainly under Win95) any kerning is actually done.
1146 * str: According to MSDN this should be null-terminated. That is not true; a
1147 * null will not terminate it early.
1148 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1149 * than count. I have seen it be either the size of the full string or
1150 * 1 less than the size of the full string. I have not seen it bear any
1151 * resemblance to the portion that would fit.
1152 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1153 * trailing intercharacter spacing and any trailing justification.
1156 * Currently we do this by measuring each character etc. We should do it by
1157 * passing the request to the driver, perhaps by extending the
1158 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1159 * thinking about kerning issues and rounding issues in the justification.
1162 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1163 INT maxExt, LPINT lpnFit,
1164 LPINT alpDx, LPSIZE size )
1173 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1175 if (count < 0) return FALSE;
1177 dc = get_dc_ptr(hdc);
1178 if (!dc) return FALSE;
1180 GetTextMetricsW(hdc, &tm);
1182 /* If we need to calculate nFit, then we need the partial extents even if
1183 the user hasn't provided us with an array. */
1186 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1190 SetLastError(ERROR_OUTOFMEMORY);
1197 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
1198 ret = dev->funcs->pGetTextExtentExPoint(dev, str, count, 0, NULL, dxs, size);
1200 /* Perform device size to world size transformations. */
1203 INT extra = dc->charExtra,
1204 breakExtra = dc->breakExtra,
1205 breakRem = dc->breakRem,
1210 for (i = 0; i < count; ++i)
1212 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1213 dxs[i] += (i+1) * extra;
1214 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1216 dxs[i] += breakExtra;
1223 if (dxs[i] <= maxExt)
1226 breakRem = dc->breakRem;
1228 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1229 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1231 if (!dxs && count > 1 && (breakExtra || breakRem))
1233 for (i = 0; i < count; i++)
1235 if (str[i] == tm.tmBreakChar)
1237 size->cx += breakExtra;
1252 HeapFree(GetProcessHeap(), 0, dxs);
1254 release_dc_ptr( dc );
1256 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1260 /***********************************************************************
1261 * GetTextMetricsA (GDI32.@)
1263 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1267 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1268 FONT_TextMetricWToA( &tm32, metrics );
1272 /***********************************************************************
1273 * GetTextMetricsW (GDI32.@)
1275 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1279 DC * dc = get_dc_ptr( hdc );
1280 if (!dc) return FALSE;
1282 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1283 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1287 /* device layer returns values in device units
1288 * therefore we have to convert them to logical */
1290 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1291 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1293 #define WDPTOLP(x) ((x<0)? \
1294 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1295 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1296 #define HDPTOLP(y) ((y<0)? \
1297 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1298 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1300 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1301 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1302 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1303 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1304 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1305 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1306 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1307 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1311 TRACE("text metrics:\n"
1312 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1313 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1314 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1315 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1316 " PitchAndFamily = %02x\n"
1317 " --------------------\n"
1318 " InternalLeading = %i\n"
1322 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1323 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1324 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1325 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1326 metrics->tmPitchAndFamily,
1327 metrics->tmInternalLeading,
1330 metrics->tmHeight );
1332 release_dc_ptr( dc );
1337 /***********************************************************************
1338 * GetOutlineTextMetricsA (GDI32.@)
1339 * Gets metrics for TrueType fonts.
1342 * If the supplied buffer isn't big enough Windows partially fills it up to
1343 * its given length and returns that length.
1346 * Success: Non-zero or size of required buffer
1349 UINT WINAPI GetOutlineTextMetricsA(
1350 HDC hdc, /* [in] Handle of device context */
1351 UINT cbData, /* [in] Size of metric data array */
1352 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1354 char buf[512], *ptr;
1356 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1357 OUTLINETEXTMETRICA *output = lpOTM;
1360 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1362 if(ret > sizeof(buf))
1363 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1364 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1366 needed = sizeof(OUTLINETEXTMETRICA);
1367 if(lpOTMW->otmpFamilyName)
1368 needed += WideCharToMultiByte(CP_ACP, 0,
1369 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1370 NULL, 0, NULL, NULL);
1371 if(lpOTMW->otmpFaceName)
1372 needed += WideCharToMultiByte(CP_ACP, 0,
1373 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1374 NULL, 0, NULL, NULL);
1375 if(lpOTMW->otmpStyleName)
1376 needed += WideCharToMultiByte(CP_ACP, 0,
1377 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1378 NULL, 0, NULL, NULL);
1379 if(lpOTMW->otmpFullName)
1380 needed += WideCharToMultiByte(CP_ACP, 0,
1381 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1382 NULL, 0, NULL, NULL);
1389 TRACE("needed = %d\n", needed);
1391 /* Since the supplied buffer isn't big enough, we'll alloc one
1392 that is and memcpy the first cbData bytes into the lpOTM at
1394 output = HeapAlloc(GetProcessHeap(), 0, needed);
1396 ret = output->otmSize = min(needed, cbData);
1397 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1398 output->otmFiller = 0;
1399 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1400 output->otmfsSelection = lpOTMW->otmfsSelection;
1401 output->otmfsType = lpOTMW->otmfsType;
1402 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1403 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1404 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1405 output->otmEMSquare = lpOTMW->otmEMSquare;
1406 output->otmAscent = lpOTMW->otmAscent;
1407 output->otmDescent = lpOTMW->otmDescent;
1408 output->otmLineGap = lpOTMW->otmLineGap;
1409 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1410 output->otmsXHeight = lpOTMW->otmsXHeight;
1411 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1412 output->otmMacAscent = lpOTMW->otmMacAscent;
1413 output->otmMacDescent = lpOTMW->otmMacDescent;
1414 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1415 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1416 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1417 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1418 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1419 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1420 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1421 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1422 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1423 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1426 ptr = (char*)(output + 1);
1427 left = needed - sizeof(*output);
1429 if(lpOTMW->otmpFamilyName) {
1430 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1431 len = WideCharToMultiByte(CP_ACP, 0,
1432 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1433 ptr, left, NULL, NULL);
1437 output->otmpFamilyName = 0;
1439 if(lpOTMW->otmpFaceName) {
1440 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1441 len = WideCharToMultiByte(CP_ACP, 0,
1442 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1443 ptr, left, NULL, NULL);
1447 output->otmpFaceName = 0;
1449 if(lpOTMW->otmpStyleName) {
1450 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1451 len = WideCharToMultiByte(CP_ACP, 0,
1452 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1453 ptr, left, NULL, NULL);
1457 output->otmpStyleName = 0;
1459 if(lpOTMW->otmpFullName) {
1460 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1461 len = WideCharToMultiByte(CP_ACP, 0,
1462 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1463 ptr, left, NULL, NULL);
1466 output->otmpFullName = 0;
1470 if(output != lpOTM) {
1471 memcpy(lpOTM, output, cbData);
1472 HeapFree(GetProcessHeap(), 0, output);
1474 /* check if the string offsets really fit into the provided size */
1475 /* FIXME: should we check string length as well? */
1476 /* make sure that we don't read/write beyond the provided buffer */
1477 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1479 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1480 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1483 /* make sure that we don't read/write beyond the provided buffer */
1484 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1486 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1487 lpOTM->otmpFaceName = 0; /* doesn't fit */
1490 /* make sure that we don't read/write beyond the provided buffer */
1491 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1493 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1494 lpOTM->otmpStyleName = 0; /* doesn't fit */
1497 /* make sure that we don't read/write beyond the provided buffer */
1498 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1500 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1501 lpOTM->otmpFullName = 0; /* doesn't fit */
1506 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1507 HeapFree(GetProcessHeap(), 0, lpOTMW);
1513 /***********************************************************************
1514 * GetOutlineTextMetricsW [GDI32.@]
1516 UINT WINAPI GetOutlineTextMetricsW(
1517 HDC hdc, /* [in] Handle of device context */
1518 UINT cbData, /* [in] Size of metric data array */
1519 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1521 DC *dc = get_dc_ptr( hdc );
1522 OUTLINETEXTMETRICW *output = lpOTM;
1526 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1529 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1530 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1532 if (lpOTM && ret > cbData)
1534 output = HeapAlloc(GetProcessHeap(), 0, ret);
1535 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1540 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1541 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1543 #define WDPTOLP(x) ((x<0)? \
1544 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1545 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1546 #define HDPTOLP(y) ((y<0)? \
1547 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1548 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1550 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1551 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1552 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1553 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1554 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1555 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1556 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1557 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1558 output->otmAscent = HDPTOLP(output->otmAscent);
1559 output->otmDescent = HDPTOLP(output->otmDescent);
1560 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1561 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1562 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1563 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1564 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1565 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1566 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1567 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1568 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1569 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1570 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1571 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1572 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1573 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1574 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1575 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1576 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1577 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1578 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1579 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1580 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1581 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1586 memcpy(lpOTM, output, cbData);
1587 HeapFree(GetProcessHeap(), 0, output);
1595 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1597 INT i, count = lastChar - firstChar + 1;
1605 mbcp = GdiGetCodePage(hdc);
1613 if (lastChar > 0xffff)
1615 if ((firstChar ^ lastChar) > 0xff)
1619 if (lastChar > 0xff)
1625 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1629 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1633 str[i++] = (BYTE)(c >> 8);
1634 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1635 str[i] = 0x1f; /* FIXME: use default character */
1649 /***********************************************************************
1650 * GetCharWidthW (GDI32.@)
1651 * GetCharWidth32W (GDI32.@)
1653 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1659 DC * dc = get_dc_ptr( hdc );
1661 if (!dc) return FALSE;
1663 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1664 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1668 /* convert device units to logical */
1669 for( i = firstChar; i <= lastChar; i++, buffer++ )
1670 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1672 release_dc_ptr( dc );
1677 /***********************************************************************
1678 * GetCharWidthA (GDI32.@)
1679 * GetCharWidth32A (GDI32.@)
1681 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1689 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1693 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1695 for(i = 0; i < wlen; i++)
1697 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1705 HeapFree(GetProcessHeap(), 0, str);
1706 HeapFree(GetProcessHeap(), 0, wstr);
1712 /* helper for nulldrv_ExtTextOut */
1713 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1714 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1716 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1717 UINT indices[3] = {0, 0, 0x20};
1723 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1725 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1728 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1729 if (ret != GDI_ERROR) break;
1732 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1733 if (!image) return ERROR_SUCCESS;
1737 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1739 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1740 size = metrics->gmBlackBoxY * stride;
1742 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1743 image->is_copy = TRUE;
1744 image->free = free_heap_bits;
1746 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1747 if (ret == GDI_ERROR)
1749 HeapFree( GetProcessHeap(), 0, image->ptr );
1750 return ERROR_NOT_FOUND;
1752 return ERROR_SUCCESS;
1755 /* helper for nulldrv_ExtTextOut */
1756 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1757 LPCWSTR str, UINT count, const INT *dx )
1762 reset_bounds( &bounds );
1763 for (i = 0; i < count; i++)
1765 GLYPHMETRICS metrics;
1767 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1769 rect.left = x + metrics.gmptGlyphOrigin.x;
1770 rect.top = y - metrics.gmptGlyphOrigin.y;
1771 rect.right = rect.left + metrics.gmBlackBoxX;
1772 rect.bottom = rect.top + metrics.gmBlackBoxY;
1773 add_bounds_rect( &bounds, &rect );
1777 if (flags & ETO_PDY)
1780 y += dx[ i * 2 + 1];
1786 x += metrics.gmCellIncX;
1787 y += metrics.gmCellIncY;
1793 /* helper for nulldrv_ExtTextOut */
1794 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1795 const struct gdi_image_bits *image, const RECT *clip )
1797 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1798 UINT x, y, i, count, max_count;
1799 BYTE *ptr = image->ptr;
1800 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1802 RECT rect, clipped_rect;
1804 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1805 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1806 rect.right = rect.left + metrics->gmBlackBoxX;
1807 rect.bottom = rect.top + metrics->gmBlackBoxY;
1808 if (!clip) clipped_rect = rect;
1809 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1811 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1812 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1816 ptr += (clipped_rect.top - rect.top) * stride;
1817 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1819 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1821 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1822 pts[count].x = rect.left + x;
1823 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1824 pts[count + 1].x = rect.left + x;
1825 if (pts[count + 1].x > pts[count].x)
1827 pts[count].y = pts[count + 1].y = y;
1832 assert( count <= max_count );
1833 DPtoLP( hdc, pts, count );
1834 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1835 HeapFree( GetProcessHeap(), 0, pts );
1838 /***********************************************************************
1839 * nulldrv_ExtTextOut
1841 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1842 LPCWSTR str, UINT count, const INT *dx )
1844 DC *dc = get_nulldrv_dc( dev );
1850 if (flags & ETO_OPAQUE)
1853 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1857 orig = SelectObject( dev->hdc, brush );
1858 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1859 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1860 SelectObject( dev->hdc, orig );
1861 DeleteObject( brush );
1865 if (!count) return TRUE;
1867 if (dc->aa_flags != GGO_BITMAP)
1869 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1870 BITMAPINFO *info = (BITMAPINFO *)buffer;
1871 struct gdi_image_bits bits;
1872 struct bitblt_coords src, dst;
1874 /* FIXME Subpixel modes */
1875 UINT aa_flags = GGO_GRAY4_BITMAP;
1877 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1878 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1879 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1880 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1882 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1883 src.x = src.visrect.left;
1884 src.y = src.visrect.top;
1885 src.width = src.visrect.right - src.visrect.left;
1886 src.height = src.visrect.bottom - src.visrect.top;
1888 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1889 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1891 /* we can avoid the GetImage, just query the needed format */
1892 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1893 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1894 info->bmiHeader.biWidth = src.width;
1895 info->bmiHeader.biHeight = -src.height;
1896 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1897 if (!err || err == ERROR_BAD_FORMAT)
1899 /* make the source rectangle relative to the source bits */
1901 src.visrect.left = src.visrect.top = 0;
1902 src.visrect.right = src.width;
1903 src.visrect.bottom = src.height;
1905 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1906 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1907 bits.is_copy = TRUE;
1908 bits.free = free_heap_bits;
1909 err = ERROR_SUCCESS;
1914 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1915 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1916 if (!err && !bits.is_copy)
1918 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1921 if (bits.free) bits.free( &bits );
1922 return ERROR_OUTOFMEMORY;
1924 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1925 if (bits.free) bits.free( &bits );
1927 bits.is_copy = TRUE;
1928 bits.free = free_heap_bits;
1933 /* make x,y relative to the image bits */
1934 x += src.visrect.left - dst.visrect.left;
1935 y += src.visrect.top - dst.visrect.top;
1936 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1937 aa_flags, str, count, dx );
1938 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
1939 if (bits.free) bits.free( &bits );
1944 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1945 orig = SelectObject( dev->hdc, pen );
1947 for (i = 0; i < count; i++)
1949 GLYPHMETRICS metrics;
1950 struct gdi_image_bits image;
1952 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
1955 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1956 if (image.free) image.free( &image );
1960 if (flags & ETO_PDY)
1963 y += dx[ i * 2 + 1];
1969 x += metrics.gmCellIncX;
1970 y += metrics.gmCellIncY;
1974 SelectObject( dev->hdc, orig );
1975 DeleteObject( pen );
1980 /***********************************************************************
1981 * ExtTextOutA (GDI32.@)
1985 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1986 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1994 if (flags & ETO_GLYPH_INDEX)
1995 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1997 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2000 unsigned int i = 0, j = 0;
2002 /* allocate enough for a ETO_PDY */
2003 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2005 if(IsDBCSLeadByteEx(codepage, str[i]))
2009 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2010 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2013 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2020 lpDxW[j++] = lpDx[i * 2];
2021 lpDxW[j++] = lpDx[i * 2 + 1];
2024 lpDxW[j++] = lpDx[i];
2030 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2032 HeapFree( GetProcessHeap(), 0, p );
2033 HeapFree( GetProcessHeap(), 0, lpDxW );
2038 /***********************************************************************
2039 * ExtTextOutW (GDI32.@)
2041 * Draws text using the currently selected font, background color, and text color.
2045 * x,y [I] coordinates of string
2047 * ETO_GRAYED - undocumented on MSDN
2048 * ETO_OPAQUE - use background color for fill the rectangle
2049 * ETO_CLIPPED - clipping text to the rectangle
2050 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2051 * than encoded characters. Implies ETO_IGNORELANGUAGE
2052 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2053 * Affects BiDi ordering
2054 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2055 * ETO_PDY - unimplemented
2056 * ETO_NUMERICSLATIN - unimplemented always assumed -
2057 * do not translate numbers into locale representations
2058 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2059 * lprect [I] dimensions for clipping or/and opaquing
2060 * str [I] text string
2061 * count [I] number of symbols in string
2062 * lpDx [I] optional parameter with distance between drawing characters
2068 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2069 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2072 LPWSTR reordered_str = (LPWSTR)str;
2073 WORD *glyphs = NULL;
2074 UINT align = GetTextAlign( hdc );
2075 DWORD layout = GetLayout( hdc );
2079 double cosEsc, sinEsc;
2083 BOOL done_extents = FALSE;
2084 POINT *deltas = NULL, width = {0, 0};
2086 DC * dc = get_dc_ptr( hdc );
2089 static int quietfixme = 0;
2091 if (!dc) return FALSE;
2093 breakRem = dc->breakRem;
2095 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2097 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2102 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2103 type = GetObjectType(hdc);
2104 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2106 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2107 release_dc_ptr( dc );
2112 flags &= ~ETO_CLIPPED;
2114 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2115 if (layout & LAYOUT_RTL)
2117 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2118 align ^= TA_RTLREADING;
2121 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2124 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2126 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2127 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2128 reordered_str, count, NULL, &glyphs, &cGlyphs);
2130 flags |= ETO_IGNORELANGUAGE;
2133 flags |= ETO_GLYPH_INDEX;
2134 if (cGlyphs != count)
2138 else if(flags & ETO_GLYPH_INDEX)
2139 glyphs = reordered_str;
2141 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2142 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2143 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2145 if(align & TA_UPDATECP)
2147 GetCurrentPositionEx( hdc, &pt );
2152 GetTextMetricsW(hdc, &tm);
2153 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2155 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2156 lf.lfEscapement = 0;
2158 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2159 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2161 lf.lfEscapement = -lf.lfEscapement;
2164 if(lf.lfEscapement != 0)
2166 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2167 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2175 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
2179 if(flags & ETO_GLYPH_INDEX)
2180 GetTextExtentPointI(hdc, glyphs, count, &sz);
2182 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2184 done_extents = TRUE;
2187 rc.right = x + sz.cx;
2188 rc.bottom = y + sz.cy;
2195 LPtoDP(hdc, (POINT*)&rc, 2);
2197 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
2198 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
2201 if (lprect && (flags & ETO_OPAQUE))
2202 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2212 LPtoDP(hdc, &pt, 1);
2216 char_extra = GetTextCharacterExtra(hdc);
2217 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2221 POINT total = {0, 0}, desired[2];
2223 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2224 for(i = 0; i < count; i++)
2230 deltas[i].x = lpDx[i * 2] + char_extra;
2231 deltas[i].y = -lpDx[i * 2 + 1];
2235 deltas[i].x = lpDx[i] + char_extra;
2242 if(flags & ETO_GLYPH_INDEX)
2243 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2245 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2247 deltas[i].x = tmpsz.cx;
2251 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2253 deltas[i].x = deltas[i].x + dc->breakExtra;
2260 total.x += deltas[i].x;
2261 total.y += deltas[i].y;
2263 desired[0].x = desired[0].y = 0;
2265 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2266 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2268 LPtoDP(hdc, desired, 2);
2269 desired[1].x -= desired[0].x;
2270 desired[1].y -= desired[0].y;
2272 if (dc->GraphicsMode == GM_COMPATIBLE)
2274 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2275 desired[1].x = -desired[1].x;
2276 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2277 desired[1].y = -desired[1].y;
2281 if (layout & LAYOUT_RTL) desired[1].x = -desired[1].x;
2284 deltas[i].x = desired[1].x - width.x;
2285 deltas[i].y = desired[1].y - width.y;
2295 if(flags & ETO_GLYPH_INDEX)
2296 GetTextExtentPointI(hdc, glyphs, count, &sz);
2298 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2299 done_extents = TRUE;
2301 width.x = abs(INTERNAL_XWSTODS(dc, sz.cx));
2305 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2306 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2307 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2310 if (align & TA_UPDATECP)
2314 DPtoLP(hdc, &pt, 1);
2315 MoveToEx(hdc, pt.x, pt.y, NULL);
2327 if (align & TA_UPDATECP)
2331 DPtoLP(hdc, &pt, 1);
2332 MoveToEx(hdc, pt.x, pt.y, NULL);
2337 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2340 y += tm.tmAscent * cosEsc;
2341 x += tm.tmAscent * sinEsc;
2345 y -= tm.tmDescent * cosEsc;
2346 x -= tm.tmDescent * sinEsc;
2353 if (GetBkMode(hdc) != TRANSPARENT)
2355 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2357 if(!(flags & ETO_OPAQUE) || !lprect ||
2358 x < rc.left || x + width.x >= rc.right ||
2359 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2363 text_box.right = x + width.x;
2364 text_box.top = y - tm.tmAscent;
2365 text_box.bottom = y + tm.tmDescent;
2367 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2368 if (!is_rect_empty( &text_box ))
2369 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2374 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2375 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2378 HeapFree(GetProcessHeap(), 0, deltas);
2379 if(glyphs != reordered_str)
2380 HeapFree(GetProcessHeap(), 0, glyphs);
2381 if(reordered_str != str)
2382 HeapFree(GetProcessHeap(), 0, reordered_str);
2384 release_dc_ptr( dc );
2386 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2388 int underlinePos, strikeoutPos;
2389 int underlineWidth, strikeoutWidth;
2390 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2391 OUTLINETEXTMETRICW* otm = NULL;
2393 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2394 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2396 hbrush = SelectObject(hdc, hbrush);
2401 underlineWidth = tm.tmAscent / 20 + 1;
2402 strikeoutPos = tm.tmAscent / 2;
2403 strikeoutWidth = underlineWidth;
2407 otm = HeapAlloc(GetProcessHeap(), 0, size);
2408 GetOutlineTextMetricsW(hdc, size, otm);
2409 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2410 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2411 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2412 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2413 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2414 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2415 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2416 HeapFree(GetProcessHeap(), 0, otm);
2422 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2423 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2424 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2425 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2426 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2427 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2428 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2429 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2430 pts[4].x = pts[0].x;
2431 pts[4].y = pts[0].y;
2432 DPtoLP(hdc, pts, 5);
2433 Polygon(hdc, pts, 5);
2438 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2439 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2440 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2441 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2442 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2443 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2444 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2445 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2446 pts[4].x = pts[0].x;
2447 pts[4].y = pts[0].y;
2448 DPtoLP(hdc, pts, 5);
2449 Polygon(hdc, pts, 5);
2452 SelectObject(hdc, hpen);
2453 hbrush = SelectObject(hdc, hbrush);
2454 DeleteObject(hbrush);
2461 /***********************************************************************
2462 * TextOutA (GDI32.@)
2464 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2466 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2470 /***********************************************************************
2471 * TextOutW (GDI32.@)
2473 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2475 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2479 /***********************************************************************
2480 * PolyTextOutA (GDI32.@)
2484 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2486 for (; cStrings>0; cStrings--, pptxt++)
2487 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2494 /***********************************************************************
2495 * PolyTextOutW (GDI32.@)
2497 * Draw several Strings
2503 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2505 for (; cStrings>0; cStrings--, pptxt++)
2506 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2512 /***********************************************************************
2513 * SetMapperFlags (GDI32.@)
2515 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2517 DC *dc = get_dc_ptr( hdc );
2518 DWORD ret = GDI_ERROR;
2522 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2523 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2524 if (flags != GDI_ERROR)
2526 ret = dc->mapperFlags;
2527 dc->mapperFlags = flags;
2529 release_dc_ptr( dc );
2534 /***********************************************************************
2535 * GetAspectRatioFilterEx (GDI32.@)
2537 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2539 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2544 /***********************************************************************
2545 * GetCharABCWidthsA (GDI32.@)
2547 * See GetCharABCWidthsW.
2549 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2557 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2561 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2564 HeapFree(GetProcessHeap(), 0, str);
2568 for(i = 0; i < wlen; i++)
2570 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2578 HeapFree(GetProcessHeap(), 0, str);
2579 HeapFree(GetProcessHeap(), 0, wstr);
2585 /******************************************************************************
2586 * GetCharABCWidthsW [GDI32.@]
2588 * Retrieves widths of characters in range.
2591 * hdc [I] Handle of device context
2592 * firstChar [I] First character in range to query
2593 * lastChar [I] Last character in range to query
2594 * abc [O] Address of character-width structure
2597 * Only works with TrueType fonts
2603 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2606 DC *dc = get_dc_ptr(hdc);
2612 if (!dc) return FALSE;
2616 release_dc_ptr( dc );
2620 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2621 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2622 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2624 release_dc_ptr( dc );
2628 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2629 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2632 /* convert device units to logical */
2633 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2634 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2635 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2636 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2640 release_dc_ptr( dc );
2645 /******************************************************************************
2646 * GetCharABCWidthsI [GDI32.@]
2648 * Retrieves widths of characters in range.
2651 * hdc [I] Handle of device context
2652 * firstChar [I] First glyphs in range to query
2653 * count [I] Last glyphs in range to query
2654 * pgi [i] Array of glyphs to query
2655 * abc [O] Address of character-width structure
2658 * Only works with TrueType fonts
2664 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2665 LPWORD pgi, LPABC abc)
2667 DC *dc = get_dc_ptr(hdc);
2672 if (!dc) return FALSE;
2676 release_dc_ptr( dc );
2680 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2681 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2684 /* convert device units to logical */
2685 for( i = 0; i < count; i++, abc++ ) {
2686 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2687 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2688 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2692 release_dc_ptr( dc );
2697 /***********************************************************************
2698 * GetGlyphOutlineA (GDI32.@)
2700 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2701 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2702 LPVOID lpBuffer, const MAT2 *lpmat2 )
2704 if (!lpmat2) return GDI_ERROR;
2706 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2711 cp = GdiGetCodePage(hdc);
2712 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2714 mbchs[0] = (uChar & 0xff00) >> 8;
2715 mbchs[1] = (uChar & 0xff);
2718 mbchs[0] = (uChar & 0xff);
2721 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2724 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2728 /***********************************************************************
2729 * GetGlyphOutlineW (GDI32.@)
2731 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2732 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2733 LPVOID lpBuffer, const MAT2 *lpmat2 )
2739 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2740 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2742 if (!lpmat2) return GDI_ERROR;
2744 dc = get_dc_ptr(hdc);
2745 if(!dc) return GDI_ERROR;
2747 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2748 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2749 release_dc_ptr( dc );
2754 /***********************************************************************
2755 * CreateScalableFontResourceA (GDI32.@)
2757 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2758 LPCSTR lpszResourceFile,
2759 LPCSTR lpszFontFile,
2760 LPCSTR lpszCurrentPath )
2762 LPWSTR lpszResourceFileW = NULL;
2763 LPWSTR lpszFontFileW = NULL;
2764 LPWSTR lpszCurrentPathW = NULL;
2768 if (lpszResourceFile)
2770 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2771 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2772 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2777 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2778 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2779 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2782 if (lpszCurrentPath)
2784 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2785 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2786 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2789 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2790 lpszFontFileW, lpszCurrentPathW);
2792 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2793 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2794 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2799 /***********************************************************************
2800 * CreateScalableFontResourceW (GDI32.@)
2802 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2803 LPCWSTR font_file, LPCWSTR font_path )
2805 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2806 debugstr_w(font_file), debugstr_w(font_path) );
2808 return WineEngCreateScalableFontResource( hidden, resource_file,
2809 font_file, font_path );
2812 /*************************************************************************
2813 * GetKerningPairsA (GDI32.@)
2815 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2816 LPKERNINGPAIR kern_pairA )
2820 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2821 KERNINGPAIR *kern_pairW;
2823 if (!cPairs && kern_pairA)
2825 SetLastError(ERROR_INVALID_PARAMETER);
2829 cp = GdiGetCodePage(hDC);
2831 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2832 * to fail on an invalid character for CP_SYMBOL.
2834 cpi.DefaultChar[0] = 0;
2835 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2837 FIXME("Can't find codepage %u info\n", cp);
2841 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2842 if (!total_kern_pairs) return 0;
2844 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2845 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2847 for (i = 0; i < total_kern_pairs; i++)
2851 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2854 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2857 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2862 if (kern_pairs_copied >= cPairs) break;
2864 kern_pairA->wFirst = (BYTE)first;
2865 kern_pairA->wSecond = (BYTE)second;
2866 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2869 kern_pairs_copied++;
2872 HeapFree(GetProcessHeap(), 0, kern_pairW);
2874 return kern_pairs_copied;
2877 /*************************************************************************
2878 * GetKerningPairsW (GDI32.@)
2880 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2881 LPKERNINGPAIR lpKerningPairs )
2887 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2889 if (!cPairs && lpKerningPairs)
2891 SetLastError(ERROR_INVALID_PARAMETER);
2895 dc = get_dc_ptr(hDC);
2898 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2899 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2900 release_dc_ptr( dc );
2904 /*************************************************************************
2905 * TranslateCharsetInfo [GDI32.@]
2907 * Fills a CHARSETINFO structure for a character set, code page, or
2908 * font. This allows making the correspondence between different labels
2909 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2910 * of the same encoding.
2912 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2913 * only one codepage should be set in *lpSrc.
2916 * TRUE on success, FALSE on failure.
2919 BOOL WINAPI TranslateCharsetInfo(
2920 LPDWORD lpSrc, /* [in]
2921 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2922 if flags == TCI_SRCCHARSET: a character set value
2923 if flags == TCI_SRCCODEPAGE: a code page value
2925 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2926 DWORD flags /* [in] determines interpretation of lpSrc */)
2930 case TCI_SRCFONTSIG:
2931 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2933 case TCI_SRCCODEPAGE:
2934 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2936 case TCI_SRCCHARSET:
2937 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2942 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2943 *lpCs = FONT_tci[index];
2947 /*************************************************************************
2948 * GetFontLanguageInfo (GDI32.@)
2950 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2952 FONTSIGNATURE fontsig;
2953 static const DWORD GCP_DBCS_MASK=0x003F0000,
2954 GCP_DIACRITIC_MASK=0x00000000,
2955 FLI_GLYPHS_MASK=0x00000000,
2956 GCP_GLYPHSHAPE_MASK=0x00000040,
2957 GCP_KASHIDA_MASK=0x00000000,
2958 GCP_LIGATE_MASK=0x00000000,
2959 GCP_USEKERNING_MASK=0x00000000,
2960 GCP_REORDER_MASK=0x00000060;
2964 GetTextCharsetInfo( hdc, &fontsig, 0 );
2965 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2967 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2970 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2971 result|=GCP_DIACRITIC;
2973 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2976 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2977 result|=GCP_GLYPHSHAPE;
2979 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2980 result|=GCP_KASHIDA;
2982 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2985 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2986 result|=GCP_USEKERNING;
2988 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2989 if( GetTextAlign( hdc) & TA_RTLREADING )
2990 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2991 result|=GCP_REORDER;
2997 /*************************************************************************
2998 * GetFontData [GDI32.@]
3000 * Retrieve data for TrueType font.
3004 * success: Number of bytes returned
3005 * failure: GDI_ERROR
3009 * Calls SetLastError()
3012 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3013 LPVOID buffer, DWORD length)
3015 DC *dc = get_dc_ptr(hdc);
3019 if(!dc) return GDI_ERROR;
3021 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3022 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3023 release_dc_ptr( dc );
3027 /*************************************************************************
3028 * GetGlyphIndicesA [GDI32.@]
3030 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3031 LPWORD pgi, DWORD flags)
3037 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3038 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3040 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3041 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3042 HeapFree(GetProcessHeap(), 0, lpstrW);
3047 /*************************************************************************
3048 * GetGlyphIndicesW [GDI32.@]
3050 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3051 LPWORD pgi, DWORD flags)
3053 DC *dc = get_dc_ptr(hdc);
3057 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3058 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3060 if(!dc) return GDI_ERROR;
3062 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3063 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3064 release_dc_ptr( dc );
3068 /*************************************************************************
3069 * GetCharacterPlacementA [GDI32.@]
3071 * See GetCharacterPlacementW.
3074 * the web browser control of ie4 calls this with dwFlags=0
3077 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3078 INT nMaxExtent, GCP_RESULTSA *lpResults,
3083 GCP_RESULTSW resultsW;
3087 TRACE("%s, %d, %d, 0x%08x\n",
3088 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3090 /* both structs are equal in size */
3091 memcpy(&resultsW, lpResults, sizeof(resultsW));
3093 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3094 if(lpResults->lpOutString)
3095 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3097 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3099 lpResults->nGlyphs = resultsW.nGlyphs;
3100 lpResults->nMaxFit = resultsW.nMaxFit;
3102 if(lpResults->lpOutString) {
3103 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3104 lpResults->lpOutString, uCount, NULL, NULL );
3107 HeapFree(GetProcessHeap(), 0, lpStringW);
3108 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3113 /*************************************************************************
3114 * GetCharacterPlacementW [GDI32.@]
3116 * Retrieve information about a string. This includes the width, reordering,
3117 * Glyphing and so on.
3121 * The width and height of the string if successful, 0 if failed.
3125 * All flags except GCP_REORDER are not yet implemented.
3126 * Reordering is not 100% compliant to the Windows BiDi method.
3127 * Caret positioning is not yet implemented for BiDi.
3128 * Classes are not yet implemented.
3132 GetCharacterPlacementW(
3133 HDC hdc, /* [in] Device context for which the rendering is to be done */
3134 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3135 INT uCount, /* [in] Number of WORDS in string. */
3136 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3137 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
3138 DWORD dwFlags /* [in] Flags specifying how to process the string */
3145 TRACE("%s, %d, %d, 0x%08x\n",
3146 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3148 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3149 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3150 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3151 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3152 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3154 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
3155 if(lpResults->lpClass) FIXME("classes not implemented\n");
3156 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3157 FIXME("Caret positions for complex scripts not implemented\n");
3159 nSet = (UINT)uCount;
3160 if(nSet > lpResults->nGlyphs)
3161 nSet = lpResults->nGlyphs;
3163 /* return number of initialized fields */
3164 lpResults->nGlyphs = nSet;
3166 if((dwFlags&GCP_REORDER)==0 )
3168 /* Treat the case where no special handling was requested in a fastpath way */
3169 /* copy will do if the GCP_REORDER flag is not set */
3170 if(lpResults->lpOutString)
3171 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3173 if(lpResults->lpOrder)
3175 for(i = 0; i < nSet; i++)
3176 lpResults->lpOrder[i] = i;
3180 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3181 nSet, lpResults->lpOrder, NULL, NULL );
3184 /* FIXME: Will use the placement chars */
3185 if (lpResults->lpDx)
3188 for (i = 0; i < nSet; i++)
3190 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3191 lpResults->lpDx[i]= c;
3195 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3199 lpResults->lpCaretPos[0] = 0;
3200 for (i = 1; i < nSet; i++)
3201 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3202 lpResults->lpCaretPos[i] = (pos += size.cx);
3205 if(lpResults->lpGlyphs)
3206 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3208 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3209 ret = MAKELONG(size.cx, size.cy);
3214 /*************************************************************************
3215 * GetCharABCWidthsFloatA [GDI32.@]
3217 * See GetCharABCWidthsFloatW.
3219 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3226 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3230 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3232 for (i = 0; i < wlen; i++)
3234 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3242 HeapFree( GetProcessHeap(), 0, str );
3243 HeapFree( GetProcessHeap(), 0, wstr );
3248 /*************************************************************************
3249 * GetCharABCWidthsFloatW [GDI32.@]
3251 * Retrieves widths of a range of characters.
3254 * hdc [I] Handle to device context.
3255 * first [I] First character in range to query.
3256 * last [I] Last character in range to query.
3257 * abcf [O] Array of LPABCFLOAT structures.
3263 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3269 DC *dc = get_dc_ptr( hdc );
3271 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3273 if (!dc) return FALSE;
3275 if (!abcf) goto done;
3276 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3278 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3279 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3282 /* convert device units to logical */
3283 for (i = first; i <= last; i++, abcf++)
3285 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3286 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3287 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3290 HeapFree( GetProcessHeap(), 0, abc );
3293 release_dc_ptr( dc );
3297 /*************************************************************************
3298 * GetCharWidthFloatA [GDI32.@]
3300 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3301 UINT iLastChar, PFLOAT pxBuffer)
3303 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3307 /*************************************************************************
3308 * GetCharWidthFloatW [GDI32.@]
3310 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3311 UINT iLastChar, PFLOAT pxBuffer)
3313 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3318 /***********************************************************************
3320 * Font Resource API *
3322 ***********************************************************************/
3324 /***********************************************************************
3325 * AddFontResourceA (GDI32.@)
3327 INT WINAPI AddFontResourceA( LPCSTR str )
3329 return AddFontResourceExA( str, 0, NULL);
3332 /***********************************************************************
3333 * AddFontResourceW (GDI32.@)
3335 INT WINAPI AddFontResourceW( LPCWSTR str )
3337 return AddFontResourceExW(str, 0, NULL);
3341 /***********************************************************************
3342 * AddFontResourceExA (GDI32.@)
3344 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3346 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3347 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3350 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3351 ret = AddFontResourceExW(strW, fl, pdv);
3352 HeapFree(GetProcessHeap(), 0, strW);
3356 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3358 HRSRC rsrc = FindResourceW(hModule, name, type);
3359 HGLOBAL hMem = LoadResource(hModule, rsrc);
3360 LPVOID *pMem = LockResource(hMem);
3361 int *num_total = (int *)lParam;
3364 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3365 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3367 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3371 *num_total += num_in_res;
3375 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3377 HANDLE file, mapping;
3380 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3381 if (file == INVALID_HANDLE_VALUE) return NULL;
3383 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3385 CloseHandle( file );
3389 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3390 CloseHandle( file );
3391 if (!mapping) return NULL;
3393 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3394 CloseHandle( mapping );
3399 static WCHAR *get_scalable_filename( const WCHAR *res )
3402 BYTE *ptr = map_file( res, &size );
3403 const IMAGE_DOS_HEADER *dos;
3404 const IMAGE_OS2_HEADER *ne;
3406 WORD rsrc_off, align, type_id, count;
3407 DWORD res_off, res_len, i;
3410 if (!ptr) return NULL;
3412 if (size.u.LowPart < sizeof( *dos )) goto fail;
3413 dos = (const IMAGE_DOS_HEADER *)ptr;
3414 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3415 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3416 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3417 rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
3418 if (size.u.LowPart < rsrc_off + 10) goto fail;
3419 align = *(WORD *)(ptr + rsrc_off);
3421 type_id = *(WORD *)(ptr + rsrc_off);
3422 while (type_id && type_id != 0x80cc)
3424 count = *(WORD *)(ptr + rsrc_off + 2);
3425 rsrc_off += 8 + count * 12;
3426 if (size.u.LowPart < rsrc_off + 8) goto fail;
3427 type_id = *(WORD *)(ptr + rsrc_off);
3429 if (!type_id) goto fail;
3430 count = *(WORD *)(ptr + rsrc_off + 2);
3431 if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;
3433 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3434 res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
3435 if (size.u.LowPart < res_off + res_len) goto fail;
3437 for (i = 0; i < res_len; i++)
3438 if (ptr[ res_off + i ] == 0) break;
3439 if (i == res_len) goto fail;
3441 len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
3442 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3443 if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );
3446 UnmapViewOfFile( ptr );
3450 /***********************************************************************
3451 * AddFontResourceExW (GDI32.@)
3453 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3455 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3460 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3461 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3462 if (hModule != NULL)
3464 int num_resources = 0;
3465 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3467 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3468 wine_dbgstr_w(str));
3469 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3470 ret = num_resources;
3471 FreeLibrary(hModule);
3473 else if ((filename = get_scalable_filename( str )) != NULL)
3475 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3476 HeapFree( GetProcessHeap(), 0, filename );
3482 /***********************************************************************
3483 * RemoveFontResourceA (GDI32.@)
3485 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3487 return RemoveFontResourceExA(str, 0, 0);
3490 /***********************************************************************
3491 * RemoveFontResourceW (GDI32.@)
3493 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3495 return RemoveFontResourceExW(str, 0, 0);
3498 /***********************************************************************
3499 * AddFontMemResourceEx (GDI32.@)
3501 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3506 if (!pbFont || !cbFont || !pcFonts)
3508 SetLastError(ERROR_INVALID_PARAMETER);
3512 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3517 *pcFonts = num_fonts;
3521 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3522 RemoveFontMemResourceEx(ret);
3530 /***********************************************************************
3531 * RemoveFontMemResourceEx (GDI32.@)
3533 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3535 FIXME("(%p) stub\n", fh);
3539 /***********************************************************************
3540 * RemoveFontResourceExA (GDI32.@)
3542 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3544 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3545 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3548 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3549 ret = RemoveFontResourceExW(strW, fl, pdv);
3550 HeapFree(GetProcessHeap(), 0, strW);
3554 /***********************************************************************
3555 * RemoveFontResourceExW (GDI32.@)
3557 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3559 return WineEngRemoveFontResourceEx(str, fl, pdv);
3562 /***********************************************************************
3563 * GetTextCharset (GDI32.@)
3565 UINT WINAPI GetTextCharset(HDC hdc)
3567 /* MSDN docs say this is equivalent */
3568 return GetTextCharsetInfo(hdc, NULL, 0);
3571 /***********************************************************************
3572 * GetTextCharsetInfo (GDI32.@)
3574 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3576 UINT ret = DEFAULT_CHARSET;
3577 DC *dc = get_dc_ptr(hdc);
3582 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3583 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3584 release_dc_ptr( dc );
3587 if (ret == DEFAULT_CHARSET && fs)
3588 memset(fs, 0, sizeof(FONTSIGNATURE));
3592 /***********************************************************************
3593 * GdiGetCharDimensions (GDI32.@)
3595 * Gets the average width of the characters in the English alphabet.
3598 * hdc [I] Handle to the device context to measure on.
3599 * lptm [O] Pointer to memory to store the text metrics into.
3600 * height [O] On exit, the maximum height of characters in the English alphabet.
3603 * The average width of characters in the English alphabet.
3606 * This function is used by the dialog manager to get the size of a dialog
3607 * unit. It should also be used by other pieces of code that need to know
3608 * the size of a dialog unit in logical units without having access to the
3609 * window handle of the dialog.
3610 * Windows caches the font metrics from this function, but we don't and
3611 * there doesn't appear to be an immediate advantage to do so.
3614 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3616 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3619 static const WCHAR alphabet[] = {
3620 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3621 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3622 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3624 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3626 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3628 if (height) *height = sz.cy;
3629 return (sz.cx / 26 + 1) / 2;
3632 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3634 FIXME("(%d): stub\n", fEnableEUDC);
3638 /***********************************************************************
3639 * GetCharWidthI (GDI32.@)
3641 * Retrieve widths of characters.
3644 * hdc [I] Handle to a device context.
3645 * first [I] First glyph in range to query.
3646 * count [I] Number of glyph indices to query.
3647 * glyphs [I] Array of glyphs to query.
3648 * buffer [O] Buffer to receive character widths.
3651 * Only works with TrueType fonts.
3657 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3662 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3664 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3667 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3669 HeapFree(GetProcessHeap(), 0, abc);
3673 for (i = 0; i < count; i++)
3674 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3676 HeapFree(GetProcessHeap(), 0, abc);
3680 /***********************************************************************
3681 * GetFontUnicodeRanges (GDI32.@)
3683 * Retrieve a list of supported Unicode characters in a font.
3686 * hdc [I] Handle to a device context.
3687 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3690 * Success: Number of bytes written to the buffer pointed to by lpgs.
3694 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3698 DC *dc = get_dc_ptr(hdc);
3700 TRACE("(%p, %p)\n", hdc, lpgs);
3704 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3705 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3711 /*************************************************************
3712 * FontIsLinked (GDI32.@)
3714 BOOL WINAPI FontIsLinked(HDC hdc)
3716 DC *dc = get_dc_ptr(hdc);
3720 if (!dc) return FALSE;
3721 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3722 ret = dev->funcs->pFontIsLinked( dev );
3724 TRACE("returning %d\n", ret);
3728 /*************************************************************
3729 * GdiRealizationInfo (GDI32.@)
3731 * Returns a structure that contains some font information.
3733 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3735 DC *dc = get_dc_ptr(hdc);
3739 if (!dc) return FALSE;
3740 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3741 ret = dev->funcs->pGdiRealizationInfo( dev, info );