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 POINT *deltas = NULL, width = {0, 0};
2102 DC * dc = get_dc_ptr( hdc );
2105 static int quietfixme = 0;
2107 if (!dc) return FALSE;
2109 breakRem = dc->breakRem;
2111 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2113 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2118 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2119 type = GetObjectType(hdc);
2120 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2122 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2123 release_dc_ptr( dc );
2127 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2128 if (layout & LAYOUT_RTL)
2130 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2131 align ^= TA_RTLREADING;
2134 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2137 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2139 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2140 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2141 reordered_str, count, NULL, &glyphs, &cGlyphs);
2143 flags |= ETO_IGNORELANGUAGE;
2146 flags |= ETO_GLYPH_INDEX;
2147 if (cGlyphs != count)
2151 else if(flags & ETO_GLYPH_INDEX)
2152 glyphs = reordered_str;
2154 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2155 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2156 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2158 if(align & TA_UPDATECP)
2160 GetCurrentPositionEx( hdc, &pt );
2165 GetTextMetricsW(hdc, &tm);
2166 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2168 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2169 lf.lfEscapement = 0;
2171 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2172 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2174 lf.lfEscapement = -lf.lfEscapement;
2177 if(lf.lfEscapement != 0)
2179 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2180 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2191 LPtoDP(hdc, (POINT*)&rc, 2);
2193 if (flags & ETO_OPAQUE)
2194 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2196 else flags &= ~ETO_CLIPPED;
2206 LPtoDP(hdc, &pt, 1);
2210 char_extra = GetTextCharacterExtra(hdc);
2211 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2214 POINT total = {0, 0}, desired[2];
2216 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2219 if (flags & ETO_PDY)
2221 for (i = 0; i < count; i++)
2223 deltas[i].x = lpDx[i * 2] + char_extra;
2224 deltas[i].y = -lpDx[i * 2 + 1];
2229 for (i = 0; i < count; i++)
2231 deltas[i].x = lpDx[i] + char_extra;
2238 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2240 if (flags & ETO_GLYPH_INDEX)
2241 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2243 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2245 deltas[0].x = dx[0];
2247 for (i = 1; i < count; i++)
2249 deltas[i].x = dx[i] - dx[i - 1];
2252 HeapFree( GetProcessHeap(), 0, dx );
2255 for(i = 0; i < count; i++)
2257 total.x += deltas[i].x;
2258 total.y += deltas[i].y;
2260 desired[0].x = desired[0].y = 0;
2262 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2263 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2265 LPtoDP(hdc, desired, 2);
2266 desired[1].x -= desired[0].x;
2267 desired[1].y -= desired[0].y;
2269 if (dc->GraphicsMode == GM_COMPATIBLE)
2271 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2272 desired[1].x = -desired[1].x;
2273 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2274 desired[1].y = -desired[1].y;
2277 deltas[i].x = desired[1].x - width.x;
2278 deltas[i].y = desired[1].y - width.y;
2288 if(flags & ETO_GLYPH_INDEX)
2289 GetTextExtentPointI(hdc, glyphs, count, &sz);
2291 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2292 desired[0].x = desired[0].y = 0;
2293 desired[1].x = sz.cx;
2295 LPtoDP(hdc, desired, 2);
2296 desired[1].x -= desired[0].x;
2297 desired[1].y -= desired[0].y;
2299 if (dc->GraphicsMode == GM_COMPATIBLE)
2301 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2302 desired[1].x = -desired[1].x;
2303 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2304 desired[1].y = -desired[1].y;
2309 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2310 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2311 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2314 if (align & TA_UPDATECP)
2318 DPtoLP(hdc, &pt, 1);
2319 MoveToEx(hdc, pt.x, pt.y, NULL);
2331 if (align & TA_UPDATECP)
2335 DPtoLP(hdc, &pt, 1);
2336 MoveToEx(hdc, pt.x, pt.y, NULL);
2341 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2344 y += tm.tmAscent * cosEsc;
2345 x += tm.tmAscent * sinEsc;
2349 y -= tm.tmDescent * cosEsc;
2350 x -= tm.tmDescent * sinEsc;
2357 if (GetBkMode(hdc) != TRANSPARENT)
2359 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2361 if(!(flags & ETO_OPAQUE) || !lprect ||
2362 x < rc.left || x + width.x >= rc.right ||
2363 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2367 text_box.right = x + width.x;
2368 text_box.top = y - tm.tmAscent;
2369 text_box.bottom = y + tm.tmDescent;
2371 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2372 if (!is_rect_empty( &text_box ))
2373 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2378 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2379 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2382 HeapFree(GetProcessHeap(), 0, deltas);
2383 if(glyphs != reordered_str)
2384 HeapFree(GetProcessHeap(), 0, glyphs);
2385 if(reordered_str != str)
2386 HeapFree(GetProcessHeap(), 0, reordered_str);
2388 release_dc_ptr( dc );
2390 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2392 int underlinePos, strikeoutPos;
2393 int underlineWidth, strikeoutWidth;
2394 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2395 OUTLINETEXTMETRICW* otm = NULL;
2397 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2398 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2400 hbrush = SelectObject(hdc, hbrush);
2405 underlineWidth = tm.tmAscent / 20 + 1;
2406 strikeoutPos = tm.tmAscent / 2;
2407 strikeoutWidth = underlineWidth;
2411 otm = HeapAlloc(GetProcessHeap(), 0, size);
2412 GetOutlineTextMetricsW(hdc, size, otm);
2413 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2414 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2415 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2416 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2417 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2418 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2419 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2420 HeapFree(GetProcessHeap(), 0, otm);
2426 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2427 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2428 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2429 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2430 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2431 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2432 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2433 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2434 pts[4].x = pts[0].x;
2435 pts[4].y = pts[0].y;
2436 DPtoLP(hdc, pts, 5);
2437 Polygon(hdc, pts, 5);
2442 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2443 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2444 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2445 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2446 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2447 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2448 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2449 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2450 pts[4].x = pts[0].x;
2451 pts[4].y = pts[0].y;
2452 DPtoLP(hdc, pts, 5);
2453 Polygon(hdc, pts, 5);
2456 SelectObject(hdc, hpen);
2457 hbrush = SelectObject(hdc, hbrush);
2458 DeleteObject(hbrush);
2465 /***********************************************************************
2466 * TextOutA (GDI32.@)
2468 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2470 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2474 /***********************************************************************
2475 * TextOutW (GDI32.@)
2477 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2479 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2483 /***********************************************************************
2484 * PolyTextOutA (GDI32.@)
2488 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2490 for (; cStrings>0; cStrings--, pptxt++)
2491 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2498 /***********************************************************************
2499 * PolyTextOutW (GDI32.@)
2501 * Draw several Strings
2507 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2509 for (; cStrings>0; cStrings--, pptxt++)
2510 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2516 /***********************************************************************
2517 * SetMapperFlags (GDI32.@)
2519 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2521 DC *dc = get_dc_ptr( hdc );
2522 DWORD ret = GDI_ERROR;
2526 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2527 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2528 if (flags != GDI_ERROR)
2530 ret = dc->mapperFlags;
2531 dc->mapperFlags = flags;
2533 release_dc_ptr( dc );
2538 /***********************************************************************
2539 * GetAspectRatioFilterEx (GDI32.@)
2541 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2543 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2548 /***********************************************************************
2549 * GetCharABCWidthsA (GDI32.@)
2551 * See GetCharABCWidthsW.
2553 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2561 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2565 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2568 HeapFree(GetProcessHeap(), 0, str);
2572 for(i = 0; i < wlen; i++)
2574 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2582 HeapFree(GetProcessHeap(), 0, str);
2583 HeapFree(GetProcessHeap(), 0, wstr);
2589 /******************************************************************************
2590 * GetCharABCWidthsW [GDI32.@]
2592 * Retrieves widths of characters in range.
2595 * hdc [I] Handle of device context
2596 * firstChar [I] First character in range to query
2597 * lastChar [I] Last character in range to query
2598 * abc [O] Address of character-width structure
2601 * Only works with TrueType fonts
2607 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2610 DC *dc = get_dc_ptr(hdc);
2616 if (!dc) return FALSE;
2620 release_dc_ptr( dc );
2624 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2625 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2626 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2628 release_dc_ptr( dc );
2632 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2633 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2636 /* convert device units to logical */
2637 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2638 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2639 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2640 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2644 release_dc_ptr( dc );
2649 /******************************************************************************
2650 * GetCharABCWidthsI [GDI32.@]
2652 * Retrieves widths of characters in range.
2655 * hdc [I] Handle of device context
2656 * firstChar [I] First glyphs in range to query
2657 * count [I] Last glyphs in range to query
2658 * pgi [i] Array of glyphs to query
2659 * abc [O] Address of character-width structure
2662 * Only works with TrueType fonts
2668 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2669 LPWORD pgi, LPABC abc)
2671 DC *dc = get_dc_ptr(hdc);
2676 if (!dc) return FALSE;
2680 release_dc_ptr( dc );
2684 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2685 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2688 /* convert device units to logical */
2689 for( i = 0; i < count; i++, abc++ ) {
2690 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2691 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2692 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2696 release_dc_ptr( dc );
2701 /***********************************************************************
2702 * GetGlyphOutlineA (GDI32.@)
2704 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2705 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2706 LPVOID lpBuffer, const MAT2 *lpmat2 )
2708 if (!lpmat2) return GDI_ERROR;
2710 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2715 cp = GdiGetCodePage(hdc);
2716 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2718 mbchs[0] = (uChar & 0xff00) >> 8;
2719 mbchs[1] = (uChar & 0xff);
2722 mbchs[0] = (uChar & 0xff);
2725 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2728 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2732 /***********************************************************************
2733 * GetGlyphOutlineW (GDI32.@)
2735 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2736 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2737 LPVOID lpBuffer, const MAT2 *lpmat2 )
2743 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2744 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2746 if (!lpmat2) return GDI_ERROR;
2748 dc = get_dc_ptr(hdc);
2749 if(!dc) return GDI_ERROR;
2751 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2752 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2753 release_dc_ptr( dc );
2758 /***********************************************************************
2759 * CreateScalableFontResourceA (GDI32.@)
2761 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2762 LPCSTR lpszResourceFile,
2763 LPCSTR lpszFontFile,
2764 LPCSTR lpszCurrentPath )
2766 LPWSTR lpszResourceFileW = NULL;
2767 LPWSTR lpszFontFileW = NULL;
2768 LPWSTR lpszCurrentPathW = NULL;
2772 if (lpszResourceFile)
2774 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2775 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2776 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2781 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2782 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2783 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2786 if (lpszCurrentPath)
2788 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2789 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2790 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2793 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2794 lpszFontFileW, lpszCurrentPathW);
2796 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2797 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2798 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2803 /***********************************************************************
2804 * CreateScalableFontResourceW (GDI32.@)
2806 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2807 LPCWSTR font_file, LPCWSTR font_path )
2809 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2810 debugstr_w(font_file), debugstr_w(font_path) );
2812 return WineEngCreateScalableFontResource( hidden, resource_file,
2813 font_file, font_path );
2816 /*************************************************************************
2817 * GetKerningPairsA (GDI32.@)
2819 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2820 LPKERNINGPAIR kern_pairA )
2824 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2825 KERNINGPAIR *kern_pairW;
2827 if (!cPairs && kern_pairA)
2829 SetLastError(ERROR_INVALID_PARAMETER);
2833 cp = GdiGetCodePage(hDC);
2835 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2836 * to fail on an invalid character for CP_SYMBOL.
2838 cpi.DefaultChar[0] = 0;
2839 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2841 FIXME("Can't find codepage %u info\n", cp);
2845 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2846 if (!total_kern_pairs) return 0;
2848 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2849 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2851 for (i = 0; i < total_kern_pairs; i++)
2855 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2858 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2861 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2866 if (kern_pairs_copied >= cPairs) break;
2868 kern_pairA->wFirst = (BYTE)first;
2869 kern_pairA->wSecond = (BYTE)second;
2870 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2873 kern_pairs_copied++;
2876 HeapFree(GetProcessHeap(), 0, kern_pairW);
2878 return kern_pairs_copied;
2881 /*************************************************************************
2882 * GetKerningPairsW (GDI32.@)
2884 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2885 LPKERNINGPAIR lpKerningPairs )
2891 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2893 if (!cPairs && lpKerningPairs)
2895 SetLastError(ERROR_INVALID_PARAMETER);
2899 dc = get_dc_ptr(hDC);
2902 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2903 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2904 release_dc_ptr( dc );
2908 /*************************************************************************
2909 * TranslateCharsetInfo [GDI32.@]
2911 * Fills a CHARSETINFO structure for a character set, code page, or
2912 * font. This allows making the correspondence between different labels
2913 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2914 * of the same encoding.
2916 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2917 * only one codepage should be set in *lpSrc.
2920 * TRUE on success, FALSE on failure.
2923 BOOL WINAPI TranslateCharsetInfo(
2924 LPDWORD lpSrc, /* [in]
2925 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2926 if flags == TCI_SRCCHARSET: a character set value
2927 if flags == TCI_SRCCODEPAGE: a code page value
2929 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2930 DWORD flags /* [in] determines interpretation of lpSrc */)
2934 case TCI_SRCFONTSIG:
2935 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2937 case TCI_SRCCODEPAGE:
2938 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2940 case TCI_SRCCHARSET:
2941 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2946 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2947 *lpCs = FONT_tci[index];
2951 /*************************************************************************
2952 * GetFontLanguageInfo (GDI32.@)
2954 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2956 FONTSIGNATURE fontsig;
2957 static const DWORD GCP_DBCS_MASK=0x003F0000,
2958 GCP_DIACRITIC_MASK=0x00000000,
2959 FLI_GLYPHS_MASK=0x00000000,
2960 GCP_GLYPHSHAPE_MASK=0x00000040,
2961 GCP_KASHIDA_MASK=0x00000000,
2962 GCP_LIGATE_MASK=0x00000000,
2963 GCP_USEKERNING_MASK=0x00000000,
2964 GCP_REORDER_MASK=0x00000060;
2968 GetTextCharsetInfo( hdc, &fontsig, 0 );
2969 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2971 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2974 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2975 result|=GCP_DIACRITIC;
2977 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2980 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2981 result|=GCP_GLYPHSHAPE;
2983 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2984 result|=GCP_KASHIDA;
2986 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2989 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2990 result|=GCP_USEKERNING;
2992 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2993 if( GetTextAlign( hdc) & TA_RTLREADING )
2994 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2995 result|=GCP_REORDER;
3001 /*************************************************************************
3002 * GetFontData [GDI32.@]
3004 * Retrieve data for TrueType font.
3008 * success: Number of bytes returned
3009 * failure: GDI_ERROR
3013 * Calls SetLastError()
3016 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3017 LPVOID buffer, DWORD length)
3019 DC *dc = get_dc_ptr(hdc);
3023 if(!dc) return GDI_ERROR;
3025 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3026 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3027 release_dc_ptr( dc );
3031 /*************************************************************************
3032 * GetGlyphIndicesA [GDI32.@]
3034 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3035 LPWORD pgi, DWORD flags)
3041 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3042 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3044 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3045 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3046 HeapFree(GetProcessHeap(), 0, lpstrW);
3051 /*************************************************************************
3052 * GetGlyphIndicesW [GDI32.@]
3054 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3055 LPWORD pgi, DWORD flags)
3057 DC *dc = get_dc_ptr(hdc);
3061 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3062 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3064 if(!dc) return GDI_ERROR;
3066 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3067 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3068 release_dc_ptr( dc );
3072 /*************************************************************************
3073 * GetCharacterPlacementA [GDI32.@]
3075 * See GetCharacterPlacementW.
3078 * the web browser control of ie4 calls this with dwFlags=0
3081 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3082 INT nMaxExtent, GCP_RESULTSA *lpResults,
3087 GCP_RESULTSW resultsW;
3091 TRACE("%s, %d, %d, 0x%08x\n",
3092 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3094 /* both structs are equal in size */
3095 memcpy(&resultsW, lpResults, sizeof(resultsW));
3097 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3098 if(lpResults->lpOutString)
3099 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3101 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3103 lpResults->nGlyphs = resultsW.nGlyphs;
3104 lpResults->nMaxFit = resultsW.nMaxFit;
3106 if(lpResults->lpOutString) {
3107 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3108 lpResults->lpOutString, uCount, NULL, NULL );
3111 HeapFree(GetProcessHeap(), 0, lpStringW);
3112 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3117 /*************************************************************************
3118 * GetCharacterPlacementW [GDI32.@]
3120 * Retrieve information about a string. This includes the width, reordering,
3121 * Glyphing and so on.
3125 * The width and height of the string if successful, 0 if failed.
3129 * All flags except GCP_REORDER are not yet implemented.
3130 * Reordering is not 100% compliant to the Windows BiDi method.
3131 * Caret positioning is not yet implemented for BiDi.
3132 * Classes are not yet implemented.
3136 GetCharacterPlacementW(
3137 HDC hdc, /* [in] Device context for which the rendering is to be done */
3138 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3139 INT uCount, /* [in] Number of WORDS in string. */
3140 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3141 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3142 DWORD dwFlags /* [in] Flags specifying how to process the string */
3149 TRACE("%s, %d, %d, 0x%08x\n",
3150 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3152 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3153 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3154 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3155 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3156 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3158 if(dwFlags&(~GCP_REORDER))
3159 FIXME("flags 0x%08x ignored\n", dwFlags);
3160 if(lpResults->lpClass)
3161 FIXME("classes not implemented\n");
3162 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3163 FIXME("Caret positions for complex scripts not implemented\n");
3165 nSet = (UINT)uCount;
3166 if(nSet > lpResults->nGlyphs)
3167 nSet = lpResults->nGlyphs;
3169 /* return number of initialized fields */
3170 lpResults->nGlyphs = nSet;
3172 if((dwFlags&GCP_REORDER)==0 )
3174 /* Treat the case where no special handling was requested in a fastpath way */
3175 /* copy will do if the GCP_REORDER flag is not set */
3176 if(lpResults->lpOutString)
3177 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3179 if(lpResults->lpOrder)
3181 for(i = 0; i < nSet; i++)
3182 lpResults->lpOrder[i] = i;
3187 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3188 nSet, lpResults->lpOrder, NULL, NULL );
3191 /* FIXME: Will use the placement chars */
3192 if (lpResults->lpDx)
3195 for (i = 0; i < nSet; i++)
3197 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3198 lpResults->lpDx[i]= c;
3202 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3206 lpResults->lpCaretPos[0] = 0;
3207 for (i = 1; i < nSet; i++)
3208 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3209 lpResults->lpCaretPos[i] = (pos += size.cx);
3212 if(lpResults->lpGlyphs)
3213 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3215 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3216 ret = MAKELONG(size.cx, size.cy);
3221 /*************************************************************************
3222 * GetCharABCWidthsFloatA [GDI32.@]
3224 * See GetCharABCWidthsFloatW.
3226 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3233 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3237 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3239 for (i = 0; i < wlen; i++)
3241 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3249 HeapFree( GetProcessHeap(), 0, str );
3250 HeapFree( GetProcessHeap(), 0, wstr );
3255 /*************************************************************************
3256 * GetCharABCWidthsFloatW [GDI32.@]
3258 * Retrieves widths of a range of characters.
3261 * hdc [I] Handle to device context.
3262 * first [I] First character in range to query.
3263 * last [I] Last character in range to query.
3264 * abcf [O] Array of LPABCFLOAT structures.
3270 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3276 DC *dc = get_dc_ptr( hdc );
3278 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3280 if (!dc) return FALSE;
3282 if (!abcf) goto done;
3283 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3285 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3286 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3289 /* convert device units to logical */
3290 for (i = first; i <= last; i++, abcf++)
3292 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3293 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3294 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3297 HeapFree( GetProcessHeap(), 0, abc );
3300 release_dc_ptr( dc );
3304 /*************************************************************************
3305 * GetCharWidthFloatA [GDI32.@]
3307 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3308 UINT iLastChar, PFLOAT pxBuffer)
3310 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3314 /*************************************************************************
3315 * GetCharWidthFloatW [GDI32.@]
3317 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3318 UINT iLastChar, PFLOAT pxBuffer)
3320 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3325 /***********************************************************************
3327 * Font Resource API *
3329 ***********************************************************************/
3331 /***********************************************************************
3332 * AddFontResourceA (GDI32.@)
3334 INT WINAPI AddFontResourceA( LPCSTR str )
3336 return AddFontResourceExA( str, 0, NULL);
3339 /***********************************************************************
3340 * AddFontResourceW (GDI32.@)
3342 INT WINAPI AddFontResourceW( LPCWSTR str )
3344 return AddFontResourceExW(str, 0, NULL);
3348 /***********************************************************************
3349 * AddFontResourceExA (GDI32.@)
3351 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3353 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3354 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3357 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3358 ret = AddFontResourceExW(strW, fl, pdv);
3359 HeapFree(GetProcessHeap(), 0, strW);
3363 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3365 HRSRC rsrc = FindResourceW(hModule, name, type);
3366 HGLOBAL hMem = LoadResource(hModule, rsrc);
3367 LPVOID *pMem = LockResource(hMem);
3368 int *num_total = (int *)lParam;
3371 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3372 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3374 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3378 *num_total += num_in_res;
3382 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3384 HANDLE file, mapping;
3387 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3388 if (file == INVALID_HANDLE_VALUE) return NULL;
3390 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3392 CloseHandle( file );
3396 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3397 CloseHandle( file );
3398 if (!mapping) return NULL;
3400 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3401 CloseHandle( mapping );
3406 static WCHAR *get_scalable_filename( const WCHAR *res )
3409 BYTE *ptr = map_file( res, &size );
3410 const IMAGE_DOS_HEADER *dos;
3411 const IMAGE_OS2_HEADER *ne;
3413 WORD rsrc_off, align, type_id, count;
3414 DWORD res_off, res_len, i;
3417 if (!ptr) return NULL;
3419 if (size.u.LowPart < sizeof( *dos )) goto fail;
3420 dos = (const IMAGE_DOS_HEADER *)ptr;
3421 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3422 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3423 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3424 rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
3425 if (size.u.LowPart < rsrc_off + 10) goto fail;
3426 align = *(WORD *)(ptr + rsrc_off);
3428 type_id = *(WORD *)(ptr + rsrc_off);
3429 while (type_id && type_id != 0x80cc)
3431 count = *(WORD *)(ptr + rsrc_off + 2);
3432 rsrc_off += 8 + count * 12;
3433 if (size.u.LowPart < rsrc_off + 8) goto fail;
3434 type_id = *(WORD *)(ptr + rsrc_off);
3436 if (!type_id) goto fail;
3437 count = *(WORD *)(ptr + rsrc_off + 2);
3438 if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;
3440 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3441 res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
3442 if (size.u.LowPart < res_off + res_len) goto fail;
3444 for (i = 0; i < res_len; i++)
3445 if (ptr[ res_off + i ] == 0) break;
3446 if (i == res_len) goto fail;
3448 len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
3449 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3450 if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );
3453 UnmapViewOfFile( ptr );
3457 /***********************************************************************
3458 * AddFontResourceExW (GDI32.@)
3460 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3462 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3467 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3468 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3469 if (hModule != NULL)
3471 int num_resources = 0;
3472 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3474 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3475 wine_dbgstr_w(str));
3476 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3477 ret = num_resources;
3478 FreeLibrary(hModule);
3480 else if ((filename = get_scalable_filename( str )) != NULL)
3482 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3483 HeapFree( GetProcessHeap(), 0, filename );
3489 /***********************************************************************
3490 * RemoveFontResourceA (GDI32.@)
3492 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3494 return RemoveFontResourceExA(str, 0, 0);
3497 /***********************************************************************
3498 * RemoveFontResourceW (GDI32.@)
3500 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3502 return RemoveFontResourceExW(str, 0, 0);
3505 /***********************************************************************
3506 * AddFontMemResourceEx (GDI32.@)
3508 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3513 if (!pbFont || !cbFont || !pcFonts)
3515 SetLastError(ERROR_INVALID_PARAMETER);
3519 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3524 *pcFonts = num_fonts;
3528 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3529 RemoveFontMemResourceEx(ret);
3537 /***********************************************************************
3538 * RemoveFontMemResourceEx (GDI32.@)
3540 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3542 FIXME("(%p) stub\n", fh);
3546 /***********************************************************************
3547 * RemoveFontResourceExA (GDI32.@)
3549 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3551 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3552 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3555 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3556 ret = RemoveFontResourceExW(strW, fl, pdv);
3557 HeapFree(GetProcessHeap(), 0, strW);
3561 /***********************************************************************
3562 * RemoveFontResourceExW (GDI32.@)
3564 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3566 return WineEngRemoveFontResourceEx(str, fl, pdv);
3569 /***********************************************************************
3570 * GetTextCharset (GDI32.@)
3572 UINT WINAPI GetTextCharset(HDC hdc)
3574 /* MSDN docs say this is equivalent */
3575 return GetTextCharsetInfo(hdc, NULL, 0);
3578 /***********************************************************************
3579 * GetTextCharsetInfo (GDI32.@)
3581 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3583 UINT ret = DEFAULT_CHARSET;
3584 DC *dc = get_dc_ptr(hdc);
3589 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3590 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3591 release_dc_ptr( dc );
3594 if (ret == DEFAULT_CHARSET && fs)
3595 memset(fs, 0, sizeof(FONTSIGNATURE));
3599 /***********************************************************************
3600 * GdiGetCharDimensions (GDI32.@)
3602 * Gets the average width of the characters in the English alphabet.
3605 * hdc [I] Handle to the device context to measure on.
3606 * lptm [O] Pointer to memory to store the text metrics into.
3607 * height [O] On exit, the maximum height of characters in the English alphabet.
3610 * The average width of characters in the English alphabet.
3613 * This function is used by the dialog manager to get the size of a dialog
3614 * unit. It should also be used by other pieces of code that need to know
3615 * the size of a dialog unit in logical units without having access to the
3616 * window handle of the dialog.
3617 * Windows caches the font metrics from this function, but we don't and
3618 * there doesn't appear to be an immediate advantage to do so.
3621 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3623 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3626 static const WCHAR alphabet[] = {
3627 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3628 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3629 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3631 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3633 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3635 if (height) *height = sz.cy;
3636 return (sz.cx / 26 + 1) / 2;
3639 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3641 FIXME("(%d): stub\n", fEnableEUDC);
3645 /***********************************************************************
3646 * GetCharWidthI (GDI32.@)
3648 * Retrieve widths of characters.
3651 * hdc [I] Handle to a device context.
3652 * first [I] First glyph in range to query.
3653 * count [I] Number of glyph indices to query.
3654 * glyphs [I] Array of glyphs to query.
3655 * buffer [O] Buffer to receive character widths.
3658 * Only works with TrueType fonts.
3664 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3669 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3671 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3674 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3676 HeapFree(GetProcessHeap(), 0, abc);
3680 for (i = 0; i < count; i++)
3681 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3683 HeapFree(GetProcessHeap(), 0, abc);
3687 /***********************************************************************
3688 * GetFontUnicodeRanges (GDI32.@)
3690 * Retrieve a list of supported Unicode characters in a font.
3693 * hdc [I] Handle to a device context.
3694 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3697 * Success: Number of bytes written to the buffer pointed to by lpgs.
3701 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3705 DC *dc = get_dc_ptr(hdc);
3707 TRACE("(%p, %p)\n", hdc, lpgs);
3711 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3712 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3718 /*************************************************************
3719 * FontIsLinked (GDI32.@)
3721 BOOL WINAPI FontIsLinked(HDC hdc)
3723 DC *dc = get_dc_ptr(hdc);
3727 if (!dc) return FALSE;
3728 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3729 ret = dev->funcs->pFontIsLinked( dev );
3731 TRACE("returning %d\n", ret);
3735 /*************************************************************
3736 * GdiRealizationInfo (GDI32.@)
3738 * Returns a structure that contains some font information.
3740 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3742 DC *dc = get_dc_ptr(hdc);
3746 if (!dc) return FALSE;
3747 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3748 ret = dev->funcs->pGdiRealizationInfo( dev, info );