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;
311 /* compute positions for text rendering, in device coords */
312 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
315 PHYSDEV dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
317 size->cx = size->cy = 0;
318 if (!count) return TRUE;
320 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
321 dev->funcs->pGetTextMetrics( dev, &tm );
323 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
325 if (dc->breakExtra || dc->breakRem)
327 int i, space = 0, rem = dc->breakRem;
329 for (i = 0; i < count; i++)
331 if (str[i] == tm.tmBreakChar)
333 space += dc->breakExtra;
343 size->cx = dx[count - 1];
344 size->cy = tm.tmHeight;
348 /* compute positions for text rendering, in device coords */
349 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
352 PHYSDEV dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
354 size->cx = size->cy = 0;
355 if (!count) return TRUE;
357 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
358 dev->funcs->pGetTextMetrics( dev, &tm );
360 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
362 if (dc->breakExtra || dc->breakRem)
365 int i, space = 0, rem = dc->breakRem;
367 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
368 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
370 for (i = 0; i < count; i++)
372 if (indices[i] == space_index)
374 space += dc->breakExtra;
384 size->cx = dx[count - 1];
385 size->cy = tm.tmHeight;
389 /***********************************************************************
390 * GdiGetCodePage (GDI32.@)
392 DWORD WINAPI GdiGetCodePage( HDC hdc )
395 DC *dc = get_dc_ptr( hdc );
399 cp = dc->font_code_page;
400 release_dc_ptr( dc );
405 /***********************************************************************
408 * Returns a Unicode translation of str using the charset of the
409 * currently selected font in hdc. If count is -1 then str is assumed
410 * to be '\0' terminated, otherwise it contains the number of bytes to
411 * convert. If plenW is non-NULL, on return it will point to the
412 * number of WCHARs that have been written. If pCP is non-NULL, on
413 * return it will point to the codepage used in the conversion. The
414 * caller should free the returned LPWSTR from the process heap
417 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
423 cp = GdiGetCodePage( hdc );
425 if(count == -1) count = strlen(str);
426 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
427 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
428 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
429 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
430 if(plenW) *plenW = lenW;
435 /***********************************************************************
436 * CreateFontIndirectExA (GDI32.@)
438 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
440 ENUMLOGFONTEXDVW enumexW;
442 if (!penumexA) return 0;
444 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
445 enumexW.elfDesignVector = penumexA->elfDesignVector;
446 return CreateFontIndirectExW( &enumexW );
449 /***********************************************************************
450 * CreateFontIndirectExW (GDI32.@)
452 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
458 if (!penumex) return 0;
460 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
461 penumex->elfEnumLogfontEx.elfStyle[0] ||
462 penumex->elfEnumLogfontEx.elfScript[0])
464 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
465 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
466 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
467 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
470 plf = &penumex->elfEnumLogfontEx.elfLogFont;
471 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
473 fontPtr->logfont = *plf;
475 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
477 HeapFree( GetProcessHeap(), 0, fontPtr );
481 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
482 plf->lfHeight, plf->lfWidth,
483 plf->lfEscapement, plf->lfOrientation,
484 plf->lfPitchAndFamily,
485 plf->lfOutPrecision, plf->lfClipPrecision,
486 plf->lfQuality, plf->lfCharSet,
487 debugstr_w(plf->lfFaceName),
488 plf->lfWeight > 400 ? "Bold" : "",
489 plf->lfItalic ? "Italic" : "",
490 plf->lfUnderline ? "Underline" : "", hFont);
495 /***********************************************************************
496 * CreateFontIndirectA (GDI32.@)
498 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
504 FONT_LogFontAToW( plfA, &lfW );
505 return CreateFontIndirectW( &lfW );
508 /***********************************************************************
509 * CreateFontIndirectW (GDI32.@)
511 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
513 ENUMLOGFONTEXDVW exdv;
517 exdv.elfEnumLogfontEx.elfLogFont = *plf;
518 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
519 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
520 exdv.elfEnumLogfontEx.elfScript[0] = 0;
521 return CreateFontIndirectExW( &exdv );
524 /*************************************************************************
525 * CreateFontA (GDI32.@)
527 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
528 INT orient, INT weight, DWORD italic,
529 DWORD underline, DWORD strikeout, DWORD charset,
530 DWORD outpres, DWORD clippres, DWORD quality,
531 DWORD pitch, LPCSTR name )
535 logfont.lfHeight = height;
536 logfont.lfWidth = width;
537 logfont.lfEscapement = esc;
538 logfont.lfOrientation = orient;
539 logfont.lfWeight = weight;
540 logfont.lfItalic = italic;
541 logfont.lfUnderline = underline;
542 logfont.lfStrikeOut = strikeout;
543 logfont.lfCharSet = charset;
544 logfont.lfOutPrecision = outpres;
545 logfont.lfClipPrecision = clippres;
546 logfont.lfQuality = quality;
547 logfont.lfPitchAndFamily = pitch;
550 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
552 logfont.lfFaceName[0] = '\0';
554 return CreateFontIndirectA( &logfont );
557 /*************************************************************************
558 * CreateFontW (GDI32.@)
560 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
561 INT orient, INT weight, DWORD italic,
562 DWORD underline, DWORD strikeout, DWORD charset,
563 DWORD outpres, DWORD clippres, DWORD quality,
564 DWORD pitch, LPCWSTR name )
568 logfont.lfHeight = height;
569 logfont.lfWidth = width;
570 logfont.lfEscapement = esc;
571 logfont.lfOrientation = orient;
572 logfont.lfWeight = weight;
573 logfont.lfItalic = italic;
574 logfont.lfUnderline = underline;
575 logfont.lfStrikeOut = strikeout;
576 logfont.lfCharSet = charset;
577 logfont.lfOutPrecision = outpres;
578 logfont.lfClipPrecision = clippres;
579 logfont.lfQuality = quality;
580 logfont.lfPitchAndFamily = pitch;
583 lstrcpynW(logfont.lfFaceName, name,
584 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
586 logfont.lfFaceName[0] = '\0';
588 return CreateFontIndirectW( &logfont );
591 static void update_font_code_page( DC *dc )
594 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
596 /* Hmm, nicely designed api this one! */
597 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
598 dc->font_code_page = csi.ciACP;
602 dc->font_code_page = GetOEMCP();
604 case DEFAULT_CHARSET:
605 dc->font_code_page = GetACP();
615 /* FIXME: These have no place here, but because x11drv
616 enumerates fonts with these (made up) charsets some apps
617 might use them and then the FIXME below would become
618 annoying. Now we could pick the intended codepage for
619 each of these, but since it's broken anyway we'll just
620 use CP_ACP and hope it'll go away...
622 dc->font_code_page = CP_ACP;
626 FIXME("Can't find codepage for charset %d\n", charset);
627 dc->font_code_page = CP_ACP;
632 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
635 /***********************************************************************
638 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
641 DC *dc = get_dc_ptr( hdc );
647 if (!GDI_inc_ref_count( handle ))
649 release_dc_ptr( dc );
653 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
654 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
658 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
659 update_font_code_page( dc );
660 GDI_dec_ref_count( ret );
662 else GDI_dec_ref_count( handle );
664 release_dc_ptr( dc );
669 /***********************************************************************
672 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
674 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
680 FONT_LogFontWToA( &font->logfont, &lfA );
681 if (count > sizeof(lfA)) count = sizeof(lfA);
682 memcpy( buffer, &lfA, count );
684 else count = sizeof(lfA);
685 GDI_ReleaseObj( handle );
689 /***********************************************************************
692 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
694 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
699 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
700 memcpy( buffer, &font->logfont, count );
702 else count = sizeof(LOGFONTW);
703 GDI_ReleaseObj( handle );
708 /***********************************************************************
711 static BOOL FONT_DeleteObject( HGDIOBJ handle )
715 if (!(obj = free_gdi_handle( handle ))) return FALSE;
716 return HeapFree( GetProcessHeap(), 0, obj );
720 /***********************************************************************
723 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
725 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
726 'D','e','s','k','t','o','p',0 };
730 if (*aa_flags) return 0;
732 GetObjectW( font, sizeof(lf), &lf );
733 switch (lf.lfQuality)
735 case NONANTIALIASED_QUALITY:
736 *aa_flags = GGO_BITMAP;
738 case ANTIALIASED_QUALITY:
739 *aa_flags = GGO_GRAY4_BITMAP;
741 case CLEARTYPE_QUALITY:
742 case CLEARTYPE_NATURAL_QUALITY:
743 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
744 *aa_flags = get_subpixel_orientation( key );
748 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
749 *aa_flags = get_default_smoothing( key );
757 /***********************************************************************
760 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
761 * We have to use other types because of the FONTENUMPROCW definition.
763 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
764 DWORD fType, LPARAM lp )
766 struct font_enum *pfe = (struct font_enum *)lp;
769 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
770 if ((!pfe->lpLogFontParam ||
771 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
772 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
773 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
775 /* convert font metrics */
776 ENUMLOGFONTEXA logfont;
777 NEWTEXTMETRICEXA tmA;
781 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
782 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
783 plf = (LOGFONTW *)&logfont.elfLogFont;
784 ptm = (TEXTMETRICW *)&tmA;
786 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
792 /***********************************************************************
793 * FONT_EnumFontFamiliesEx
795 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
796 LPARAM lParam, BOOL unicode )
799 DC *dc = get_dc_ptr( hDC );
804 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
806 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
807 fe.lpLogFontParam = plf;
808 fe.lpEnumFunc = efproc;
810 fe.unicode = unicode;
813 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
814 release_dc_ptr( dc );
816 return ret ? fe.retval : 0;
819 /***********************************************************************
820 * EnumFontFamiliesExW (GDI32.@)
822 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
823 FONTENUMPROCW efproc,
824 LPARAM lParam, DWORD dwFlags )
826 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
829 /***********************************************************************
830 * EnumFontFamiliesExA (GDI32.@)
832 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
833 FONTENUMPROCA efproc,
834 LPARAM lParam, DWORD dwFlags)
840 FONT_LogFontAToW( plf, &lfW );
845 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
848 /***********************************************************************
849 * EnumFontFamiliesA (GDI32.@)
851 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
852 FONTENUMPROCA efproc, LPARAM lpData )
858 if (!*lpFamily) return 1;
859 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
860 lf.lfCharSet = DEFAULT_CHARSET;
861 lf.lfPitchAndFamily = 0;
866 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
869 /***********************************************************************
870 * EnumFontFamiliesW (GDI32.@)
872 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
873 FONTENUMPROCW efproc, LPARAM lpData )
879 if (!*lpFamily) return 1;
880 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
881 lf.lfCharSet = DEFAULT_CHARSET;
882 lf.lfPitchAndFamily = 0;
887 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
890 /***********************************************************************
891 * EnumFontsA (GDI32.@)
893 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
896 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
899 /***********************************************************************
900 * EnumFontsW (GDI32.@)
902 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
905 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
909 /***********************************************************************
910 * GetTextCharacterExtra (GDI32.@)
912 INT WINAPI GetTextCharacterExtra( HDC hdc )
915 DC *dc = get_dc_ptr( hdc );
916 if (!dc) return 0x80000000;
918 release_dc_ptr( dc );
923 /***********************************************************************
924 * SetTextCharacterExtra (GDI32.@)
926 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
928 INT ret = 0x80000000;
929 DC * dc = get_dc_ptr( hdc );
933 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
934 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
935 if (extra != 0x80000000)
938 dc->charExtra = extra;
940 release_dc_ptr( dc );
946 /***********************************************************************
947 * SetTextJustification (GDI32.@)
949 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
953 DC * dc = get_dc_ptr( hdc );
955 if (!dc) return FALSE;
957 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
958 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
961 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
962 if (!extra) breaks = 0;
965 dc->breakExtra = extra / breaks;
966 dc->breakRem = extra - (breaks * dc->breakExtra);
974 release_dc_ptr( dc );
979 /***********************************************************************
980 * GetTextFaceA (GDI32.@)
982 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
984 INT res = GetTextFaceW(hdc, 0, NULL);
985 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
986 GetTextFaceW( hdc, res, nameW );
992 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
996 /* GetTextFaceA does NOT include the nul byte in the return count. */
1003 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1004 HeapFree( GetProcessHeap(), 0, nameW );
1008 /***********************************************************************
1009 * GetTextFaceW (GDI32.@)
1011 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1016 DC * dc = get_dc_ptr( hdc );
1019 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1020 ret = dev->funcs->pGetTextFace( dev, count, name );
1021 release_dc_ptr( dc );
1026 /***********************************************************************
1027 * GetTextExtentPoint32A (GDI32.@)
1029 * See GetTextExtentPoint32W.
1031 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1038 if (count < 0) return FALSE;
1040 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1044 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1045 HeapFree( GetProcessHeap(), 0, p );
1048 TRACE("(%p %s %d %p): returning %d x %d\n",
1049 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1054 /***********************************************************************
1055 * GetTextExtentPoint32W [GDI32.@]
1057 * Computes width/height for a string.
1059 * Computes width and height of the specified string.
1065 BOOL WINAPI GetTextExtentPoint32W(
1066 HDC hdc, /* [in] Handle of device context */
1067 LPCWSTR str, /* [in] Address of text string */
1068 INT count, /* [in] Number of characters in string */
1069 LPSIZE size) /* [out] Address of structure for string size */
1071 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1074 /***********************************************************************
1075 * GetTextExtentExPointI [GDI32.@]
1077 * Computes width and height of the array of glyph indices.
1080 * hdc [I] Handle of device context.
1081 * indices [I] Glyph index array.
1082 * count [I] Number of glyphs in array.
1083 * max_ext [I] Maximum width in glyphs.
1084 * nfit [O] Maximum number of characters.
1085 * dxs [O] Partial string widths.
1086 * size [O] Returned string size.
1092 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1093 LPINT nfit, LPINT dxs, LPSIZE size )
1098 INT buffer[256], *pos = dxs;
1100 if (count < 0) return FALSE;
1102 dc = get_dc_ptr( hdc );
1103 if (!dc) return FALSE;
1108 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1110 release_dc_ptr( dc );
1115 ret = get_char_positions_indices( dc, indices, count, pos, size );
1120 for (i = 0; i < count; i++)
1122 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1123 if (dx > (unsigned int)max_ext) break;
1124 if (dxs) dxs[i] = dx;
1126 if (nfit) *nfit = i;
1129 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1130 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1133 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1134 release_dc_ptr( dc );
1136 TRACE("(%p %p %d %p): returning %d x %d\n",
1137 hdc, indices, count, size, size->cx, size->cy );
1141 /***********************************************************************
1142 * GetTextExtentPointI [GDI32.@]
1144 * Computes width and height of the array of glyph indices.
1147 * hdc [I] Handle of device context.
1148 * indices [I] Glyph index array.
1149 * count [I] Number of glyphs in array.
1150 * size [O] Returned string size.
1156 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1158 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1162 /***********************************************************************
1163 * GetTextExtentPointA (GDI32.@)
1165 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1168 TRACE("not bug compatible.\n");
1169 return GetTextExtentPoint32A( hdc, str, count, size );
1172 /***********************************************************************
1173 * GetTextExtentPointW (GDI32.@)
1175 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1178 TRACE("not bug compatible.\n");
1179 return GetTextExtentPoint32W( hdc, str, count, size );
1183 /***********************************************************************
1184 * GetTextExtentExPointA (GDI32.@)
1186 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1187 INT maxExt, LPINT lpnFit,
1188 LPINT alpDx, LPSIZE size )
1195 if (count < 0) return FALSE;
1196 if (maxExt < -1) return FALSE;
1200 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1201 if (!walpDx) return FALSE;
1204 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1205 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1208 INT n = lpnFit ? *lpnFit : wlen;
1210 for(i = 0, j = 0; i < n; i++, j++)
1212 alpDx[j] = walpDx[i];
1213 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1216 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1217 HeapFree( GetProcessHeap(), 0, p );
1218 HeapFree( GetProcessHeap(), 0, walpDx );
1223 /***********************************************************************
1224 * GetTextExtentExPointW (GDI32.@)
1226 * Return the size of the string as it would be if it was output properly by
1229 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1230 LPINT nfit, LPINT dxs, LPSIZE size )
1235 INT buffer[256], *pos = dxs;
1237 if (count < 0) return FALSE;
1239 dc = get_dc_ptr(hdc);
1240 if (!dc) return FALSE;
1245 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1247 release_dc_ptr( dc );
1252 ret = get_char_positions( dc, str, count, pos, size );
1257 for (i = 0; i < count; i++)
1259 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1260 if (dx > (unsigned int)max_ext) break;
1261 if (dxs) dxs[i] = dx;
1263 if (nfit) *nfit = i;
1266 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1267 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1270 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1271 release_dc_ptr( dc );
1273 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1277 /***********************************************************************
1278 * GetTextMetricsA (GDI32.@)
1280 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1284 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1285 FONT_TextMetricWToA( &tm32, metrics );
1289 /***********************************************************************
1290 * GetTextMetricsW (GDI32.@)
1292 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1296 DC * dc = get_dc_ptr( hdc );
1297 if (!dc) return FALSE;
1299 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1300 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1304 /* device layer returns values in device units
1305 * therefore we have to convert them to logical */
1307 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1308 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1310 #define WDPTOLP(x) ((x<0)? \
1311 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1312 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1313 #define HDPTOLP(y) ((y<0)? \
1314 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1315 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1317 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1318 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1319 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1320 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1321 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1322 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1323 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1324 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1328 TRACE("text metrics:\n"
1329 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1330 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1331 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1332 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1333 " PitchAndFamily = %02x\n"
1334 " --------------------\n"
1335 " InternalLeading = %i\n"
1339 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1340 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1341 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1342 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1343 metrics->tmPitchAndFamily,
1344 metrics->tmInternalLeading,
1347 metrics->tmHeight );
1349 release_dc_ptr( dc );
1354 /***********************************************************************
1355 * GetOutlineTextMetricsA (GDI32.@)
1356 * Gets metrics for TrueType fonts.
1359 * If the supplied buffer isn't big enough Windows partially fills it up to
1360 * its given length and returns that length.
1363 * Success: Non-zero or size of required buffer
1366 UINT WINAPI GetOutlineTextMetricsA(
1367 HDC hdc, /* [in] Handle of device context */
1368 UINT cbData, /* [in] Size of metric data array */
1369 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1371 char buf[512], *ptr;
1373 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1374 OUTLINETEXTMETRICA *output = lpOTM;
1377 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1379 if(ret > sizeof(buf))
1380 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1381 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1383 needed = sizeof(OUTLINETEXTMETRICA);
1384 if(lpOTMW->otmpFamilyName)
1385 needed += WideCharToMultiByte(CP_ACP, 0,
1386 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1387 NULL, 0, NULL, NULL);
1388 if(lpOTMW->otmpFaceName)
1389 needed += WideCharToMultiByte(CP_ACP, 0,
1390 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1391 NULL, 0, NULL, NULL);
1392 if(lpOTMW->otmpStyleName)
1393 needed += WideCharToMultiByte(CP_ACP, 0,
1394 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1395 NULL, 0, NULL, NULL);
1396 if(lpOTMW->otmpFullName)
1397 needed += WideCharToMultiByte(CP_ACP, 0,
1398 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1399 NULL, 0, NULL, NULL);
1406 TRACE("needed = %d\n", needed);
1408 /* Since the supplied buffer isn't big enough, we'll alloc one
1409 that is and memcpy the first cbData bytes into the lpOTM at
1411 output = HeapAlloc(GetProcessHeap(), 0, needed);
1413 ret = output->otmSize = min(needed, cbData);
1414 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1415 output->otmFiller = 0;
1416 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1417 output->otmfsSelection = lpOTMW->otmfsSelection;
1418 output->otmfsType = lpOTMW->otmfsType;
1419 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1420 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1421 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1422 output->otmEMSquare = lpOTMW->otmEMSquare;
1423 output->otmAscent = lpOTMW->otmAscent;
1424 output->otmDescent = lpOTMW->otmDescent;
1425 output->otmLineGap = lpOTMW->otmLineGap;
1426 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1427 output->otmsXHeight = lpOTMW->otmsXHeight;
1428 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1429 output->otmMacAscent = lpOTMW->otmMacAscent;
1430 output->otmMacDescent = lpOTMW->otmMacDescent;
1431 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1432 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1433 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1434 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1435 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1436 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1437 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1438 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1439 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1440 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1443 ptr = (char*)(output + 1);
1444 left = needed - sizeof(*output);
1446 if(lpOTMW->otmpFamilyName) {
1447 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1448 len = WideCharToMultiByte(CP_ACP, 0,
1449 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1450 ptr, left, NULL, NULL);
1454 output->otmpFamilyName = 0;
1456 if(lpOTMW->otmpFaceName) {
1457 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1458 len = WideCharToMultiByte(CP_ACP, 0,
1459 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1460 ptr, left, NULL, NULL);
1464 output->otmpFaceName = 0;
1466 if(lpOTMW->otmpStyleName) {
1467 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1468 len = WideCharToMultiByte(CP_ACP, 0,
1469 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1470 ptr, left, NULL, NULL);
1474 output->otmpStyleName = 0;
1476 if(lpOTMW->otmpFullName) {
1477 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1478 len = WideCharToMultiByte(CP_ACP, 0,
1479 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1480 ptr, left, NULL, NULL);
1483 output->otmpFullName = 0;
1487 if(output != lpOTM) {
1488 memcpy(lpOTM, output, cbData);
1489 HeapFree(GetProcessHeap(), 0, output);
1491 /* check if the string offsets really fit into the provided size */
1492 /* FIXME: should we check string length as well? */
1493 /* make sure that we don't read/write beyond the provided buffer */
1494 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1496 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1497 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1500 /* make sure that we don't read/write beyond the provided buffer */
1501 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1503 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1504 lpOTM->otmpFaceName = 0; /* doesn't fit */
1507 /* make sure that we don't read/write beyond the provided buffer */
1508 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1510 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1511 lpOTM->otmpStyleName = 0; /* doesn't fit */
1514 /* make sure that we don't read/write beyond the provided buffer */
1515 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1517 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1518 lpOTM->otmpFullName = 0; /* doesn't fit */
1523 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1524 HeapFree(GetProcessHeap(), 0, lpOTMW);
1530 /***********************************************************************
1531 * GetOutlineTextMetricsW [GDI32.@]
1533 UINT WINAPI GetOutlineTextMetricsW(
1534 HDC hdc, /* [in] Handle of device context */
1535 UINT cbData, /* [in] Size of metric data array */
1536 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1538 DC *dc = get_dc_ptr( hdc );
1539 OUTLINETEXTMETRICW *output = lpOTM;
1543 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1546 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1547 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1549 if (lpOTM && ret > cbData)
1551 output = HeapAlloc(GetProcessHeap(), 0, ret);
1552 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1557 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1558 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1560 #define WDPTOLP(x) ((x<0)? \
1561 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1562 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1563 #define HDPTOLP(y) ((y<0)? \
1564 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1565 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1567 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1568 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1569 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1570 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1571 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1572 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1573 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1574 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1575 output->otmAscent = HDPTOLP(output->otmAscent);
1576 output->otmDescent = HDPTOLP(output->otmDescent);
1577 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1578 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1579 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1580 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1581 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1582 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1583 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1584 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1585 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1586 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1587 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1588 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1589 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1590 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1591 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1592 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1593 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1594 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1595 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1596 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1597 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1598 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1603 memcpy(lpOTM, output, cbData);
1604 HeapFree(GetProcessHeap(), 0, output);
1612 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1614 INT i, count = lastChar - firstChar + 1;
1622 mbcp = GdiGetCodePage(hdc);
1630 if (lastChar > 0xffff)
1632 if ((firstChar ^ lastChar) > 0xff)
1636 if (lastChar > 0xff)
1642 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1646 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1650 str[i++] = (BYTE)(c >> 8);
1651 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1652 str[i] = 0x1f; /* FIXME: use default character */
1666 /***********************************************************************
1667 * GetCharWidthW (GDI32.@)
1668 * GetCharWidth32W (GDI32.@)
1670 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1676 DC * dc = get_dc_ptr( hdc );
1678 if (!dc) return FALSE;
1680 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1681 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1685 /* convert device units to logical */
1686 for( i = firstChar; i <= lastChar; i++, buffer++ )
1687 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1689 release_dc_ptr( dc );
1694 /***********************************************************************
1695 * GetCharWidthA (GDI32.@)
1696 * GetCharWidth32A (GDI32.@)
1698 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1706 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1710 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1712 for(i = 0; i < wlen; i++)
1714 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1722 HeapFree(GetProcessHeap(), 0, str);
1723 HeapFree(GetProcessHeap(), 0, wstr);
1729 /* helper for nulldrv_ExtTextOut */
1730 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1731 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1733 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1734 UINT indices[3] = {0, 0, 0x20};
1740 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1742 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1745 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1746 if (ret != GDI_ERROR) break;
1749 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1750 if (!image) return ERROR_SUCCESS;
1754 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1756 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1757 size = metrics->gmBlackBoxY * stride;
1759 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1760 image->is_copy = TRUE;
1761 image->free = free_heap_bits;
1763 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1764 if (ret == GDI_ERROR)
1766 HeapFree( GetProcessHeap(), 0, image->ptr );
1767 return ERROR_NOT_FOUND;
1769 return ERROR_SUCCESS;
1772 /* helper for nulldrv_ExtTextOut */
1773 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1774 LPCWSTR str, UINT count, const INT *dx )
1779 reset_bounds( &bounds );
1780 for (i = 0; i < count; i++)
1782 GLYPHMETRICS metrics;
1784 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1786 rect.left = x + metrics.gmptGlyphOrigin.x;
1787 rect.top = y - metrics.gmptGlyphOrigin.y;
1788 rect.right = rect.left + metrics.gmBlackBoxX;
1789 rect.bottom = rect.top + metrics.gmBlackBoxY;
1790 add_bounds_rect( &bounds, &rect );
1794 if (flags & ETO_PDY)
1797 y += dx[ i * 2 + 1];
1803 x += metrics.gmCellIncX;
1804 y += metrics.gmCellIncY;
1810 /* helper for nulldrv_ExtTextOut */
1811 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1812 const struct gdi_image_bits *image, const RECT *clip )
1814 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1815 UINT x, y, i, count, max_count;
1816 BYTE *ptr = image->ptr;
1817 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1819 RECT rect, clipped_rect;
1821 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1822 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1823 rect.right = rect.left + metrics->gmBlackBoxX;
1824 rect.bottom = rect.top + metrics->gmBlackBoxY;
1825 if (!clip) clipped_rect = rect;
1826 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1828 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1829 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1833 ptr += (clipped_rect.top - rect.top) * stride;
1834 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1836 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1838 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1839 pts[count].x = rect.left + x;
1840 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1841 pts[count + 1].x = rect.left + x;
1842 if (pts[count + 1].x > pts[count].x)
1844 pts[count].y = pts[count + 1].y = y;
1849 assert( count <= max_count );
1850 DPtoLP( hdc, pts, count );
1851 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1852 HeapFree( GetProcessHeap(), 0, pts );
1855 /***********************************************************************
1856 * nulldrv_ExtTextOut
1858 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1859 LPCWSTR str, UINT count, const INT *dx )
1861 DC *dc = get_nulldrv_dc( dev );
1867 if (flags & ETO_OPAQUE)
1870 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1874 orig = SelectObject( dev->hdc, brush );
1875 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1876 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1877 SelectObject( dev->hdc, orig );
1878 DeleteObject( brush );
1882 if (!count) return TRUE;
1884 if (dc->aa_flags != GGO_BITMAP)
1886 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1887 BITMAPINFO *info = (BITMAPINFO *)buffer;
1888 struct gdi_image_bits bits;
1889 struct bitblt_coords src, dst;
1891 /* FIXME Subpixel modes */
1892 UINT aa_flags = GGO_GRAY4_BITMAP;
1894 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1895 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1896 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1897 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1899 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1900 src.x = src.visrect.left;
1901 src.y = src.visrect.top;
1902 src.width = src.visrect.right - src.visrect.left;
1903 src.height = src.visrect.bottom - src.visrect.top;
1905 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1906 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1908 /* we can avoid the GetImage, just query the needed format */
1909 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1910 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1911 info->bmiHeader.biWidth = src.width;
1912 info->bmiHeader.biHeight = -src.height;
1913 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1914 if (!err || err == ERROR_BAD_FORMAT)
1916 /* make the source rectangle relative to the source bits */
1918 src.visrect.left = src.visrect.top = 0;
1919 src.visrect.right = src.width;
1920 src.visrect.bottom = src.height;
1922 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1923 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1924 bits.is_copy = TRUE;
1925 bits.free = free_heap_bits;
1926 err = ERROR_SUCCESS;
1931 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1932 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1933 if (!err && !bits.is_copy)
1935 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1938 if (bits.free) bits.free( &bits );
1939 return ERROR_OUTOFMEMORY;
1941 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1942 if (bits.free) bits.free( &bits );
1944 bits.is_copy = TRUE;
1945 bits.free = free_heap_bits;
1950 /* make x,y relative to the image bits */
1951 x += src.visrect.left - dst.visrect.left;
1952 y += src.visrect.top - dst.visrect.top;
1953 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1954 aa_flags, str, count, dx );
1955 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
1956 if (bits.free) bits.free( &bits );
1961 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1962 orig = SelectObject( dev->hdc, pen );
1964 for (i = 0; i < count; i++)
1966 GLYPHMETRICS metrics;
1967 struct gdi_image_bits image;
1969 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
1972 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1973 if (image.free) image.free( &image );
1977 if (flags & ETO_PDY)
1980 y += dx[ i * 2 + 1];
1986 x += metrics.gmCellIncX;
1987 y += metrics.gmCellIncY;
1991 SelectObject( dev->hdc, orig );
1992 DeleteObject( pen );
1997 /***********************************************************************
1998 * ExtTextOutA (GDI32.@)
2002 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2003 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2011 if (flags & ETO_GLYPH_INDEX)
2012 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2014 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2017 unsigned int i = 0, j = 0;
2019 /* allocate enough for a ETO_PDY */
2020 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2022 if(IsDBCSLeadByteEx(codepage, str[i]))
2026 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2027 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2030 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2037 lpDxW[j++] = lpDx[i * 2];
2038 lpDxW[j++] = lpDx[i * 2 + 1];
2041 lpDxW[j++] = lpDx[i];
2047 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2049 HeapFree( GetProcessHeap(), 0, p );
2050 HeapFree( GetProcessHeap(), 0, lpDxW );
2055 /***********************************************************************
2056 * ExtTextOutW (GDI32.@)
2058 * Draws text using the currently selected font, background color, and text color.
2062 * x,y [I] coordinates of string
2064 * ETO_GRAYED - undocumented on MSDN
2065 * ETO_OPAQUE - use background color for fill the rectangle
2066 * ETO_CLIPPED - clipping text to the rectangle
2067 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2068 * than encoded characters. Implies ETO_IGNORELANGUAGE
2069 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2070 * Affects BiDi ordering
2071 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2072 * ETO_PDY - unimplemented
2073 * ETO_NUMERICSLATIN - unimplemented always assumed -
2074 * do not translate numbers into locale representations
2075 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2076 * lprect [I] dimensions for clipping or/and opaquing
2077 * str [I] text string
2078 * count [I] number of symbols in string
2079 * lpDx [I] optional parameter with distance between drawing characters
2085 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2086 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2089 LPWSTR reordered_str = (LPWSTR)str;
2090 WORD *glyphs = NULL;
2091 UINT align = GetTextAlign( hdc );
2092 DWORD layout = GetLayout( hdc );
2096 double cosEsc, sinEsc;
2100 BOOL done_extents = FALSE;
2101 POINT *deltas = NULL, width = {0, 0};
2103 DC * dc = get_dc_ptr( hdc );
2106 static int quietfixme = 0;
2108 if (!dc) return FALSE;
2110 breakRem = dc->breakRem;
2112 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2114 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2119 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2120 type = GetObjectType(hdc);
2121 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2123 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2124 release_dc_ptr( dc );
2129 flags &= ~ETO_CLIPPED;
2131 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2132 if (layout & LAYOUT_RTL)
2134 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2135 align ^= TA_RTLREADING;
2138 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2141 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2143 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2144 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2145 reordered_str, count, NULL, &glyphs, &cGlyphs);
2147 flags |= ETO_IGNORELANGUAGE;
2150 flags |= ETO_GLYPH_INDEX;
2151 if (cGlyphs != count)
2155 else if(flags & ETO_GLYPH_INDEX)
2156 glyphs = reordered_str;
2158 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2159 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2160 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2162 if(align & TA_UPDATECP)
2164 GetCurrentPositionEx( hdc, &pt );
2169 GetTextMetricsW(hdc, &tm);
2170 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2172 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2173 lf.lfEscapement = 0;
2175 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2176 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2178 lf.lfEscapement = -lf.lfEscapement;
2181 if(lf.lfEscapement != 0)
2183 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2184 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2192 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
2196 if(flags & ETO_GLYPH_INDEX)
2197 GetTextExtentPointI(hdc, glyphs, count, &sz);
2199 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2201 done_extents = TRUE;
2204 rc.right = x + sz.cx;
2205 rc.bottom = y + sz.cy;
2212 LPtoDP(hdc, (POINT*)&rc, 2);
2216 if (lprect && (flags & ETO_OPAQUE))
2217 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2227 LPtoDP(hdc, &pt, 1);
2231 char_extra = GetTextCharacterExtra(hdc);
2232 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2236 POINT total = {0, 0}, desired[2];
2238 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2239 for(i = 0; i < count; i++)
2245 deltas[i].x = lpDx[i * 2] + char_extra;
2246 deltas[i].y = -lpDx[i * 2 + 1];
2250 deltas[i].x = lpDx[i] + char_extra;
2257 if(flags & ETO_GLYPH_INDEX)
2258 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2260 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2262 deltas[i].x = tmpsz.cx;
2266 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2268 deltas[i].x = deltas[i].x + dc->breakExtra;
2275 total.x += deltas[i].x;
2276 total.y += deltas[i].y;
2278 desired[0].x = desired[0].y = 0;
2280 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2281 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2283 LPtoDP(hdc, desired, 2);
2284 desired[1].x -= desired[0].x;
2285 desired[1].y -= desired[0].y;
2287 if (dc->GraphicsMode == GM_COMPATIBLE)
2289 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2290 desired[1].x = -desired[1].x;
2291 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2292 desired[1].y = -desired[1].y;
2295 deltas[i].x = desired[1].x - width.x;
2296 deltas[i].y = desired[1].y - width.y;
2308 if(flags & ETO_GLYPH_INDEX)
2309 GetTextExtentPointI(hdc, glyphs, count, &sz);
2311 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2312 done_extents = TRUE;
2314 desired[0].x = desired[0].y = 0;
2315 desired[1].x = sz.cx;
2317 LPtoDP(hdc, desired, 2);
2318 desired[1].x -= desired[0].x;
2319 desired[1].y -= desired[0].y;
2321 if (dc->GraphicsMode == GM_COMPATIBLE)
2323 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2324 desired[1].x = -desired[1].x;
2325 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2326 desired[1].y = -desired[1].y;
2331 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2332 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2333 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2336 if (align & TA_UPDATECP)
2340 DPtoLP(hdc, &pt, 1);
2341 MoveToEx(hdc, pt.x, pt.y, NULL);
2353 if (align & TA_UPDATECP)
2357 DPtoLP(hdc, &pt, 1);
2358 MoveToEx(hdc, pt.x, pt.y, NULL);
2363 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2366 y += tm.tmAscent * cosEsc;
2367 x += tm.tmAscent * sinEsc;
2371 y -= tm.tmDescent * cosEsc;
2372 x -= tm.tmDescent * sinEsc;
2379 if (GetBkMode(hdc) != TRANSPARENT)
2381 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2383 if(!(flags & ETO_OPAQUE) || !lprect ||
2384 x < rc.left || x + width.x >= rc.right ||
2385 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2389 text_box.right = x + width.x;
2390 text_box.top = y - tm.tmAscent;
2391 text_box.bottom = y + tm.tmDescent;
2393 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2394 if (!is_rect_empty( &text_box ))
2395 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2400 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2401 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2404 HeapFree(GetProcessHeap(), 0, deltas);
2405 if(glyphs != reordered_str)
2406 HeapFree(GetProcessHeap(), 0, glyphs);
2407 if(reordered_str != str)
2408 HeapFree(GetProcessHeap(), 0, reordered_str);
2410 release_dc_ptr( dc );
2412 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2414 int underlinePos, strikeoutPos;
2415 int underlineWidth, strikeoutWidth;
2416 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2417 OUTLINETEXTMETRICW* otm = NULL;
2419 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2420 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2422 hbrush = SelectObject(hdc, hbrush);
2427 underlineWidth = tm.tmAscent / 20 + 1;
2428 strikeoutPos = tm.tmAscent / 2;
2429 strikeoutWidth = underlineWidth;
2433 otm = HeapAlloc(GetProcessHeap(), 0, size);
2434 GetOutlineTextMetricsW(hdc, size, otm);
2435 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2436 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2437 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2438 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2439 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2440 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2441 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2442 HeapFree(GetProcessHeap(), 0, otm);
2448 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2449 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2450 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2451 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2452 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2453 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2454 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2455 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2456 pts[4].x = pts[0].x;
2457 pts[4].y = pts[0].y;
2458 DPtoLP(hdc, pts, 5);
2459 Polygon(hdc, pts, 5);
2464 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2465 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2466 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2467 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2468 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2469 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2470 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2471 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2472 pts[4].x = pts[0].x;
2473 pts[4].y = pts[0].y;
2474 DPtoLP(hdc, pts, 5);
2475 Polygon(hdc, pts, 5);
2478 SelectObject(hdc, hpen);
2479 hbrush = SelectObject(hdc, hbrush);
2480 DeleteObject(hbrush);
2487 /***********************************************************************
2488 * TextOutA (GDI32.@)
2490 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2492 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2496 /***********************************************************************
2497 * TextOutW (GDI32.@)
2499 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2501 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2505 /***********************************************************************
2506 * PolyTextOutA (GDI32.@)
2510 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2512 for (; cStrings>0; cStrings--, pptxt++)
2513 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2520 /***********************************************************************
2521 * PolyTextOutW (GDI32.@)
2523 * Draw several Strings
2529 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2531 for (; cStrings>0; cStrings--, pptxt++)
2532 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2538 /***********************************************************************
2539 * SetMapperFlags (GDI32.@)
2541 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2543 DC *dc = get_dc_ptr( hdc );
2544 DWORD ret = GDI_ERROR;
2548 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2549 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2550 if (flags != GDI_ERROR)
2552 ret = dc->mapperFlags;
2553 dc->mapperFlags = flags;
2555 release_dc_ptr( dc );
2560 /***********************************************************************
2561 * GetAspectRatioFilterEx (GDI32.@)
2563 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2565 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2570 /***********************************************************************
2571 * GetCharABCWidthsA (GDI32.@)
2573 * See GetCharABCWidthsW.
2575 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2583 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2587 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2590 HeapFree(GetProcessHeap(), 0, str);
2594 for(i = 0; i < wlen; i++)
2596 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2604 HeapFree(GetProcessHeap(), 0, str);
2605 HeapFree(GetProcessHeap(), 0, wstr);
2611 /******************************************************************************
2612 * GetCharABCWidthsW [GDI32.@]
2614 * Retrieves widths of characters in range.
2617 * hdc [I] Handle of device context
2618 * firstChar [I] First character in range to query
2619 * lastChar [I] Last character in range to query
2620 * abc [O] Address of character-width structure
2623 * Only works with TrueType fonts
2629 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2632 DC *dc = get_dc_ptr(hdc);
2638 if (!dc) return FALSE;
2642 release_dc_ptr( dc );
2646 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2647 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2648 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2650 release_dc_ptr( dc );
2654 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2655 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2658 /* convert device units to logical */
2659 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2660 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2661 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2662 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2666 release_dc_ptr( dc );
2671 /******************************************************************************
2672 * GetCharABCWidthsI [GDI32.@]
2674 * Retrieves widths of characters in range.
2677 * hdc [I] Handle of device context
2678 * firstChar [I] First glyphs in range to query
2679 * count [I] Last glyphs in range to query
2680 * pgi [i] Array of glyphs to query
2681 * abc [O] Address of character-width structure
2684 * Only works with TrueType fonts
2690 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2691 LPWORD pgi, LPABC abc)
2693 DC *dc = get_dc_ptr(hdc);
2698 if (!dc) return FALSE;
2702 release_dc_ptr( dc );
2706 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2707 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2710 /* convert device units to logical */
2711 for( i = 0; i < count; i++, abc++ ) {
2712 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2713 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2714 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2718 release_dc_ptr( dc );
2723 /***********************************************************************
2724 * GetGlyphOutlineA (GDI32.@)
2726 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2727 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2728 LPVOID lpBuffer, const MAT2 *lpmat2 )
2730 if (!lpmat2) return GDI_ERROR;
2732 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2737 cp = GdiGetCodePage(hdc);
2738 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2740 mbchs[0] = (uChar & 0xff00) >> 8;
2741 mbchs[1] = (uChar & 0xff);
2744 mbchs[0] = (uChar & 0xff);
2747 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2750 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2754 /***********************************************************************
2755 * GetGlyphOutlineW (GDI32.@)
2757 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2758 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2759 LPVOID lpBuffer, const MAT2 *lpmat2 )
2765 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2766 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2768 if (!lpmat2) return GDI_ERROR;
2770 dc = get_dc_ptr(hdc);
2771 if(!dc) return GDI_ERROR;
2773 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2774 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2775 release_dc_ptr( dc );
2780 /***********************************************************************
2781 * CreateScalableFontResourceA (GDI32.@)
2783 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2784 LPCSTR lpszResourceFile,
2785 LPCSTR lpszFontFile,
2786 LPCSTR lpszCurrentPath )
2788 LPWSTR lpszResourceFileW = NULL;
2789 LPWSTR lpszFontFileW = NULL;
2790 LPWSTR lpszCurrentPathW = NULL;
2794 if (lpszResourceFile)
2796 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2797 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2798 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2803 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2804 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2805 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2808 if (lpszCurrentPath)
2810 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2811 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2812 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2815 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2816 lpszFontFileW, lpszCurrentPathW);
2818 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2819 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2820 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2825 /***********************************************************************
2826 * CreateScalableFontResourceW (GDI32.@)
2828 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2829 LPCWSTR font_file, LPCWSTR font_path )
2831 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2832 debugstr_w(font_file), debugstr_w(font_path) );
2834 return WineEngCreateScalableFontResource( hidden, resource_file,
2835 font_file, font_path );
2838 /*************************************************************************
2839 * GetKerningPairsA (GDI32.@)
2841 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2842 LPKERNINGPAIR kern_pairA )
2846 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2847 KERNINGPAIR *kern_pairW;
2849 if (!cPairs && kern_pairA)
2851 SetLastError(ERROR_INVALID_PARAMETER);
2855 cp = GdiGetCodePage(hDC);
2857 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2858 * to fail on an invalid character for CP_SYMBOL.
2860 cpi.DefaultChar[0] = 0;
2861 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2863 FIXME("Can't find codepage %u info\n", cp);
2867 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2868 if (!total_kern_pairs) return 0;
2870 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2871 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2873 for (i = 0; i < total_kern_pairs; i++)
2877 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2880 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2883 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2888 if (kern_pairs_copied >= cPairs) break;
2890 kern_pairA->wFirst = (BYTE)first;
2891 kern_pairA->wSecond = (BYTE)second;
2892 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2895 kern_pairs_copied++;
2898 HeapFree(GetProcessHeap(), 0, kern_pairW);
2900 return kern_pairs_copied;
2903 /*************************************************************************
2904 * GetKerningPairsW (GDI32.@)
2906 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2907 LPKERNINGPAIR lpKerningPairs )
2913 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2915 if (!cPairs && lpKerningPairs)
2917 SetLastError(ERROR_INVALID_PARAMETER);
2921 dc = get_dc_ptr(hDC);
2924 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2925 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2926 release_dc_ptr( dc );
2930 /*************************************************************************
2931 * TranslateCharsetInfo [GDI32.@]
2933 * Fills a CHARSETINFO structure for a character set, code page, or
2934 * font. This allows making the correspondence between different labels
2935 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2936 * of the same encoding.
2938 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2939 * only one codepage should be set in *lpSrc.
2942 * TRUE on success, FALSE on failure.
2945 BOOL WINAPI TranslateCharsetInfo(
2946 LPDWORD lpSrc, /* [in]
2947 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2948 if flags == TCI_SRCCHARSET: a character set value
2949 if flags == TCI_SRCCODEPAGE: a code page value
2951 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2952 DWORD flags /* [in] determines interpretation of lpSrc */)
2956 case TCI_SRCFONTSIG:
2957 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2959 case TCI_SRCCODEPAGE:
2960 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2962 case TCI_SRCCHARSET:
2963 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2968 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2969 *lpCs = FONT_tci[index];
2973 /*************************************************************************
2974 * GetFontLanguageInfo (GDI32.@)
2976 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2978 FONTSIGNATURE fontsig;
2979 static const DWORD GCP_DBCS_MASK=0x003F0000,
2980 GCP_DIACRITIC_MASK=0x00000000,
2981 FLI_GLYPHS_MASK=0x00000000,
2982 GCP_GLYPHSHAPE_MASK=0x00000040,
2983 GCP_KASHIDA_MASK=0x00000000,
2984 GCP_LIGATE_MASK=0x00000000,
2985 GCP_USEKERNING_MASK=0x00000000,
2986 GCP_REORDER_MASK=0x00000060;
2990 GetTextCharsetInfo( hdc, &fontsig, 0 );
2991 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2993 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2996 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2997 result|=GCP_DIACRITIC;
2999 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3002 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3003 result|=GCP_GLYPHSHAPE;
3005 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3006 result|=GCP_KASHIDA;
3008 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3011 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3012 result|=GCP_USEKERNING;
3014 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3015 if( GetTextAlign( hdc) & TA_RTLREADING )
3016 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3017 result|=GCP_REORDER;
3023 /*************************************************************************
3024 * GetFontData [GDI32.@]
3026 * Retrieve data for TrueType font.
3030 * success: Number of bytes returned
3031 * failure: GDI_ERROR
3035 * Calls SetLastError()
3038 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3039 LPVOID buffer, DWORD length)
3041 DC *dc = get_dc_ptr(hdc);
3045 if(!dc) return GDI_ERROR;
3047 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3048 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3049 release_dc_ptr( dc );
3053 /*************************************************************************
3054 * GetGlyphIndicesA [GDI32.@]
3056 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3057 LPWORD pgi, DWORD flags)
3063 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3064 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3066 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3067 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3068 HeapFree(GetProcessHeap(), 0, lpstrW);
3073 /*************************************************************************
3074 * GetGlyphIndicesW [GDI32.@]
3076 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3077 LPWORD pgi, DWORD flags)
3079 DC *dc = get_dc_ptr(hdc);
3083 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3084 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3086 if(!dc) return GDI_ERROR;
3088 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3089 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3090 release_dc_ptr( dc );
3094 /*************************************************************************
3095 * GetCharacterPlacementA [GDI32.@]
3097 * See GetCharacterPlacementW.
3100 * the web browser control of ie4 calls this with dwFlags=0
3103 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3104 INT nMaxExtent, GCP_RESULTSA *lpResults,
3109 GCP_RESULTSW resultsW;
3113 TRACE("%s, %d, %d, 0x%08x\n",
3114 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3116 /* both structs are equal in size */
3117 memcpy(&resultsW, lpResults, sizeof(resultsW));
3119 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3120 if(lpResults->lpOutString)
3121 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3123 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3125 lpResults->nGlyphs = resultsW.nGlyphs;
3126 lpResults->nMaxFit = resultsW.nMaxFit;
3128 if(lpResults->lpOutString) {
3129 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3130 lpResults->lpOutString, uCount, NULL, NULL );
3133 HeapFree(GetProcessHeap(), 0, lpStringW);
3134 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3139 /*************************************************************************
3140 * GetCharacterPlacementW [GDI32.@]
3142 * Retrieve information about a string. This includes the width, reordering,
3143 * Glyphing and so on.
3147 * The width and height of the string if successful, 0 if failed.
3151 * All flags except GCP_REORDER are not yet implemented.
3152 * Reordering is not 100% compliant to the Windows BiDi method.
3153 * Caret positioning is not yet implemented for BiDi.
3154 * Classes are not yet implemented.
3158 GetCharacterPlacementW(
3159 HDC hdc, /* [in] Device context for which the rendering is to be done */
3160 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3161 INT uCount, /* [in] Number of WORDS in string. */
3162 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3163 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3164 DWORD dwFlags /* [in] Flags specifying how to process the string */
3171 TRACE("%s, %d, %d, 0x%08x\n",
3172 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3174 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3175 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3176 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3177 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3178 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3180 if(dwFlags&(~GCP_REORDER))
3181 FIXME("flags 0x%08x ignored\n", dwFlags);
3182 if(lpResults->lpClass)
3183 FIXME("classes not implemented\n");
3184 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3185 FIXME("Caret positions for complex scripts not implemented\n");
3187 nSet = (UINT)uCount;
3188 if(nSet > lpResults->nGlyphs)
3189 nSet = lpResults->nGlyphs;
3191 /* return number of initialized fields */
3192 lpResults->nGlyphs = nSet;
3194 if((dwFlags&GCP_REORDER)==0 )
3196 /* Treat the case where no special handling was requested in a fastpath way */
3197 /* copy will do if the GCP_REORDER flag is not set */
3198 if(lpResults->lpOutString)
3199 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3201 if(lpResults->lpOrder)
3203 for(i = 0; i < nSet; i++)
3204 lpResults->lpOrder[i] = i;
3209 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3210 nSet, lpResults->lpOrder, NULL, NULL );
3213 /* FIXME: Will use the placement chars */
3214 if (lpResults->lpDx)
3217 for (i = 0; i < nSet; i++)
3219 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3220 lpResults->lpDx[i]= c;
3224 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3228 lpResults->lpCaretPos[0] = 0;
3229 for (i = 1; i < nSet; i++)
3230 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3231 lpResults->lpCaretPos[i] = (pos += size.cx);
3234 if(lpResults->lpGlyphs)
3235 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3237 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3238 ret = MAKELONG(size.cx, size.cy);
3243 /*************************************************************************
3244 * GetCharABCWidthsFloatA [GDI32.@]
3246 * See GetCharABCWidthsFloatW.
3248 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3255 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3259 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3261 for (i = 0; i < wlen; i++)
3263 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3271 HeapFree( GetProcessHeap(), 0, str );
3272 HeapFree( GetProcessHeap(), 0, wstr );
3277 /*************************************************************************
3278 * GetCharABCWidthsFloatW [GDI32.@]
3280 * Retrieves widths of a range of characters.
3283 * hdc [I] Handle to device context.
3284 * first [I] First character in range to query.
3285 * last [I] Last character in range to query.
3286 * abcf [O] Array of LPABCFLOAT structures.
3292 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3298 DC *dc = get_dc_ptr( hdc );
3300 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3302 if (!dc) return FALSE;
3304 if (!abcf) goto done;
3305 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3307 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3308 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3311 /* convert device units to logical */
3312 for (i = first; i <= last; i++, abcf++)
3314 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3315 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3316 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3319 HeapFree( GetProcessHeap(), 0, abc );
3322 release_dc_ptr( dc );
3326 /*************************************************************************
3327 * GetCharWidthFloatA [GDI32.@]
3329 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3330 UINT iLastChar, PFLOAT pxBuffer)
3332 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3336 /*************************************************************************
3337 * GetCharWidthFloatW [GDI32.@]
3339 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3340 UINT iLastChar, PFLOAT pxBuffer)
3342 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3347 /***********************************************************************
3349 * Font Resource API *
3351 ***********************************************************************/
3353 /***********************************************************************
3354 * AddFontResourceA (GDI32.@)
3356 INT WINAPI AddFontResourceA( LPCSTR str )
3358 return AddFontResourceExA( str, 0, NULL);
3361 /***********************************************************************
3362 * AddFontResourceW (GDI32.@)
3364 INT WINAPI AddFontResourceW( LPCWSTR str )
3366 return AddFontResourceExW(str, 0, NULL);
3370 /***********************************************************************
3371 * AddFontResourceExA (GDI32.@)
3373 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3375 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3376 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3379 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3380 ret = AddFontResourceExW(strW, fl, pdv);
3381 HeapFree(GetProcessHeap(), 0, strW);
3385 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3387 HRSRC rsrc = FindResourceW(hModule, name, type);
3388 HGLOBAL hMem = LoadResource(hModule, rsrc);
3389 LPVOID *pMem = LockResource(hMem);
3390 int *num_total = (int *)lParam;
3393 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3394 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3396 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3400 *num_total += num_in_res;
3404 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3406 HANDLE file, mapping;
3409 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3410 if (file == INVALID_HANDLE_VALUE) return NULL;
3412 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3414 CloseHandle( file );
3418 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3419 CloseHandle( file );
3420 if (!mapping) return NULL;
3422 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3423 CloseHandle( mapping );
3428 static WCHAR *get_scalable_filename( const WCHAR *res )
3431 BYTE *ptr = map_file( res, &size );
3432 const IMAGE_DOS_HEADER *dos;
3433 const IMAGE_OS2_HEADER *ne;
3435 WORD rsrc_off, align, type_id, count;
3436 DWORD res_off, res_len, i;
3439 if (!ptr) return NULL;
3441 if (size.u.LowPart < sizeof( *dos )) goto fail;
3442 dos = (const IMAGE_DOS_HEADER *)ptr;
3443 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3444 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3445 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3446 rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
3447 if (size.u.LowPart < rsrc_off + 10) goto fail;
3448 align = *(WORD *)(ptr + rsrc_off);
3450 type_id = *(WORD *)(ptr + rsrc_off);
3451 while (type_id && type_id != 0x80cc)
3453 count = *(WORD *)(ptr + rsrc_off + 2);
3454 rsrc_off += 8 + count * 12;
3455 if (size.u.LowPart < rsrc_off + 8) goto fail;
3456 type_id = *(WORD *)(ptr + rsrc_off);
3458 if (!type_id) goto fail;
3459 count = *(WORD *)(ptr + rsrc_off + 2);
3460 if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;
3462 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3463 res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
3464 if (size.u.LowPart < res_off + res_len) goto fail;
3466 for (i = 0; i < res_len; i++)
3467 if (ptr[ res_off + i ] == 0) break;
3468 if (i == res_len) goto fail;
3470 len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
3471 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3472 if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );
3475 UnmapViewOfFile( ptr );
3479 /***********************************************************************
3480 * AddFontResourceExW (GDI32.@)
3482 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3484 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3489 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3490 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3491 if (hModule != NULL)
3493 int num_resources = 0;
3494 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3496 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3497 wine_dbgstr_w(str));
3498 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3499 ret = num_resources;
3500 FreeLibrary(hModule);
3502 else if ((filename = get_scalable_filename( str )) != NULL)
3504 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3505 HeapFree( GetProcessHeap(), 0, filename );
3511 /***********************************************************************
3512 * RemoveFontResourceA (GDI32.@)
3514 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3516 return RemoveFontResourceExA(str, 0, 0);
3519 /***********************************************************************
3520 * RemoveFontResourceW (GDI32.@)
3522 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3524 return RemoveFontResourceExW(str, 0, 0);
3527 /***********************************************************************
3528 * AddFontMemResourceEx (GDI32.@)
3530 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3535 if (!pbFont || !cbFont || !pcFonts)
3537 SetLastError(ERROR_INVALID_PARAMETER);
3541 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3546 *pcFonts = num_fonts;
3550 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3551 RemoveFontMemResourceEx(ret);
3559 /***********************************************************************
3560 * RemoveFontMemResourceEx (GDI32.@)
3562 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3564 FIXME("(%p) stub\n", fh);
3568 /***********************************************************************
3569 * RemoveFontResourceExA (GDI32.@)
3571 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3573 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3574 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3577 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3578 ret = RemoveFontResourceExW(strW, fl, pdv);
3579 HeapFree(GetProcessHeap(), 0, strW);
3583 /***********************************************************************
3584 * RemoveFontResourceExW (GDI32.@)
3586 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3588 return WineEngRemoveFontResourceEx(str, fl, pdv);
3591 /***********************************************************************
3592 * GetTextCharset (GDI32.@)
3594 UINT WINAPI GetTextCharset(HDC hdc)
3596 /* MSDN docs say this is equivalent */
3597 return GetTextCharsetInfo(hdc, NULL, 0);
3600 /***********************************************************************
3601 * GetTextCharsetInfo (GDI32.@)
3603 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3605 UINT ret = DEFAULT_CHARSET;
3606 DC *dc = get_dc_ptr(hdc);
3611 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3612 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3613 release_dc_ptr( dc );
3616 if (ret == DEFAULT_CHARSET && fs)
3617 memset(fs, 0, sizeof(FONTSIGNATURE));
3621 /***********************************************************************
3622 * GdiGetCharDimensions (GDI32.@)
3624 * Gets the average width of the characters in the English alphabet.
3627 * hdc [I] Handle to the device context to measure on.
3628 * lptm [O] Pointer to memory to store the text metrics into.
3629 * height [O] On exit, the maximum height of characters in the English alphabet.
3632 * The average width of characters in the English alphabet.
3635 * This function is used by the dialog manager to get the size of a dialog
3636 * unit. It should also be used by other pieces of code that need to know
3637 * the size of a dialog unit in logical units without having access to the
3638 * window handle of the dialog.
3639 * Windows caches the font metrics from this function, but we don't and
3640 * there doesn't appear to be an immediate advantage to do so.
3643 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3645 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3648 static const WCHAR alphabet[] = {
3649 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3650 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3651 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3653 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3655 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3657 if (height) *height = sz.cy;
3658 return (sz.cx / 26 + 1) / 2;
3661 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3663 FIXME("(%d): stub\n", fEnableEUDC);
3667 /***********************************************************************
3668 * GetCharWidthI (GDI32.@)
3670 * Retrieve widths of characters.
3673 * hdc [I] Handle to a device context.
3674 * first [I] First glyph in range to query.
3675 * count [I] Number of glyph indices to query.
3676 * glyphs [I] Array of glyphs to query.
3677 * buffer [O] Buffer to receive character widths.
3680 * Only works with TrueType fonts.
3686 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3691 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3693 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3696 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3698 HeapFree(GetProcessHeap(), 0, abc);
3702 for (i = 0; i < count; i++)
3703 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3705 HeapFree(GetProcessHeap(), 0, abc);
3709 /***********************************************************************
3710 * GetFontUnicodeRanges (GDI32.@)
3712 * Retrieve a list of supported Unicode characters in a font.
3715 * hdc [I] Handle to a device context.
3716 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3719 * Success: Number of bytes written to the buffer pointed to by lpgs.
3723 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3727 DC *dc = get_dc_ptr(hdc);
3729 TRACE("(%p, %p)\n", hdc, lpgs);
3733 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3734 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3740 /*************************************************************
3741 * FontIsLinked (GDI32.@)
3743 BOOL WINAPI FontIsLinked(HDC hdc)
3745 DC *dc = get_dc_ptr(hdc);
3749 if (!dc) return FALSE;
3750 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3751 ret = dev->funcs->pFontIsLinked( dev );
3753 TRACE("returning %d\n", ret);
3757 /*************************************************************
3758 * GdiRealizationInfo (GDI32.@)
3760 * Returns a structure that contains some font information.
3762 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3764 DC *dc = get_dc_ptr(hdc);
3768 if (!dc) return FALSE;
3769 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3770 ret = dev->funcs->pGdiRealizationInfo( dev, info );