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 )
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 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
324 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
326 if (dc->breakExtra || dc->breakRem)
328 int i, space = 0, rem = dc->breakRem;
330 for (i = 0; i < count; i++)
332 if (str[i] == tm.tmBreakChar)
334 space += dc->breakExtra;
344 size->cx = dx[count - 1];
345 size->cy = tm.tmHeight;
349 /* compute positions for text rendering, in device coords */
350 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
355 size->cx = size->cy = 0;
356 if (!count) return TRUE;
358 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
359 dev->funcs->pGetTextMetrics( dev, &tm );
361 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
362 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
364 if (dc->breakExtra || dc->breakRem)
367 int i, space = 0, rem = dc->breakRem;
369 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
370 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
372 for (i = 0; i < count; i++)
374 if (indices[i] == space_index)
376 space += dc->breakExtra;
386 size->cx = dx[count - 1];
387 size->cy = tm.tmHeight;
391 /***********************************************************************
392 * GdiGetCodePage (GDI32.@)
394 DWORD WINAPI GdiGetCodePage( HDC hdc )
397 DC *dc = get_dc_ptr( hdc );
401 cp = dc->font_code_page;
402 release_dc_ptr( dc );
407 /***********************************************************************
410 * Returns a Unicode translation of str using the charset of the
411 * currently selected font in hdc. If count is -1 then str is assumed
412 * to be '\0' terminated, otherwise it contains the number of bytes to
413 * convert. If plenW is non-NULL, on return it will point to the
414 * number of WCHARs that have been written. If pCP is non-NULL, on
415 * return it will point to the codepage used in the conversion. The
416 * caller should free the returned LPWSTR from the process heap
419 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
425 cp = GdiGetCodePage( hdc );
427 if(count == -1) count = strlen(str);
428 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
429 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
430 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
431 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
432 if(plenW) *plenW = lenW;
437 /***********************************************************************
438 * CreateFontIndirectExA (GDI32.@)
440 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
442 ENUMLOGFONTEXDVW enumexW;
444 if (!penumexA) return 0;
446 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
447 enumexW.elfDesignVector = penumexA->elfDesignVector;
448 return CreateFontIndirectExW( &enumexW );
451 /***********************************************************************
452 * CreateFontIndirectExW (GDI32.@)
454 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
460 if (!penumex) return 0;
462 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
463 penumex->elfEnumLogfontEx.elfStyle[0] ||
464 penumex->elfEnumLogfontEx.elfScript[0])
466 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
467 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
468 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
469 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
472 plf = &penumex->elfEnumLogfontEx.elfLogFont;
473 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
475 fontPtr->logfont = *plf;
477 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
479 HeapFree( GetProcessHeap(), 0, fontPtr );
483 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
484 plf->lfHeight, plf->lfWidth,
485 plf->lfEscapement, plf->lfOrientation,
486 plf->lfPitchAndFamily,
487 plf->lfOutPrecision, plf->lfClipPrecision,
488 plf->lfQuality, plf->lfCharSet,
489 debugstr_w(plf->lfFaceName),
490 plf->lfWeight > 400 ? "Bold" : "",
491 plf->lfItalic ? "Italic" : "",
492 plf->lfUnderline ? "Underline" : "", hFont);
497 /***********************************************************************
498 * CreateFontIndirectA (GDI32.@)
500 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
506 FONT_LogFontAToW( plfA, &lfW );
507 return CreateFontIndirectW( &lfW );
510 /***********************************************************************
511 * CreateFontIndirectW (GDI32.@)
513 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
515 ENUMLOGFONTEXDVW exdv;
519 exdv.elfEnumLogfontEx.elfLogFont = *plf;
520 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
521 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
522 exdv.elfEnumLogfontEx.elfScript[0] = 0;
523 return CreateFontIndirectExW( &exdv );
526 /*************************************************************************
527 * CreateFontA (GDI32.@)
529 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
530 INT orient, INT weight, DWORD italic,
531 DWORD underline, DWORD strikeout, DWORD charset,
532 DWORD outpres, DWORD clippres, DWORD quality,
533 DWORD pitch, LPCSTR name )
537 logfont.lfHeight = height;
538 logfont.lfWidth = width;
539 logfont.lfEscapement = esc;
540 logfont.lfOrientation = orient;
541 logfont.lfWeight = weight;
542 logfont.lfItalic = italic;
543 logfont.lfUnderline = underline;
544 logfont.lfStrikeOut = strikeout;
545 logfont.lfCharSet = charset;
546 logfont.lfOutPrecision = outpres;
547 logfont.lfClipPrecision = clippres;
548 logfont.lfQuality = quality;
549 logfont.lfPitchAndFamily = pitch;
552 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
554 logfont.lfFaceName[0] = '\0';
556 return CreateFontIndirectA( &logfont );
559 /*************************************************************************
560 * CreateFontW (GDI32.@)
562 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
563 INT orient, INT weight, DWORD italic,
564 DWORD underline, DWORD strikeout, DWORD charset,
565 DWORD outpres, DWORD clippres, DWORD quality,
566 DWORD pitch, LPCWSTR name )
570 logfont.lfHeight = height;
571 logfont.lfWidth = width;
572 logfont.lfEscapement = esc;
573 logfont.lfOrientation = orient;
574 logfont.lfWeight = weight;
575 logfont.lfItalic = italic;
576 logfont.lfUnderline = underline;
577 logfont.lfStrikeOut = strikeout;
578 logfont.lfCharSet = charset;
579 logfont.lfOutPrecision = outpres;
580 logfont.lfClipPrecision = clippres;
581 logfont.lfQuality = quality;
582 logfont.lfPitchAndFamily = pitch;
585 lstrcpynW(logfont.lfFaceName, name,
586 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
588 logfont.lfFaceName[0] = '\0';
590 return CreateFontIndirectW( &logfont );
593 static void update_font_code_page( DC *dc )
596 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
598 /* Hmm, nicely designed api this one! */
599 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
600 dc->font_code_page = csi.ciACP;
604 dc->font_code_page = GetOEMCP();
606 case DEFAULT_CHARSET:
607 dc->font_code_page = GetACP();
617 /* FIXME: These have no place here, but because x11drv
618 enumerates fonts with these (made up) charsets some apps
619 might use them and then the FIXME below would become
620 annoying. Now we could pick the intended codepage for
621 each of these, but since it's broken anyway we'll just
622 use CP_ACP and hope it'll go away...
624 dc->font_code_page = CP_ACP;
628 FIXME("Can't find codepage for charset %d\n", charset);
629 dc->font_code_page = CP_ACP;
634 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
637 /***********************************************************************
640 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
643 DC *dc = get_dc_ptr( hdc );
649 if (!GDI_inc_ref_count( handle ))
651 release_dc_ptr( dc );
655 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
656 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
660 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
661 update_font_code_page( dc );
662 GDI_dec_ref_count( ret );
664 else GDI_dec_ref_count( handle );
666 release_dc_ptr( dc );
671 /***********************************************************************
674 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
676 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
682 FONT_LogFontWToA( &font->logfont, &lfA );
683 if (count > sizeof(lfA)) count = sizeof(lfA);
684 memcpy( buffer, &lfA, count );
686 else count = sizeof(lfA);
687 GDI_ReleaseObj( handle );
691 /***********************************************************************
694 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
696 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
701 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
702 memcpy( buffer, &font->logfont, count );
704 else count = sizeof(LOGFONTW);
705 GDI_ReleaseObj( handle );
710 /***********************************************************************
713 static BOOL FONT_DeleteObject( HGDIOBJ handle )
717 if (!(obj = free_gdi_handle( handle ))) return FALSE;
718 return HeapFree( GetProcessHeap(), 0, obj );
722 /***********************************************************************
725 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
727 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
728 'D','e','s','k','t','o','p',0 };
732 if (*aa_flags) return 0;
734 GetObjectW( font, sizeof(lf), &lf );
735 switch (lf.lfQuality)
737 case NONANTIALIASED_QUALITY:
738 *aa_flags = GGO_BITMAP;
740 case ANTIALIASED_QUALITY:
741 *aa_flags = GGO_GRAY4_BITMAP;
743 case CLEARTYPE_QUALITY:
744 case CLEARTYPE_NATURAL_QUALITY:
745 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
746 *aa_flags = get_subpixel_orientation( key );
750 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
751 *aa_flags = get_default_smoothing( key );
759 /***********************************************************************
762 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
763 * We have to use other types because of the FONTENUMPROCW definition.
765 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
766 DWORD fType, LPARAM lp )
768 struct font_enum *pfe = (struct font_enum *)lp;
771 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
772 if ((!pfe->lpLogFontParam ||
773 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
774 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
775 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
777 /* convert font metrics */
778 ENUMLOGFONTEXA logfont;
779 NEWTEXTMETRICEXA tmA;
783 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
784 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
785 plf = (LOGFONTW *)&logfont.elfLogFont;
786 ptm = (TEXTMETRICW *)&tmA;
788 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
794 /***********************************************************************
795 * FONT_EnumFontFamiliesEx
797 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
798 LPARAM lParam, BOOL unicode )
801 DC *dc = get_dc_ptr( hDC );
806 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
808 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
809 fe.lpLogFontParam = plf;
810 fe.lpEnumFunc = efproc;
812 fe.unicode = unicode;
815 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
816 release_dc_ptr( dc );
818 return ret ? fe.retval : 0;
821 /***********************************************************************
822 * EnumFontFamiliesExW (GDI32.@)
824 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
825 FONTENUMPROCW efproc,
826 LPARAM lParam, DWORD dwFlags )
828 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
831 /***********************************************************************
832 * EnumFontFamiliesExA (GDI32.@)
834 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
835 FONTENUMPROCA efproc,
836 LPARAM lParam, DWORD dwFlags)
842 FONT_LogFontAToW( plf, &lfW );
847 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
850 /***********************************************************************
851 * EnumFontFamiliesA (GDI32.@)
853 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
854 FONTENUMPROCA efproc, LPARAM lpData )
860 if (!*lpFamily) return 1;
861 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
862 lf.lfCharSet = DEFAULT_CHARSET;
863 lf.lfPitchAndFamily = 0;
868 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
871 /***********************************************************************
872 * EnumFontFamiliesW (GDI32.@)
874 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
875 FONTENUMPROCW efproc, LPARAM lpData )
881 if (!*lpFamily) return 1;
882 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
883 lf.lfCharSet = DEFAULT_CHARSET;
884 lf.lfPitchAndFamily = 0;
889 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
892 /***********************************************************************
893 * EnumFontsA (GDI32.@)
895 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
898 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
901 /***********************************************************************
902 * EnumFontsW (GDI32.@)
904 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
907 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
911 /***********************************************************************
912 * GetTextCharacterExtra (GDI32.@)
914 INT WINAPI GetTextCharacterExtra( HDC hdc )
917 DC *dc = get_dc_ptr( hdc );
918 if (!dc) return 0x80000000;
920 release_dc_ptr( dc );
925 /***********************************************************************
926 * SetTextCharacterExtra (GDI32.@)
928 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
930 INT ret = 0x80000000;
931 DC * dc = get_dc_ptr( hdc );
935 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
936 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
937 if (extra != 0x80000000)
940 dc->charExtra = extra;
942 release_dc_ptr( dc );
948 /***********************************************************************
949 * SetTextJustification (GDI32.@)
951 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
955 DC * dc = get_dc_ptr( hdc );
957 if (!dc) return FALSE;
959 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
960 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
963 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
964 if (!extra) breaks = 0;
967 dc->breakExtra = extra / breaks;
968 dc->breakRem = extra - (breaks * dc->breakExtra);
976 release_dc_ptr( dc );
981 /***********************************************************************
982 * GetTextFaceA (GDI32.@)
984 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
986 INT res = GetTextFaceW(hdc, 0, NULL);
987 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
988 GetTextFaceW( hdc, res, nameW );
994 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
998 /* GetTextFaceA does NOT include the nul byte in the return count. */
1005 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1006 HeapFree( GetProcessHeap(), 0, nameW );
1010 /***********************************************************************
1011 * GetTextFaceW (GDI32.@)
1013 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1018 DC * dc = get_dc_ptr( hdc );
1021 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1022 ret = dev->funcs->pGetTextFace( dev, count, name );
1023 release_dc_ptr( dc );
1028 /***********************************************************************
1029 * GetTextExtentPoint32A (GDI32.@)
1031 * See GetTextExtentPoint32W.
1033 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1040 if (count < 0) return FALSE;
1042 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1046 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1047 HeapFree( GetProcessHeap(), 0, p );
1050 TRACE("(%p %s %d %p): returning %d x %d\n",
1051 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1056 /***********************************************************************
1057 * GetTextExtentPoint32W [GDI32.@]
1059 * Computes width/height for a string.
1061 * Computes width and height of the specified string.
1067 BOOL WINAPI GetTextExtentPoint32W(
1068 HDC hdc, /* [in] Handle of device context */
1069 LPCWSTR str, /* [in] Address of text string */
1070 INT count, /* [in] Number of characters in string */
1071 LPSIZE size) /* [out] Address of structure for string size */
1073 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1076 /***********************************************************************
1077 * GetTextExtentExPointI [GDI32.@]
1079 * Computes width and height of the array of glyph indices.
1082 * hdc [I] Handle of device context.
1083 * indices [I] Glyph index array.
1084 * count [I] Number of glyphs in array.
1085 * max_ext [I] Maximum width in glyphs.
1086 * nfit [O] Maximum number of characters.
1087 * dxs [O] Partial string widths.
1088 * size [O] Returned string size.
1094 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1095 LPINT nfit, LPINT dxs, LPSIZE size )
1100 INT buffer[256], *pos = dxs;
1102 if (count < 0) return FALSE;
1104 dc = get_dc_ptr( hdc );
1105 if (!dc) return FALSE;
1110 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1112 release_dc_ptr( dc );
1117 ret = get_char_positions_indices( dc, indices, count, pos, size );
1122 for (i = 0; i < count; i++)
1124 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1125 if (dx > (unsigned int)max_ext) break;
1126 if (dxs) dxs[i] = dx;
1128 if (nfit) *nfit = i;
1131 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1132 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1135 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1136 release_dc_ptr( dc );
1138 TRACE("(%p %p %d %p): returning %d x %d\n",
1139 hdc, indices, count, size, size->cx, size->cy );
1143 /***********************************************************************
1144 * GetTextExtentPointI [GDI32.@]
1146 * Computes width and height of the array of glyph indices.
1149 * hdc [I] Handle of device context.
1150 * indices [I] Glyph index array.
1151 * count [I] Number of glyphs in array.
1152 * size [O] Returned string size.
1158 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1160 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1164 /***********************************************************************
1165 * GetTextExtentPointA (GDI32.@)
1167 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1170 TRACE("not bug compatible.\n");
1171 return GetTextExtentPoint32A( hdc, str, count, size );
1174 /***********************************************************************
1175 * GetTextExtentPointW (GDI32.@)
1177 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1180 TRACE("not bug compatible.\n");
1181 return GetTextExtentPoint32W( hdc, str, count, size );
1185 /***********************************************************************
1186 * GetTextExtentExPointA (GDI32.@)
1188 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1189 INT maxExt, LPINT lpnFit,
1190 LPINT alpDx, LPSIZE size )
1197 if (count < 0) return FALSE;
1198 if (maxExt < -1) return FALSE;
1202 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1203 if (!walpDx) return FALSE;
1206 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1207 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1210 INT n = lpnFit ? *lpnFit : wlen;
1212 for(i = 0, j = 0; i < n; i++, j++)
1214 alpDx[j] = walpDx[i];
1215 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1218 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1219 HeapFree( GetProcessHeap(), 0, p );
1220 HeapFree( GetProcessHeap(), 0, walpDx );
1225 /***********************************************************************
1226 * GetTextExtentExPointW (GDI32.@)
1228 * Return the size of the string as it would be if it was output properly by
1231 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1232 LPINT nfit, LPINT dxs, LPSIZE size )
1237 INT buffer[256], *pos = dxs;
1239 if (count < 0) return FALSE;
1241 dc = get_dc_ptr(hdc);
1242 if (!dc) return FALSE;
1247 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1249 release_dc_ptr( dc );
1254 ret = get_char_positions( dc, str, count, pos, size );
1259 for (i = 0; i < count; i++)
1261 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1262 if (dx > (unsigned int)max_ext) break;
1263 if (dxs) dxs[i] = dx;
1265 if (nfit) *nfit = i;
1268 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1269 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1272 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1273 release_dc_ptr( dc );
1275 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1279 /***********************************************************************
1280 * GetTextMetricsA (GDI32.@)
1282 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1286 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1287 FONT_TextMetricWToA( &tm32, metrics );
1291 /***********************************************************************
1292 * GetTextMetricsW (GDI32.@)
1294 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1298 DC * dc = get_dc_ptr( hdc );
1299 if (!dc) return FALSE;
1301 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1302 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1306 /* device layer returns values in device units
1307 * therefore we have to convert them to logical */
1309 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1310 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1312 #define WDPTOLP(x) ((x<0)? \
1313 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1314 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1315 #define HDPTOLP(y) ((y<0)? \
1316 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1317 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1319 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1320 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1321 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1322 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1323 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1324 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1325 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1326 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1330 TRACE("text metrics:\n"
1331 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1332 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1333 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1334 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1335 " PitchAndFamily = %02x\n"
1336 " --------------------\n"
1337 " InternalLeading = %i\n"
1341 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1342 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1343 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1344 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1345 metrics->tmPitchAndFamily,
1346 metrics->tmInternalLeading,
1349 metrics->tmHeight );
1351 release_dc_ptr( dc );
1356 /***********************************************************************
1357 * GetOutlineTextMetricsA (GDI32.@)
1358 * Gets metrics for TrueType fonts.
1361 * If the supplied buffer isn't big enough Windows partially fills it up to
1362 * its given length and returns that length.
1365 * Success: Non-zero or size of required buffer
1368 UINT WINAPI GetOutlineTextMetricsA(
1369 HDC hdc, /* [in] Handle of device context */
1370 UINT cbData, /* [in] Size of metric data array */
1371 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1373 char buf[512], *ptr;
1375 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1376 OUTLINETEXTMETRICA *output = lpOTM;
1379 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1381 if(ret > sizeof(buf))
1382 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1383 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1385 needed = sizeof(OUTLINETEXTMETRICA);
1386 if(lpOTMW->otmpFamilyName)
1387 needed += WideCharToMultiByte(CP_ACP, 0,
1388 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1389 NULL, 0, NULL, NULL);
1390 if(lpOTMW->otmpFaceName)
1391 needed += WideCharToMultiByte(CP_ACP, 0,
1392 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1393 NULL, 0, NULL, NULL);
1394 if(lpOTMW->otmpStyleName)
1395 needed += WideCharToMultiByte(CP_ACP, 0,
1396 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1397 NULL, 0, NULL, NULL);
1398 if(lpOTMW->otmpFullName)
1399 needed += WideCharToMultiByte(CP_ACP, 0,
1400 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1401 NULL, 0, NULL, NULL);
1408 TRACE("needed = %d\n", needed);
1410 /* Since the supplied buffer isn't big enough, we'll alloc one
1411 that is and memcpy the first cbData bytes into the lpOTM at
1413 output = HeapAlloc(GetProcessHeap(), 0, needed);
1415 ret = output->otmSize = min(needed, cbData);
1416 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1417 output->otmFiller = 0;
1418 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1419 output->otmfsSelection = lpOTMW->otmfsSelection;
1420 output->otmfsType = lpOTMW->otmfsType;
1421 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1422 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1423 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1424 output->otmEMSquare = lpOTMW->otmEMSquare;
1425 output->otmAscent = lpOTMW->otmAscent;
1426 output->otmDescent = lpOTMW->otmDescent;
1427 output->otmLineGap = lpOTMW->otmLineGap;
1428 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1429 output->otmsXHeight = lpOTMW->otmsXHeight;
1430 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1431 output->otmMacAscent = lpOTMW->otmMacAscent;
1432 output->otmMacDescent = lpOTMW->otmMacDescent;
1433 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1434 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1435 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1436 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1437 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1438 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1439 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1440 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1441 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1442 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1445 ptr = (char*)(output + 1);
1446 left = needed - sizeof(*output);
1448 if(lpOTMW->otmpFamilyName) {
1449 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1450 len = WideCharToMultiByte(CP_ACP, 0,
1451 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1452 ptr, left, NULL, NULL);
1456 output->otmpFamilyName = 0;
1458 if(lpOTMW->otmpFaceName) {
1459 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1460 len = WideCharToMultiByte(CP_ACP, 0,
1461 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1462 ptr, left, NULL, NULL);
1466 output->otmpFaceName = 0;
1468 if(lpOTMW->otmpStyleName) {
1469 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1470 len = WideCharToMultiByte(CP_ACP, 0,
1471 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1472 ptr, left, NULL, NULL);
1476 output->otmpStyleName = 0;
1478 if(lpOTMW->otmpFullName) {
1479 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1480 len = WideCharToMultiByte(CP_ACP, 0,
1481 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1482 ptr, left, NULL, NULL);
1485 output->otmpFullName = 0;
1489 if(output != lpOTM) {
1490 memcpy(lpOTM, output, cbData);
1491 HeapFree(GetProcessHeap(), 0, output);
1493 /* check if the string offsets really fit into the provided size */
1494 /* FIXME: should we check string length as well? */
1495 /* make sure that we don't read/write beyond the provided buffer */
1496 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1498 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1499 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1502 /* make sure that we don't read/write beyond the provided buffer */
1503 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1505 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1506 lpOTM->otmpFaceName = 0; /* doesn't fit */
1509 /* make sure that we don't read/write beyond the provided buffer */
1510 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1512 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1513 lpOTM->otmpStyleName = 0; /* doesn't fit */
1516 /* make sure that we don't read/write beyond the provided buffer */
1517 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1519 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1520 lpOTM->otmpFullName = 0; /* doesn't fit */
1525 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1526 HeapFree(GetProcessHeap(), 0, lpOTMW);
1532 /***********************************************************************
1533 * GetOutlineTextMetricsW [GDI32.@]
1535 UINT WINAPI GetOutlineTextMetricsW(
1536 HDC hdc, /* [in] Handle of device context */
1537 UINT cbData, /* [in] Size of metric data array */
1538 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1540 DC *dc = get_dc_ptr( hdc );
1541 OUTLINETEXTMETRICW *output = lpOTM;
1545 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1548 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1549 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1551 if (lpOTM && ret > cbData)
1553 output = HeapAlloc(GetProcessHeap(), 0, ret);
1554 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1559 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1560 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1562 #define WDPTOLP(x) ((x<0)? \
1563 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1564 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1565 #define HDPTOLP(y) ((y<0)? \
1566 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1567 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1569 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1570 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1571 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1572 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1573 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1574 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1575 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1576 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1577 output->otmAscent = HDPTOLP(output->otmAscent);
1578 output->otmDescent = HDPTOLP(output->otmDescent);
1579 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1580 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1581 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1582 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1583 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1584 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1585 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1586 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1587 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1588 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1589 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1590 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1591 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1592 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1593 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1594 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1595 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1596 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1597 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1598 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1599 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1600 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1605 memcpy(lpOTM, output, cbData);
1606 HeapFree(GetProcessHeap(), 0, output);
1614 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1616 INT i, count = lastChar - firstChar + 1;
1624 mbcp = GdiGetCodePage(hdc);
1632 if (lastChar > 0xffff)
1634 if ((firstChar ^ lastChar) > 0xff)
1638 if (lastChar > 0xff)
1644 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1648 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1652 str[i++] = (BYTE)(c >> 8);
1653 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1654 str[i] = 0x1f; /* FIXME: use default character */
1668 /***********************************************************************
1669 * GetCharWidthW (GDI32.@)
1670 * GetCharWidth32W (GDI32.@)
1672 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1678 DC * dc = get_dc_ptr( hdc );
1680 if (!dc) return FALSE;
1682 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1683 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1687 /* convert device units to logical */
1688 for( i = firstChar; i <= lastChar; i++, buffer++ )
1689 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1691 release_dc_ptr( dc );
1696 /***********************************************************************
1697 * GetCharWidthA (GDI32.@)
1698 * GetCharWidth32A (GDI32.@)
1700 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1708 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1712 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1714 for(i = 0; i < wlen; i++)
1716 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1724 HeapFree(GetProcessHeap(), 0, str);
1725 HeapFree(GetProcessHeap(), 0, wstr);
1731 /* helper for nulldrv_ExtTextOut */
1732 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1733 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1735 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1736 UINT indices[3] = {0, 0, 0x20};
1742 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1744 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1747 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1748 if (ret != GDI_ERROR) break;
1751 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1752 if (!image) return ERROR_SUCCESS;
1756 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1758 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1759 size = metrics->gmBlackBoxY * stride;
1761 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1762 image->is_copy = TRUE;
1763 image->free = free_heap_bits;
1765 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1766 if (ret == GDI_ERROR)
1768 HeapFree( GetProcessHeap(), 0, image->ptr );
1769 return ERROR_NOT_FOUND;
1771 return ERROR_SUCCESS;
1774 /* helper for nulldrv_ExtTextOut */
1775 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1776 LPCWSTR str, UINT count, const INT *dx )
1781 reset_bounds( &bounds );
1782 for (i = 0; i < count; i++)
1784 GLYPHMETRICS metrics;
1786 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1788 rect.left = x + metrics.gmptGlyphOrigin.x;
1789 rect.top = y - metrics.gmptGlyphOrigin.y;
1790 rect.right = rect.left + metrics.gmBlackBoxX;
1791 rect.bottom = rect.top + metrics.gmBlackBoxY;
1792 add_bounds_rect( &bounds, &rect );
1796 if (flags & ETO_PDY)
1799 y += dx[ i * 2 + 1];
1805 x += metrics.gmCellIncX;
1806 y += metrics.gmCellIncY;
1812 /* helper for nulldrv_ExtTextOut */
1813 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1814 const struct gdi_image_bits *image, const RECT *clip )
1816 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1817 UINT x, y, i, count, max_count;
1818 BYTE *ptr = image->ptr;
1819 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1821 RECT rect, clipped_rect;
1823 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1824 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1825 rect.right = rect.left + metrics->gmBlackBoxX;
1826 rect.bottom = rect.top + metrics->gmBlackBoxY;
1827 if (!clip) clipped_rect = rect;
1828 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1830 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1831 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1835 ptr += (clipped_rect.top - rect.top) * stride;
1836 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1838 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1840 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1841 pts[count].x = rect.left + x;
1842 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1843 pts[count + 1].x = rect.left + x;
1844 if (pts[count + 1].x > pts[count].x)
1846 pts[count].y = pts[count + 1].y = y;
1851 assert( count <= max_count );
1852 DPtoLP( hdc, pts, count );
1853 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1854 HeapFree( GetProcessHeap(), 0, pts );
1857 /***********************************************************************
1858 * nulldrv_ExtTextOut
1860 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1861 LPCWSTR str, UINT count, const INT *dx )
1863 DC *dc = get_nulldrv_dc( dev );
1869 if (flags & ETO_OPAQUE)
1872 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1876 orig = SelectObject( dev->hdc, brush );
1877 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1878 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1879 SelectObject( dev->hdc, orig );
1880 DeleteObject( brush );
1884 if (!count) return TRUE;
1886 if (dc->aa_flags != GGO_BITMAP)
1888 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1889 BITMAPINFO *info = (BITMAPINFO *)buffer;
1890 struct gdi_image_bits bits;
1891 struct bitblt_coords src, dst;
1893 /* FIXME Subpixel modes */
1894 UINT aa_flags = GGO_GRAY4_BITMAP;
1896 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1897 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1898 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1899 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1901 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1902 src.x = src.visrect.left;
1903 src.y = src.visrect.top;
1904 src.width = src.visrect.right - src.visrect.left;
1905 src.height = src.visrect.bottom - src.visrect.top;
1907 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1908 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1910 /* we can avoid the GetImage, just query the needed format */
1911 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1912 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1913 info->bmiHeader.biWidth = src.width;
1914 info->bmiHeader.biHeight = -src.height;
1915 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1916 if (!err || err == ERROR_BAD_FORMAT)
1918 /* make the source rectangle relative to the source bits */
1920 src.visrect.left = src.visrect.top = 0;
1921 src.visrect.right = src.width;
1922 src.visrect.bottom = src.height;
1924 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1925 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1926 bits.is_copy = TRUE;
1927 bits.free = free_heap_bits;
1928 err = ERROR_SUCCESS;
1933 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1934 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1935 if (!err && !bits.is_copy)
1937 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1940 if (bits.free) bits.free( &bits );
1941 return ERROR_OUTOFMEMORY;
1943 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1944 if (bits.free) bits.free( &bits );
1946 bits.is_copy = TRUE;
1947 bits.free = free_heap_bits;
1952 /* make x,y relative to the image bits */
1953 x += src.visrect.left - dst.visrect.left;
1954 y += src.visrect.top - dst.visrect.top;
1955 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1956 aa_flags, str, count, dx );
1957 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
1958 if (bits.free) bits.free( &bits );
1963 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1964 orig = SelectObject( dev->hdc, pen );
1966 for (i = 0; i < count; i++)
1968 GLYPHMETRICS metrics;
1969 struct gdi_image_bits image;
1971 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
1974 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1975 if (image.free) image.free( &image );
1979 if (flags & ETO_PDY)
1982 y += dx[ i * 2 + 1];
1988 x += metrics.gmCellIncX;
1989 y += metrics.gmCellIncY;
1993 SelectObject( dev->hdc, orig );
1994 DeleteObject( pen );
1999 /***********************************************************************
2000 * ExtTextOutA (GDI32.@)
2004 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2005 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2013 if (flags & ETO_GLYPH_INDEX)
2014 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2016 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2019 unsigned int i = 0, j = 0;
2021 /* allocate enough for a ETO_PDY */
2022 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2024 if(IsDBCSLeadByteEx(codepage, str[i]))
2028 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2029 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2032 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2039 lpDxW[j++] = lpDx[i * 2];
2040 lpDxW[j++] = lpDx[i * 2 + 1];
2043 lpDxW[j++] = lpDx[i];
2049 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2051 HeapFree( GetProcessHeap(), 0, p );
2052 HeapFree( GetProcessHeap(), 0, lpDxW );
2057 /***********************************************************************
2058 * ExtTextOutW (GDI32.@)
2060 * Draws text using the currently selected font, background color, and text color.
2064 * x,y [I] coordinates of string
2066 * ETO_GRAYED - undocumented on MSDN
2067 * ETO_OPAQUE - use background color for fill the rectangle
2068 * ETO_CLIPPED - clipping text to the rectangle
2069 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2070 * than encoded characters. Implies ETO_IGNORELANGUAGE
2071 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2072 * Affects BiDi ordering
2073 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2074 * ETO_PDY - unimplemented
2075 * ETO_NUMERICSLATIN - unimplemented always assumed -
2076 * do not translate numbers into locale representations
2077 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2078 * lprect [I] dimensions for clipping or/and opaquing
2079 * str [I] text string
2080 * count [I] number of symbols in string
2081 * lpDx [I] optional parameter with distance between drawing characters
2087 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2088 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2091 LPWSTR reordered_str = (LPWSTR)str;
2092 WORD *glyphs = NULL;
2093 UINT align = GetTextAlign( hdc );
2094 DWORD layout = GetLayout( hdc );
2098 double cosEsc, sinEsc;
2102 POINT *deltas = NULL, width = {0, 0};
2104 DC * dc = get_dc_ptr( hdc );
2107 static int quietfixme = 0;
2109 if (!dc) return FALSE;
2111 breakRem = dc->breakRem;
2113 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2115 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2120 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2121 type = GetObjectType(hdc);
2122 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2124 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2125 release_dc_ptr( dc );
2129 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2130 if (layout & LAYOUT_RTL)
2132 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2133 align ^= TA_RTLREADING;
2136 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2139 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2141 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2142 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2143 reordered_str, count, NULL, &glyphs, &cGlyphs);
2145 flags |= ETO_IGNORELANGUAGE;
2148 flags |= ETO_GLYPH_INDEX;
2149 if (cGlyphs != count)
2153 else if(flags & ETO_GLYPH_INDEX)
2154 glyphs = reordered_str;
2156 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2157 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2158 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2160 if(align & TA_UPDATECP)
2162 GetCurrentPositionEx( hdc, &pt );
2167 GetTextMetricsW(hdc, &tm);
2168 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2170 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2171 lf.lfEscapement = 0;
2173 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2174 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2176 lf.lfEscapement = -lf.lfEscapement;
2179 if(lf.lfEscapement != 0)
2181 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2182 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2193 LPtoDP(hdc, (POINT*)&rc, 2);
2195 if (flags & ETO_OPAQUE)
2196 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2198 else flags &= ~ETO_CLIPPED;
2208 LPtoDP(hdc, &pt, 1);
2212 char_extra = GetTextCharacterExtra(hdc);
2213 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2216 POINT total = {0, 0}, desired[2];
2218 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2221 if (flags & ETO_PDY)
2223 for (i = 0; i < count; i++)
2225 deltas[i].x = lpDx[i * 2] + char_extra;
2226 deltas[i].y = -lpDx[i * 2 + 1];
2231 for (i = 0; i < count; i++)
2233 deltas[i].x = lpDx[i] + char_extra;
2240 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2242 if (flags & ETO_GLYPH_INDEX)
2243 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2245 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2247 deltas[0].x = dx[0];
2249 for (i = 1; i < count; i++)
2251 deltas[i].x = dx[i] - dx[i - 1];
2254 HeapFree( GetProcessHeap(), 0, dx );
2257 for(i = 0; i < count; i++)
2259 total.x += deltas[i].x;
2260 total.y += deltas[i].y;
2262 desired[0].x = desired[0].y = 0;
2264 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2265 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2267 LPtoDP(hdc, desired, 2);
2268 desired[1].x -= desired[0].x;
2269 desired[1].y -= desired[0].y;
2271 if (dc->GraphicsMode == GM_COMPATIBLE)
2273 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2274 desired[1].x = -desired[1].x;
2275 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2276 desired[1].y = -desired[1].y;
2279 deltas[i].x = desired[1].x - width.x;
2280 deltas[i].y = desired[1].y - width.y;
2290 if(flags & ETO_GLYPH_INDEX)
2291 GetTextExtentPointI(hdc, glyphs, count, &sz);
2293 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2294 desired[0].x = desired[0].y = 0;
2295 desired[1].x = sz.cx;
2297 LPtoDP(hdc, desired, 2);
2298 desired[1].x -= desired[0].x;
2299 desired[1].y -= desired[0].y;
2301 if (dc->GraphicsMode == GM_COMPATIBLE)
2303 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2304 desired[1].x = -desired[1].x;
2305 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2306 desired[1].y = -desired[1].y;
2311 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2312 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2313 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2316 if (align & TA_UPDATECP)
2320 DPtoLP(hdc, &pt, 1);
2321 MoveToEx(hdc, pt.x, pt.y, NULL);
2333 if (align & TA_UPDATECP)
2337 DPtoLP(hdc, &pt, 1);
2338 MoveToEx(hdc, pt.x, pt.y, NULL);
2343 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2346 y += tm.tmAscent * cosEsc;
2347 x += tm.tmAscent * sinEsc;
2351 y -= tm.tmDescent * cosEsc;
2352 x -= tm.tmDescent * sinEsc;
2359 if (GetBkMode(hdc) != TRANSPARENT)
2361 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2363 if(!(flags & ETO_OPAQUE) || !lprect ||
2364 x < rc.left || x + width.x >= rc.right ||
2365 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2369 text_box.right = x + width.x;
2370 text_box.top = y - tm.tmAscent;
2371 text_box.bottom = y + tm.tmDescent;
2373 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2374 if (!is_rect_empty( &text_box ))
2375 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2380 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2381 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2384 HeapFree(GetProcessHeap(), 0, deltas);
2385 if(glyphs != reordered_str)
2386 HeapFree(GetProcessHeap(), 0, glyphs);
2387 if(reordered_str != str)
2388 HeapFree(GetProcessHeap(), 0, reordered_str);
2390 release_dc_ptr( dc );
2392 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2394 int underlinePos, strikeoutPos;
2395 int underlineWidth, strikeoutWidth;
2396 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2397 OUTLINETEXTMETRICW* otm = NULL;
2399 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2400 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2402 hbrush = SelectObject(hdc, hbrush);
2407 underlineWidth = tm.tmAscent / 20 + 1;
2408 strikeoutPos = tm.tmAscent / 2;
2409 strikeoutWidth = underlineWidth;
2413 otm = HeapAlloc(GetProcessHeap(), 0, size);
2414 GetOutlineTextMetricsW(hdc, size, otm);
2415 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2416 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2417 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2418 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2419 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2420 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2421 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2422 HeapFree(GetProcessHeap(), 0, otm);
2428 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2429 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2430 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2431 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2432 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2433 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2434 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2435 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2436 pts[4].x = pts[0].x;
2437 pts[4].y = pts[0].y;
2438 DPtoLP(hdc, pts, 5);
2439 Polygon(hdc, pts, 5);
2444 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2445 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2446 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2447 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2448 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2449 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2450 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2451 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2452 pts[4].x = pts[0].x;
2453 pts[4].y = pts[0].y;
2454 DPtoLP(hdc, pts, 5);
2455 Polygon(hdc, pts, 5);
2458 SelectObject(hdc, hpen);
2459 hbrush = SelectObject(hdc, hbrush);
2460 DeleteObject(hbrush);
2467 /***********************************************************************
2468 * TextOutA (GDI32.@)
2470 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2472 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2476 /***********************************************************************
2477 * TextOutW (GDI32.@)
2479 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2481 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2485 /***********************************************************************
2486 * PolyTextOutA (GDI32.@)
2490 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2492 for (; cStrings>0; cStrings--, pptxt++)
2493 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2500 /***********************************************************************
2501 * PolyTextOutW (GDI32.@)
2503 * Draw several Strings
2509 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2511 for (; cStrings>0; cStrings--, pptxt++)
2512 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2518 /***********************************************************************
2519 * SetMapperFlags (GDI32.@)
2521 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2523 DC *dc = get_dc_ptr( hdc );
2524 DWORD ret = GDI_ERROR;
2528 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2529 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2530 if (flags != GDI_ERROR)
2532 ret = dc->mapperFlags;
2533 dc->mapperFlags = flags;
2535 release_dc_ptr( dc );
2540 /***********************************************************************
2541 * GetAspectRatioFilterEx (GDI32.@)
2543 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2545 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2550 /***********************************************************************
2551 * GetCharABCWidthsA (GDI32.@)
2553 * See GetCharABCWidthsW.
2555 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2563 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2567 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2570 HeapFree(GetProcessHeap(), 0, str);
2574 for(i = 0; i < wlen; i++)
2576 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2584 HeapFree(GetProcessHeap(), 0, str);
2585 HeapFree(GetProcessHeap(), 0, wstr);
2591 /******************************************************************************
2592 * GetCharABCWidthsW [GDI32.@]
2594 * Retrieves widths of characters in range.
2597 * hdc [I] Handle of device context
2598 * firstChar [I] First character in range to query
2599 * lastChar [I] Last character in range to query
2600 * abc [O] Address of character-width structure
2603 * Only works with TrueType fonts
2609 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2612 DC *dc = get_dc_ptr(hdc);
2618 if (!dc) return FALSE;
2622 release_dc_ptr( dc );
2626 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2627 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2628 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2630 release_dc_ptr( dc );
2634 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2635 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2638 /* convert device units to logical */
2639 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2640 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2641 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2642 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2646 release_dc_ptr( dc );
2651 /******************************************************************************
2652 * GetCharABCWidthsI [GDI32.@]
2654 * Retrieves widths of characters in range.
2657 * hdc [I] Handle of device context
2658 * firstChar [I] First glyphs in range to query
2659 * count [I] Last glyphs in range to query
2660 * pgi [i] Array of glyphs to query
2661 * abc [O] Address of character-width structure
2664 * Only works with TrueType fonts
2670 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2671 LPWORD pgi, LPABC abc)
2673 DC *dc = get_dc_ptr(hdc);
2678 if (!dc) return FALSE;
2682 release_dc_ptr( dc );
2686 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2687 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2690 /* convert device units to logical */
2691 for( i = 0; i < count; i++, abc++ ) {
2692 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2693 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2694 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2698 release_dc_ptr( dc );
2703 /***********************************************************************
2704 * GetGlyphOutlineA (GDI32.@)
2706 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2707 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2708 LPVOID lpBuffer, const MAT2 *lpmat2 )
2710 if (!lpmat2) return GDI_ERROR;
2712 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2717 cp = GdiGetCodePage(hdc);
2718 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2720 mbchs[0] = (uChar & 0xff00) >> 8;
2721 mbchs[1] = (uChar & 0xff);
2724 mbchs[0] = (uChar & 0xff);
2727 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2730 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2734 /***********************************************************************
2735 * GetGlyphOutlineW (GDI32.@)
2737 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2738 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2739 LPVOID lpBuffer, const MAT2 *lpmat2 )
2745 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2746 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2748 if (!lpmat2) return GDI_ERROR;
2750 dc = get_dc_ptr(hdc);
2751 if(!dc) return GDI_ERROR;
2753 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2754 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2755 release_dc_ptr( dc );
2760 /***********************************************************************
2761 * CreateScalableFontResourceA (GDI32.@)
2763 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2764 LPCSTR lpszResourceFile,
2765 LPCSTR lpszFontFile,
2766 LPCSTR lpszCurrentPath )
2768 LPWSTR lpszResourceFileW = NULL;
2769 LPWSTR lpszFontFileW = NULL;
2770 LPWSTR lpszCurrentPathW = NULL;
2774 if (lpszResourceFile)
2776 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2777 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2778 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2783 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2784 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2785 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2788 if (lpszCurrentPath)
2790 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2791 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2792 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2795 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2796 lpszFontFileW, lpszCurrentPathW);
2798 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2799 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2800 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2805 /***********************************************************************
2806 * CreateScalableFontResourceW (GDI32.@)
2808 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2809 LPCWSTR font_file, LPCWSTR font_path )
2811 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2812 debugstr_w(font_file), debugstr_w(font_path) );
2814 return WineEngCreateScalableFontResource( hidden, resource_file,
2815 font_file, font_path );
2818 /*************************************************************************
2819 * GetKerningPairsA (GDI32.@)
2821 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2822 LPKERNINGPAIR kern_pairA )
2826 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2827 KERNINGPAIR *kern_pairW;
2829 if (!cPairs && kern_pairA)
2831 SetLastError(ERROR_INVALID_PARAMETER);
2835 cp = GdiGetCodePage(hDC);
2837 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2838 * to fail on an invalid character for CP_SYMBOL.
2840 cpi.DefaultChar[0] = 0;
2841 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2843 FIXME("Can't find codepage %u info\n", cp);
2847 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2848 if (!total_kern_pairs) return 0;
2850 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2851 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2853 for (i = 0; i < total_kern_pairs; i++)
2857 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2860 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2863 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2868 if (kern_pairs_copied >= cPairs) break;
2870 kern_pairA->wFirst = (BYTE)first;
2871 kern_pairA->wSecond = (BYTE)second;
2872 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2875 kern_pairs_copied++;
2878 HeapFree(GetProcessHeap(), 0, kern_pairW);
2880 return kern_pairs_copied;
2883 /*************************************************************************
2884 * GetKerningPairsW (GDI32.@)
2886 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2887 LPKERNINGPAIR lpKerningPairs )
2893 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2895 if (!cPairs && lpKerningPairs)
2897 SetLastError(ERROR_INVALID_PARAMETER);
2901 dc = get_dc_ptr(hDC);
2904 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2905 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2906 release_dc_ptr( dc );
2910 /*************************************************************************
2911 * TranslateCharsetInfo [GDI32.@]
2913 * Fills a CHARSETINFO structure for a character set, code page, or
2914 * font. This allows making the correspondence between different labels
2915 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2916 * of the same encoding.
2918 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2919 * only one codepage should be set in *lpSrc.
2922 * TRUE on success, FALSE on failure.
2925 BOOL WINAPI TranslateCharsetInfo(
2926 LPDWORD lpSrc, /* [in]
2927 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2928 if flags == TCI_SRCCHARSET: a character set value
2929 if flags == TCI_SRCCODEPAGE: a code page value
2931 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2932 DWORD flags /* [in] determines interpretation of lpSrc */)
2936 case TCI_SRCFONTSIG:
2937 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2939 case TCI_SRCCODEPAGE:
2940 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2942 case TCI_SRCCHARSET:
2943 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2948 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2949 *lpCs = FONT_tci[index];
2953 /*************************************************************************
2954 * GetFontLanguageInfo (GDI32.@)
2956 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2958 FONTSIGNATURE fontsig;
2959 static const DWORD GCP_DBCS_MASK=0x003F0000,
2960 GCP_DIACRITIC_MASK=0x00000000,
2961 FLI_GLYPHS_MASK=0x00000000,
2962 GCP_GLYPHSHAPE_MASK=0x00000040,
2963 GCP_KASHIDA_MASK=0x00000000,
2964 GCP_LIGATE_MASK=0x00000000,
2965 GCP_USEKERNING_MASK=0x00000000,
2966 GCP_REORDER_MASK=0x00000060;
2970 GetTextCharsetInfo( hdc, &fontsig, 0 );
2971 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2973 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2976 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2977 result|=GCP_DIACRITIC;
2979 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2982 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2983 result|=GCP_GLYPHSHAPE;
2985 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2986 result|=GCP_KASHIDA;
2988 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2991 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2992 result|=GCP_USEKERNING;
2994 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2995 if( GetTextAlign( hdc) & TA_RTLREADING )
2996 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2997 result|=GCP_REORDER;
3003 /*************************************************************************
3004 * GetFontData [GDI32.@]
3006 * Retrieve data for TrueType font.
3010 * success: Number of bytes returned
3011 * failure: GDI_ERROR
3015 * Calls SetLastError()
3018 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3019 LPVOID buffer, DWORD length)
3021 DC *dc = get_dc_ptr(hdc);
3025 if(!dc) return GDI_ERROR;
3027 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3028 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3029 release_dc_ptr( dc );
3033 /*************************************************************************
3034 * GetGlyphIndicesA [GDI32.@]
3036 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3037 LPWORD pgi, DWORD flags)
3043 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3044 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3046 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3047 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3048 HeapFree(GetProcessHeap(), 0, lpstrW);
3053 /*************************************************************************
3054 * GetGlyphIndicesW [GDI32.@]
3056 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3057 LPWORD pgi, DWORD flags)
3059 DC *dc = get_dc_ptr(hdc);
3063 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3064 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3066 if(!dc) return GDI_ERROR;
3068 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3069 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3070 release_dc_ptr( dc );
3074 /*************************************************************************
3075 * GetCharacterPlacementA [GDI32.@]
3077 * See GetCharacterPlacementW.
3080 * the web browser control of ie4 calls this with dwFlags=0
3083 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3084 INT nMaxExtent, GCP_RESULTSA *lpResults,
3089 GCP_RESULTSW resultsW;
3093 TRACE("%s, %d, %d, 0x%08x\n",
3094 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3096 /* both structs are equal in size */
3097 memcpy(&resultsW, lpResults, sizeof(resultsW));
3099 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3100 if(lpResults->lpOutString)
3101 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3103 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3105 lpResults->nGlyphs = resultsW.nGlyphs;
3106 lpResults->nMaxFit = resultsW.nMaxFit;
3108 if(lpResults->lpOutString) {
3109 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3110 lpResults->lpOutString, uCount, NULL, NULL );
3113 HeapFree(GetProcessHeap(), 0, lpStringW);
3114 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3119 /*************************************************************************
3120 * GetCharacterPlacementW [GDI32.@]
3122 * Retrieve information about a string. This includes the width, reordering,
3123 * Glyphing and so on.
3127 * The width and height of the string if successful, 0 if failed.
3131 * All flags except GCP_REORDER are not yet implemented.
3132 * Reordering is not 100% compliant to the Windows BiDi method.
3133 * Caret positioning is not yet implemented for BiDi.
3134 * Classes are not yet implemented.
3138 GetCharacterPlacementW(
3139 HDC hdc, /* [in] Device context for which the rendering is to be done */
3140 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3141 INT uCount, /* [in] Number of WORDS in string. */
3142 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3143 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3144 DWORD dwFlags /* [in] Flags specifying how to process the string */
3151 TRACE("%s, %d, %d, 0x%08x\n",
3152 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3154 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3155 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3156 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3157 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3158 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3160 if(dwFlags&(~GCP_REORDER))
3161 FIXME("flags 0x%08x ignored\n", dwFlags);
3162 if(lpResults->lpClass)
3163 FIXME("classes not implemented\n");
3164 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3165 FIXME("Caret positions for complex scripts not implemented\n");
3167 nSet = (UINT)uCount;
3168 if(nSet > lpResults->nGlyphs)
3169 nSet = lpResults->nGlyphs;
3171 /* return number of initialized fields */
3172 lpResults->nGlyphs = nSet;
3174 if((dwFlags&GCP_REORDER)==0 )
3176 /* Treat the case where no special handling was requested in a fastpath way */
3177 /* copy will do if the GCP_REORDER flag is not set */
3178 if(lpResults->lpOutString)
3179 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3181 if(lpResults->lpOrder)
3183 for(i = 0; i < nSet; i++)
3184 lpResults->lpOrder[i] = i;
3189 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3190 nSet, lpResults->lpOrder, NULL, NULL );
3193 /* FIXME: Will use the placement chars */
3194 if (lpResults->lpDx)
3197 for (i = 0; i < nSet; i++)
3199 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3200 lpResults->lpDx[i]= c;
3204 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3208 lpResults->lpCaretPos[0] = 0;
3209 for (i = 1; i < nSet; i++)
3210 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3211 lpResults->lpCaretPos[i] = (pos += size.cx);
3214 if(lpResults->lpGlyphs)
3215 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3217 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3218 ret = MAKELONG(size.cx, size.cy);
3223 /*************************************************************************
3224 * GetCharABCWidthsFloatA [GDI32.@]
3226 * See GetCharABCWidthsFloatW.
3228 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3235 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3239 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3241 for (i = 0; i < wlen; i++)
3243 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3251 HeapFree( GetProcessHeap(), 0, str );
3252 HeapFree( GetProcessHeap(), 0, wstr );
3257 /*************************************************************************
3258 * GetCharABCWidthsFloatW [GDI32.@]
3260 * Retrieves widths of a range of characters.
3263 * hdc [I] Handle to device context.
3264 * first [I] First character in range to query.
3265 * last [I] Last character in range to query.
3266 * abcf [O] Array of LPABCFLOAT structures.
3272 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3278 DC *dc = get_dc_ptr( hdc );
3280 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3282 if (!dc) return FALSE;
3284 if (!abcf) goto done;
3285 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3287 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3288 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3291 /* convert device units to logical */
3292 for (i = first; i <= last; i++, abcf++)
3294 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3295 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3296 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3299 HeapFree( GetProcessHeap(), 0, abc );
3302 release_dc_ptr( dc );
3306 /*************************************************************************
3307 * GetCharWidthFloatA [GDI32.@]
3309 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3310 UINT iLastChar, PFLOAT pxBuffer)
3312 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3316 /*************************************************************************
3317 * GetCharWidthFloatW [GDI32.@]
3319 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3320 UINT iLastChar, PFLOAT pxBuffer)
3322 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3327 /***********************************************************************
3329 * Font Resource API *
3331 ***********************************************************************/
3333 /***********************************************************************
3334 * AddFontResourceA (GDI32.@)
3336 INT WINAPI AddFontResourceA( LPCSTR str )
3338 return AddFontResourceExA( str, 0, NULL);
3341 /***********************************************************************
3342 * AddFontResourceW (GDI32.@)
3344 INT WINAPI AddFontResourceW( LPCWSTR str )
3346 return AddFontResourceExW(str, 0, NULL);
3350 /***********************************************************************
3351 * AddFontResourceExA (GDI32.@)
3353 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3355 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3356 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3359 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3360 ret = AddFontResourceExW(strW, fl, pdv);
3361 HeapFree(GetProcessHeap(), 0, strW);
3365 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3367 HRSRC rsrc = FindResourceW(hModule, name, type);
3368 HGLOBAL hMem = LoadResource(hModule, rsrc);
3369 LPVOID *pMem = LockResource(hMem);
3370 int *num_total = (int *)lParam;
3373 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3374 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3376 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3380 *num_total += num_in_res;
3384 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3386 HANDLE file, mapping;
3389 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3390 if (file == INVALID_HANDLE_VALUE) return NULL;
3392 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3394 CloseHandle( file );
3398 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3399 CloseHandle( file );
3400 if (!mapping) return NULL;
3402 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3403 CloseHandle( mapping );
3408 static WCHAR *get_scalable_filename( const WCHAR *res )
3411 BYTE *ptr = map_file( res, &size );
3412 const IMAGE_DOS_HEADER *dos;
3413 const IMAGE_OS2_HEADER *ne;
3415 WORD rsrc_off, align, type_id, count;
3416 DWORD res_off, res_len, i;
3419 if (!ptr) return NULL;
3421 if (size.u.LowPart < sizeof( *dos )) goto fail;
3422 dos = (const IMAGE_DOS_HEADER *)ptr;
3423 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3424 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3425 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3426 rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
3427 if (size.u.LowPart < rsrc_off + 10) goto fail;
3428 align = *(WORD *)(ptr + rsrc_off);
3430 type_id = *(WORD *)(ptr + rsrc_off);
3431 while (type_id && type_id != 0x80cc)
3433 count = *(WORD *)(ptr + rsrc_off + 2);
3434 rsrc_off += 8 + count * 12;
3435 if (size.u.LowPart < rsrc_off + 8) goto fail;
3436 type_id = *(WORD *)(ptr + rsrc_off);
3438 if (!type_id) goto fail;
3439 count = *(WORD *)(ptr + rsrc_off + 2);
3440 if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;
3442 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3443 res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
3444 if (size.u.LowPart < res_off + res_len) goto fail;
3446 for (i = 0; i < res_len; i++)
3447 if (ptr[ res_off + i ] == 0) break;
3448 if (i == res_len) goto fail;
3450 len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
3451 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3452 if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );
3455 UnmapViewOfFile( ptr );
3459 /***********************************************************************
3460 * AddFontResourceExW (GDI32.@)
3462 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3464 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3469 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3470 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3471 if (hModule != NULL)
3473 int num_resources = 0;
3474 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3476 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3477 wine_dbgstr_w(str));
3478 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3479 ret = num_resources;
3480 FreeLibrary(hModule);
3482 else if ((filename = get_scalable_filename( str )) != NULL)
3484 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3485 HeapFree( GetProcessHeap(), 0, filename );
3491 /***********************************************************************
3492 * RemoveFontResourceA (GDI32.@)
3494 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3496 return RemoveFontResourceExA(str, 0, 0);
3499 /***********************************************************************
3500 * RemoveFontResourceW (GDI32.@)
3502 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3504 return RemoveFontResourceExW(str, 0, 0);
3507 /***********************************************************************
3508 * AddFontMemResourceEx (GDI32.@)
3510 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3515 if (!pbFont || !cbFont || !pcFonts)
3517 SetLastError(ERROR_INVALID_PARAMETER);
3521 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3526 *pcFonts = num_fonts;
3530 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3531 RemoveFontMemResourceEx(ret);
3539 /***********************************************************************
3540 * RemoveFontMemResourceEx (GDI32.@)
3542 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3544 FIXME("(%p) stub\n", fh);
3548 /***********************************************************************
3549 * RemoveFontResourceExA (GDI32.@)
3551 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3553 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3554 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3557 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3558 ret = RemoveFontResourceExW(strW, fl, pdv);
3559 HeapFree(GetProcessHeap(), 0, strW);
3563 /***********************************************************************
3564 * RemoveFontResourceExW (GDI32.@)
3566 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3568 return WineEngRemoveFontResourceEx(str, fl, pdv);
3571 /***********************************************************************
3572 * GetTextCharset (GDI32.@)
3574 UINT WINAPI GetTextCharset(HDC hdc)
3576 /* MSDN docs say this is equivalent */
3577 return GetTextCharsetInfo(hdc, NULL, 0);
3580 /***********************************************************************
3581 * GetTextCharsetInfo (GDI32.@)
3583 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3585 UINT ret = DEFAULT_CHARSET;
3586 DC *dc = get_dc_ptr(hdc);
3591 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3592 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3593 release_dc_ptr( dc );
3596 if (ret == DEFAULT_CHARSET && fs)
3597 memset(fs, 0, sizeof(FONTSIGNATURE));
3601 /***********************************************************************
3602 * GdiGetCharDimensions (GDI32.@)
3604 * Gets the average width of the characters in the English alphabet.
3607 * hdc [I] Handle to the device context to measure on.
3608 * lptm [O] Pointer to memory to store the text metrics into.
3609 * height [O] On exit, the maximum height of characters in the English alphabet.
3612 * The average width of characters in the English alphabet.
3615 * This function is used by the dialog manager to get the size of a dialog
3616 * unit. It should also be used by other pieces of code that need to know
3617 * the size of a dialog unit in logical units without having access to the
3618 * window handle of the dialog.
3619 * Windows caches the font metrics from this function, but we don't and
3620 * there doesn't appear to be an immediate advantage to do so.
3623 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3625 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3628 static const WCHAR alphabet[] = {
3629 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3630 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3631 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3633 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3635 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3637 if (height) *height = sz.cy;
3638 return (sz.cx / 26 + 1) / 2;
3641 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3643 FIXME("(%d): stub\n", fEnableEUDC);
3647 /***********************************************************************
3648 * GetCharWidthI (GDI32.@)
3650 * Retrieve widths of characters.
3653 * hdc [I] Handle to a device context.
3654 * first [I] First glyph in range to query.
3655 * count [I] Number of glyph indices to query.
3656 * glyphs [I] Array of glyphs to query.
3657 * buffer [O] Buffer to receive character widths.
3660 * Only works with TrueType fonts.
3666 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3671 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3673 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3676 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3678 HeapFree(GetProcessHeap(), 0, abc);
3682 for (i = 0; i < count; i++)
3683 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3685 HeapFree(GetProcessHeap(), 0, abc);
3689 /***********************************************************************
3690 * GetFontUnicodeRanges (GDI32.@)
3692 * Retrieve a list of supported Unicode characters in a font.
3695 * hdc [I] Handle to a device context.
3696 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3699 * Success: Number of bytes written to the buffer pointed to by lpgs.
3703 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3707 DC *dc = get_dc_ptr(hdc);
3709 TRACE("(%p, %p)\n", hdc, lpgs);
3713 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3714 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3720 /*************************************************************
3721 * FontIsLinked (GDI32.@)
3723 BOOL WINAPI FontIsLinked(HDC hdc)
3725 DC *dc = get_dc_ptr(hdc);
3729 if (!dc) return FALSE;
3730 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3731 ret = dev->funcs->pFontIsLinked( dev );
3733 TRACE("returning %d\n", ret);
3737 /*************************************************************
3738 * GdiRealizationInfo (GDI32.@)
3740 * Returns a structure that contains some font information.
3742 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3744 DC *dc = get_dc_ptr(hdc);
3748 if (!dc) return FALSE;
3749 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3750 ret = dev->funcs->pGdiRealizationInfo( dev, info );