gdi32: GetCharWidth32A/W return positive widths for all layouts and various DC transf...
[wine/multimedia.git] / dlls / gdi32 / font.c
blob9e516bee43afd3f36cd44d0100a1033c1c0bbfa8
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <limits.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include "winerror.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "winreg.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)
51 double floatWidth;
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)
64 double floatHeight;
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)
74 POINT pt[2];
75 pt[0].x = pt[0].y = 0;
76 pt[1].x = width;
77 pt[1].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)
84 POINT pt[2];
85 pt[0].x = pt[0].y = 0;
86 pt[1].x = 0;
87 pt[1].y = height;
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 */
106 typedef struct
108 LOGFONTW logfont;
109 } FONTOBJ;
111 struct font_enum
113 LPLOGFONTW lpLogFontParam;
114 FONTENUMPROCW lpEnumFunc;
115 LPARAM lpData;
116 BOOL unicode;
117 HDC hdc;
118 INT retval;
122 * For TranslateCharsetInfo
124 #define MAXTCIINDEX 32
125 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
126 /* ANSI */
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}} },
144 /* ANSI and OEM */
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,
169 LF_FACESIZE);
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);
238 else
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 )
265 WCHAR buf[12];
266 DWORD count = sizeof(buf), type, err;
268 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
269 if (!err)
271 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
272 else *value = atoiW( buf );
274 return err;
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};
281 DWORD orient;
283 /* FIXME: handle vertical orientations even though Windows doesn't */
284 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
286 switch (orient)
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};
300 DWORD enabled, type;
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 )
314 TEXTMETRICW tm;
315 PHYSDEV dev;
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;
335 if (rem > 0)
337 space++;
338 rem--;
341 dx[i] += space;
344 size->cx = dx[count - 1];
345 size->cy = tm.tmHeight;
346 return TRUE;
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 )
352 TEXTMETRICW tm;
353 PHYSDEV dev;
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)
366 WORD space_index;
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;
377 if (rem > 0)
379 space++;
380 rem--;
383 dx[i] += space;
386 size->cx = dx[count - 1];
387 size->cy = tm.tmHeight;
388 return TRUE;
391 /***********************************************************************
392 * GdiGetCodePage (GDI32.@)
394 DWORD WINAPI GdiGetCodePage( HDC hdc )
396 UINT cp = CP_ACP;
397 DC *dc = get_dc_ptr( hdc );
399 if (dc)
401 cp = dc->font_code_page;
402 release_dc_ptr( dc );
404 return cp;
407 /***********************************************************************
408 * FONT_mbtowc
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
417 * itself.
419 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
421 UINT cp;
422 INT lenW;
423 LPWSTR strW;
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;
433 if(pCP) *pCP = cp;
434 return strW;
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 )
456 HFONT hFont;
457 FONTOBJ *fontPtr;
458 const LOGFONTW *plf;
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 );
480 return 0;
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);
494 return hFont;
497 /***********************************************************************
498 * CreateFontIndirectA (GDI32.@)
500 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
502 LOGFONTW lfW;
504 if (!plfA) return 0;
506 FONT_LogFontAToW( plfA, &lfW );
507 return CreateFontIndirectW( &lfW );
510 /***********************************************************************
511 * CreateFontIndirectW (GDI32.@)
513 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
515 ENUMLOGFONTEXDVW exdv;
517 if (!plf) return 0;
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 )
535 LOGFONTA logfont;
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;
551 if (name)
552 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
553 else
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 )
568 LOGFONTW logfont;
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;
584 if (name)
585 lstrcpynW(logfont.lfFaceName, name,
586 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
587 else
588 logfont.lfFaceName[0] = '\0';
590 return CreateFontIndirectW( &logfont );
593 #define ASSOC_CHARSET_OEM 1
594 #define ASSOC_CHARSET_ANSI 2
595 #define ASSOC_CHARSET_SYMBOL 4
597 static DWORD get_associated_charset_info(void)
599 static DWORD associated_charset = -1;
601 if (associated_charset == -1)
603 static const WCHAR assoc_charset_reg_keyW[] = {'S','y','s','t','e','m','\\',
604 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
605 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
606 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
607 static const WCHAR ansiW[] = {'A','N','S','I','(','0','0',')','\0'};
608 static const WCHAR oemW[] = {'O','E','M','(','F','F',')','\0'};
609 static const WCHAR symbolW[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
610 static const WCHAR yesW[] = {'Y','E','S','\0'};
611 HKEY hkey;
612 WCHAR dataW[32];
613 DWORD type, data_len;
615 associated_charset = 0;
617 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
618 assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS)
619 return 0;
621 data_len = sizeof(dataW);
622 if (!RegQueryValueExW(hkey, ansiW, NULL, &type, (LPBYTE)dataW, &data_len) &&
623 type == REG_SZ && !strcmpiW(dataW, yesW))
624 associated_charset |= ASSOC_CHARSET_ANSI;
626 data_len = sizeof(dataW);
627 if (!RegQueryValueExW(hkey, oemW, NULL, &type, (LPBYTE)dataW, &data_len) &&
628 type == REG_SZ && !strcmpiW(dataW, yesW))
629 associated_charset |= ASSOC_CHARSET_OEM;
631 data_len = sizeof(dataW);
632 if (!RegQueryValueExW(hkey, symbolW, NULL, &type, (LPBYTE)dataW, &data_len) &&
633 type == REG_SZ && !strcmpiW(dataW, yesW))
634 associated_charset |= ASSOC_CHARSET_SYMBOL;
636 RegCloseKey(hkey);
638 TRACE("associated_charset = %d\n", associated_charset);
641 return associated_charset;
644 static void update_font_code_page( DC *dc )
646 CHARSETINFO csi;
647 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
649 if (charset == ANSI_CHARSET &&
650 get_associated_charset_info() & ASSOC_CHARSET_ANSI)
651 charset = DEFAULT_CHARSET;
653 /* Hmm, nicely designed api this one! */
654 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
655 dc->font_code_page = csi.ciACP;
656 else {
657 switch(charset) {
658 case OEM_CHARSET:
659 dc->font_code_page = GetOEMCP();
660 break;
661 case DEFAULT_CHARSET:
662 dc->font_code_page = GetACP();
663 break;
665 case VISCII_CHARSET:
666 case TCVN_CHARSET:
667 case KOI8_CHARSET:
668 case ISO3_CHARSET:
669 case ISO4_CHARSET:
670 case ISO10_CHARSET:
671 case CELTIC_CHARSET:
672 /* FIXME: These have no place here, but because x11drv
673 enumerates fonts with these (made up) charsets some apps
674 might use them and then the FIXME below would become
675 annoying. Now we could pick the intended codepage for
676 each of these, but since it's broken anyway we'll just
677 use CP_ACP and hope it'll go away...
679 dc->font_code_page = CP_ACP;
680 break;
682 default:
683 FIXME("Can't find codepage for charset %d\n", charset);
684 dc->font_code_page = CP_ACP;
685 break;
689 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
692 /***********************************************************************
693 * FONT_SelectObject
695 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
697 HGDIOBJ ret = 0;
698 DC *dc = get_dc_ptr( hdc );
699 PHYSDEV physdev;
700 UINT aa_flags = 0;
702 if (!dc) return 0;
704 if (!GDI_inc_ref_count( handle ))
706 release_dc_ptr( dc );
707 return 0;
710 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
711 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
713 ret = dc->hFont;
714 dc->hFont = handle;
715 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
716 update_font_code_page( dc );
717 GDI_dec_ref_count( ret );
719 else GDI_dec_ref_count( handle );
721 release_dc_ptr( dc );
722 return ret;
726 /***********************************************************************
727 * FONT_GetObjectA
729 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
731 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
732 LOGFONTA lfA;
734 if (!font) return 0;
735 if (buffer)
737 FONT_LogFontWToA( &font->logfont, &lfA );
738 if (count > sizeof(lfA)) count = sizeof(lfA);
739 memcpy( buffer, &lfA, count );
741 else count = sizeof(lfA);
742 GDI_ReleaseObj( handle );
743 return count;
746 /***********************************************************************
747 * FONT_GetObjectW
749 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
751 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
753 if (!font) return 0;
754 if (buffer)
756 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
757 memcpy( buffer, &font->logfont, count );
759 else count = sizeof(LOGFONTW);
760 GDI_ReleaseObj( handle );
761 return count;
765 /***********************************************************************
766 * FONT_DeleteObject
768 static BOOL FONT_DeleteObject( HGDIOBJ handle )
770 FONTOBJ *obj;
772 if (!(obj = free_gdi_handle( handle ))) return FALSE;
773 return HeapFree( GetProcessHeap(), 0, obj );
777 /***********************************************************************
778 * nulldrv_SelectFont
780 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
782 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
783 'D','e','s','k','t','o','p',0 };
784 static int orientation = -1, smoothing = -1;
785 LOGFONTW lf;
786 HKEY key;
788 if (*aa_flags) return 0;
790 GetObjectW( font, sizeof(lf), &lf );
791 switch (lf.lfQuality)
793 case NONANTIALIASED_QUALITY:
794 *aa_flags = GGO_BITMAP;
795 break;
796 case ANTIALIASED_QUALITY:
797 *aa_flags = GGO_GRAY4_BITMAP;
798 break;
799 case CLEARTYPE_QUALITY:
800 case CLEARTYPE_NATURAL_QUALITY:
801 if (orientation == -1)
803 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
804 orientation = get_subpixel_orientation( key );
805 RegCloseKey( key );
807 *aa_flags = orientation;
808 break;
809 default:
810 if (smoothing == -1)
812 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
813 smoothing = get_default_smoothing( key );
814 RegCloseKey( key );
816 *aa_flags = smoothing;
817 break;
819 return 0;
823 /***********************************************************************
824 * FONT_EnumInstance
826 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
827 * We have to use other types because of the FONTENUMPROCW definition.
829 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
830 DWORD fType, LPARAM lp )
832 struct font_enum *pfe = (struct font_enum *)lp;
833 INT ret = 1;
835 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
836 if ((!pfe->lpLogFontParam ||
837 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
838 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
839 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
841 /* convert font metrics */
842 ENUMLOGFONTEXA logfont;
843 NEWTEXTMETRICEXA tmA;
845 if (!pfe->unicode)
847 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
848 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
849 plf = (LOGFONTW *)&logfont.elfLogFont;
850 ptm = (TEXTMETRICW *)&tmA;
852 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
853 pfe->retval = ret;
855 return ret;
858 /***********************************************************************
859 * FONT_EnumFontFamiliesEx
861 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
862 LPARAM lParam, BOOL unicode )
864 INT ret = 0;
865 DC *dc = get_dc_ptr( hDC );
866 struct font_enum fe;
868 if (dc)
870 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
872 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
873 fe.lpLogFontParam = plf;
874 fe.lpEnumFunc = efproc;
875 fe.lpData = lParam;
876 fe.unicode = unicode;
877 fe.hdc = hDC;
878 fe.retval = 1;
879 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
880 release_dc_ptr( dc );
882 return ret ? fe.retval : 0;
885 /***********************************************************************
886 * EnumFontFamiliesExW (GDI32.@)
888 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
889 FONTENUMPROCW efproc,
890 LPARAM lParam, DWORD dwFlags )
892 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
895 /***********************************************************************
896 * EnumFontFamiliesExA (GDI32.@)
898 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
899 FONTENUMPROCA efproc,
900 LPARAM lParam, DWORD dwFlags)
902 LOGFONTW lfW, *plfW;
904 if (plf)
906 FONT_LogFontAToW( plf, &lfW );
907 plfW = &lfW;
909 else plfW = NULL;
911 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
914 /***********************************************************************
915 * EnumFontFamiliesA (GDI32.@)
917 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
918 FONTENUMPROCA efproc, LPARAM lpData )
920 LOGFONTA lf, *plf;
922 if (lpFamily)
924 if (!*lpFamily) return 1;
925 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
926 lf.lfCharSet = DEFAULT_CHARSET;
927 lf.lfPitchAndFamily = 0;
928 plf = &lf;
930 else plf = NULL;
932 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
935 /***********************************************************************
936 * EnumFontFamiliesW (GDI32.@)
938 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
939 FONTENUMPROCW efproc, LPARAM lpData )
941 LOGFONTW lf, *plf;
943 if (lpFamily)
945 if (!*lpFamily) return 1;
946 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
947 lf.lfCharSet = DEFAULT_CHARSET;
948 lf.lfPitchAndFamily = 0;
949 plf = &lf;
951 else plf = NULL;
953 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
956 /***********************************************************************
957 * EnumFontsA (GDI32.@)
959 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
960 LPARAM lpData )
962 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
965 /***********************************************************************
966 * EnumFontsW (GDI32.@)
968 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
969 LPARAM lpData )
971 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
975 /***********************************************************************
976 * GetTextCharacterExtra (GDI32.@)
978 INT WINAPI GetTextCharacterExtra( HDC hdc )
980 INT ret;
981 DC *dc = get_dc_ptr( hdc );
982 if (!dc) return 0x80000000;
983 ret = dc->charExtra;
984 release_dc_ptr( dc );
985 return ret;
989 /***********************************************************************
990 * SetTextCharacterExtra (GDI32.@)
992 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
994 INT ret = 0x80000000;
995 DC * dc = get_dc_ptr( hdc );
997 if (dc)
999 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
1000 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
1001 if (extra != 0x80000000)
1003 ret = dc->charExtra;
1004 dc->charExtra = extra;
1006 release_dc_ptr( dc );
1008 return ret;
1012 /***********************************************************************
1013 * SetTextJustification (GDI32.@)
1015 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1017 BOOL ret;
1018 PHYSDEV physdev;
1019 DC * dc = get_dc_ptr( hdc );
1021 if (!dc) return FALSE;
1023 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1024 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1025 if (ret)
1027 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
1028 if (!extra) breaks = 0;
1029 if (breaks)
1031 dc->breakExtra = extra / breaks;
1032 dc->breakRem = extra - (breaks * dc->breakExtra);
1034 else
1036 dc->breakExtra = 0;
1037 dc->breakRem = 0;
1040 release_dc_ptr( dc );
1041 return ret;
1045 /***********************************************************************
1046 * GetTextFaceA (GDI32.@)
1048 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1050 INT res = GetTextFaceW(hdc, 0, NULL);
1051 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1052 GetTextFaceW( hdc, res, nameW );
1054 if (name)
1056 if (count)
1058 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1059 if (res == 0)
1060 res = count;
1061 name[count-1] = 0;
1062 /* GetTextFaceA does NOT include the nul byte in the return count. */
1063 res--;
1065 else
1066 res = 0;
1068 else
1069 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1070 HeapFree( GetProcessHeap(), 0, nameW );
1071 return res;
1074 /***********************************************************************
1075 * GetTextFaceW (GDI32.@)
1077 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1079 PHYSDEV dev;
1080 INT ret;
1082 DC * dc = get_dc_ptr( hdc );
1083 if (!dc) return 0;
1085 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1086 ret = dev->funcs->pGetTextFace( dev, count, name );
1087 release_dc_ptr( dc );
1088 return ret;
1092 /***********************************************************************
1093 * GetTextExtentPoint32A (GDI32.@)
1095 * See GetTextExtentPoint32W.
1097 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1098 LPSIZE size )
1100 BOOL ret = FALSE;
1101 INT wlen;
1102 LPWSTR p;
1104 if (count < 0) return FALSE;
1106 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1108 if (p)
1110 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1111 HeapFree( GetProcessHeap(), 0, p );
1114 TRACE("(%p %s %d %p): returning %d x %d\n",
1115 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1116 return ret;
1120 /***********************************************************************
1121 * GetTextExtentPoint32W [GDI32.@]
1123 * Computes width/height for a string.
1125 * Computes width and height of the specified string.
1127 * RETURNS
1128 * Success: TRUE
1129 * Failure: FALSE
1131 BOOL WINAPI GetTextExtentPoint32W(
1132 HDC hdc, /* [in] Handle of device context */
1133 LPCWSTR str, /* [in] Address of text string */
1134 INT count, /* [in] Number of characters in string */
1135 LPSIZE size) /* [out] Address of structure for string size */
1137 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1140 /***********************************************************************
1141 * GetTextExtentExPointI [GDI32.@]
1143 * Computes width and height of the array of glyph indices.
1145 * PARAMS
1146 * hdc [I] Handle of device context.
1147 * indices [I] Glyph index array.
1148 * count [I] Number of glyphs in array.
1149 * max_ext [I] Maximum width in glyphs.
1150 * nfit [O] Maximum number of characters.
1151 * dxs [O] Partial string widths.
1152 * size [O] Returned string size.
1154 * RETURNS
1155 * Success: TRUE
1156 * Failure: FALSE
1158 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1159 LPINT nfit, LPINT dxs, LPSIZE size )
1161 DC *dc;
1162 int i;
1163 BOOL ret;
1164 INT buffer[256], *pos = dxs;
1166 if (count < 0) return FALSE;
1168 dc = get_dc_ptr( hdc );
1169 if (!dc) return FALSE;
1171 if (!dxs)
1173 pos = buffer;
1174 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1176 release_dc_ptr( dc );
1177 return FALSE;
1181 ret = get_char_positions_indices( dc, indices, count, pos, size );
1182 if (ret)
1184 if (dxs || nfit)
1186 for (i = 0; i < count; i++)
1188 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1189 if (nfit && dx > (unsigned int)max_ext) break;
1190 if (dxs) dxs[i] = dx;
1192 if (nfit) *nfit = i;
1195 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1196 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1199 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1200 release_dc_ptr( dc );
1202 TRACE("(%p %p %d %p): returning %d x %d\n",
1203 hdc, indices, count, size, size->cx, size->cy );
1204 return ret;
1207 /***********************************************************************
1208 * GetTextExtentPointI [GDI32.@]
1210 * Computes width and height of the array of glyph indices.
1212 * PARAMS
1213 * hdc [I] Handle of device context.
1214 * indices [I] Glyph index array.
1215 * count [I] Number of glyphs in array.
1216 * size [O] Returned string size.
1218 * RETURNS
1219 * Success: TRUE
1220 * Failure: FALSE
1222 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1224 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1228 /***********************************************************************
1229 * GetTextExtentPointA (GDI32.@)
1231 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1232 LPSIZE size )
1234 TRACE("not bug compatible.\n");
1235 return GetTextExtentPoint32A( hdc, str, count, size );
1238 /***********************************************************************
1239 * GetTextExtentPointW (GDI32.@)
1241 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1242 LPSIZE size )
1244 TRACE("not bug compatible.\n");
1245 return GetTextExtentPoint32W( hdc, str, count, size );
1249 /***********************************************************************
1250 * GetTextExtentExPointA (GDI32.@)
1252 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1253 INT maxExt, LPINT lpnFit,
1254 LPINT alpDx, LPSIZE size )
1256 BOOL ret;
1257 INT wlen;
1258 INT *walpDx = NULL;
1259 LPWSTR p = NULL;
1261 if (count < 0) return FALSE;
1262 if (maxExt < -1) return FALSE;
1264 if (alpDx)
1266 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1267 if (!walpDx) return FALSE;
1270 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1271 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1272 if (walpDx)
1274 INT n = lpnFit ? *lpnFit : wlen;
1275 INT i, j;
1276 for(i = 0, j = 0; i < n; i++, j++)
1278 alpDx[j] = walpDx[i];
1279 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1282 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1283 HeapFree( GetProcessHeap(), 0, p );
1284 HeapFree( GetProcessHeap(), 0, walpDx );
1285 return ret;
1289 /***********************************************************************
1290 * GetTextExtentExPointW (GDI32.@)
1292 * Return the size of the string as it would be if it was output properly by
1293 * e.g. TextOut.
1295 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1296 LPINT nfit, LPINT dxs, LPSIZE size )
1298 DC *dc;
1299 int i;
1300 BOOL ret;
1301 INT buffer[256], *pos = dxs;
1303 if (count < 0) return FALSE;
1305 dc = get_dc_ptr(hdc);
1306 if (!dc) return FALSE;
1308 if (!dxs)
1310 pos = buffer;
1311 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1313 release_dc_ptr( dc );
1314 return FALSE;
1318 ret = get_char_positions( dc, str, count, pos, size );
1319 if (ret)
1321 if (dxs || nfit)
1323 for (i = 0; i < count; i++)
1325 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1326 if (nfit && dx > (unsigned int)max_ext) break;
1327 if (dxs) dxs[i] = dx;
1329 if (nfit) *nfit = i;
1332 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1333 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1336 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1337 release_dc_ptr( dc );
1339 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1340 return ret;
1343 /***********************************************************************
1344 * GetTextMetricsA (GDI32.@)
1346 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1348 TEXTMETRICW tm32;
1350 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1351 FONT_TextMetricWToA( &tm32, metrics );
1352 return TRUE;
1355 /***********************************************************************
1356 * GetTextMetricsW (GDI32.@)
1358 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1360 PHYSDEV physdev;
1361 BOOL ret = FALSE;
1362 DC * dc = get_dc_ptr( hdc );
1363 if (!dc) return FALSE;
1365 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1366 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1368 if (ret)
1370 /* device layer returns values in device units
1371 * therefore we have to convert them to logical */
1373 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1374 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1376 #define WDPTOLP(x) ((x<0)? \
1377 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1378 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1379 #define HDPTOLP(y) ((y<0)? \
1380 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1381 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1383 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1384 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1385 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1386 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1387 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1388 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1389 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1390 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1391 ret = TRUE;
1392 #undef WDPTOLP
1393 #undef HDPTOLP
1394 TRACE("text metrics:\n"
1395 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1396 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1397 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1398 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1399 " PitchAndFamily = %02x\n"
1400 " --------------------\n"
1401 " InternalLeading = %i\n"
1402 " Ascent = %i\n"
1403 " Descent = %i\n"
1404 " Height = %i\n",
1405 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1406 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1407 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1408 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1409 metrics->tmPitchAndFamily,
1410 metrics->tmInternalLeading,
1411 metrics->tmAscent,
1412 metrics->tmDescent,
1413 metrics->tmHeight );
1415 release_dc_ptr( dc );
1416 return ret;
1420 /***********************************************************************
1421 * GetOutlineTextMetricsA (GDI32.@)
1422 * Gets metrics for TrueType fonts.
1424 * NOTES
1425 * If the supplied buffer isn't big enough Windows partially fills it up to
1426 * its given length and returns that length.
1428 * RETURNS
1429 * Success: Non-zero or size of required buffer
1430 * Failure: 0
1432 UINT WINAPI GetOutlineTextMetricsA(
1433 HDC hdc, /* [in] Handle of device context */
1434 UINT cbData, /* [in] Size of metric data array */
1435 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1437 char buf[512], *ptr;
1438 UINT ret, needed;
1439 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1440 OUTLINETEXTMETRICA *output = lpOTM;
1441 INT left, len;
1443 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1444 return 0;
1445 if(ret > sizeof(buf))
1446 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1447 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1449 needed = sizeof(OUTLINETEXTMETRICA);
1450 if(lpOTMW->otmpFamilyName)
1451 needed += WideCharToMultiByte(CP_ACP, 0,
1452 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1453 NULL, 0, NULL, NULL);
1454 if(lpOTMW->otmpFaceName)
1455 needed += WideCharToMultiByte(CP_ACP, 0,
1456 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1457 NULL, 0, NULL, NULL);
1458 if(lpOTMW->otmpStyleName)
1459 needed += WideCharToMultiByte(CP_ACP, 0,
1460 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1461 NULL, 0, NULL, NULL);
1462 if(lpOTMW->otmpFullName)
1463 needed += WideCharToMultiByte(CP_ACP, 0,
1464 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1465 NULL, 0, NULL, NULL);
1467 if(!lpOTM) {
1468 ret = needed;
1469 goto end;
1472 TRACE("needed = %d\n", needed);
1473 if(needed > cbData)
1474 /* Since the supplied buffer isn't big enough, we'll alloc one
1475 that is and memcpy the first cbData bytes into the lpOTM at
1476 the end. */
1477 output = HeapAlloc(GetProcessHeap(), 0, needed);
1479 ret = output->otmSize = min(needed, cbData);
1480 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1481 output->otmFiller = 0;
1482 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1483 output->otmfsSelection = lpOTMW->otmfsSelection;
1484 output->otmfsType = lpOTMW->otmfsType;
1485 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1486 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1487 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1488 output->otmEMSquare = lpOTMW->otmEMSquare;
1489 output->otmAscent = lpOTMW->otmAscent;
1490 output->otmDescent = lpOTMW->otmDescent;
1491 output->otmLineGap = lpOTMW->otmLineGap;
1492 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1493 output->otmsXHeight = lpOTMW->otmsXHeight;
1494 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1495 output->otmMacAscent = lpOTMW->otmMacAscent;
1496 output->otmMacDescent = lpOTMW->otmMacDescent;
1497 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1498 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1499 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1500 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1501 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1502 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1503 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1504 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1505 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1506 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1509 ptr = (char*)(output + 1);
1510 left = needed - sizeof(*output);
1512 if(lpOTMW->otmpFamilyName) {
1513 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1514 len = WideCharToMultiByte(CP_ACP, 0,
1515 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1516 ptr, left, NULL, NULL);
1517 left -= len;
1518 ptr += len;
1519 } else
1520 output->otmpFamilyName = 0;
1522 if(lpOTMW->otmpFaceName) {
1523 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1524 len = WideCharToMultiByte(CP_ACP, 0,
1525 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1526 ptr, left, NULL, NULL);
1527 left -= len;
1528 ptr += len;
1529 } else
1530 output->otmpFaceName = 0;
1532 if(lpOTMW->otmpStyleName) {
1533 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1534 len = WideCharToMultiByte(CP_ACP, 0,
1535 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1536 ptr, left, NULL, NULL);
1537 left -= len;
1538 ptr += len;
1539 } else
1540 output->otmpStyleName = 0;
1542 if(lpOTMW->otmpFullName) {
1543 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1544 len = WideCharToMultiByte(CP_ACP, 0,
1545 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1546 ptr, left, NULL, NULL);
1547 left -= len;
1548 } else
1549 output->otmpFullName = 0;
1551 assert(left == 0);
1553 if(output != lpOTM) {
1554 memcpy(lpOTM, output, cbData);
1555 HeapFree(GetProcessHeap(), 0, output);
1557 /* check if the string offsets really fit into the provided size */
1558 /* FIXME: should we check string length as well? */
1559 /* make sure that we don't read/write beyond the provided buffer */
1560 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1562 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1563 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1566 /* make sure that we don't read/write beyond the provided buffer */
1567 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1569 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1570 lpOTM->otmpFaceName = 0; /* doesn't fit */
1573 /* make sure that we don't read/write beyond the provided buffer */
1574 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1576 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1577 lpOTM->otmpStyleName = 0; /* doesn't fit */
1580 /* make sure that we don't read/write beyond the provided buffer */
1581 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1583 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1584 lpOTM->otmpFullName = 0; /* doesn't fit */
1588 end:
1589 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1590 HeapFree(GetProcessHeap(), 0, lpOTMW);
1592 return ret;
1596 /***********************************************************************
1597 * GetOutlineTextMetricsW [GDI32.@]
1599 UINT WINAPI GetOutlineTextMetricsW(
1600 HDC hdc, /* [in] Handle of device context */
1601 UINT cbData, /* [in] Size of metric data array */
1602 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1604 DC *dc = get_dc_ptr( hdc );
1605 OUTLINETEXTMETRICW *output = lpOTM;
1606 PHYSDEV dev;
1607 UINT ret;
1609 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1610 if(!dc) return 0;
1612 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1613 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1615 if (lpOTM && ret > cbData)
1617 output = HeapAlloc(GetProcessHeap(), 0, ret);
1618 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1621 if (lpOTM && ret)
1623 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1624 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1626 #define WDPTOLP(x) ((x<0)? \
1627 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1628 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1629 #define HDPTOLP(y) ((y<0)? \
1630 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1631 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1633 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1634 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1635 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1636 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1637 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1638 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1639 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1640 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1641 output->otmAscent = HDPTOLP(output->otmAscent);
1642 output->otmDescent = HDPTOLP(output->otmDescent);
1643 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1644 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1645 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1646 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1647 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1648 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1649 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1650 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1651 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1652 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1653 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1654 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1655 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1656 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1657 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1658 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1659 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1660 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1661 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1662 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1663 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1664 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1665 #undef WDPTOLP
1666 #undef HDPTOLP
1667 if(output != lpOTM)
1669 memcpy(lpOTM, output, cbData);
1670 HeapFree(GetProcessHeap(), 0, output);
1671 ret = cbData;
1674 release_dc_ptr(dc);
1675 return ret;
1678 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1680 INT i, count = lastChar - firstChar + 1;
1681 UINT mbcp;
1682 UINT c;
1683 LPSTR str;
1685 if (count <= 0)
1686 return NULL;
1688 mbcp = GdiGetCodePage(hdc);
1689 switch (mbcp)
1691 case 932:
1692 case 936:
1693 case 949:
1694 case 950:
1695 case 1361:
1696 if (lastChar > 0xffff)
1697 return NULL;
1698 if ((firstChar ^ lastChar) > 0xff)
1699 return NULL;
1700 break;
1701 default:
1702 if (lastChar > 0xff)
1703 return NULL;
1704 mbcp = 0;
1705 break;
1708 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1709 if (str == NULL)
1710 return NULL;
1712 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1714 if (mbcp) {
1715 if (c > 0xff)
1716 str[i++] = (BYTE)(c >> 8);
1717 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1718 str[i] = 0x1f; /* FIXME: use default character */
1719 else
1720 str[i] = (BYTE)c;
1722 else
1723 str[i] = (BYTE)c;
1725 str[i] = '\0';
1727 *pByteLen = i;
1729 return str;
1732 /***********************************************************************
1733 * GetCharWidthW (GDI32.@)
1734 * GetCharWidth32W (GDI32.@)
1736 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1737 LPINT buffer )
1739 UINT i;
1740 BOOL ret;
1741 PHYSDEV dev;
1742 DC * dc = get_dc_ptr( hdc );
1744 if (!dc) return FALSE;
1746 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1747 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1749 if (ret)
1751 #define WDPTOLP(x) ((x<0)? \
1752 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1753 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1754 /* convert device units to logical */
1755 for( i = firstChar; i <= lastChar; i++, buffer++ )
1756 *buffer = WDPTOLP(*buffer);
1757 #undef WDPTOLP
1759 release_dc_ptr( dc );
1760 return ret;
1764 /***********************************************************************
1765 * GetCharWidthA (GDI32.@)
1766 * GetCharWidth32A (GDI32.@)
1768 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1769 LPINT buffer )
1771 INT i, wlen;
1772 LPSTR str;
1773 LPWSTR wstr;
1774 BOOL ret = TRUE;
1776 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1777 if(str == NULL)
1778 return FALSE;
1780 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1782 for(i = 0; i < wlen; i++)
1784 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1786 ret = FALSE;
1787 break;
1789 buffer++;
1792 HeapFree(GetProcessHeap(), 0, str);
1793 HeapFree(GetProcessHeap(), 0, wstr);
1795 return ret;
1799 /* helper for nulldrv_ExtTextOut */
1800 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1801 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1803 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1804 UINT indices[3] = {0, 0, 0x20};
1805 unsigned int i;
1806 DWORD ret, size;
1807 int stride;
1809 indices[0] = index;
1810 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1812 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1814 index = indices[i];
1815 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1816 if (ret != GDI_ERROR) break;
1819 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1820 if (!image) return ERROR_SUCCESS;
1822 image->ptr = NULL;
1823 image->free = NULL;
1824 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1826 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1827 size = metrics->gmBlackBoxY * stride;
1829 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1830 image->is_copy = TRUE;
1831 image->free = free_heap_bits;
1833 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1834 if (ret == GDI_ERROR)
1836 HeapFree( GetProcessHeap(), 0, image->ptr );
1837 return ERROR_NOT_FOUND;
1839 return ERROR_SUCCESS;
1842 /* helper for nulldrv_ExtTextOut */
1843 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1844 LPCWSTR str, UINT count, const INT *dx )
1846 UINT i;
1847 RECT rect, bounds;
1849 reset_bounds( &bounds );
1850 for (i = 0; i < count; i++)
1852 GLYPHMETRICS metrics;
1854 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1856 rect.left = x + metrics.gmptGlyphOrigin.x;
1857 rect.top = y - metrics.gmptGlyphOrigin.y;
1858 rect.right = rect.left + metrics.gmBlackBoxX;
1859 rect.bottom = rect.top + metrics.gmBlackBoxY;
1860 add_bounds_rect( &bounds, &rect );
1862 if (dx)
1864 if (flags & ETO_PDY)
1866 x += dx[ i * 2 ];
1867 y += dx[ i * 2 + 1];
1869 else x += dx[ i ];
1871 else
1873 x += metrics.gmCellIncX;
1874 y += metrics.gmCellIncY;
1877 return bounds;
1880 /* helper for nulldrv_ExtTextOut */
1881 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1882 const struct gdi_image_bits *image, const RECT *clip )
1884 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1885 UINT i, count, max_count;
1886 LONG x, y;
1887 BYTE *ptr = image->ptr;
1888 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1889 POINT *pts;
1890 RECT rect, clipped_rect;
1892 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1893 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1894 rect.right = rect.left + metrics->gmBlackBoxX;
1895 rect.bottom = rect.top + metrics->gmBlackBoxY;
1896 if (!clip) clipped_rect = rect;
1897 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1899 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1900 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1901 if (!pts) return;
1903 count = 0;
1904 ptr += (clipped_rect.top - rect.top) * stride;
1905 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1907 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1909 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1910 pts[count].x = rect.left + x;
1911 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1912 pts[count + 1].x = rect.left + x;
1913 if (pts[count + 1].x > pts[count].x)
1915 pts[count].y = pts[count + 1].y = y;
1916 count += 2;
1920 assert( count <= max_count );
1921 DPtoLP( hdc, pts, count );
1922 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1923 HeapFree( GetProcessHeap(), 0, pts );
1926 /***********************************************************************
1927 * nulldrv_ExtTextOut
1929 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1930 LPCWSTR str, UINT count, const INT *dx )
1932 DC *dc = get_nulldrv_dc( dev );
1933 UINT i;
1934 DWORD err;
1935 HGDIOBJ orig;
1936 HPEN pen;
1938 if (flags & ETO_OPAQUE)
1940 RECT rc = *rect;
1941 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1943 if (brush)
1945 orig = SelectObject( dev->hdc, brush );
1946 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1947 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1948 SelectObject( dev->hdc, orig );
1949 DeleteObject( brush );
1953 if (!count) return TRUE;
1955 if (dc->aa_flags != GGO_BITMAP)
1957 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1958 BITMAPINFO *info = (BITMAPINFO *)buffer;
1959 struct gdi_image_bits bits;
1960 struct bitblt_coords src, dst;
1961 PHYSDEV dst_dev;
1962 /* FIXME Subpixel modes */
1963 UINT aa_flags = GGO_GRAY4_BITMAP;
1965 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1966 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1967 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1968 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1970 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1971 src.x = src.visrect.left;
1972 src.y = src.visrect.top;
1973 src.width = src.visrect.right - src.visrect.left;
1974 src.height = src.visrect.bottom - src.visrect.top;
1975 dst = src;
1976 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1977 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1979 /* we can avoid the GetImage, just query the needed format */
1980 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1981 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1982 info->bmiHeader.biWidth = src.width;
1983 info->bmiHeader.biHeight = -src.height;
1984 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1985 if (!err || err == ERROR_BAD_FORMAT)
1987 /* make the source rectangle relative to the source bits */
1988 src.x = src.y = 0;
1989 src.visrect.left = src.visrect.top = 0;
1990 src.visrect.right = src.width;
1991 src.visrect.bottom = src.height;
1993 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1994 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1995 bits.is_copy = TRUE;
1996 bits.free = free_heap_bits;
1997 err = ERROR_SUCCESS;
2000 else
2002 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
2003 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
2004 if (!err && !bits.is_copy)
2006 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
2007 if (!ptr)
2009 if (bits.free) bits.free( &bits );
2010 return ERROR_OUTOFMEMORY;
2012 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
2013 if (bits.free) bits.free( &bits );
2014 bits.ptr = ptr;
2015 bits.is_copy = TRUE;
2016 bits.free = free_heap_bits;
2019 if (!err)
2021 /* make x,y relative to the image bits */
2022 x += src.visrect.left - dst.visrect.left;
2023 y += src.visrect.top - dst.visrect.top;
2024 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
2025 aa_flags, str, count, dx );
2026 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2027 if (bits.free) bits.free( &bits );
2028 return !err;
2032 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
2033 orig = SelectObject( dev->hdc, pen );
2035 for (i = 0; i < count; i++)
2037 GLYPHMETRICS metrics;
2038 struct gdi_image_bits image;
2040 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2041 if (err) continue;
2043 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2044 if (image.free) image.free( &image );
2046 if (dx)
2048 if (flags & ETO_PDY)
2050 x += dx[ i * 2 ];
2051 y += dx[ i * 2 + 1];
2053 else x += dx[ i ];
2055 else
2057 x += metrics.gmCellIncX;
2058 y += metrics.gmCellIncY;
2062 SelectObject( dev->hdc, orig );
2063 DeleteObject( pen );
2064 return TRUE;
2068 /***********************************************************************
2069 * ExtTextOutA (GDI32.@)
2071 * See ExtTextOutW.
2073 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2074 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2076 INT wlen;
2077 UINT codepage;
2078 LPWSTR p;
2079 BOOL ret;
2080 LPINT lpDxW = NULL;
2082 if (flags & ETO_GLYPH_INDEX)
2083 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2085 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2087 if (lpDx) {
2088 unsigned int i = 0, j = 0;
2090 /* allocate enough for a ETO_PDY */
2091 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2092 while(i < count) {
2093 if(IsDBCSLeadByteEx(codepage, str[i]))
2095 if(flags & ETO_PDY)
2097 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2098 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2100 else
2101 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2102 i = i + 2;
2104 else
2106 if(flags & ETO_PDY)
2108 lpDxW[j++] = lpDx[i * 2];
2109 lpDxW[j++] = lpDx[i * 2 + 1];
2111 else
2112 lpDxW[j++] = lpDx[i];
2113 i = i + 1;
2118 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2120 HeapFree( GetProcessHeap(), 0, p );
2121 HeapFree( GetProcessHeap(), 0, lpDxW );
2122 return ret;
2126 /***********************************************************************
2127 * ExtTextOutW (GDI32.@)
2129 * Draws text using the currently selected font, background color, and text color.
2132 * PARAMS
2133 * x,y [I] coordinates of string
2134 * flags [I]
2135 * ETO_GRAYED - undocumented on MSDN
2136 * ETO_OPAQUE - use background color for fill the rectangle
2137 * ETO_CLIPPED - clipping text to the rectangle
2138 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2139 * than encoded characters. Implies ETO_IGNORELANGUAGE
2140 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2141 * Affects BiDi ordering
2142 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2143 * ETO_PDY - unimplemented
2144 * ETO_NUMERICSLATIN - unimplemented always assumed -
2145 * do not translate numbers into locale representations
2146 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2147 * lprect [I] dimensions for clipping or/and opaquing
2148 * str [I] text string
2149 * count [I] number of symbols in string
2150 * lpDx [I] optional parameter with distance between drawing characters
2152 * RETURNS
2153 * Success: TRUE
2154 * Failure: FALSE
2156 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2157 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2159 BOOL ret = FALSE;
2160 LPWSTR reordered_str = (LPWSTR)str;
2161 WORD *glyphs = NULL;
2162 UINT align = GetTextAlign( hdc );
2163 DWORD layout = GetLayout( hdc );
2164 POINT pt;
2165 TEXTMETRICW tm;
2166 LOGFONTW lf;
2167 double cosEsc, sinEsc;
2168 INT char_extra;
2169 SIZE sz;
2170 RECT rc;
2171 POINT *deltas = NULL, width = {0, 0};
2172 DWORD type;
2173 DC * dc = get_dc_ptr( hdc );
2174 PHYSDEV physdev;
2175 INT breakRem;
2176 static int quietfixme = 0;
2178 if (!dc) return FALSE;
2180 breakRem = dc->breakRem;
2182 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2184 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2185 quietfixme = 1;
2188 update_dc( dc );
2189 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2190 type = GetObjectType(hdc);
2191 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2193 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2194 release_dc_ptr( dc );
2195 return ret;
2198 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2199 if (layout & LAYOUT_RTL)
2201 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2202 align ^= TA_RTLREADING;
2205 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2207 INT cGlyphs;
2208 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2210 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2211 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2212 reordered_str, count, NULL, &glyphs, &cGlyphs);
2214 flags |= ETO_IGNORELANGUAGE;
2215 if (glyphs)
2217 flags |= ETO_GLYPH_INDEX;
2218 if (cGlyphs != count)
2219 count = cGlyphs;
2222 else if(flags & ETO_GLYPH_INDEX)
2223 glyphs = reordered_str;
2225 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2226 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2227 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2229 if(align & TA_UPDATECP)
2231 GetCurrentPositionEx( hdc, &pt );
2232 x = pt.x;
2233 y = pt.y;
2236 GetTextMetricsW(hdc, &tm);
2237 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2239 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2240 lf.lfEscapement = 0;
2242 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2243 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2245 lf.lfEscapement = -lf.lfEscapement;
2248 if(lf.lfEscapement != 0)
2250 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2251 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2253 else
2255 cosEsc = 1;
2256 sinEsc = 0;
2259 if (lprect)
2261 rc = *lprect;
2262 LPtoDP(hdc, (POINT*)&rc, 2);
2263 order_rect( &rc );
2264 if (flags & ETO_OPAQUE)
2265 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2267 else flags &= ~ETO_CLIPPED;
2269 if(count == 0)
2271 ret = TRUE;
2272 goto done;
2275 pt.x = x;
2276 pt.y = y;
2277 LPtoDP(hdc, &pt, 1);
2278 x = pt.x;
2279 y = pt.y;
2281 char_extra = GetTextCharacterExtra(hdc);
2282 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2283 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2285 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2287 UINT i;
2288 POINT total = {0, 0}, desired[2];
2290 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2291 if (lpDx)
2293 if (flags & ETO_PDY)
2295 for (i = 0; i < count; i++)
2297 deltas[i].x = lpDx[i * 2] + char_extra;
2298 deltas[i].y = -lpDx[i * 2 + 1];
2301 else
2303 for (i = 0; i < count; i++)
2305 deltas[i].x = lpDx[i] + char_extra;
2306 deltas[i].y = 0;
2310 else
2312 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2314 if (flags & ETO_GLYPH_INDEX)
2315 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2316 else
2317 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2319 deltas[0].x = dx[0];
2320 deltas[0].y = 0;
2321 for (i = 1; i < count; i++)
2323 deltas[i].x = dx[i] - dx[i - 1];
2324 deltas[i].y = 0;
2326 HeapFree( GetProcessHeap(), 0, dx );
2329 for(i = 0; i < count; i++)
2331 total.x += deltas[i].x;
2332 total.y += deltas[i].y;
2334 desired[0].x = desired[0].y = 0;
2336 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2337 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2339 LPtoDP(hdc, desired, 2);
2340 desired[1].x -= desired[0].x;
2341 desired[1].y -= desired[0].y;
2343 if (dc->GraphicsMode == GM_COMPATIBLE)
2345 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2346 desired[1].x = -desired[1].x;
2347 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2348 desired[1].y = -desired[1].y;
2351 deltas[i].x = desired[1].x - width.x;
2352 deltas[i].y = desired[1].y - width.y;
2354 width = desired[1];
2356 flags |= ETO_PDY;
2358 else
2360 POINT desired[2];
2362 if(flags & ETO_GLYPH_INDEX)
2363 GetTextExtentPointI(hdc, glyphs, count, &sz);
2364 else
2365 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2366 desired[0].x = desired[0].y = 0;
2367 desired[1].x = sz.cx;
2368 desired[1].y = 0;
2369 LPtoDP(hdc, desired, 2);
2370 desired[1].x -= desired[0].x;
2371 desired[1].y -= desired[0].y;
2373 if (dc->GraphicsMode == GM_COMPATIBLE)
2375 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2376 desired[1].x = -desired[1].x;
2377 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2378 desired[1].y = -desired[1].y;
2380 width = desired[1];
2383 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2384 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2385 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2387 case TA_LEFT:
2388 if (align & TA_UPDATECP)
2390 pt.x = x + width.x;
2391 pt.y = y + width.y;
2392 DPtoLP(hdc, &pt, 1);
2393 MoveToEx(hdc, pt.x, pt.y, NULL);
2395 break;
2397 case TA_CENTER:
2398 x -= width.x / 2;
2399 y -= width.y / 2;
2400 break;
2402 case TA_RIGHT:
2403 x -= width.x;
2404 y -= width.y;
2405 if (align & TA_UPDATECP)
2407 pt.x = x;
2408 pt.y = y;
2409 DPtoLP(hdc, &pt, 1);
2410 MoveToEx(hdc, pt.x, pt.y, NULL);
2412 break;
2415 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2417 case TA_TOP:
2418 y += tm.tmAscent * cosEsc;
2419 x += tm.tmAscent * sinEsc;
2420 break;
2422 case TA_BOTTOM:
2423 y -= tm.tmDescent * cosEsc;
2424 x -= tm.tmDescent * sinEsc;
2425 break;
2427 case TA_BASELINE:
2428 break;
2431 if (GetBkMode(hdc) != TRANSPARENT)
2433 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2435 if(!(flags & ETO_OPAQUE) || !lprect ||
2436 x < rc.left || x + width.x >= rc.right ||
2437 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2439 RECT text_box;
2440 text_box.left = x;
2441 text_box.right = x + width.x;
2442 text_box.top = y - tm.tmAscent;
2443 text_box.bottom = y + tm.tmDescent;
2445 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2446 if (!is_rect_empty( &text_box ))
2447 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2452 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2453 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2455 done:
2456 HeapFree(GetProcessHeap(), 0, deltas);
2457 if(glyphs != reordered_str)
2458 HeapFree(GetProcessHeap(), 0, glyphs);
2459 if(reordered_str != str)
2460 HeapFree(GetProcessHeap(), 0, reordered_str);
2462 release_dc_ptr( dc );
2464 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2466 int underlinePos, strikeoutPos;
2467 int underlineWidth, strikeoutWidth;
2468 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2469 OUTLINETEXTMETRICW* otm = NULL;
2470 POINT pts[5];
2471 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2472 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2474 hbrush = SelectObject(hdc, hbrush);
2476 if(!size)
2478 underlinePos = 0;
2479 underlineWidth = tm.tmAscent / 20 + 1;
2480 strikeoutPos = tm.tmAscent / 2;
2481 strikeoutWidth = underlineWidth;
2483 else
2485 otm = HeapAlloc(GetProcessHeap(), 0, size);
2486 GetOutlineTextMetricsW(hdc, size, otm);
2487 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2488 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2489 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2490 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2491 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2492 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2493 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2494 HeapFree(GetProcessHeap(), 0, otm);
2498 if (lf.lfUnderline)
2500 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2501 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2502 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2503 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2504 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2505 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2506 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2507 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2508 pts[4].x = pts[0].x;
2509 pts[4].y = pts[0].y;
2510 DPtoLP(hdc, pts, 5);
2511 Polygon(hdc, pts, 5);
2514 if (lf.lfStrikeOut)
2516 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2517 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2518 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2519 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2520 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2521 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2522 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2523 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2524 pts[4].x = pts[0].x;
2525 pts[4].y = pts[0].y;
2526 DPtoLP(hdc, pts, 5);
2527 Polygon(hdc, pts, 5);
2530 SelectObject(hdc, hpen);
2531 hbrush = SelectObject(hdc, hbrush);
2532 DeleteObject(hbrush);
2535 return ret;
2539 /***********************************************************************
2540 * TextOutA (GDI32.@)
2542 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2544 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2548 /***********************************************************************
2549 * TextOutW (GDI32.@)
2551 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2553 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2557 /***********************************************************************
2558 * PolyTextOutA (GDI32.@)
2560 * See PolyTextOutW.
2562 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2564 for (; cStrings>0; cStrings--, pptxt++)
2565 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2566 return FALSE;
2567 return TRUE;
2572 /***********************************************************************
2573 * PolyTextOutW (GDI32.@)
2575 * Draw several Strings
2577 * RETURNS
2578 * TRUE: Success.
2579 * FALSE: Failure.
2581 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2583 for (; cStrings>0; cStrings--, pptxt++)
2584 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2585 return FALSE;
2586 return TRUE;
2590 /***********************************************************************
2591 * SetMapperFlags (GDI32.@)
2593 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2595 DC *dc = get_dc_ptr( hdc );
2596 DWORD ret = GDI_ERROR;
2598 if (dc)
2600 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2601 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2602 if (flags != GDI_ERROR)
2604 ret = dc->mapperFlags;
2605 dc->mapperFlags = flags;
2607 release_dc_ptr( dc );
2609 return ret;
2612 /***********************************************************************
2613 * GetAspectRatioFilterEx (GDI32.@)
2615 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2617 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2618 return FALSE;
2622 /***********************************************************************
2623 * GetCharABCWidthsA (GDI32.@)
2625 * See GetCharABCWidthsW.
2627 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2628 LPABC abc )
2630 INT i, wlen;
2631 LPSTR str;
2632 LPWSTR wstr;
2633 BOOL ret = TRUE;
2635 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2636 if (str == NULL)
2637 return FALSE;
2639 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2640 if (wstr == NULL)
2642 HeapFree(GetProcessHeap(), 0, str);
2643 return FALSE;
2646 for(i = 0; i < wlen; i++)
2648 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2650 ret = FALSE;
2651 break;
2653 abc++;
2656 HeapFree(GetProcessHeap(), 0, str);
2657 HeapFree(GetProcessHeap(), 0, wstr);
2659 return ret;
2663 /******************************************************************************
2664 * GetCharABCWidthsW [GDI32.@]
2666 * Retrieves widths of characters in range.
2668 * PARAMS
2669 * hdc [I] Handle of device context
2670 * firstChar [I] First character in range to query
2671 * lastChar [I] Last character in range to query
2672 * abc [O] Address of character-width structure
2674 * NOTES
2675 * Only works with TrueType fonts
2677 * RETURNS
2678 * Success: TRUE
2679 * Failure: FALSE
2681 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2682 LPABC abc )
2684 DC *dc = get_dc_ptr(hdc);
2685 PHYSDEV dev;
2686 unsigned int i;
2687 BOOL ret;
2688 TEXTMETRICW tm;
2690 if (!dc) return FALSE;
2692 if (!abc)
2694 release_dc_ptr( dc );
2695 return FALSE;
2698 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2699 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2700 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2702 release_dc_ptr( dc );
2703 return FALSE;
2706 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2707 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2708 if (ret)
2710 /* convert device units to logical */
2711 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2712 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2713 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2714 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2718 release_dc_ptr( dc );
2719 return ret;
2723 /******************************************************************************
2724 * GetCharABCWidthsI [GDI32.@]
2726 * Retrieves widths of characters in range.
2728 * PARAMS
2729 * hdc [I] Handle of device context
2730 * firstChar [I] First glyphs in range to query
2731 * count [I] Last glyphs in range to query
2732 * pgi [i] Array of glyphs to query
2733 * abc [O] Address of character-width structure
2735 * NOTES
2736 * Only works with TrueType fonts
2738 * RETURNS
2739 * Success: TRUE
2740 * Failure: FALSE
2742 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2743 LPWORD pgi, LPABC abc)
2745 DC *dc = get_dc_ptr(hdc);
2746 PHYSDEV dev;
2747 unsigned int i;
2748 BOOL ret;
2750 if (!dc) return FALSE;
2752 if (!abc)
2754 release_dc_ptr( dc );
2755 return FALSE;
2758 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2759 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2760 if (ret)
2762 /* convert device units to logical */
2763 for( i = 0; i < count; i++, abc++ ) {
2764 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2765 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2766 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2770 release_dc_ptr( dc );
2771 return ret;
2775 /***********************************************************************
2776 * GetGlyphOutlineA (GDI32.@)
2778 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2779 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2780 LPVOID lpBuffer, const MAT2 *lpmat2 )
2782 if (!lpmat2) return GDI_ERROR;
2784 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2785 UINT cp;
2786 int len;
2787 char mbchs[2];
2789 cp = GdiGetCodePage(hdc);
2790 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2791 len = 2;
2792 mbchs[0] = (uChar & 0xff00) >> 8;
2793 mbchs[1] = (uChar & 0xff);
2794 } else {
2795 len = 1;
2796 mbchs[0] = (uChar & 0xff);
2798 uChar = 0;
2799 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2802 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2803 lpmat2);
2806 /***********************************************************************
2807 * GetGlyphOutlineW (GDI32.@)
2809 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2810 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2811 LPVOID lpBuffer, const MAT2 *lpmat2 )
2813 DC *dc;
2814 DWORD ret;
2815 PHYSDEV dev;
2817 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2818 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2820 if (!lpmat2) return GDI_ERROR;
2822 dc = get_dc_ptr(hdc);
2823 if(!dc) return GDI_ERROR;
2825 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2826 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2827 release_dc_ptr( dc );
2828 return ret;
2832 /***********************************************************************
2833 * CreateScalableFontResourceA (GDI32.@)
2835 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2836 LPCSTR lpszResourceFile,
2837 LPCSTR lpszFontFile,
2838 LPCSTR lpszCurrentPath )
2840 LPWSTR lpszResourceFileW = NULL;
2841 LPWSTR lpszFontFileW = NULL;
2842 LPWSTR lpszCurrentPathW = NULL;
2843 int len;
2844 BOOL ret;
2846 if (lpszResourceFile)
2848 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2849 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2850 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2853 if (lpszFontFile)
2855 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2856 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2857 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2860 if (lpszCurrentPath)
2862 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2863 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2864 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2867 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2868 lpszFontFileW, lpszCurrentPathW);
2870 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2871 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2872 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2874 return ret;
2877 /***********************************************************************
2878 * CreateScalableFontResourceW (GDI32.@)
2880 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2881 LPCWSTR font_file, LPCWSTR font_path )
2883 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2884 debugstr_w(font_file), debugstr_w(font_path) );
2886 return WineEngCreateScalableFontResource( hidden, resource_file,
2887 font_file, font_path );
2890 /*************************************************************************
2891 * GetKerningPairsA (GDI32.@)
2893 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2894 LPKERNINGPAIR kern_pairA )
2896 UINT cp;
2897 CPINFO cpi;
2898 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2899 KERNINGPAIR *kern_pairW;
2901 if (!cPairs && kern_pairA)
2903 SetLastError(ERROR_INVALID_PARAMETER);
2904 return 0;
2907 cp = GdiGetCodePage(hDC);
2909 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2910 * to fail on an invalid character for CP_SYMBOL.
2912 cpi.DefaultChar[0] = 0;
2913 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2915 FIXME("Can't find codepage %u info\n", cp);
2916 return 0;
2919 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2920 if (!total_kern_pairs) return 0;
2922 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2923 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2925 for (i = 0; i < total_kern_pairs; i++)
2927 char first, second;
2929 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2930 continue;
2932 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2933 continue;
2935 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2936 continue;
2938 if (kern_pairA)
2940 if (kern_pairs_copied >= cPairs) break;
2942 kern_pairA->wFirst = (BYTE)first;
2943 kern_pairA->wSecond = (BYTE)second;
2944 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2945 kern_pairA++;
2947 kern_pairs_copied++;
2950 HeapFree(GetProcessHeap(), 0, kern_pairW);
2952 return kern_pairs_copied;
2955 /*************************************************************************
2956 * GetKerningPairsW (GDI32.@)
2958 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2959 LPKERNINGPAIR lpKerningPairs )
2961 DC *dc;
2962 DWORD ret;
2963 PHYSDEV dev;
2965 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2967 if (!cPairs && lpKerningPairs)
2969 SetLastError(ERROR_INVALID_PARAMETER);
2970 return 0;
2973 dc = get_dc_ptr(hDC);
2974 if (!dc) return 0;
2976 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2977 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2978 release_dc_ptr( dc );
2979 return ret;
2982 /*************************************************************************
2983 * TranslateCharsetInfo [GDI32.@]
2985 * Fills a CHARSETINFO structure for a character set, code page, or
2986 * font. This allows making the correspondence between different labels
2987 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2988 * of the same encoding.
2990 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2991 * only one codepage should be set in *lpSrc.
2993 * RETURNS
2994 * TRUE on success, FALSE on failure.
2997 BOOL WINAPI TranslateCharsetInfo(
2998 LPDWORD lpSrc, /* [in]
2999 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
3000 if flags == TCI_SRCCHARSET: a character set value
3001 if flags == TCI_SRCCODEPAGE: a code page value
3003 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
3004 DWORD flags /* [in] determines interpretation of lpSrc */)
3006 int index = 0;
3007 switch (flags) {
3008 case TCI_SRCFONTSIG:
3009 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3010 break;
3011 case TCI_SRCCODEPAGE:
3012 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3013 break;
3014 case TCI_SRCCHARSET:
3015 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3016 break;
3017 default:
3018 return FALSE;
3020 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3021 *lpCs = FONT_tci[index];
3022 return TRUE;
3025 /*************************************************************************
3026 * GetFontLanguageInfo (GDI32.@)
3028 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3030 FONTSIGNATURE fontsig;
3031 static const DWORD GCP_DBCS_MASK=0x003F0000,
3032 GCP_DIACRITIC_MASK=0x00000000,
3033 FLI_GLYPHS_MASK=0x00000000,
3034 GCP_GLYPHSHAPE_MASK=0x00000040,
3035 GCP_KASHIDA_MASK=0x00000000,
3036 GCP_LIGATE_MASK=0x00000000,
3037 GCP_USEKERNING_MASK=0x00000000,
3038 GCP_REORDER_MASK=0x00000060;
3040 DWORD result=0;
3042 GetTextCharsetInfo( hdc, &fontsig, 0 );
3043 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3045 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3046 result|=GCP_DBCS;
3048 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3049 result|=GCP_DIACRITIC;
3051 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3052 result|=FLI_GLYPHS;
3054 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3055 result|=GCP_GLYPHSHAPE;
3057 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3058 result|=GCP_KASHIDA;
3060 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3061 result|=GCP_LIGATE;
3063 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3064 result|=GCP_USEKERNING;
3066 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3067 if( GetTextAlign( hdc) & TA_RTLREADING )
3068 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3069 result|=GCP_REORDER;
3071 return result;
3075 /*************************************************************************
3076 * GetFontData [GDI32.@]
3078 * Retrieve data for TrueType font.
3080 * RETURNS
3082 * success: Number of bytes returned
3083 * failure: GDI_ERROR
3085 * NOTES
3087 * Calls SetLastError()
3090 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3091 LPVOID buffer, DWORD length)
3093 DC *dc = get_dc_ptr(hdc);
3094 PHYSDEV dev;
3095 DWORD ret;
3097 if(!dc) return GDI_ERROR;
3099 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3100 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3101 release_dc_ptr( dc );
3102 return ret;
3105 /*************************************************************************
3106 * GetGlyphIndicesA [GDI32.@]
3108 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3109 LPWORD pgi, DWORD flags)
3111 DWORD ret;
3112 WCHAR *lpstrW;
3113 INT countW;
3115 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3116 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3118 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3119 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3120 HeapFree(GetProcessHeap(), 0, lpstrW);
3122 return ret;
3125 /*************************************************************************
3126 * GetGlyphIndicesW [GDI32.@]
3128 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3129 LPWORD pgi, DWORD flags)
3131 DC *dc = get_dc_ptr(hdc);
3132 PHYSDEV dev;
3133 DWORD ret;
3135 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3136 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3138 if(!dc) return GDI_ERROR;
3140 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3141 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3142 release_dc_ptr( dc );
3143 return ret;
3146 /*************************************************************************
3147 * GetCharacterPlacementA [GDI32.@]
3149 * See GetCharacterPlacementW.
3151 * NOTES:
3152 * the web browser control of ie4 calls this with dwFlags=0
3154 DWORD WINAPI
3155 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3156 INT nMaxExtent, GCP_RESULTSA *lpResults,
3157 DWORD dwFlags)
3159 WCHAR *lpStringW;
3160 INT uCountW;
3161 GCP_RESULTSW resultsW;
3162 DWORD ret;
3163 UINT font_cp;
3165 TRACE("%s, %d, %d, 0x%08x\n",
3166 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3168 /* both structs are equal in size */
3169 memcpy(&resultsW, lpResults, sizeof(resultsW));
3171 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3172 if(lpResults->lpOutString)
3173 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3175 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3177 lpResults->nGlyphs = resultsW.nGlyphs;
3178 lpResults->nMaxFit = resultsW.nMaxFit;
3180 if(lpResults->lpOutString) {
3181 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3182 lpResults->lpOutString, uCount, NULL, NULL );
3185 HeapFree(GetProcessHeap(), 0, lpStringW);
3186 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3188 return ret;
3191 /*************************************************************************
3192 * GetCharacterPlacementW [GDI32.@]
3194 * Retrieve information about a string. This includes the width, reordering,
3195 * Glyphing and so on.
3197 * RETURNS
3199 * The width and height of the string if successful, 0 if failed.
3201 * BUGS
3203 * All flags except GCP_REORDER are not yet implemented.
3204 * Reordering is not 100% compliant to the Windows BiDi method.
3205 * Caret positioning is not yet implemented for BiDi.
3206 * Classes are not yet implemented.
3209 DWORD WINAPI
3210 GetCharacterPlacementW(
3211 HDC hdc, /* [in] Device context for which the rendering is to be done */
3212 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3213 INT uCount, /* [in] Number of WORDS in string. */
3214 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3215 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3216 DWORD dwFlags /* [in] Flags specifying how to process the string */
3219 DWORD ret=0;
3220 SIZE size;
3221 UINT i, nSet;
3223 TRACE("%s, %d, %d, 0x%08x\n",
3224 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3226 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3227 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3228 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3229 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3230 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3232 if(dwFlags&(~GCP_REORDER))
3233 FIXME("flags 0x%08x ignored\n", dwFlags);
3234 if(lpResults->lpClass)
3235 FIXME("classes not implemented\n");
3236 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3237 FIXME("Caret positions for complex scripts not implemented\n");
3239 nSet = (UINT)uCount;
3240 if(nSet > lpResults->nGlyphs)
3241 nSet = lpResults->nGlyphs;
3243 /* return number of initialized fields */
3244 lpResults->nGlyphs = nSet;
3246 if((dwFlags&GCP_REORDER)==0 )
3248 /* Treat the case where no special handling was requested in a fastpath way */
3249 /* copy will do if the GCP_REORDER flag is not set */
3250 if(lpResults->lpOutString)
3251 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3253 if(lpResults->lpOrder)
3255 for(i = 0; i < nSet; i++)
3256 lpResults->lpOrder[i] = i;
3259 else
3261 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3262 nSet, lpResults->lpOrder, NULL, NULL );
3265 /* FIXME: Will use the placement chars */
3266 if (lpResults->lpDx)
3268 int c;
3269 for (i = 0; i < nSet; i++)
3271 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3272 lpResults->lpDx[i]= c;
3276 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3278 int pos = 0;
3280 lpResults->lpCaretPos[0] = 0;
3281 for (i = 1; i < nSet; i++)
3282 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3283 lpResults->lpCaretPos[i] = (pos += size.cx);
3286 if(lpResults->lpGlyphs)
3287 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3289 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3290 ret = MAKELONG(size.cx, size.cy);
3292 return ret;
3295 /*************************************************************************
3296 * GetCharABCWidthsFloatA [GDI32.@]
3298 * See GetCharABCWidthsFloatW.
3300 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3302 INT i, wlen;
3303 LPSTR str;
3304 LPWSTR wstr;
3305 BOOL ret = TRUE;
3307 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3308 if (str == NULL)
3309 return FALSE;
3311 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3313 for (i = 0; i < wlen; i++)
3315 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3317 ret = FALSE;
3318 break;
3320 abcf++;
3323 HeapFree( GetProcessHeap(), 0, str );
3324 HeapFree( GetProcessHeap(), 0, wstr );
3326 return ret;
3329 /*************************************************************************
3330 * GetCharABCWidthsFloatW [GDI32.@]
3332 * Retrieves widths of a range of characters.
3334 * PARAMS
3335 * hdc [I] Handle to device context.
3336 * first [I] First character in range to query.
3337 * last [I] Last character in range to query.
3338 * abcf [O] Array of LPABCFLOAT structures.
3340 * RETURNS
3341 * Success: TRUE
3342 * Failure: FALSE
3344 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3346 UINT i;
3347 ABC *abc;
3348 PHYSDEV dev;
3349 BOOL ret = FALSE;
3350 DC *dc = get_dc_ptr( hdc );
3352 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3354 if (!dc) return FALSE;
3356 if (!abcf) goto done;
3357 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3359 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3360 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3361 if (ret)
3363 /* convert device units to logical */
3364 for (i = first; i <= last; i++, abcf++)
3366 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3367 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3368 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3371 HeapFree( GetProcessHeap(), 0, abc );
3373 done:
3374 release_dc_ptr( dc );
3375 return ret;
3378 /*************************************************************************
3379 * GetCharWidthFloatA [GDI32.@]
3381 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3382 UINT iLastChar, PFLOAT pxBuffer)
3384 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3385 return 0;
3388 /*************************************************************************
3389 * GetCharWidthFloatW [GDI32.@]
3391 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3392 UINT iLastChar, PFLOAT pxBuffer)
3394 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3395 return 0;
3399 /***********************************************************************
3401 * Font Resource API *
3403 ***********************************************************************/
3405 /***********************************************************************
3406 * AddFontResourceA (GDI32.@)
3408 INT WINAPI AddFontResourceA( LPCSTR str )
3410 return AddFontResourceExA( str, 0, NULL);
3413 /***********************************************************************
3414 * AddFontResourceW (GDI32.@)
3416 INT WINAPI AddFontResourceW( LPCWSTR str )
3418 return AddFontResourceExW(str, 0, NULL);
3422 /***********************************************************************
3423 * AddFontResourceExA (GDI32.@)
3425 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3427 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3428 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3429 INT ret;
3431 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3432 ret = AddFontResourceExW(strW, fl, pdv);
3433 HeapFree(GetProcessHeap(), 0, strW);
3434 return ret;
3437 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3439 HRSRC rsrc = FindResourceW(hModule, name, type);
3440 HGLOBAL hMem = LoadResource(hModule, rsrc);
3441 LPVOID *pMem = LockResource(hMem);
3442 int *num_total = (int *)lParam;
3443 DWORD num_in_res;
3445 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3446 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3448 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3449 return FALSE;
3452 *num_total += num_in_res;
3453 return TRUE;
3456 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3458 HANDLE file, mapping;
3459 void *ptr;
3461 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3462 if (file == INVALID_HANDLE_VALUE) return NULL;
3464 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3466 CloseHandle( file );
3467 return NULL;
3470 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3471 CloseHandle( file );
3472 if (!mapping) return NULL;
3474 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3475 CloseHandle( mapping );
3477 return ptr;
3480 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3482 WORD align, type_id, count;
3483 DWORD res_off;
3485 if (size < rsrc_off + 10) return NULL;
3486 align = *(WORD *)(ptr + rsrc_off);
3487 rsrc_off += 2;
3488 type_id = *(WORD *)(ptr + rsrc_off);
3489 while (type_id && type_id != type)
3491 count = *(WORD *)(ptr + rsrc_off + 2);
3492 rsrc_off += 8 + count * 12;
3493 if (size < rsrc_off + 8) return NULL;
3494 type_id = *(WORD *)(ptr + rsrc_off);
3496 if (!type_id) return NULL;
3497 count = *(WORD *)(ptr + rsrc_off + 2);
3498 if (size < rsrc_off + 8 + count * 12) return NULL;
3499 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3500 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3501 if (size < res_off + *len) return NULL;
3502 return ptr + res_off;
3505 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3507 LARGE_INTEGER size;
3508 BYTE *ptr = map_file( res, &size );
3509 const IMAGE_DOS_HEADER *dos;
3510 const IMAGE_OS2_HEADER *ne;
3511 WORD *fontdir;
3512 char *data;
3513 WCHAR *name = NULL;
3514 DWORD len;
3516 if (!ptr) return NULL;
3518 if (size.u.LowPart < sizeof( *dos )) goto fail;
3519 dos = (const IMAGE_DOS_HEADER *)ptr;
3520 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3521 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3522 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3524 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3525 if (!fontdir) goto fail;
3526 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3528 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3529 if (!data) goto fail;
3530 if (!memchr( data, 0, len )) goto fail;
3532 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3533 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3534 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3536 fail:
3537 UnmapViewOfFile( ptr );
3538 return name;
3541 /***********************************************************************
3542 * AddFontResourceExW (GDI32.@)
3544 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3546 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3547 WCHAR *filename;
3548 BOOL hidden;
3550 if (ret == 0)
3552 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3553 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3554 if (hModule != NULL)
3556 int num_resources = 0;
3557 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3559 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3560 wine_dbgstr_w(str));
3561 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3562 ret = num_resources;
3563 FreeLibrary(hModule);
3565 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3567 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3568 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3569 HeapFree( GetProcessHeap(), 0, filename );
3572 return ret;
3575 /***********************************************************************
3576 * RemoveFontResourceA (GDI32.@)
3578 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3580 return RemoveFontResourceExA(str, 0, 0);
3583 /***********************************************************************
3584 * RemoveFontResourceW (GDI32.@)
3586 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3588 return RemoveFontResourceExW(str, 0, 0);
3591 /***********************************************************************
3592 * AddFontMemResourceEx (GDI32.@)
3594 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3596 HANDLE ret;
3597 DWORD num_fonts;
3599 if (!pbFont || !cbFont || !pcFonts)
3601 SetLastError(ERROR_INVALID_PARAMETER);
3602 return NULL;
3605 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3606 if (ret)
3608 __TRY
3610 *pcFonts = num_fonts;
3612 __EXCEPT_PAGE_FAULT
3614 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3615 RemoveFontMemResourceEx(ret);
3616 ret = 0;
3618 __ENDTRY
3620 return ret;
3623 /***********************************************************************
3624 * RemoveFontMemResourceEx (GDI32.@)
3626 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3628 FIXME("(%p) stub\n", fh);
3629 return TRUE;
3632 /***********************************************************************
3633 * RemoveFontResourceExA (GDI32.@)
3635 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3637 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3638 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3639 INT ret;
3641 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3642 ret = RemoveFontResourceExW(strW, fl, pdv);
3643 HeapFree(GetProcessHeap(), 0, strW);
3644 return ret;
3647 /***********************************************************************
3648 * RemoveFontResourceExW (GDI32.@)
3650 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3652 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3653 WCHAR *filename;
3654 BOOL hidden;
3656 if (ret == 0)
3658 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3659 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3660 if (hModule != NULL)
3662 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3663 FreeLibrary(hModule);
3665 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3667 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3668 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3669 HeapFree( GetProcessHeap(), 0, filename );
3672 return ret;
3675 /***********************************************************************
3676 * GetFontResourceInfoW (GDI32.@)
3678 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3680 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3681 return FALSE;
3684 /***********************************************************************
3685 * GetTextCharset (GDI32.@)
3687 UINT WINAPI GetTextCharset(HDC hdc)
3689 /* MSDN docs say this is equivalent */
3690 return GetTextCharsetInfo(hdc, NULL, 0);
3693 /***********************************************************************
3694 * GetTextCharsetInfo (GDI32.@)
3696 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3698 UINT ret = DEFAULT_CHARSET;
3699 DC *dc = get_dc_ptr(hdc);
3700 PHYSDEV dev;
3702 if (dc)
3704 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3705 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3706 release_dc_ptr( dc );
3709 if (ret == DEFAULT_CHARSET && fs)
3710 memset(fs, 0, sizeof(FONTSIGNATURE));
3711 return ret;
3714 /***********************************************************************
3715 * GdiGetCharDimensions (GDI32.@)
3717 * Gets the average width of the characters in the English alphabet.
3719 * PARAMS
3720 * hdc [I] Handle to the device context to measure on.
3721 * lptm [O] Pointer to memory to store the text metrics into.
3722 * height [O] On exit, the maximum height of characters in the English alphabet.
3724 * RETURNS
3725 * The average width of characters in the English alphabet.
3727 * NOTES
3728 * This function is used by the dialog manager to get the size of a dialog
3729 * unit. It should also be used by other pieces of code that need to know
3730 * the size of a dialog unit in logical units without having access to the
3731 * window handle of the dialog.
3732 * Windows caches the font metrics from this function, but we don't and
3733 * there doesn't appear to be an immediate advantage to do so.
3735 * SEE ALSO
3736 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3738 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3740 SIZE sz;
3741 static const WCHAR alphabet[] = {
3742 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3743 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3744 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3746 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3748 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3750 if (height) *height = sz.cy;
3751 return (sz.cx / 26 + 1) / 2;
3754 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3756 FIXME("(%d): stub\n", fEnableEUDC);
3757 return FALSE;
3760 /***********************************************************************
3761 * GetCharWidthI (GDI32.@)
3763 * Retrieve widths of characters.
3765 * PARAMS
3766 * hdc [I] Handle to a device context.
3767 * first [I] First glyph in range to query.
3768 * count [I] Number of glyph indices to query.
3769 * glyphs [I] Array of glyphs to query.
3770 * buffer [O] Buffer to receive character widths.
3772 * NOTES
3773 * Only works with TrueType fonts.
3775 * RETURNS
3776 * Success: TRUE
3777 * Failure: FALSE
3779 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3781 ABC *abc;
3782 unsigned int i;
3784 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3786 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3787 return FALSE;
3789 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3791 HeapFree(GetProcessHeap(), 0, abc);
3792 return FALSE;
3795 for (i = 0; i < count; i++)
3796 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3798 HeapFree(GetProcessHeap(), 0, abc);
3799 return TRUE;
3802 /***********************************************************************
3803 * GetFontUnicodeRanges (GDI32.@)
3805 * Retrieve a list of supported Unicode characters in a font.
3807 * PARAMS
3808 * hdc [I] Handle to a device context.
3809 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3811 * RETURNS
3812 * Success: Number of bytes written to the buffer pointed to by lpgs.
3813 * Failure: 0
3816 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3818 DWORD ret;
3819 PHYSDEV dev;
3820 DC *dc = get_dc_ptr(hdc);
3822 TRACE("(%p, %p)\n", hdc, lpgs);
3824 if (!dc) return 0;
3826 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3827 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3828 release_dc_ptr(dc);
3829 return ret;
3833 /*************************************************************
3834 * FontIsLinked (GDI32.@)
3836 BOOL WINAPI FontIsLinked(HDC hdc)
3838 DC *dc = get_dc_ptr(hdc);
3839 PHYSDEV dev;
3840 BOOL ret;
3842 if (!dc) return FALSE;
3843 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3844 ret = dev->funcs->pFontIsLinked( dev );
3845 release_dc_ptr(dc);
3846 TRACE("returning %d\n", ret);
3847 return ret;
3850 /*************************************************************
3851 * GdiRealizationInfo (GDI32.@)
3853 * Returns a structure that contains some font information.
3855 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3857 DC *dc = get_dc_ptr(hdc);
3858 PHYSDEV dev;
3859 BOOL ret;
3861 if (!dc) return FALSE;
3862 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3863 ret = dev->funcs->pGdiRealizationInfo( dev, info );
3864 release_dc_ptr(dc);
3865 return ret;