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, pGetTextExtentExPointI );
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 i, count, max_count;
1819 BYTE *ptr = image->ptr;
1820 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1822 RECT rect, clipped_rect;
1824 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1825 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1826 rect.right = rect.left + metrics->gmBlackBoxX;
1827 rect.bottom = rect.top + metrics->gmBlackBoxY;
1828 if (!clip) clipped_rect = rect;
1829 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1831 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1832 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1836 ptr += (clipped_rect.top - rect.top) * stride;
1837 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1839 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1841 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1842 pts[count].x = rect.left + x;
1843 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1844 pts[count + 1].x = rect.left + x;
1845 if (pts[count + 1].x > pts[count].x)
1847 pts[count].y = pts[count + 1].y = y;
1852 assert( count <= max_count );
1853 DPtoLP( hdc, pts, count );
1854 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1855 HeapFree( GetProcessHeap(), 0, pts );
1858 /***********************************************************************
1859 * nulldrv_ExtTextOut
1861 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1862 LPCWSTR str, UINT count, const INT *dx )
1864 DC *dc = get_nulldrv_dc( dev );
1870 if (flags & ETO_OPAQUE)
1873 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1877 orig = SelectObject( dev->hdc, brush );
1878 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1879 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1880 SelectObject( dev->hdc, orig );
1881 DeleteObject( brush );
1885 if (!count) return TRUE;
1887 if (dc->aa_flags != GGO_BITMAP)
1889 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1890 BITMAPINFO *info = (BITMAPINFO *)buffer;
1891 struct gdi_image_bits bits;
1892 struct bitblt_coords src, dst;
1894 /* FIXME Subpixel modes */
1895 UINT aa_flags = GGO_GRAY4_BITMAP;
1897 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1898 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1899 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1900 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1902 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1903 src.x = src.visrect.left;
1904 src.y = src.visrect.top;
1905 src.width = src.visrect.right - src.visrect.left;
1906 src.height = src.visrect.bottom - src.visrect.top;
1908 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1909 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1911 /* we can avoid the GetImage, just query the needed format */
1912 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1913 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1914 info->bmiHeader.biWidth = src.width;
1915 info->bmiHeader.biHeight = -src.height;
1916 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1917 if (!err || err == ERROR_BAD_FORMAT)
1919 /* make the source rectangle relative to the source bits */
1921 src.visrect.left = src.visrect.top = 0;
1922 src.visrect.right = src.width;
1923 src.visrect.bottom = src.height;
1925 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1926 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1927 bits.is_copy = TRUE;
1928 bits.free = free_heap_bits;
1929 err = ERROR_SUCCESS;
1934 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1935 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1936 if (!err && !bits.is_copy)
1938 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1941 if (bits.free) bits.free( &bits );
1942 return ERROR_OUTOFMEMORY;
1944 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1945 if (bits.free) bits.free( &bits );
1947 bits.is_copy = TRUE;
1948 bits.free = free_heap_bits;
1953 /* make x,y relative to the image bits */
1954 x += src.visrect.left - dst.visrect.left;
1955 y += src.visrect.top - dst.visrect.top;
1956 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1957 aa_flags, str, count, dx );
1958 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
1959 if (bits.free) bits.free( &bits );
1964 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1965 orig = SelectObject( dev->hdc, pen );
1967 for (i = 0; i < count; i++)
1969 GLYPHMETRICS metrics;
1970 struct gdi_image_bits image;
1972 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
1975 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1976 if (image.free) image.free( &image );
1980 if (flags & ETO_PDY)
1983 y += dx[ i * 2 + 1];
1989 x += metrics.gmCellIncX;
1990 y += metrics.gmCellIncY;
1994 SelectObject( dev->hdc, orig );
1995 DeleteObject( pen );
2000 /***********************************************************************
2001 * ExtTextOutA (GDI32.@)
2005 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2006 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2014 if (flags & ETO_GLYPH_INDEX)
2015 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2017 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2020 unsigned int i = 0, j = 0;
2022 /* allocate enough for a ETO_PDY */
2023 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2025 if(IsDBCSLeadByteEx(codepage, str[i]))
2029 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2030 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2033 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2040 lpDxW[j++] = lpDx[i * 2];
2041 lpDxW[j++] = lpDx[i * 2 + 1];
2044 lpDxW[j++] = lpDx[i];
2050 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2052 HeapFree( GetProcessHeap(), 0, p );
2053 HeapFree( GetProcessHeap(), 0, lpDxW );
2058 /***********************************************************************
2059 * ExtTextOutW (GDI32.@)
2061 * Draws text using the currently selected font, background color, and text color.
2065 * x,y [I] coordinates of string
2067 * ETO_GRAYED - undocumented on MSDN
2068 * ETO_OPAQUE - use background color for fill the rectangle
2069 * ETO_CLIPPED - clipping text to the rectangle
2070 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2071 * than encoded characters. Implies ETO_IGNORELANGUAGE
2072 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2073 * Affects BiDi ordering
2074 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2075 * ETO_PDY - unimplemented
2076 * ETO_NUMERICSLATIN - unimplemented always assumed -
2077 * do not translate numbers into locale representations
2078 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2079 * lprect [I] dimensions for clipping or/and opaquing
2080 * str [I] text string
2081 * count [I] number of symbols in string
2082 * lpDx [I] optional parameter with distance between drawing characters
2088 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2089 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2092 LPWSTR reordered_str = (LPWSTR)str;
2093 WORD *glyphs = NULL;
2094 UINT align = GetTextAlign( hdc );
2095 DWORD layout = GetLayout( hdc );
2099 double cosEsc, sinEsc;
2103 POINT *deltas = NULL, width = {0, 0};
2105 DC * dc = get_dc_ptr( hdc );
2108 static int quietfixme = 0;
2110 if (!dc) return FALSE;
2112 breakRem = dc->breakRem;
2114 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2116 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2121 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2122 type = GetObjectType(hdc);
2123 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2125 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2126 release_dc_ptr( dc );
2130 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2131 if (layout & LAYOUT_RTL)
2133 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2134 align ^= TA_RTLREADING;
2137 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2140 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2142 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2143 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2144 reordered_str, count, NULL, &glyphs, &cGlyphs);
2146 flags |= ETO_IGNORELANGUAGE;
2149 flags |= ETO_GLYPH_INDEX;
2150 if (cGlyphs != count)
2154 else if(flags & ETO_GLYPH_INDEX)
2155 glyphs = reordered_str;
2157 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2158 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2159 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2161 if(align & TA_UPDATECP)
2163 GetCurrentPositionEx( hdc, &pt );
2168 GetTextMetricsW(hdc, &tm);
2169 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2171 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2172 lf.lfEscapement = 0;
2174 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2175 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2177 lf.lfEscapement = -lf.lfEscapement;
2180 if(lf.lfEscapement != 0)
2182 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2183 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2194 LPtoDP(hdc, (POINT*)&rc, 2);
2196 if (flags & ETO_OPAQUE)
2197 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2199 else flags &= ~ETO_CLIPPED;
2209 LPtoDP(hdc, &pt, 1);
2213 char_extra = GetTextCharacterExtra(hdc);
2214 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2217 POINT total = {0, 0}, desired[2];
2219 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2222 if (flags & ETO_PDY)
2224 for (i = 0; i < count; i++)
2226 deltas[i].x = lpDx[i * 2] + char_extra;
2227 deltas[i].y = -lpDx[i * 2 + 1];
2232 for (i = 0; i < count; i++)
2234 deltas[i].x = lpDx[i] + char_extra;
2241 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2243 if (flags & ETO_GLYPH_INDEX)
2244 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2246 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2248 deltas[0].x = dx[0];
2250 for (i = 1; i < count; i++)
2252 deltas[i].x = dx[i] - dx[i - 1];
2255 HeapFree( GetProcessHeap(), 0, dx );
2258 for(i = 0; i < count; i++)
2260 total.x += deltas[i].x;
2261 total.y += deltas[i].y;
2263 desired[0].x = desired[0].y = 0;
2265 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2266 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2268 LPtoDP(hdc, desired, 2);
2269 desired[1].x -= desired[0].x;
2270 desired[1].y -= desired[0].y;
2272 if (dc->GraphicsMode == GM_COMPATIBLE)
2274 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2275 desired[1].x = -desired[1].x;
2276 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2277 desired[1].y = -desired[1].y;
2280 deltas[i].x = desired[1].x - width.x;
2281 deltas[i].y = desired[1].y - width.y;
2291 if(flags & ETO_GLYPH_INDEX)
2292 GetTextExtentPointI(hdc, glyphs, count, &sz);
2294 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2295 desired[0].x = desired[0].y = 0;
2296 desired[1].x = sz.cx;
2298 LPtoDP(hdc, desired, 2);
2299 desired[1].x -= desired[0].x;
2300 desired[1].y -= desired[0].y;
2302 if (dc->GraphicsMode == GM_COMPATIBLE)
2304 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2305 desired[1].x = -desired[1].x;
2306 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2307 desired[1].y = -desired[1].y;
2312 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2313 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2314 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2317 if (align & TA_UPDATECP)
2321 DPtoLP(hdc, &pt, 1);
2322 MoveToEx(hdc, pt.x, pt.y, NULL);
2334 if (align & TA_UPDATECP)
2338 DPtoLP(hdc, &pt, 1);
2339 MoveToEx(hdc, pt.x, pt.y, NULL);
2344 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2347 y += tm.tmAscent * cosEsc;
2348 x += tm.tmAscent * sinEsc;
2352 y -= tm.tmDescent * cosEsc;
2353 x -= tm.tmDescent * sinEsc;
2360 if (GetBkMode(hdc) != TRANSPARENT)
2362 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2364 if(!(flags & ETO_OPAQUE) || !lprect ||
2365 x < rc.left || x + width.x >= rc.right ||
2366 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2370 text_box.right = x + width.x;
2371 text_box.top = y - tm.tmAscent;
2372 text_box.bottom = y + tm.tmDescent;
2374 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2375 if (!is_rect_empty( &text_box ))
2376 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2381 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2382 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2385 HeapFree(GetProcessHeap(), 0, deltas);
2386 if(glyphs != reordered_str)
2387 HeapFree(GetProcessHeap(), 0, glyphs);
2388 if(reordered_str != str)
2389 HeapFree(GetProcessHeap(), 0, reordered_str);
2391 release_dc_ptr( dc );
2393 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2395 int underlinePos, strikeoutPos;
2396 int underlineWidth, strikeoutWidth;
2397 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2398 OUTLINETEXTMETRICW* otm = NULL;
2400 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2401 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2403 hbrush = SelectObject(hdc, hbrush);
2408 underlineWidth = tm.tmAscent / 20 + 1;
2409 strikeoutPos = tm.tmAscent / 2;
2410 strikeoutWidth = underlineWidth;
2414 otm = HeapAlloc(GetProcessHeap(), 0, size);
2415 GetOutlineTextMetricsW(hdc, size, otm);
2416 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2417 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2418 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2419 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2420 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2421 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2422 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2423 HeapFree(GetProcessHeap(), 0, otm);
2429 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2430 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2431 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2432 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2433 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2434 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2435 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2436 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2437 pts[4].x = pts[0].x;
2438 pts[4].y = pts[0].y;
2439 DPtoLP(hdc, pts, 5);
2440 Polygon(hdc, pts, 5);
2445 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2446 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2447 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2448 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2449 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2450 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2451 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2452 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2453 pts[4].x = pts[0].x;
2454 pts[4].y = pts[0].y;
2455 DPtoLP(hdc, pts, 5);
2456 Polygon(hdc, pts, 5);
2459 SelectObject(hdc, hpen);
2460 hbrush = SelectObject(hdc, hbrush);
2461 DeleteObject(hbrush);
2468 /***********************************************************************
2469 * TextOutA (GDI32.@)
2471 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2473 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2477 /***********************************************************************
2478 * TextOutW (GDI32.@)
2480 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2482 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2486 /***********************************************************************
2487 * PolyTextOutA (GDI32.@)
2491 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2493 for (; cStrings>0; cStrings--, pptxt++)
2494 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2501 /***********************************************************************
2502 * PolyTextOutW (GDI32.@)
2504 * Draw several Strings
2510 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2512 for (; cStrings>0; cStrings--, pptxt++)
2513 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2519 /***********************************************************************
2520 * SetMapperFlags (GDI32.@)
2522 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2524 DC *dc = get_dc_ptr( hdc );
2525 DWORD ret = GDI_ERROR;
2529 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2530 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2531 if (flags != GDI_ERROR)
2533 ret = dc->mapperFlags;
2534 dc->mapperFlags = flags;
2536 release_dc_ptr( dc );
2541 /***********************************************************************
2542 * GetAspectRatioFilterEx (GDI32.@)
2544 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2546 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2551 /***********************************************************************
2552 * GetCharABCWidthsA (GDI32.@)
2554 * See GetCharABCWidthsW.
2556 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2564 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2568 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2571 HeapFree(GetProcessHeap(), 0, str);
2575 for(i = 0; i < wlen; i++)
2577 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2585 HeapFree(GetProcessHeap(), 0, str);
2586 HeapFree(GetProcessHeap(), 0, wstr);
2592 /******************************************************************************
2593 * GetCharABCWidthsW [GDI32.@]
2595 * Retrieves widths of characters in range.
2598 * hdc [I] Handle of device context
2599 * firstChar [I] First character in range to query
2600 * lastChar [I] Last character in range to query
2601 * abc [O] Address of character-width structure
2604 * Only works with TrueType fonts
2610 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2613 DC *dc = get_dc_ptr(hdc);
2619 if (!dc) return FALSE;
2623 release_dc_ptr( dc );
2627 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2628 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2629 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2631 release_dc_ptr( dc );
2635 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2636 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2639 /* convert device units to logical */
2640 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2641 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2642 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2643 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2647 release_dc_ptr( dc );
2652 /******************************************************************************
2653 * GetCharABCWidthsI [GDI32.@]
2655 * Retrieves widths of characters in range.
2658 * hdc [I] Handle of device context
2659 * firstChar [I] First glyphs in range to query
2660 * count [I] Last glyphs in range to query
2661 * pgi [i] Array of glyphs to query
2662 * abc [O] Address of character-width structure
2665 * Only works with TrueType fonts
2671 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2672 LPWORD pgi, LPABC abc)
2674 DC *dc = get_dc_ptr(hdc);
2679 if (!dc) return FALSE;
2683 release_dc_ptr( dc );
2687 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2688 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2691 /* convert device units to logical */
2692 for( i = 0; i < count; i++, abc++ ) {
2693 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2694 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2695 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2699 release_dc_ptr( dc );
2704 /***********************************************************************
2705 * GetGlyphOutlineA (GDI32.@)
2707 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2708 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2709 LPVOID lpBuffer, const MAT2 *lpmat2 )
2711 if (!lpmat2) return GDI_ERROR;
2713 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2718 cp = GdiGetCodePage(hdc);
2719 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2721 mbchs[0] = (uChar & 0xff00) >> 8;
2722 mbchs[1] = (uChar & 0xff);
2725 mbchs[0] = (uChar & 0xff);
2728 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2731 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2735 /***********************************************************************
2736 * GetGlyphOutlineW (GDI32.@)
2738 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2739 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2740 LPVOID lpBuffer, const MAT2 *lpmat2 )
2746 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2747 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2749 if (!lpmat2) return GDI_ERROR;
2751 dc = get_dc_ptr(hdc);
2752 if(!dc) return GDI_ERROR;
2754 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2755 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2756 release_dc_ptr( dc );
2761 /***********************************************************************
2762 * CreateScalableFontResourceA (GDI32.@)
2764 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2765 LPCSTR lpszResourceFile,
2766 LPCSTR lpszFontFile,
2767 LPCSTR lpszCurrentPath )
2769 LPWSTR lpszResourceFileW = NULL;
2770 LPWSTR lpszFontFileW = NULL;
2771 LPWSTR lpszCurrentPathW = NULL;
2775 if (lpszResourceFile)
2777 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2778 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2779 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2784 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2785 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2786 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2789 if (lpszCurrentPath)
2791 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2792 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2793 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2796 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2797 lpszFontFileW, lpszCurrentPathW);
2799 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2800 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2801 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2806 /***********************************************************************
2807 * CreateScalableFontResourceW (GDI32.@)
2809 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2810 LPCWSTR font_file, LPCWSTR font_path )
2812 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2813 debugstr_w(font_file), debugstr_w(font_path) );
2815 return WineEngCreateScalableFontResource( hidden, resource_file,
2816 font_file, font_path );
2819 /*************************************************************************
2820 * GetKerningPairsA (GDI32.@)
2822 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2823 LPKERNINGPAIR kern_pairA )
2827 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2828 KERNINGPAIR *kern_pairW;
2830 if (!cPairs && kern_pairA)
2832 SetLastError(ERROR_INVALID_PARAMETER);
2836 cp = GdiGetCodePage(hDC);
2838 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2839 * to fail on an invalid character for CP_SYMBOL.
2841 cpi.DefaultChar[0] = 0;
2842 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2844 FIXME("Can't find codepage %u info\n", cp);
2848 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2849 if (!total_kern_pairs) return 0;
2851 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2852 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2854 for (i = 0; i < total_kern_pairs; i++)
2858 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2861 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2864 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2869 if (kern_pairs_copied >= cPairs) break;
2871 kern_pairA->wFirst = (BYTE)first;
2872 kern_pairA->wSecond = (BYTE)second;
2873 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2876 kern_pairs_copied++;
2879 HeapFree(GetProcessHeap(), 0, kern_pairW);
2881 return kern_pairs_copied;
2884 /*************************************************************************
2885 * GetKerningPairsW (GDI32.@)
2887 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2888 LPKERNINGPAIR lpKerningPairs )
2894 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2896 if (!cPairs && lpKerningPairs)
2898 SetLastError(ERROR_INVALID_PARAMETER);
2902 dc = get_dc_ptr(hDC);
2905 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2906 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2907 release_dc_ptr( dc );
2911 /*************************************************************************
2912 * TranslateCharsetInfo [GDI32.@]
2914 * Fills a CHARSETINFO structure for a character set, code page, or
2915 * font. This allows making the correspondence between different labels
2916 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2917 * of the same encoding.
2919 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2920 * only one codepage should be set in *lpSrc.
2923 * TRUE on success, FALSE on failure.
2926 BOOL WINAPI TranslateCharsetInfo(
2927 LPDWORD lpSrc, /* [in]
2928 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2929 if flags == TCI_SRCCHARSET: a character set value
2930 if flags == TCI_SRCCODEPAGE: a code page value
2932 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2933 DWORD flags /* [in] determines interpretation of lpSrc */)
2937 case TCI_SRCFONTSIG:
2938 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2940 case TCI_SRCCODEPAGE:
2941 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2943 case TCI_SRCCHARSET:
2944 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2949 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2950 *lpCs = FONT_tci[index];
2954 /*************************************************************************
2955 * GetFontLanguageInfo (GDI32.@)
2957 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2959 FONTSIGNATURE fontsig;
2960 static const DWORD GCP_DBCS_MASK=0x003F0000,
2961 GCP_DIACRITIC_MASK=0x00000000,
2962 FLI_GLYPHS_MASK=0x00000000,
2963 GCP_GLYPHSHAPE_MASK=0x00000040,
2964 GCP_KASHIDA_MASK=0x00000000,
2965 GCP_LIGATE_MASK=0x00000000,
2966 GCP_USEKERNING_MASK=0x00000000,
2967 GCP_REORDER_MASK=0x00000060;
2971 GetTextCharsetInfo( hdc, &fontsig, 0 );
2972 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2974 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2977 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2978 result|=GCP_DIACRITIC;
2980 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2983 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2984 result|=GCP_GLYPHSHAPE;
2986 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2987 result|=GCP_KASHIDA;
2989 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2992 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2993 result|=GCP_USEKERNING;
2995 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2996 if( GetTextAlign( hdc) & TA_RTLREADING )
2997 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2998 result|=GCP_REORDER;
3004 /*************************************************************************
3005 * GetFontData [GDI32.@]
3007 * Retrieve data for TrueType font.
3011 * success: Number of bytes returned
3012 * failure: GDI_ERROR
3016 * Calls SetLastError()
3019 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3020 LPVOID buffer, DWORD length)
3022 DC *dc = get_dc_ptr(hdc);
3026 if(!dc) return GDI_ERROR;
3028 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3029 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3030 release_dc_ptr( dc );
3034 /*************************************************************************
3035 * GetGlyphIndicesA [GDI32.@]
3037 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3038 LPWORD pgi, DWORD flags)
3044 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3045 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3047 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3048 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3049 HeapFree(GetProcessHeap(), 0, lpstrW);
3054 /*************************************************************************
3055 * GetGlyphIndicesW [GDI32.@]
3057 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3058 LPWORD pgi, DWORD flags)
3060 DC *dc = get_dc_ptr(hdc);
3064 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3065 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3067 if(!dc) return GDI_ERROR;
3069 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3070 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3071 release_dc_ptr( dc );
3075 /*************************************************************************
3076 * GetCharacterPlacementA [GDI32.@]
3078 * See GetCharacterPlacementW.
3081 * the web browser control of ie4 calls this with dwFlags=0
3084 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3085 INT nMaxExtent, GCP_RESULTSA *lpResults,
3090 GCP_RESULTSW resultsW;
3094 TRACE("%s, %d, %d, 0x%08x\n",
3095 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3097 /* both structs are equal in size */
3098 memcpy(&resultsW, lpResults, sizeof(resultsW));
3100 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3101 if(lpResults->lpOutString)
3102 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3104 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3106 lpResults->nGlyphs = resultsW.nGlyphs;
3107 lpResults->nMaxFit = resultsW.nMaxFit;
3109 if(lpResults->lpOutString) {
3110 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3111 lpResults->lpOutString, uCount, NULL, NULL );
3114 HeapFree(GetProcessHeap(), 0, lpStringW);
3115 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3120 /*************************************************************************
3121 * GetCharacterPlacementW [GDI32.@]
3123 * Retrieve information about a string. This includes the width, reordering,
3124 * Glyphing and so on.
3128 * The width and height of the string if successful, 0 if failed.
3132 * All flags except GCP_REORDER are not yet implemented.
3133 * Reordering is not 100% compliant to the Windows BiDi method.
3134 * Caret positioning is not yet implemented for BiDi.
3135 * Classes are not yet implemented.
3139 GetCharacterPlacementW(
3140 HDC hdc, /* [in] Device context for which the rendering is to be done */
3141 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3142 INT uCount, /* [in] Number of WORDS in string. */
3143 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3144 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3145 DWORD dwFlags /* [in] Flags specifying how to process the string */
3152 TRACE("%s, %d, %d, 0x%08x\n",
3153 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3155 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3156 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3157 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3158 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3159 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3161 if(dwFlags&(~GCP_REORDER))
3162 FIXME("flags 0x%08x ignored\n", dwFlags);
3163 if(lpResults->lpClass)
3164 FIXME("classes not implemented\n");
3165 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3166 FIXME("Caret positions for complex scripts not implemented\n");
3168 nSet = (UINT)uCount;
3169 if(nSet > lpResults->nGlyphs)
3170 nSet = lpResults->nGlyphs;
3172 /* return number of initialized fields */
3173 lpResults->nGlyphs = nSet;
3175 if((dwFlags&GCP_REORDER)==0 )
3177 /* Treat the case where no special handling was requested in a fastpath way */
3178 /* copy will do if the GCP_REORDER flag is not set */
3179 if(lpResults->lpOutString)
3180 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3182 if(lpResults->lpOrder)
3184 for(i = 0; i < nSet; i++)
3185 lpResults->lpOrder[i] = i;
3190 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3191 nSet, lpResults->lpOrder, NULL, NULL );
3194 /* FIXME: Will use the placement chars */
3195 if (lpResults->lpDx)
3198 for (i = 0; i < nSet; i++)
3200 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3201 lpResults->lpDx[i]= c;
3205 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3209 lpResults->lpCaretPos[0] = 0;
3210 for (i = 1; i < nSet; i++)
3211 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3212 lpResults->lpCaretPos[i] = (pos += size.cx);
3215 if(lpResults->lpGlyphs)
3216 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3218 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3219 ret = MAKELONG(size.cx, size.cy);
3224 /*************************************************************************
3225 * GetCharABCWidthsFloatA [GDI32.@]
3227 * See GetCharABCWidthsFloatW.
3229 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3236 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3240 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3242 for (i = 0; i < wlen; i++)
3244 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3252 HeapFree( GetProcessHeap(), 0, str );
3253 HeapFree( GetProcessHeap(), 0, wstr );
3258 /*************************************************************************
3259 * GetCharABCWidthsFloatW [GDI32.@]
3261 * Retrieves widths of a range of characters.
3264 * hdc [I] Handle to device context.
3265 * first [I] First character in range to query.
3266 * last [I] Last character in range to query.
3267 * abcf [O] Array of LPABCFLOAT structures.
3273 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3279 DC *dc = get_dc_ptr( hdc );
3281 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3283 if (!dc) return FALSE;
3285 if (!abcf) goto done;
3286 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3288 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3289 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3292 /* convert device units to logical */
3293 for (i = first; i <= last; i++, abcf++)
3295 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3296 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3297 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3300 HeapFree( GetProcessHeap(), 0, abc );
3303 release_dc_ptr( dc );
3307 /*************************************************************************
3308 * GetCharWidthFloatA [GDI32.@]
3310 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3311 UINT iLastChar, PFLOAT pxBuffer)
3313 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3317 /*************************************************************************
3318 * GetCharWidthFloatW [GDI32.@]
3320 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3321 UINT iLastChar, PFLOAT pxBuffer)
3323 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3328 /***********************************************************************
3330 * Font Resource API *
3332 ***********************************************************************/
3334 /***********************************************************************
3335 * AddFontResourceA (GDI32.@)
3337 INT WINAPI AddFontResourceA( LPCSTR str )
3339 return AddFontResourceExA( str, 0, NULL);
3342 /***********************************************************************
3343 * AddFontResourceW (GDI32.@)
3345 INT WINAPI AddFontResourceW( LPCWSTR str )
3347 return AddFontResourceExW(str, 0, NULL);
3351 /***********************************************************************
3352 * AddFontResourceExA (GDI32.@)
3354 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3356 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3357 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3360 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3361 ret = AddFontResourceExW(strW, fl, pdv);
3362 HeapFree(GetProcessHeap(), 0, strW);
3366 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3368 HRSRC rsrc = FindResourceW(hModule, name, type);
3369 HGLOBAL hMem = LoadResource(hModule, rsrc);
3370 LPVOID *pMem = LockResource(hMem);
3371 int *num_total = (int *)lParam;
3374 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3375 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3377 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3381 *num_total += num_in_res;
3385 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3387 HANDLE file, mapping;
3390 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3391 if (file == INVALID_HANDLE_VALUE) return NULL;
3393 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3395 CloseHandle( file );
3399 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3400 CloseHandle( file );
3401 if (!mapping) return NULL;
3403 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3404 CloseHandle( mapping );
3409 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3411 WORD align, type_id, count;
3414 if (size < rsrc_off + 10) return NULL;
3415 align = *(WORD *)(ptr + rsrc_off);
3417 type_id = *(WORD *)(ptr + rsrc_off);
3418 while (type_id && type_id != type)
3420 count = *(WORD *)(ptr + rsrc_off + 2);
3421 rsrc_off += 8 + count * 12;
3422 if (size < rsrc_off + 8) return NULL;
3423 type_id = *(WORD *)(ptr + rsrc_off);
3425 if (!type_id) return NULL;
3426 count = *(WORD *)(ptr + rsrc_off + 2);
3427 if (size < rsrc_off + 8 + count * 12) return NULL;
3428 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3429 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3430 if (size < res_off + *len) return NULL;
3431 return ptr + res_off;
3434 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3437 BYTE *ptr = map_file( res, &size );
3438 const IMAGE_DOS_HEADER *dos;
3439 const IMAGE_OS2_HEADER *ne;
3445 if (!ptr) return NULL;
3447 if (size.u.LowPart < sizeof( *dos )) goto fail;
3448 dos = (const IMAGE_DOS_HEADER *)ptr;
3449 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3450 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3451 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3453 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3454 if (!fontdir) goto fail;
3455 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3457 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3458 if (!data) goto fail;
3459 if (!memchr( data, 0, len )) goto fail;
3461 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3462 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3463 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3466 UnmapViewOfFile( ptr );
3470 /***********************************************************************
3471 * AddFontResourceExW (GDI32.@)
3473 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3475 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3481 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3482 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3483 if (hModule != NULL)
3485 int num_resources = 0;
3486 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3488 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3489 wine_dbgstr_w(str));
3490 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3491 ret = num_resources;
3492 FreeLibrary(hModule);
3494 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3496 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3497 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3498 HeapFree( GetProcessHeap(), 0, filename );
3504 /***********************************************************************
3505 * RemoveFontResourceA (GDI32.@)
3507 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3509 return RemoveFontResourceExA(str, 0, 0);
3512 /***********************************************************************
3513 * RemoveFontResourceW (GDI32.@)
3515 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3517 return RemoveFontResourceExW(str, 0, 0);
3520 /***********************************************************************
3521 * AddFontMemResourceEx (GDI32.@)
3523 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3528 if (!pbFont || !cbFont || !pcFonts)
3530 SetLastError(ERROR_INVALID_PARAMETER);
3534 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3539 *pcFonts = num_fonts;
3543 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3544 RemoveFontMemResourceEx(ret);
3552 /***********************************************************************
3553 * RemoveFontMemResourceEx (GDI32.@)
3555 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3557 FIXME("(%p) stub\n", fh);
3561 /***********************************************************************
3562 * RemoveFontResourceExA (GDI32.@)
3564 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3566 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3567 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3570 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3571 ret = RemoveFontResourceExW(strW, fl, pdv);
3572 HeapFree(GetProcessHeap(), 0, strW);
3576 /***********************************************************************
3577 * RemoveFontResourceExW (GDI32.@)
3579 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3581 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3587 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3588 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3589 if (hModule != NULL)
3591 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3592 FreeLibrary(hModule);
3594 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3596 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3597 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3598 HeapFree( GetProcessHeap(), 0, filename );
3604 /***********************************************************************
3605 * GetFontResourceInfoW (GDI32.@)
3607 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3609 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3613 /***********************************************************************
3614 * GetTextCharset (GDI32.@)
3616 UINT WINAPI GetTextCharset(HDC hdc)
3618 /* MSDN docs say this is equivalent */
3619 return GetTextCharsetInfo(hdc, NULL, 0);
3622 /***********************************************************************
3623 * GetTextCharsetInfo (GDI32.@)
3625 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3627 UINT ret = DEFAULT_CHARSET;
3628 DC *dc = get_dc_ptr(hdc);
3633 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3634 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3635 release_dc_ptr( dc );
3638 if (ret == DEFAULT_CHARSET && fs)
3639 memset(fs, 0, sizeof(FONTSIGNATURE));
3643 /***********************************************************************
3644 * GdiGetCharDimensions (GDI32.@)
3646 * Gets the average width of the characters in the English alphabet.
3649 * hdc [I] Handle to the device context to measure on.
3650 * lptm [O] Pointer to memory to store the text metrics into.
3651 * height [O] On exit, the maximum height of characters in the English alphabet.
3654 * The average width of characters in the English alphabet.
3657 * This function is used by the dialog manager to get the size of a dialog
3658 * unit. It should also be used by other pieces of code that need to know
3659 * the size of a dialog unit in logical units without having access to the
3660 * window handle of the dialog.
3661 * Windows caches the font metrics from this function, but we don't and
3662 * there doesn't appear to be an immediate advantage to do so.
3665 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3667 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3670 static const WCHAR alphabet[] = {
3671 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3672 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3673 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3675 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3677 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3679 if (height) *height = sz.cy;
3680 return (sz.cx / 26 + 1) / 2;
3683 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3685 FIXME("(%d): stub\n", fEnableEUDC);
3689 /***********************************************************************
3690 * GetCharWidthI (GDI32.@)
3692 * Retrieve widths of characters.
3695 * hdc [I] Handle to a device context.
3696 * first [I] First glyph in range to query.
3697 * count [I] Number of glyph indices to query.
3698 * glyphs [I] Array of glyphs to query.
3699 * buffer [O] Buffer to receive character widths.
3702 * Only works with TrueType fonts.
3708 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3713 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3715 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3718 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3720 HeapFree(GetProcessHeap(), 0, abc);
3724 for (i = 0; i < count; i++)
3725 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3727 HeapFree(GetProcessHeap(), 0, abc);
3731 /***********************************************************************
3732 * GetFontUnicodeRanges (GDI32.@)
3734 * Retrieve a list of supported Unicode characters in a font.
3737 * hdc [I] Handle to a device context.
3738 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3741 * Success: Number of bytes written to the buffer pointed to by lpgs.
3745 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3749 DC *dc = get_dc_ptr(hdc);
3751 TRACE("(%p, %p)\n", hdc, lpgs);
3755 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3756 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3762 /*************************************************************
3763 * FontIsLinked (GDI32.@)
3765 BOOL WINAPI FontIsLinked(HDC hdc)
3767 DC *dc = get_dc_ptr(hdc);
3771 if (!dc) return FALSE;
3772 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3773 ret = dev->funcs->pFontIsLinked( dev );
3775 TRACE("returning %d\n", ret);
3779 /*************************************************************
3780 * GdiRealizationInfo (GDI32.@)
3782 * Returns a structure that contains some font information.
3784 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3786 DC *dc = get_dc_ptr(hdc);
3790 if (!dc) return FALSE;
3791 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3792 ret = dev->funcs->pGdiRealizationInfo( dev, info );