libwine: Add libwine's directory (@loader_path) to rpath.
[wine.git] / dlls / gdi32 / font.c
blob8fb101f59d6f4d13b4c53972fc8e6acac0983ff3
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 LOGFONTW lf;
785 HKEY key;
787 if (*aa_flags) return 0;
789 GetObjectW( font, sizeof(lf), &lf );
790 switch (lf.lfQuality)
792 case NONANTIALIASED_QUALITY:
793 *aa_flags = GGO_BITMAP;
794 break;
795 case ANTIALIASED_QUALITY:
796 *aa_flags = GGO_GRAY4_BITMAP;
797 break;
798 case CLEARTYPE_QUALITY:
799 case CLEARTYPE_NATURAL_QUALITY:
800 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
801 *aa_flags = get_subpixel_orientation( key );
802 RegCloseKey( key );
803 break;
804 default:
805 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
806 *aa_flags = get_default_smoothing( key );
807 RegCloseKey( key );
808 break;
810 return 0;
814 /***********************************************************************
815 * FONT_EnumInstance
817 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
818 * We have to use other types because of the FONTENUMPROCW definition.
820 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
821 DWORD fType, LPARAM lp )
823 struct font_enum *pfe = (struct font_enum *)lp;
824 INT ret = 1;
826 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
827 if ((!pfe->lpLogFontParam ||
828 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
829 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
830 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
832 /* convert font metrics */
833 ENUMLOGFONTEXA logfont;
834 NEWTEXTMETRICEXA tmA;
836 if (!pfe->unicode)
838 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
839 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
840 plf = (LOGFONTW *)&logfont.elfLogFont;
841 ptm = (TEXTMETRICW *)&tmA;
843 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
844 pfe->retval = ret;
846 return ret;
849 /***********************************************************************
850 * FONT_EnumFontFamiliesEx
852 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
853 LPARAM lParam, BOOL unicode )
855 INT ret = 0;
856 DC *dc = get_dc_ptr( hDC );
857 struct font_enum fe;
859 if (dc)
861 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
863 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
864 fe.lpLogFontParam = plf;
865 fe.lpEnumFunc = efproc;
866 fe.lpData = lParam;
867 fe.unicode = unicode;
868 fe.hdc = hDC;
869 fe.retval = 1;
870 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
871 release_dc_ptr( dc );
873 return ret ? fe.retval : 0;
876 /***********************************************************************
877 * EnumFontFamiliesExW (GDI32.@)
879 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
880 FONTENUMPROCW efproc,
881 LPARAM lParam, DWORD dwFlags )
883 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
886 /***********************************************************************
887 * EnumFontFamiliesExA (GDI32.@)
889 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
890 FONTENUMPROCA efproc,
891 LPARAM lParam, DWORD dwFlags)
893 LOGFONTW lfW, *plfW;
895 if (plf)
897 FONT_LogFontAToW( plf, &lfW );
898 plfW = &lfW;
900 else plfW = NULL;
902 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
905 /***********************************************************************
906 * EnumFontFamiliesA (GDI32.@)
908 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
909 FONTENUMPROCA efproc, LPARAM lpData )
911 LOGFONTA lf, *plf;
913 if (lpFamily)
915 if (!*lpFamily) return 1;
916 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
917 lf.lfCharSet = DEFAULT_CHARSET;
918 lf.lfPitchAndFamily = 0;
919 plf = &lf;
921 else plf = NULL;
923 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
926 /***********************************************************************
927 * EnumFontFamiliesW (GDI32.@)
929 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
930 FONTENUMPROCW efproc, LPARAM lpData )
932 LOGFONTW lf, *plf;
934 if (lpFamily)
936 if (!*lpFamily) return 1;
937 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
938 lf.lfCharSet = DEFAULT_CHARSET;
939 lf.lfPitchAndFamily = 0;
940 plf = &lf;
942 else plf = NULL;
944 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
947 /***********************************************************************
948 * EnumFontsA (GDI32.@)
950 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
951 LPARAM lpData )
953 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
956 /***********************************************************************
957 * EnumFontsW (GDI32.@)
959 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
960 LPARAM lpData )
962 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
966 /***********************************************************************
967 * GetTextCharacterExtra (GDI32.@)
969 INT WINAPI GetTextCharacterExtra( HDC hdc )
971 INT ret;
972 DC *dc = get_dc_ptr( hdc );
973 if (!dc) return 0x80000000;
974 ret = dc->charExtra;
975 release_dc_ptr( dc );
976 return ret;
980 /***********************************************************************
981 * SetTextCharacterExtra (GDI32.@)
983 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
985 INT ret = 0x80000000;
986 DC * dc = get_dc_ptr( hdc );
988 if (dc)
990 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
991 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
992 if (extra != 0x80000000)
994 ret = dc->charExtra;
995 dc->charExtra = extra;
997 release_dc_ptr( dc );
999 return ret;
1003 /***********************************************************************
1004 * SetTextJustification (GDI32.@)
1006 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1008 BOOL ret;
1009 PHYSDEV physdev;
1010 DC * dc = get_dc_ptr( hdc );
1012 if (!dc) return FALSE;
1014 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1015 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1016 if (ret)
1018 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
1019 if (!extra) breaks = 0;
1020 if (breaks)
1022 dc->breakExtra = extra / breaks;
1023 dc->breakRem = extra - (breaks * dc->breakExtra);
1025 else
1027 dc->breakExtra = 0;
1028 dc->breakRem = 0;
1031 release_dc_ptr( dc );
1032 return ret;
1036 /***********************************************************************
1037 * GetTextFaceA (GDI32.@)
1039 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1041 INT res = GetTextFaceW(hdc, 0, NULL);
1042 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1043 GetTextFaceW( hdc, res, nameW );
1045 if (name)
1047 if (count)
1049 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1050 if (res == 0)
1051 res = count;
1052 name[count-1] = 0;
1053 /* GetTextFaceA does NOT include the nul byte in the return count. */
1054 res--;
1056 else
1057 res = 0;
1059 else
1060 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1061 HeapFree( GetProcessHeap(), 0, nameW );
1062 return res;
1065 /***********************************************************************
1066 * GetTextFaceW (GDI32.@)
1068 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1070 PHYSDEV dev;
1071 INT ret;
1073 DC * dc = get_dc_ptr( hdc );
1074 if (!dc) return 0;
1076 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1077 ret = dev->funcs->pGetTextFace( dev, count, name );
1078 release_dc_ptr( dc );
1079 return ret;
1083 /***********************************************************************
1084 * GetTextExtentPoint32A (GDI32.@)
1086 * See GetTextExtentPoint32W.
1088 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1089 LPSIZE size )
1091 BOOL ret = FALSE;
1092 INT wlen;
1093 LPWSTR p;
1095 if (count < 0) return FALSE;
1097 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1099 if (p)
1101 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1102 HeapFree( GetProcessHeap(), 0, p );
1105 TRACE("(%p %s %d %p): returning %d x %d\n",
1106 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1107 return ret;
1111 /***********************************************************************
1112 * GetTextExtentPoint32W [GDI32.@]
1114 * Computes width/height for a string.
1116 * Computes width and height of the specified string.
1118 * RETURNS
1119 * Success: TRUE
1120 * Failure: FALSE
1122 BOOL WINAPI GetTextExtentPoint32W(
1123 HDC hdc, /* [in] Handle of device context */
1124 LPCWSTR str, /* [in] Address of text string */
1125 INT count, /* [in] Number of characters in string */
1126 LPSIZE size) /* [out] Address of structure for string size */
1128 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1131 /***********************************************************************
1132 * GetTextExtentExPointI [GDI32.@]
1134 * Computes width and height of the array of glyph indices.
1136 * PARAMS
1137 * hdc [I] Handle of device context.
1138 * indices [I] Glyph index array.
1139 * count [I] Number of glyphs in array.
1140 * max_ext [I] Maximum width in glyphs.
1141 * nfit [O] Maximum number of characters.
1142 * dxs [O] Partial string widths.
1143 * size [O] Returned string size.
1145 * RETURNS
1146 * Success: TRUE
1147 * Failure: FALSE
1149 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1150 LPINT nfit, LPINT dxs, LPSIZE size )
1152 DC *dc;
1153 int i;
1154 BOOL ret;
1155 INT buffer[256], *pos = dxs;
1157 if (count < 0) return FALSE;
1159 dc = get_dc_ptr( hdc );
1160 if (!dc) return FALSE;
1162 if (!dxs)
1164 pos = buffer;
1165 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1167 release_dc_ptr( dc );
1168 return FALSE;
1172 ret = get_char_positions_indices( dc, indices, count, pos, size );
1173 if (ret)
1175 if (dxs || nfit)
1177 for (i = 0; i < count; i++)
1179 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1180 if (dx > (unsigned int)max_ext) break;
1181 if (dxs) dxs[i] = dx;
1183 if (nfit) *nfit = i;
1186 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1187 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1190 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1191 release_dc_ptr( dc );
1193 TRACE("(%p %p %d %p): returning %d x %d\n",
1194 hdc, indices, count, size, size->cx, size->cy );
1195 return ret;
1198 /***********************************************************************
1199 * GetTextExtentPointI [GDI32.@]
1201 * Computes width and height of the array of glyph indices.
1203 * PARAMS
1204 * hdc [I] Handle of device context.
1205 * indices [I] Glyph index array.
1206 * count [I] Number of glyphs in array.
1207 * size [O] Returned string size.
1209 * RETURNS
1210 * Success: TRUE
1211 * Failure: FALSE
1213 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1215 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1219 /***********************************************************************
1220 * GetTextExtentPointA (GDI32.@)
1222 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1223 LPSIZE size )
1225 TRACE("not bug compatible.\n");
1226 return GetTextExtentPoint32A( hdc, str, count, size );
1229 /***********************************************************************
1230 * GetTextExtentPointW (GDI32.@)
1232 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1233 LPSIZE size )
1235 TRACE("not bug compatible.\n");
1236 return GetTextExtentPoint32W( hdc, str, count, size );
1240 /***********************************************************************
1241 * GetTextExtentExPointA (GDI32.@)
1243 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1244 INT maxExt, LPINT lpnFit,
1245 LPINT alpDx, LPSIZE size )
1247 BOOL ret;
1248 INT wlen;
1249 INT *walpDx = NULL;
1250 LPWSTR p = NULL;
1252 if (count < 0) return FALSE;
1253 if (maxExt < -1) return FALSE;
1255 if (alpDx)
1257 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1258 if (!walpDx) return FALSE;
1261 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1262 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1263 if (walpDx)
1265 INT n = lpnFit ? *lpnFit : wlen;
1266 INT i, j;
1267 for(i = 0, j = 0; i < n; i++, j++)
1269 alpDx[j] = walpDx[i];
1270 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1273 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1274 HeapFree( GetProcessHeap(), 0, p );
1275 HeapFree( GetProcessHeap(), 0, walpDx );
1276 return ret;
1280 /***********************************************************************
1281 * GetTextExtentExPointW (GDI32.@)
1283 * Return the size of the string as it would be if it was output properly by
1284 * e.g. TextOut.
1286 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1287 LPINT nfit, LPINT dxs, LPSIZE size )
1289 DC *dc;
1290 int i;
1291 BOOL ret;
1292 INT buffer[256], *pos = dxs;
1294 if (count < 0) return FALSE;
1296 dc = get_dc_ptr(hdc);
1297 if (!dc) return FALSE;
1299 if (!dxs)
1301 pos = buffer;
1302 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1304 release_dc_ptr( dc );
1305 return FALSE;
1309 ret = get_char_positions( dc, str, count, pos, size );
1310 if (ret)
1312 if (dxs || nfit)
1314 for (i = 0; i < count; i++)
1316 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1317 if (dx > (unsigned int)max_ext) break;
1318 if (dxs) dxs[i] = dx;
1320 if (nfit) *nfit = i;
1323 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1324 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1327 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1328 release_dc_ptr( dc );
1330 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1331 return ret;
1334 /***********************************************************************
1335 * GetTextMetricsA (GDI32.@)
1337 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1339 TEXTMETRICW tm32;
1341 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1342 FONT_TextMetricWToA( &tm32, metrics );
1343 return TRUE;
1346 /***********************************************************************
1347 * GetTextMetricsW (GDI32.@)
1349 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1351 PHYSDEV physdev;
1352 BOOL ret = FALSE;
1353 DC * dc = get_dc_ptr( hdc );
1354 if (!dc) return FALSE;
1356 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1357 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1359 if (ret)
1361 /* device layer returns values in device units
1362 * therefore we have to convert them to logical */
1364 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1365 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1367 #define WDPTOLP(x) ((x<0)? \
1368 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1369 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1370 #define HDPTOLP(y) ((y<0)? \
1371 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1372 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1374 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1375 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1376 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1377 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1378 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1379 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1380 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1381 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1382 ret = TRUE;
1383 #undef WDPTOLP
1384 #undef HDPTOLP
1385 TRACE("text metrics:\n"
1386 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1387 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1388 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1389 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1390 " PitchAndFamily = %02x\n"
1391 " --------------------\n"
1392 " InternalLeading = %i\n"
1393 " Ascent = %i\n"
1394 " Descent = %i\n"
1395 " Height = %i\n",
1396 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1397 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1398 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1399 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1400 metrics->tmPitchAndFamily,
1401 metrics->tmInternalLeading,
1402 metrics->tmAscent,
1403 metrics->tmDescent,
1404 metrics->tmHeight );
1406 release_dc_ptr( dc );
1407 return ret;
1411 /***********************************************************************
1412 * GetOutlineTextMetricsA (GDI32.@)
1413 * Gets metrics for TrueType fonts.
1415 * NOTES
1416 * If the supplied buffer isn't big enough Windows partially fills it up to
1417 * its given length and returns that length.
1419 * RETURNS
1420 * Success: Non-zero or size of required buffer
1421 * Failure: 0
1423 UINT WINAPI GetOutlineTextMetricsA(
1424 HDC hdc, /* [in] Handle of device context */
1425 UINT cbData, /* [in] Size of metric data array */
1426 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1428 char buf[512], *ptr;
1429 UINT ret, needed;
1430 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1431 OUTLINETEXTMETRICA *output = lpOTM;
1432 INT left, len;
1434 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1435 return 0;
1436 if(ret > sizeof(buf))
1437 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1438 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1440 needed = sizeof(OUTLINETEXTMETRICA);
1441 if(lpOTMW->otmpFamilyName)
1442 needed += WideCharToMultiByte(CP_ACP, 0,
1443 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1444 NULL, 0, NULL, NULL);
1445 if(lpOTMW->otmpFaceName)
1446 needed += WideCharToMultiByte(CP_ACP, 0,
1447 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1448 NULL, 0, NULL, NULL);
1449 if(lpOTMW->otmpStyleName)
1450 needed += WideCharToMultiByte(CP_ACP, 0,
1451 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1452 NULL, 0, NULL, NULL);
1453 if(lpOTMW->otmpFullName)
1454 needed += WideCharToMultiByte(CP_ACP, 0,
1455 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1456 NULL, 0, NULL, NULL);
1458 if(!lpOTM) {
1459 ret = needed;
1460 goto end;
1463 TRACE("needed = %d\n", needed);
1464 if(needed > cbData)
1465 /* Since the supplied buffer isn't big enough, we'll alloc one
1466 that is and memcpy the first cbData bytes into the lpOTM at
1467 the end. */
1468 output = HeapAlloc(GetProcessHeap(), 0, needed);
1470 ret = output->otmSize = min(needed, cbData);
1471 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1472 output->otmFiller = 0;
1473 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1474 output->otmfsSelection = lpOTMW->otmfsSelection;
1475 output->otmfsType = lpOTMW->otmfsType;
1476 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1477 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1478 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1479 output->otmEMSquare = lpOTMW->otmEMSquare;
1480 output->otmAscent = lpOTMW->otmAscent;
1481 output->otmDescent = lpOTMW->otmDescent;
1482 output->otmLineGap = lpOTMW->otmLineGap;
1483 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1484 output->otmsXHeight = lpOTMW->otmsXHeight;
1485 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1486 output->otmMacAscent = lpOTMW->otmMacAscent;
1487 output->otmMacDescent = lpOTMW->otmMacDescent;
1488 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1489 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1490 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1491 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1492 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1493 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1494 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1495 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1496 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1497 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1500 ptr = (char*)(output + 1);
1501 left = needed - sizeof(*output);
1503 if(lpOTMW->otmpFamilyName) {
1504 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1505 len = WideCharToMultiByte(CP_ACP, 0,
1506 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1507 ptr, left, NULL, NULL);
1508 left -= len;
1509 ptr += len;
1510 } else
1511 output->otmpFamilyName = 0;
1513 if(lpOTMW->otmpFaceName) {
1514 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1515 len = WideCharToMultiByte(CP_ACP, 0,
1516 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1517 ptr, left, NULL, NULL);
1518 left -= len;
1519 ptr += len;
1520 } else
1521 output->otmpFaceName = 0;
1523 if(lpOTMW->otmpStyleName) {
1524 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1525 len = WideCharToMultiByte(CP_ACP, 0,
1526 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1527 ptr, left, NULL, NULL);
1528 left -= len;
1529 ptr += len;
1530 } else
1531 output->otmpStyleName = 0;
1533 if(lpOTMW->otmpFullName) {
1534 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1535 len = WideCharToMultiByte(CP_ACP, 0,
1536 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1537 ptr, left, NULL, NULL);
1538 left -= len;
1539 } else
1540 output->otmpFullName = 0;
1542 assert(left == 0);
1544 if(output != lpOTM) {
1545 memcpy(lpOTM, output, cbData);
1546 HeapFree(GetProcessHeap(), 0, output);
1548 /* check if the string offsets really fit into the provided size */
1549 /* FIXME: should we check string length as well? */
1550 /* make sure that we don't read/write beyond the provided buffer */
1551 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1553 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1554 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1557 /* make sure that we don't read/write beyond the provided buffer */
1558 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1560 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1561 lpOTM->otmpFaceName = 0; /* doesn't fit */
1564 /* make sure that we don't read/write beyond the provided buffer */
1565 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1567 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1568 lpOTM->otmpStyleName = 0; /* doesn't fit */
1571 /* make sure that we don't read/write beyond the provided buffer */
1572 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1574 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1575 lpOTM->otmpFullName = 0; /* doesn't fit */
1579 end:
1580 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1581 HeapFree(GetProcessHeap(), 0, lpOTMW);
1583 return ret;
1587 /***********************************************************************
1588 * GetOutlineTextMetricsW [GDI32.@]
1590 UINT WINAPI GetOutlineTextMetricsW(
1591 HDC hdc, /* [in] Handle of device context */
1592 UINT cbData, /* [in] Size of metric data array */
1593 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1595 DC *dc = get_dc_ptr( hdc );
1596 OUTLINETEXTMETRICW *output = lpOTM;
1597 PHYSDEV dev;
1598 UINT ret;
1600 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1601 if(!dc) return 0;
1603 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1604 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1606 if (lpOTM && ret > cbData)
1608 output = HeapAlloc(GetProcessHeap(), 0, ret);
1609 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1612 if (lpOTM && ret)
1614 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1615 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1617 #define WDPTOLP(x) ((x<0)? \
1618 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1619 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1620 #define HDPTOLP(y) ((y<0)? \
1621 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1622 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1624 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1625 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1626 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1627 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1628 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1629 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1630 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1631 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1632 output->otmAscent = HDPTOLP(output->otmAscent);
1633 output->otmDescent = HDPTOLP(output->otmDescent);
1634 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1635 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1636 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1637 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1638 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1639 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1640 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1641 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1642 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1643 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1644 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1645 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1646 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1647 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1648 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1649 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1650 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1651 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1652 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1653 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1654 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1655 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1656 #undef WDPTOLP
1657 #undef HDPTOLP
1658 if(output != lpOTM)
1660 memcpy(lpOTM, output, cbData);
1661 HeapFree(GetProcessHeap(), 0, output);
1662 ret = cbData;
1665 release_dc_ptr(dc);
1666 return ret;
1669 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1671 INT i, count = lastChar - firstChar + 1;
1672 UINT mbcp;
1673 UINT c;
1674 LPSTR str;
1676 if (count <= 0)
1677 return NULL;
1679 mbcp = GdiGetCodePage(hdc);
1680 switch (mbcp)
1682 case 932:
1683 case 936:
1684 case 949:
1685 case 950:
1686 case 1361:
1687 if (lastChar > 0xffff)
1688 return NULL;
1689 if ((firstChar ^ lastChar) > 0xff)
1690 return NULL;
1691 break;
1692 default:
1693 if (lastChar > 0xff)
1694 return NULL;
1695 mbcp = 0;
1696 break;
1699 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1700 if (str == NULL)
1701 return NULL;
1703 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1705 if (mbcp) {
1706 if (c > 0xff)
1707 str[i++] = (BYTE)(c >> 8);
1708 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1709 str[i] = 0x1f; /* FIXME: use default character */
1710 else
1711 str[i] = (BYTE)c;
1713 else
1714 str[i] = (BYTE)c;
1716 str[i] = '\0';
1718 *pByteLen = i;
1720 return str;
1723 /***********************************************************************
1724 * GetCharWidthW (GDI32.@)
1725 * GetCharWidth32W (GDI32.@)
1727 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1728 LPINT buffer )
1730 UINT i;
1731 BOOL ret;
1732 PHYSDEV dev;
1733 DC * dc = get_dc_ptr( hdc );
1735 if (!dc) return FALSE;
1737 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1738 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1740 if (ret)
1742 /* convert device units to logical */
1743 for( i = firstChar; i <= lastChar; i++, buffer++ )
1744 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1746 release_dc_ptr( dc );
1747 return ret;
1751 /***********************************************************************
1752 * GetCharWidthA (GDI32.@)
1753 * GetCharWidth32A (GDI32.@)
1755 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1756 LPINT buffer )
1758 INT i, wlen;
1759 LPSTR str;
1760 LPWSTR wstr;
1761 BOOL ret = TRUE;
1763 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1764 if(str == NULL)
1765 return FALSE;
1767 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1769 for(i = 0; i < wlen; i++)
1771 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1773 ret = FALSE;
1774 break;
1776 buffer++;
1779 HeapFree(GetProcessHeap(), 0, str);
1780 HeapFree(GetProcessHeap(), 0, wstr);
1782 return ret;
1786 /* helper for nulldrv_ExtTextOut */
1787 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1788 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1790 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1791 UINT indices[3] = {0, 0, 0x20};
1792 unsigned int i;
1793 DWORD ret, size;
1794 int stride;
1796 indices[0] = index;
1797 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1799 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1801 index = indices[i];
1802 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1803 if (ret != GDI_ERROR) break;
1806 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1807 if (!image) return ERROR_SUCCESS;
1809 image->ptr = NULL;
1810 image->free = NULL;
1811 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1813 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1814 size = metrics->gmBlackBoxY * stride;
1816 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1817 image->is_copy = TRUE;
1818 image->free = free_heap_bits;
1820 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1821 if (ret == GDI_ERROR)
1823 HeapFree( GetProcessHeap(), 0, image->ptr );
1824 return ERROR_NOT_FOUND;
1826 return ERROR_SUCCESS;
1829 /* helper for nulldrv_ExtTextOut */
1830 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1831 LPCWSTR str, UINT count, const INT *dx )
1833 UINT i;
1834 RECT rect, bounds;
1836 reset_bounds( &bounds );
1837 for (i = 0; i < count; i++)
1839 GLYPHMETRICS metrics;
1841 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1843 rect.left = x + metrics.gmptGlyphOrigin.x;
1844 rect.top = y - metrics.gmptGlyphOrigin.y;
1845 rect.right = rect.left + metrics.gmBlackBoxX;
1846 rect.bottom = rect.top + metrics.gmBlackBoxY;
1847 add_bounds_rect( &bounds, &rect );
1849 if (dx)
1851 if (flags & ETO_PDY)
1853 x += dx[ i * 2 ];
1854 y += dx[ i * 2 + 1];
1856 else x += dx[ i ];
1858 else
1860 x += metrics.gmCellIncX;
1861 y += metrics.gmCellIncY;
1864 return bounds;
1867 /* helper for nulldrv_ExtTextOut */
1868 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1869 const struct gdi_image_bits *image, const RECT *clip )
1871 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1872 UINT i, count, max_count;
1873 LONG x, y;
1874 BYTE *ptr = image->ptr;
1875 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1876 POINT *pts;
1877 RECT rect, clipped_rect;
1879 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1880 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1881 rect.right = rect.left + metrics->gmBlackBoxX;
1882 rect.bottom = rect.top + metrics->gmBlackBoxY;
1883 if (!clip) clipped_rect = rect;
1884 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1886 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1887 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1888 if (!pts) return;
1890 count = 0;
1891 ptr += (clipped_rect.top - rect.top) * stride;
1892 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1894 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1896 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1897 pts[count].x = rect.left + x;
1898 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1899 pts[count + 1].x = rect.left + x;
1900 if (pts[count + 1].x > pts[count].x)
1902 pts[count].y = pts[count + 1].y = y;
1903 count += 2;
1907 assert( count <= max_count );
1908 DPtoLP( hdc, pts, count );
1909 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1910 HeapFree( GetProcessHeap(), 0, pts );
1913 /***********************************************************************
1914 * nulldrv_ExtTextOut
1916 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1917 LPCWSTR str, UINT count, const INT *dx )
1919 DC *dc = get_nulldrv_dc( dev );
1920 UINT i;
1921 DWORD err;
1922 HGDIOBJ orig;
1923 HPEN pen;
1925 if (flags & ETO_OPAQUE)
1927 RECT rc = *rect;
1928 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1930 if (brush)
1932 orig = SelectObject( dev->hdc, brush );
1933 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1934 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1935 SelectObject( dev->hdc, orig );
1936 DeleteObject( brush );
1940 if (!count) return TRUE;
1942 if (dc->aa_flags != GGO_BITMAP)
1944 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1945 BITMAPINFO *info = (BITMAPINFO *)buffer;
1946 struct gdi_image_bits bits;
1947 struct bitblt_coords src, dst;
1948 PHYSDEV dst_dev;
1949 /* FIXME Subpixel modes */
1950 UINT aa_flags = GGO_GRAY4_BITMAP;
1952 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1953 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1954 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1955 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1957 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1958 src.x = src.visrect.left;
1959 src.y = src.visrect.top;
1960 src.width = src.visrect.right - src.visrect.left;
1961 src.height = src.visrect.bottom - src.visrect.top;
1962 dst = src;
1963 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1964 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1966 /* we can avoid the GetImage, just query the needed format */
1967 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1968 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1969 info->bmiHeader.biWidth = src.width;
1970 info->bmiHeader.biHeight = -src.height;
1971 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1972 if (!err || err == ERROR_BAD_FORMAT)
1974 /* make the source rectangle relative to the source bits */
1975 src.x = src.y = 0;
1976 src.visrect.left = src.visrect.top = 0;
1977 src.visrect.right = src.width;
1978 src.visrect.bottom = src.height;
1980 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1981 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1982 bits.is_copy = TRUE;
1983 bits.free = free_heap_bits;
1984 err = ERROR_SUCCESS;
1987 else
1989 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1990 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1991 if (!err && !bits.is_copy)
1993 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1994 if (!ptr)
1996 if (bits.free) bits.free( &bits );
1997 return ERROR_OUTOFMEMORY;
1999 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
2000 if (bits.free) bits.free( &bits );
2001 bits.ptr = ptr;
2002 bits.is_copy = TRUE;
2003 bits.free = free_heap_bits;
2006 if (!err)
2008 /* make x,y relative to the image bits */
2009 x += src.visrect.left - dst.visrect.left;
2010 y += src.visrect.top - dst.visrect.top;
2011 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
2012 aa_flags, str, count, dx );
2013 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2014 if (bits.free) bits.free( &bits );
2015 return !err;
2019 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
2020 orig = SelectObject( dev->hdc, pen );
2022 for (i = 0; i < count; i++)
2024 GLYPHMETRICS metrics;
2025 struct gdi_image_bits image;
2027 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2028 if (err) continue;
2030 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2031 if (image.free) image.free( &image );
2033 if (dx)
2035 if (flags & ETO_PDY)
2037 x += dx[ i * 2 ];
2038 y += dx[ i * 2 + 1];
2040 else x += dx[ i ];
2042 else
2044 x += metrics.gmCellIncX;
2045 y += metrics.gmCellIncY;
2049 SelectObject( dev->hdc, orig );
2050 DeleteObject( pen );
2051 return TRUE;
2055 /***********************************************************************
2056 * ExtTextOutA (GDI32.@)
2058 * See ExtTextOutW.
2060 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2061 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2063 INT wlen;
2064 UINT codepage;
2065 LPWSTR p;
2066 BOOL ret;
2067 LPINT lpDxW = NULL;
2069 if (flags & ETO_GLYPH_INDEX)
2070 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2072 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2074 if (lpDx) {
2075 unsigned int i = 0, j = 0;
2077 /* allocate enough for a ETO_PDY */
2078 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2079 while(i < count) {
2080 if(IsDBCSLeadByteEx(codepage, str[i]))
2082 if(flags & ETO_PDY)
2084 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2085 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2087 else
2088 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2089 i = i + 2;
2091 else
2093 if(flags & ETO_PDY)
2095 lpDxW[j++] = lpDx[i * 2];
2096 lpDxW[j++] = lpDx[i * 2 + 1];
2098 else
2099 lpDxW[j++] = lpDx[i];
2100 i = i + 1;
2105 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2107 HeapFree( GetProcessHeap(), 0, p );
2108 HeapFree( GetProcessHeap(), 0, lpDxW );
2109 return ret;
2113 /***********************************************************************
2114 * ExtTextOutW (GDI32.@)
2116 * Draws text using the currently selected font, background color, and text color.
2119 * PARAMS
2120 * x,y [I] coordinates of string
2121 * flags [I]
2122 * ETO_GRAYED - undocumented on MSDN
2123 * ETO_OPAQUE - use background color for fill the rectangle
2124 * ETO_CLIPPED - clipping text to the rectangle
2125 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2126 * than encoded characters. Implies ETO_IGNORELANGUAGE
2127 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2128 * Affects BiDi ordering
2129 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2130 * ETO_PDY - unimplemented
2131 * ETO_NUMERICSLATIN - unimplemented always assumed -
2132 * do not translate numbers into locale representations
2133 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2134 * lprect [I] dimensions for clipping or/and opaquing
2135 * str [I] text string
2136 * count [I] number of symbols in string
2137 * lpDx [I] optional parameter with distance between drawing characters
2139 * RETURNS
2140 * Success: TRUE
2141 * Failure: FALSE
2143 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2144 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2146 BOOL ret = FALSE;
2147 LPWSTR reordered_str = (LPWSTR)str;
2148 WORD *glyphs = NULL;
2149 UINT align = GetTextAlign( hdc );
2150 DWORD layout = GetLayout( hdc );
2151 POINT pt;
2152 TEXTMETRICW tm;
2153 LOGFONTW lf;
2154 double cosEsc, sinEsc;
2155 INT char_extra;
2156 SIZE sz;
2157 RECT rc;
2158 POINT *deltas = NULL, width = {0, 0};
2159 DWORD type;
2160 DC * dc = get_dc_ptr( hdc );
2161 PHYSDEV physdev;
2162 INT breakRem;
2163 static int quietfixme = 0;
2165 if (!dc) return FALSE;
2167 breakRem = dc->breakRem;
2169 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2171 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2172 quietfixme = 1;
2175 update_dc( dc );
2176 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2177 type = GetObjectType(hdc);
2178 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2180 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2181 release_dc_ptr( dc );
2182 return ret;
2185 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2186 if (layout & LAYOUT_RTL)
2188 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2189 align ^= TA_RTLREADING;
2192 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2194 INT cGlyphs;
2195 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2197 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2198 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2199 reordered_str, count, NULL, &glyphs, &cGlyphs);
2201 flags |= ETO_IGNORELANGUAGE;
2202 if (glyphs)
2204 flags |= ETO_GLYPH_INDEX;
2205 if (cGlyphs != count)
2206 count = cGlyphs;
2209 else if(flags & ETO_GLYPH_INDEX)
2210 glyphs = reordered_str;
2212 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2213 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2214 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2216 if(align & TA_UPDATECP)
2218 GetCurrentPositionEx( hdc, &pt );
2219 x = pt.x;
2220 y = pt.y;
2223 GetTextMetricsW(hdc, &tm);
2224 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2226 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2227 lf.lfEscapement = 0;
2229 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2230 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2232 lf.lfEscapement = -lf.lfEscapement;
2235 if(lf.lfEscapement != 0)
2237 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2238 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2240 else
2242 cosEsc = 1;
2243 sinEsc = 0;
2246 if (lprect)
2248 rc = *lprect;
2249 LPtoDP(hdc, (POINT*)&rc, 2);
2250 order_rect( &rc );
2251 if (flags & ETO_OPAQUE)
2252 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2254 else flags &= ~ETO_CLIPPED;
2256 if(count == 0)
2258 ret = TRUE;
2259 goto done;
2262 pt.x = x;
2263 pt.y = y;
2264 LPtoDP(hdc, &pt, 1);
2265 x = pt.x;
2266 y = pt.y;
2268 char_extra = GetTextCharacterExtra(hdc);
2269 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2270 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2272 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2274 UINT i;
2275 POINT total = {0, 0}, desired[2];
2277 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2278 if (lpDx)
2280 if (flags & ETO_PDY)
2282 for (i = 0; i < count; i++)
2284 deltas[i].x = lpDx[i * 2] + char_extra;
2285 deltas[i].y = -lpDx[i * 2 + 1];
2288 else
2290 for (i = 0; i < count; i++)
2292 deltas[i].x = lpDx[i] + char_extra;
2293 deltas[i].y = 0;
2297 else
2299 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2301 if (flags & ETO_GLYPH_INDEX)
2302 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2303 else
2304 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2306 deltas[0].x = dx[0];
2307 deltas[0].y = 0;
2308 for (i = 1; i < count; i++)
2310 deltas[i].x = dx[i] - dx[i - 1];
2311 deltas[i].y = 0;
2313 HeapFree( GetProcessHeap(), 0, dx );
2316 for(i = 0; i < count; i++)
2318 total.x += deltas[i].x;
2319 total.y += deltas[i].y;
2321 desired[0].x = desired[0].y = 0;
2323 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2324 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2326 LPtoDP(hdc, desired, 2);
2327 desired[1].x -= desired[0].x;
2328 desired[1].y -= desired[0].y;
2330 if (dc->GraphicsMode == GM_COMPATIBLE)
2332 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2333 desired[1].x = -desired[1].x;
2334 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2335 desired[1].y = -desired[1].y;
2338 deltas[i].x = desired[1].x - width.x;
2339 deltas[i].y = desired[1].y - width.y;
2341 width = desired[1];
2343 flags |= ETO_PDY;
2345 else
2347 POINT desired[2];
2349 if(flags & ETO_GLYPH_INDEX)
2350 GetTextExtentPointI(hdc, glyphs, count, &sz);
2351 else
2352 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2353 desired[0].x = desired[0].y = 0;
2354 desired[1].x = sz.cx;
2355 desired[1].y = 0;
2356 LPtoDP(hdc, desired, 2);
2357 desired[1].x -= desired[0].x;
2358 desired[1].y -= desired[0].y;
2360 if (dc->GraphicsMode == GM_COMPATIBLE)
2362 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2363 desired[1].x = -desired[1].x;
2364 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2365 desired[1].y = -desired[1].y;
2367 width = desired[1];
2370 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2371 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2372 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2374 case TA_LEFT:
2375 if (align & TA_UPDATECP)
2377 pt.x = x + width.x;
2378 pt.y = y + width.y;
2379 DPtoLP(hdc, &pt, 1);
2380 MoveToEx(hdc, pt.x, pt.y, NULL);
2382 break;
2384 case TA_CENTER:
2385 x -= width.x / 2;
2386 y -= width.y / 2;
2387 break;
2389 case TA_RIGHT:
2390 x -= width.x;
2391 y -= width.y;
2392 if (align & TA_UPDATECP)
2394 pt.x = x;
2395 pt.y = y;
2396 DPtoLP(hdc, &pt, 1);
2397 MoveToEx(hdc, pt.x, pt.y, NULL);
2399 break;
2402 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2404 case TA_TOP:
2405 y += tm.tmAscent * cosEsc;
2406 x += tm.tmAscent * sinEsc;
2407 break;
2409 case TA_BOTTOM:
2410 y -= tm.tmDescent * cosEsc;
2411 x -= tm.tmDescent * sinEsc;
2412 break;
2414 case TA_BASELINE:
2415 break;
2418 if (GetBkMode(hdc) != TRANSPARENT)
2420 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2422 if(!(flags & ETO_OPAQUE) || !lprect ||
2423 x < rc.left || x + width.x >= rc.right ||
2424 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2426 RECT text_box;
2427 text_box.left = x;
2428 text_box.right = x + width.x;
2429 text_box.top = y - tm.tmAscent;
2430 text_box.bottom = y + tm.tmDescent;
2432 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2433 if (!is_rect_empty( &text_box ))
2434 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2439 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2440 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2442 done:
2443 HeapFree(GetProcessHeap(), 0, deltas);
2444 if(glyphs != reordered_str)
2445 HeapFree(GetProcessHeap(), 0, glyphs);
2446 if(reordered_str != str)
2447 HeapFree(GetProcessHeap(), 0, reordered_str);
2449 release_dc_ptr( dc );
2451 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2453 int underlinePos, strikeoutPos;
2454 int underlineWidth, strikeoutWidth;
2455 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2456 OUTLINETEXTMETRICW* otm = NULL;
2457 POINT pts[5];
2458 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2459 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2461 hbrush = SelectObject(hdc, hbrush);
2463 if(!size)
2465 underlinePos = 0;
2466 underlineWidth = tm.tmAscent / 20 + 1;
2467 strikeoutPos = tm.tmAscent / 2;
2468 strikeoutWidth = underlineWidth;
2470 else
2472 otm = HeapAlloc(GetProcessHeap(), 0, size);
2473 GetOutlineTextMetricsW(hdc, size, otm);
2474 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2475 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2476 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2477 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2478 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2479 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2480 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2481 HeapFree(GetProcessHeap(), 0, otm);
2485 if (lf.lfUnderline)
2487 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2488 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2489 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2490 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2491 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2492 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2493 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2494 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2495 pts[4].x = pts[0].x;
2496 pts[4].y = pts[0].y;
2497 DPtoLP(hdc, pts, 5);
2498 Polygon(hdc, pts, 5);
2501 if (lf.lfStrikeOut)
2503 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2504 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2505 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2506 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2507 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2508 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2509 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2510 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2511 pts[4].x = pts[0].x;
2512 pts[4].y = pts[0].y;
2513 DPtoLP(hdc, pts, 5);
2514 Polygon(hdc, pts, 5);
2517 SelectObject(hdc, hpen);
2518 hbrush = SelectObject(hdc, hbrush);
2519 DeleteObject(hbrush);
2522 return ret;
2526 /***********************************************************************
2527 * TextOutA (GDI32.@)
2529 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2531 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2535 /***********************************************************************
2536 * TextOutW (GDI32.@)
2538 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2540 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2544 /***********************************************************************
2545 * PolyTextOutA (GDI32.@)
2547 * See PolyTextOutW.
2549 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2551 for (; cStrings>0; cStrings--, pptxt++)
2552 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2553 return FALSE;
2554 return TRUE;
2559 /***********************************************************************
2560 * PolyTextOutW (GDI32.@)
2562 * Draw several Strings
2564 * RETURNS
2565 * TRUE: Success.
2566 * FALSE: Failure.
2568 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2570 for (; cStrings>0; cStrings--, pptxt++)
2571 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2572 return FALSE;
2573 return TRUE;
2577 /***********************************************************************
2578 * SetMapperFlags (GDI32.@)
2580 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2582 DC *dc = get_dc_ptr( hdc );
2583 DWORD ret = GDI_ERROR;
2585 if (dc)
2587 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2588 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2589 if (flags != GDI_ERROR)
2591 ret = dc->mapperFlags;
2592 dc->mapperFlags = flags;
2594 release_dc_ptr( dc );
2596 return ret;
2599 /***********************************************************************
2600 * GetAspectRatioFilterEx (GDI32.@)
2602 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2604 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2605 return FALSE;
2609 /***********************************************************************
2610 * GetCharABCWidthsA (GDI32.@)
2612 * See GetCharABCWidthsW.
2614 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2615 LPABC abc )
2617 INT i, wlen;
2618 LPSTR str;
2619 LPWSTR wstr;
2620 BOOL ret = TRUE;
2622 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2623 if (str == NULL)
2624 return FALSE;
2626 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2627 if (wstr == NULL)
2629 HeapFree(GetProcessHeap(), 0, str);
2630 return FALSE;
2633 for(i = 0; i < wlen; i++)
2635 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2637 ret = FALSE;
2638 break;
2640 abc++;
2643 HeapFree(GetProcessHeap(), 0, str);
2644 HeapFree(GetProcessHeap(), 0, wstr);
2646 return ret;
2650 /******************************************************************************
2651 * GetCharABCWidthsW [GDI32.@]
2653 * Retrieves widths of characters in range.
2655 * PARAMS
2656 * hdc [I] Handle of device context
2657 * firstChar [I] First character in range to query
2658 * lastChar [I] Last character in range to query
2659 * abc [O] Address of character-width structure
2661 * NOTES
2662 * Only works with TrueType fonts
2664 * RETURNS
2665 * Success: TRUE
2666 * Failure: FALSE
2668 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2669 LPABC abc )
2671 DC *dc = get_dc_ptr(hdc);
2672 PHYSDEV dev;
2673 unsigned int i;
2674 BOOL ret;
2675 TEXTMETRICW tm;
2677 if (!dc) return FALSE;
2679 if (!abc)
2681 release_dc_ptr( dc );
2682 return FALSE;
2685 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2686 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2687 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2689 release_dc_ptr( dc );
2690 return FALSE;
2693 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2694 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2695 if (ret)
2697 /* convert device units to logical */
2698 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2699 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2700 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2701 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2705 release_dc_ptr( dc );
2706 return ret;
2710 /******************************************************************************
2711 * GetCharABCWidthsI [GDI32.@]
2713 * Retrieves widths of characters in range.
2715 * PARAMS
2716 * hdc [I] Handle of device context
2717 * firstChar [I] First glyphs in range to query
2718 * count [I] Last glyphs in range to query
2719 * pgi [i] Array of glyphs to query
2720 * abc [O] Address of character-width structure
2722 * NOTES
2723 * Only works with TrueType fonts
2725 * RETURNS
2726 * Success: TRUE
2727 * Failure: FALSE
2729 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2730 LPWORD pgi, LPABC abc)
2732 DC *dc = get_dc_ptr(hdc);
2733 PHYSDEV dev;
2734 unsigned int i;
2735 BOOL ret;
2737 if (!dc) return FALSE;
2739 if (!abc)
2741 release_dc_ptr( dc );
2742 return FALSE;
2745 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2746 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2747 if (ret)
2749 /* convert device units to logical */
2750 for( i = 0; i < count; i++, abc++ ) {
2751 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2752 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2753 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2757 release_dc_ptr( dc );
2758 return ret;
2762 /***********************************************************************
2763 * GetGlyphOutlineA (GDI32.@)
2765 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2766 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2767 LPVOID lpBuffer, const MAT2 *lpmat2 )
2769 if (!lpmat2) return GDI_ERROR;
2771 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2772 UINT cp;
2773 int len;
2774 char mbchs[2];
2776 cp = GdiGetCodePage(hdc);
2777 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2778 len = 2;
2779 mbchs[0] = (uChar & 0xff00) >> 8;
2780 mbchs[1] = (uChar & 0xff);
2781 } else {
2782 len = 1;
2783 mbchs[0] = (uChar & 0xff);
2785 uChar = 0;
2786 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2789 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2790 lpmat2);
2793 /***********************************************************************
2794 * GetGlyphOutlineW (GDI32.@)
2796 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2797 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2798 LPVOID lpBuffer, const MAT2 *lpmat2 )
2800 DC *dc;
2801 DWORD ret;
2802 PHYSDEV dev;
2804 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2805 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2807 if (!lpmat2) return GDI_ERROR;
2809 dc = get_dc_ptr(hdc);
2810 if(!dc) return GDI_ERROR;
2812 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2813 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2814 release_dc_ptr( dc );
2815 return ret;
2819 /***********************************************************************
2820 * CreateScalableFontResourceA (GDI32.@)
2822 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2823 LPCSTR lpszResourceFile,
2824 LPCSTR lpszFontFile,
2825 LPCSTR lpszCurrentPath )
2827 LPWSTR lpszResourceFileW = NULL;
2828 LPWSTR lpszFontFileW = NULL;
2829 LPWSTR lpszCurrentPathW = NULL;
2830 int len;
2831 BOOL ret;
2833 if (lpszResourceFile)
2835 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2836 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2837 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2840 if (lpszFontFile)
2842 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2843 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2844 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2847 if (lpszCurrentPath)
2849 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2850 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2851 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2854 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2855 lpszFontFileW, lpszCurrentPathW);
2857 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2858 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2859 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2861 return ret;
2864 /***********************************************************************
2865 * CreateScalableFontResourceW (GDI32.@)
2867 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2868 LPCWSTR font_file, LPCWSTR font_path )
2870 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2871 debugstr_w(font_file), debugstr_w(font_path) );
2873 return WineEngCreateScalableFontResource( hidden, resource_file,
2874 font_file, font_path );
2877 /*************************************************************************
2878 * GetKerningPairsA (GDI32.@)
2880 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2881 LPKERNINGPAIR kern_pairA )
2883 UINT cp;
2884 CPINFO cpi;
2885 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2886 KERNINGPAIR *kern_pairW;
2888 if (!cPairs && kern_pairA)
2890 SetLastError(ERROR_INVALID_PARAMETER);
2891 return 0;
2894 cp = GdiGetCodePage(hDC);
2896 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2897 * to fail on an invalid character for CP_SYMBOL.
2899 cpi.DefaultChar[0] = 0;
2900 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2902 FIXME("Can't find codepage %u info\n", cp);
2903 return 0;
2906 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2907 if (!total_kern_pairs) return 0;
2909 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2910 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2912 for (i = 0; i < total_kern_pairs; i++)
2914 char first, second;
2916 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2917 continue;
2919 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2920 continue;
2922 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2923 continue;
2925 if (kern_pairA)
2927 if (kern_pairs_copied >= cPairs) break;
2929 kern_pairA->wFirst = (BYTE)first;
2930 kern_pairA->wSecond = (BYTE)second;
2931 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2932 kern_pairA++;
2934 kern_pairs_copied++;
2937 HeapFree(GetProcessHeap(), 0, kern_pairW);
2939 return kern_pairs_copied;
2942 /*************************************************************************
2943 * GetKerningPairsW (GDI32.@)
2945 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2946 LPKERNINGPAIR lpKerningPairs )
2948 DC *dc;
2949 DWORD ret;
2950 PHYSDEV dev;
2952 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2954 if (!cPairs && lpKerningPairs)
2956 SetLastError(ERROR_INVALID_PARAMETER);
2957 return 0;
2960 dc = get_dc_ptr(hDC);
2961 if (!dc) return 0;
2963 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2964 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2965 release_dc_ptr( dc );
2966 return ret;
2969 /*************************************************************************
2970 * TranslateCharsetInfo [GDI32.@]
2972 * Fills a CHARSETINFO structure for a character set, code page, or
2973 * font. This allows making the correspondence between different labels
2974 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2975 * of the same encoding.
2977 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2978 * only one codepage should be set in *lpSrc.
2980 * RETURNS
2981 * TRUE on success, FALSE on failure.
2984 BOOL WINAPI TranslateCharsetInfo(
2985 LPDWORD lpSrc, /* [in]
2986 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2987 if flags == TCI_SRCCHARSET: a character set value
2988 if flags == TCI_SRCCODEPAGE: a code page value
2990 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2991 DWORD flags /* [in] determines interpretation of lpSrc */)
2993 int index = 0;
2994 switch (flags) {
2995 case TCI_SRCFONTSIG:
2996 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2997 break;
2998 case TCI_SRCCODEPAGE:
2999 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3000 break;
3001 case TCI_SRCCHARSET:
3002 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3003 break;
3004 default:
3005 return FALSE;
3007 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3008 *lpCs = FONT_tci[index];
3009 return TRUE;
3012 /*************************************************************************
3013 * GetFontLanguageInfo (GDI32.@)
3015 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3017 FONTSIGNATURE fontsig;
3018 static const DWORD GCP_DBCS_MASK=0x003F0000,
3019 GCP_DIACRITIC_MASK=0x00000000,
3020 FLI_GLYPHS_MASK=0x00000000,
3021 GCP_GLYPHSHAPE_MASK=0x00000040,
3022 GCP_KASHIDA_MASK=0x00000000,
3023 GCP_LIGATE_MASK=0x00000000,
3024 GCP_USEKERNING_MASK=0x00000000,
3025 GCP_REORDER_MASK=0x00000060;
3027 DWORD result=0;
3029 GetTextCharsetInfo( hdc, &fontsig, 0 );
3030 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3032 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3033 result|=GCP_DBCS;
3035 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3036 result|=GCP_DIACRITIC;
3038 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3039 result|=FLI_GLYPHS;
3041 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3042 result|=GCP_GLYPHSHAPE;
3044 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3045 result|=GCP_KASHIDA;
3047 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3048 result|=GCP_LIGATE;
3050 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3051 result|=GCP_USEKERNING;
3053 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3054 if( GetTextAlign( hdc) & TA_RTLREADING )
3055 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3056 result|=GCP_REORDER;
3058 return result;
3062 /*************************************************************************
3063 * GetFontData [GDI32.@]
3065 * Retrieve data for TrueType font.
3067 * RETURNS
3069 * success: Number of bytes returned
3070 * failure: GDI_ERROR
3072 * NOTES
3074 * Calls SetLastError()
3077 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3078 LPVOID buffer, DWORD length)
3080 DC *dc = get_dc_ptr(hdc);
3081 PHYSDEV dev;
3082 DWORD ret;
3084 if(!dc) return GDI_ERROR;
3086 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3087 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3088 release_dc_ptr( dc );
3089 return ret;
3092 /*************************************************************************
3093 * GetGlyphIndicesA [GDI32.@]
3095 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3096 LPWORD pgi, DWORD flags)
3098 DWORD ret;
3099 WCHAR *lpstrW;
3100 INT countW;
3102 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3103 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3105 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3106 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3107 HeapFree(GetProcessHeap(), 0, lpstrW);
3109 return ret;
3112 /*************************************************************************
3113 * GetGlyphIndicesW [GDI32.@]
3115 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3116 LPWORD pgi, DWORD flags)
3118 DC *dc = get_dc_ptr(hdc);
3119 PHYSDEV dev;
3120 DWORD ret;
3122 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3123 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3125 if(!dc) return GDI_ERROR;
3127 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3128 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3129 release_dc_ptr( dc );
3130 return ret;
3133 /*************************************************************************
3134 * GetCharacterPlacementA [GDI32.@]
3136 * See GetCharacterPlacementW.
3138 * NOTES:
3139 * the web browser control of ie4 calls this with dwFlags=0
3141 DWORD WINAPI
3142 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3143 INT nMaxExtent, GCP_RESULTSA *lpResults,
3144 DWORD dwFlags)
3146 WCHAR *lpStringW;
3147 INT uCountW;
3148 GCP_RESULTSW resultsW;
3149 DWORD ret;
3150 UINT font_cp;
3152 TRACE("%s, %d, %d, 0x%08x\n",
3153 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3155 /* both structs are equal in size */
3156 memcpy(&resultsW, lpResults, sizeof(resultsW));
3158 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3159 if(lpResults->lpOutString)
3160 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3162 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3164 lpResults->nGlyphs = resultsW.nGlyphs;
3165 lpResults->nMaxFit = resultsW.nMaxFit;
3167 if(lpResults->lpOutString) {
3168 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3169 lpResults->lpOutString, uCount, NULL, NULL );
3172 HeapFree(GetProcessHeap(), 0, lpStringW);
3173 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3175 return ret;
3178 /*************************************************************************
3179 * GetCharacterPlacementW [GDI32.@]
3181 * Retrieve information about a string. This includes the width, reordering,
3182 * Glyphing and so on.
3184 * RETURNS
3186 * The width and height of the string if successful, 0 if failed.
3188 * BUGS
3190 * All flags except GCP_REORDER are not yet implemented.
3191 * Reordering is not 100% compliant to the Windows BiDi method.
3192 * Caret positioning is not yet implemented for BiDi.
3193 * Classes are not yet implemented.
3196 DWORD WINAPI
3197 GetCharacterPlacementW(
3198 HDC hdc, /* [in] Device context for which the rendering is to be done */
3199 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3200 INT uCount, /* [in] Number of WORDS in string. */
3201 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3202 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3203 DWORD dwFlags /* [in] Flags specifying how to process the string */
3206 DWORD ret=0;
3207 SIZE size;
3208 UINT i, nSet;
3210 TRACE("%s, %d, %d, 0x%08x\n",
3211 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3213 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3214 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3215 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3216 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3217 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3219 if(dwFlags&(~GCP_REORDER))
3220 FIXME("flags 0x%08x ignored\n", dwFlags);
3221 if(lpResults->lpClass)
3222 FIXME("classes not implemented\n");
3223 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3224 FIXME("Caret positions for complex scripts not implemented\n");
3226 nSet = (UINT)uCount;
3227 if(nSet > lpResults->nGlyphs)
3228 nSet = lpResults->nGlyphs;
3230 /* return number of initialized fields */
3231 lpResults->nGlyphs = nSet;
3233 if((dwFlags&GCP_REORDER)==0 )
3235 /* Treat the case where no special handling was requested in a fastpath way */
3236 /* copy will do if the GCP_REORDER flag is not set */
3237 if(lpResults->lpOutString)
3238 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3240 if(lpResults->lpOrder)
3242 for(i = 0; i < nSet; i++)
3243 lpResults->lpOrder[i] = i;
3246 else
3248 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3249 nSet, lpResults->lpOrder, NULL, NULL );
3252 /* FIXME: Will use the placement chars */
3253 if (lpResults->lpDx)
3255 int c;
3256 for (i = 0; i < nSet; i++)
3258 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3259 lpResults->lpDx[i]= c;
3263 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3265 int pos = 0;
3267 lpResults->lpCaretPos[0] = 0;
3268 for (i = 1; i < nSet; i++)
3269 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3270 lpResults->lpCaretPos[i] = (pos += size.cx);
3273 if(lpResults->lpGlyphs)
3274 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3276 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3277 ret = MAKELONG(size.cx, size.cy);
3279 return ret;
3282 /*************************************************************************
3283 * GetCharABCWidthsFloatA [GDI32.@]
3285 * See GetCharABCWidthsFloatW.
3287 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3289 INT i, wlen;
3290 LPSTR str;
3291 LPWSTR wstr;
3292 BOOL ret = TRUE;
3294 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3295 if (str == NULL)
3296 return FALSE;
3298 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3300 for (i = 0; i < wlen; i++)
3302 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3304 ret = FALSE;
3305 break;
3307 abcf++;
3310 HeapFree( GetProcessHeap(), 0, str );
3311 HeapFree( GetProcessHeap(), 0, wstr );
3313 return ret;
3316 /*************************************************************************
3317 * GetCharABCWidthsFloatW [GDI32.@]
3319 * Retrieves widths of a range of characters.
3321 * PARAMS
3322 * hdc [I] Handle to device context.
3323 * first [I] First character in range to query.
3324 * last [I] Last character in range to query.
3325 * abcf [O] Array of LPABCFLOAT structures.
3327 * RETURNS
3328 * Success: TRUE
3329 * Failure: FALSE
3331 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3333 UINT i;
3334 ABC *abc;
3335 PHYSDEV dev;
3336 BOOL ret = FALSE;
3337 DC *dc = get_dc_ptr( hdc );
3339 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3341 if (!dc) return FALSE;
3343 if (!abcf) goto done;
3344 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3346 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3347 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3348 if (ret)
3350 /* convert device units to logical */
3351 for (i = first; i <= last; i++, abcf++)
3353 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3354 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3355 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3358 HeapFree( GetProcessHeap(), 0, abc );
3360 done:
3361 release_dc_ptr( dc );
3362 return ret;
3365 /*************************************************************************
3366 * GetCharWidthFloatA [GDI32.@]
3368 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3369 UINT iLastChar, PFLOAT pxBuffer)
3371 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3372 return 0;
3375 /*************************************************************************
3376 * GetCharWidthFloatW [GDI32.@]
3378 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3379 UINT iLastChar, PFLOAT pxBuffer)
3381 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3382 return 0;
3386 /***********************************************************************
3388 * Font Resource API *
3390 ***********************************************************************/
3392 /***********************************************************************
3393 * AddFontResourceA (GDI32.@)
3395 INT WINAPI AddFontResourceA( LPCSTR str )
3397 return AddFontResourceExA( str, 0, NULL);
3400 /***********************************************************************
3401 * AddFontResourceW (GDI32.@)
3403 INT WINAPI AddFontResourceW( LPCWSTR str )
3405 return AddFontResourceExW(str, 0, NULL);
3409 /***********************************************************************
3410 * AddFontResourceExA (GDI32.@)
3412 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3414 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3415 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3416 INT ret;
3418 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3419 ret = AddFontResourceExW(strW, fl, pdv);
3420 HeapFree(GetProcessHeap(), 0, strW);
3421 return ret;
3424 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3426 HRSRC rsrc = FindResourceW(hModule, name, type);
3427 HGLOBAL hMem = LoadResource(hModule, rsrc);
3428 LPVOID *pMem = LockResource(hMem);
3429 int *num_total = (int *)lParam;
3430 DWORD num_in_res;
3432 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3433 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3435 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3436 return FALSE;
3439 *num_total += num_in_res;
3440 return TRUE;
3443 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3445 HANDLE file, mapping;
3446 void *ptr;
3448 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3449 if (file == INVALID_HANDLE_VALUE) return NULL;
3451 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3453 CloseHandle( file );
3454 return NULL;
3457 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3458 CloseHandle( file );
3459 if (!mapping) return NULL;
3461 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3462 CloseHandle( mapping );
3464 return ptr;
3467 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3469 WORD align, type_id, count;
3470 DWORD res_off;
3472 if (size < rsrc_off + 10) return NULL;
3473 align = *(WORD *)(ptr + rsrc_off);
3474 rsrc_off += 2;
3475 type_id = *(WORD *)(ptr + rsrc_off);
3476 while (type_id && type_id != type)
3478 count = *(WORD *)(ptr + rsrc_off + 2);
3479 rsrc_off += 8 + count * 12;
3480 if (size < rsrc_off + 8) return NULL;
3481 type_id = *(WORD *)(ptr + rsrc_off);
3483 if (!type_id) return NULL;
3484 count = *(WORD *)(ptr + rsrc_off + 2);
3485 if (size < rsrc_off + 8 + count * 12) return NULL;
3486 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3487 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3488 if (size < res_off + *len) return NULL;
3489 return ptr + res_off;
3492 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3494 LARGE_INTEGER size;
3495 BYTE *ptr = map_file( res, &size );
3496 const IMAGE_DOS_HEADER *dos;
3497 const IMAGE_OS2_HEADER *ne;
3498 WORD *fontdir;
3499 char *data;
3500 WCHAR *name = NULL;
3501 DWORD len;
3503 if (!ptr) return NULL;
3505 if (size.u.LowPart < sizeof( *dos )) goto fail;
3506 dos = (const IMAGE_DOS_HEADER *)ptr;
3507 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3508 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3509 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3511 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3512 if (!fontdir) goto fail;
3513 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3515 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3516 if (!data) goto fail;
3517 if (!memchr( data, 0, len )) goto fail;
3519 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3520 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3521 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3523 fail:
3524 UnmapViewOfFile( ptr );
3525 return name;
3528 /***********************************************************************
3529 * AddFontResourceExW (GDI32.@)
3531 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3533 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3534 WCHAR *filename;
3535 BOOL hidden;
3537 if (ret == 0)
3539 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3540 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3541 if (hModule != NULL)
3543 int num_resources = 0;
3544 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3546 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3547 wine_dbgstr_w(str));
3548 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3549 ret = num_resources;
3550 FreeLibrary(hModule);
3552 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3554 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3555 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3556 HeapFree( GetProcessHeap(), 0, filename );
3559 return ret;
3562 /***********************************************************************
3563 * RemoveFontResourceA (GDI32.@)
3565 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3567 return RemoveFontResourceExA(str, 0, 0);
3570 /***********************************************************************
3571 * RemoveFontResourceW (GDI32.@)
3573 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3575 return RemoveFontResourceExW(str, 0, 0);
3578 /***********************************************************************
3579 * AddFontMemResourceEx (GDI32.@)
3581 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3583 HANDLE ret;
3584 DWORD num_fonts;
3586 if (!pbFont || !cbFont || !pcFonts)
3588 SetLastError(ERROR_INVALID_PARAMETER);
3589 return NULL;
3592 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3593 if (ret)
3595 __TRY
3597 *pcFonts = num_fonts;
3599 __EXCEPT_PAGE_FAULT
3601 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3602 RemoveFontMemResourceEx(ret);
3603 ret = 0;
3605 __ENDTRY
3607 return ret;
3610 /***********************************************************************
3611 * RemoveFontMemResourceEx (GDI32.@)
3613 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3615 FIXME("(%p) stub\n", fh);
3616 return TRUE;
3619 /***********************************************************************
3620 * RemoveFontResourceExA (GDI32.@)
3622 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3624 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3625 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3626 INT ret;
3628 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3629 ret = RemoveFontResourceExW(strW, fl, pdv);
3630 HeapFree(GetProcessHeap(), 0, strW);
3631 return ret;
3634 /***********************************************************************
3635 * RemoveFontResourceExW (GDI32.@)
3637 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3639 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3640 WCHAR *filename;
3641 BOOL hidden;
3643 if (ret == 0)
3645 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3646 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3647 if (hModule != NULL)
3649 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3650 FreeLibrary(hModule);
3652 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3654 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3655 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3656 HeapFree( GetProcessHeap(), 0, filename );
3659 return ret;
3662 /***********************************************************************
3663 * GetFontResourceInfoW (GDI32.@)
3665 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3667 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3668 return FALSE;
3671 /***********************************************************************
3672 * GetTextCharset (GDI32.@)
3674 UINT WINAPI GetTextCharset(HDC hdc)
3676 /* MSDN docs say this is equivalent */
3677 return GetTextCharsetInfo(hdc, NULL, 0);
3680 /***********************************************************************
3681 * GetTextCharsetInfo (GDI32.@)
3683 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3685 UINT ret = DEFAULT_CHARSET;
3686 DC *dc = get_dc_ptr(hdc);
3687 PHYSDEV dev;
3689 if (dc)
3691 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3692 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3693 release_dc_ptr( dc );
3696 if (ret == DEFAULT_CHARSET && fs)
3697 memset(fs, 0, sizeof(FONTSIGNATURE));
3698 return ret;
3701 /***********************************************************************
3702 * GdiGetCharDimensions (GDI32.@)
3704 * Gets the average width of the characters in the English alphabet.
3706 * PARAMS
3707 * hdc [I] Handle to the device context to measure on.
3708 * lptm [O] Pointer to memory to store the text metrics into.
3709 * height [O] On exit, the maximum height of characters in the English alphabet.
3711 * RETURNS
3712 * The average width of characters in the English alphabet.
3714 * NOTES
3715 * This function is used by the dialog manager to get the size of a dialog
3716 * unit. It should also be used by other pieces of code that need to know
3717 * the size of a dialog unit in logical units without having access to the
3718 * window handle of the dialog.
3719 * Windows caches the font metrics from this function, but we don't and
3720 * there doesn't appear to be an immediate advantage to do so.
3722 * SEE ALSO
3723 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3725 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3727 SIZE sz;
3728 static const WCHAR alphabet[] = {
3729 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3730 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3731 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3733 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3735 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3737 if (height) *height = sz.cy;
3738 return (sz.cx / 26 + 1) / 2;
3741 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3743 FIXME("(%d): stub\n", fEnableEUDC);
3744 return FALSE;
3747 /***********************************************************************
3748 * GetCharWidthI (GDI32.@)
3750 * Retrieve widths of characters.
3752 * PARAMS
3753 * hdc [I] Handle to a device context.
3754 * first [I] First glyph in range to query.
3755 * count [I] Number of glyph indices to query.
3756 * glyphs [I] Array of glyphs to query.
3757 * buffer [O] Buffer to receive character widths.
3759 * NOTES
3760 * Only works with TrueType fonts.
3762 * RETURNS
3763 * Success: TRUE
3764 * Failure: FALSE
3766 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3768 ABC *abc;
3769 unsigned int i;
3771 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3773 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3774 return FALSE;
3776 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3778 HeapFree(GetProcessHeap(), 0, abc);
3779 return FALSE;
3782 for (i = 0; i < count; i++)
3783 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3785 HeapFree(GetProcessHeap(), 0, abc);
3786 return TRUE;
3789 /***********************************************************************
3790 * GetFontUnicodeRanges (GDI32.@)
3792 * Retrieve a list of supported Unicode characters in a font.
3794 * PARAMS
3795 * hdc [I] Handle to a device context.
3796 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3798 * RETURNS
3799 * Success: Number of bytes written to the buffer pointed to by lpgs.
3800 * Failure: 0
3803 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3805 DWORD ret;
3806 PHYSDEV dev;
3807 DC *dc = get_dc_ptr(hdc);
3809 TRACE("(%p, %p)\n", hdc, lpgs);
3811 if (!dc) return 0;
3813 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3814 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3815 release_dc_ptr(dc);
3816 return ret;
3820 /*************************************************************
3821 * FontIsLinked (GDI32.@)
3823 BOOL WINAPI FontIsLinked(HDC hdc)
3825 DC *dc = get_dc_ptr(hdc);
3826 PHYSDEV dev;
3827 BOOL ret;
3829 if (!dc) return FALSE;
3830 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3831 ret = dev->funcs->pFontIsLinked( dev );
3832 release_dc_ptr(dc);
3833 TRACE("returning %d\n", ret);
3834 return ret;
3837 /*************************************************************
3838 * GdiRealizationInfo (GDI32.@)
3840 * Returns a structure that contains some font information.
3842 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3844 DC *dc = get_dc_ptr(hdc);
3845 PHYSDEV dev;
3846 BOOL ret;
3848 if (!dc) return FALSE;
3849 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3850 ret = dev->funcs->pGdiRealizationInfo( dev, info );
3851 release_dc_ptr(dc);
3852 return ret;