reg: Add reg.exe test suite.
[wine/multimedia.git] / dlls / gdi32 / font.c
blobaf3ea5bddbe65f5715e06c2884dcc7ffcac1fb4d
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 /* scale width and height but don't mirror them */
74 static inline INT width_to_LP( DC *dc, INT width )
76 return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
79 static inline INT height_to_LP( DC *dc, INT height )
81 return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
84 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
86 POINT pt[2];
87 pt[0].x = pt[0].y = 0;
88 pt[1].x = width;
89 pt[1].y = 0;
90 LPtoDP(dc->hSelf, pt, 2);
91 return pt[1].x - pt[0].x;
94 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
96 POINT pt[2];
97 pt[0].x = pt[0].y = 0;
98 pt[1].x = 0;
99 pt[1].y = height;
100 LPtoDP(dc->hSelf, pt, 2);
101 return pt[1].y - pt[0].y;
104 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
105 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
106 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
107 static BOOL FONT_DeleteObject( HGDIOBJ handle );
109 static const struct gdi_obj_funcs font_funcs =
111 FONT_SelectObject, /* pSelectObject */
112 FONT_GetObjectA, /* pGetObjectA */
113 FONT_GetObjectW, /* pGetObjectW */
114 NULL, /* pUnrealizeObject */
115 FONT_DeleteObject /* pDeleteObject */
118 typedef struct
120 LOGFONTW logfont;
121 } FONTOBJ;
123 struct font_enum
125 LPLOGFONTW lpLogFontParam;
126 FONTENUMPROCW lpEnumFunc;
127 LPARAM lpData;
128 BOOL unicode;
129 HDC hdc;
130 INT retval;
134 * For TranslateCharsetInfo
136 #define MAXTCIINDEX 32
137 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
138 /* ANSI */
139 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
140 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
141 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
142 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
143 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
144 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
145 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
146 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
147 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
148 /* reserved by ANSI */
149 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
150 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
151 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
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 /* ANSI and OEM */
157 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
158 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
159 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
160 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
161 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
162 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
163 /* reserved for alternate ANSI and OEM */
164 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
165 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
166 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
167 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
168 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
169 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
170 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
171 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
172 /* reserved for system */
173 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
174 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
177 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
179 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
180 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
181 LF_FACESIZE);
182 fontW->lfFaceName[LF_FACESIZE-1] = 0;
185 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
187 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
188 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
189 LF_FACESIZE, NULL, NULL);
190 fontA->lfFaceName[LF_FACESIZE-1] = 0;
193 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
195 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
197 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
198 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
199 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
200 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
201 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
202 fontA->elfStyle[LF_FACESIZE-1] = '\0';
203 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
204 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
205 fontA->elfScript[LF_FACESIZE-1] = '\0';
208 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
210 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
212 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
213 fontW->elfFullName, LF_FULLFACESIZE );
214 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
215 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
216 fontW->elfStyle, LF_FACESIZE );
217 fontW->elfStyle[LF_FACESIZE-1] = '\0';
218 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
219 fontW->elfScript, LF_FACESIZE );
220 fontW->elfScript[LF_FACESIZE-1] = '\0';
223 /***********************************************************************
224 * TEXTMETRIC conversion functions.
226 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
228 ptmA->tmHeight = ptmW->tmHeight;
229 ptmA->tmAscent = ptmW->tmAscent;
230 ptmA->tmDescent = ptmW->tmDescent;
231 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
232 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
233 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
234 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
235 ptmA->tmWeight = ptmW->tmWeight;
236 ptmA->tmOverhang = ptmW->tmOverhang;
237 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
238 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
239 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
240 if (ptmW->tmCharSet == SYMBOL_CHARSET)
242 ptmA->tmFirstChar = 0x1e;
243 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
245 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
247 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
248 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
250 else
252 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
253 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
255 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
256 ptmA->tmBreakChar = ptmW->tmBreakChar;
257 ptmA->tmItalic = ptmW->tmItalic;
258 ptmA->tmUnderlined = ptmW->tmUnderlined;
259 ptmA->tmStruckOut = ptmW->tmStruckOut;
260 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
261 ptmA->tmCharSet = ptmW->tmCharSet;
265 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
267 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
268 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
269 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
270 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
271 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
272 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
275 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
277 WCHAR buf[12];
278 DWORD count = sizeof(buf), type, err;
280 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
281 if (!err)
283 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
284 else *value = atoiW( buf );
286 return err;
289 static UINT get_subpixel_orientation( HKEY key )
291 static const WCHAR smoothing_orientation[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
292 'O','r','i','e','n','t','a','t','i','o','n',0};
293 DWORD orient;
295 /* FIXME: handle vertical orientations even though Windows doesn't */
296 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
298 switch (orient)
300 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
301 return WINE_GGO_HBGR_BITMAP;
302 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
303 return WINE_GGO_HRGB_BITMAP;
305 return GGO_GRAY4_BITMAP;
308 static UINT get_default_smoothing( HKEY key )
310 static const WCHAR smoothing[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
311 static const WCHAR smoothing_type[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
312 DWORD enabled, type;
314 if (get_key_value( key, smoothing, &enabled )) return 0;
315 if (!enabled) return GGO_BITMAP;
317 if (!get_key_value( key, smoothing_type, &type ) && type == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
318 return get_subpixel_orientation( key );
320 return GGO_GRAY4_BITMAP;
323 /* compute positions for text rendering, in device coords */
324 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
326 TEXTMETRICW tm;
327 PHYSDEV dev;
329 size->cx = size->cy = 0;
330 if (!count) return TRUE;
332 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
333 dev->funcs->pGetTextMetrics( dev, &tm );
335 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
336 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
338 if (dc->breakExtra || dc->breakRem)
340 int i, space = 0, rem = dc->breakRem;
342 for (i = 0; i < count; i++)
344 if (str[i] == tm.tmBreakChar)
346 space += dc->breakExtra;
347 if (rem > 0)
349 space++;
350 rem--;
353 dx[i] += space;
356 size->cx = dx[count - 1];
357 size->cy = tm.tmHeight;
358 return TRUE;
361 /* compute positions for text rendering, in device coords */
362 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
364 TEXTMETRICW tm;
365 PHYSDEV dev;
367 size->cx = size->cy = 0;
368 if (!count) return TRUE;
370 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
371 dev->funcs->pGetTextMetrics( dev, &tm );
373 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
374 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
376 if (dc->breakExtra || dc->breakRem)
378 WORD space_index;
379 int i, space = 0, rem = dc->breakRem;
381 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
382 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
384 for (i = 0; i < count; i++)
386 if (indices[i] == space_index)
388 space += dc->breakExtra;
389 if (rem > 0)
391 space++;
392 rem--;
395 dx[i] += space;
398 size->cx = dx[count - 1];
399 size->cy = tm.tmHeight;
400 return TRUE;
403 /***********************************************************************
404 * GdiGetCodePage (GDI32.@)
406 DWORD WINAPI GdiGetCodePage( HDC hdc )
408 UINT cp = CP_ACP;
409 DC *dc = get_dc_ptr( hdc );
411 if (dc)
413 cp = dc->font_code_page;
414 release_dc_ptr( dc );
416 return cp;
419 /***********************************************************************
420 * FONT_mbtowc
422 * Returns a Unicode translation of str using the charset of the
423 * currently selected font in hdc. If count is -1 then str is assumed
424 * to be '\0' terminated, otherwise it contains the number of bytes to
425 * convert. If plenW is non-NULL, on return it will point to the
426 * number of WCHARs that have been written. If pCP is non-NULL, on
427 * return it will point to the codepage used in the conversion. The
428 * caller should free the returned LPWSTR from the process heap
429 * itself.
431 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
433 UINT cp;
434 INT lenW;
435 LPWSTR strW;
437 cp = GdiGetCodePage( hdc );
439 if(count == -1) count = strlen(str);
440 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
441 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
442 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
443 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
444 if(plenW) *plenW = lenW;
445 if(pCP) *pCP = cp;
446 return strW;
449 /***********************************************************************
450 * CreateFontIndirectExA (GDI32.@)
452 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
454 ENUMLOGFONTEXDVW enumexW;
456 if (!penumexA) return 0;
458 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
459 enumexW.elfDesignVector = penumexA->elfDesignVector;
460 return CreateFontIndirectExW( &enumexW );
463 /***********************************************************************
464 * CreateFontIndirectExW (GDI32.@)
466 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
468 HFONT hFont;
469 FONTOBJ *fontPtr;
470 const LOGFONTW *plf;
472 if (!penumex) return 0;
474 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
475 penumex->elfEnumLogfontEx.elfStyle[0] ||
476 penumex->elfEnumLogfontEx.elfScript[0])
478 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
479 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
480 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
481 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
484 plf = &penumex->elfEnumLogfontEx.elfLogFont;
485 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
487 fontPtr->logfont = *plf;
489 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
491 HeapFree( GetProcessHeap(), 0, fontPtr );
492 return 0;
495 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
496 plf->lfHeight, plf->lfWidth,
497 plf->lfEscapement, plf->lfOrientation,
498 plf->lfPitchAndFamily,
499 plf->lfOutPrecision, plf->lfClipPrecision,
500 plf->lfQuality, plf->lfCharSet,
501 debugstr_w(plf->lfFaceName),
502 plf->lfWeight > 400 ? "Bold" : "",
503 plf->lfItalic ? "Italic" : "",
504 plf->lfUnderline ? "Underline" : "", hFont);
506 return hFont;
509 /***********************************************************************
510 * CreateFontIndirectA (GDI32.@)
512 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
514 LOGFONTW lfW;
516 if (!plfA) return 0;
518 FONT_LogFontAToW( plfA, &lfW );
519 return CreateFontIndirectW( &lfW );
522 /***********************************************************************
523 * CreateFontIndirectW (GDI32.@)
525 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
527 ENUMLOGFONTEXDVW exdv;
529 if (!plf) return 0;
531 exdv.elfEnumLogfontEx.elfLogFont = *plf;
532 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
533 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
534 exdv.elfEnumLogfontEx.elfScript[0] = 0;
535 return CreateFontIndirectExW( &exdv );
538 /*************************************************************************
539 * CreateFontA (GDI32.@)
541 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
542 INT orient, INT weight, DWORD italic,
543 DWORD underline, DWORD strikeout, DWORD charset,
544 DWORD outpres, DWORD clippres, DWORD quality,
545 DWORD pitch, LPCSTR name )
547 LOGFONTA logfont;
549 logfont.lfHeight = height;
550 logfont.lfWidth = width;
551 logfont.lfEscapement = esc;
552 logfont.lfOrientation = orient;
553 logfont.lfWeight = weight;
554 logfont.lfItalic = italic;
555 logfont.lfUnderline = underline;
556 logfont.lfStrikeOut = strikeout;
557 logfont.lfCharSet = charset;
558 logfont.lfOutPrecision = outpres;
559 logfont.lfClipPrecision = clippres;
560 logfont.lfQuality = quality;
561 logfont.lfPitchAndFamily = pitch;
563 if (name)
564 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
565 else
566 logfont.lfFaceName[0] = '\0';
568 return CreateFontIndirectA( &logfont );
571 /*************************************************************************
572 * CreateFontW (GDI32.@)
574 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
575 INT orient, INT weight, DWORD italic,
576 DWORD underline, DWORD strikeout, DWORD charset,
577 DWORD outpres, DWORD clippres, DWORD quality,
578 DWORD pitch, LPCWSTR name )
580 LOGFONTW logfont;
582 logfont.lfHeight = height;
583 logfont.lfWidth = width;
584 logfont.lfEscapement = esc;
585 logfont.lfOrientation = orient;
586 logfont.lfWeight = weight;
587 logfont.lfItalic = italic;
588 logfont.lfUnderline = underline;
589 logfont.lfStrikeOut = strikeout;
590 logfont.lfCharSet = charset;
591 logfont.lfOutPrecision = outpres;
592 logfont.lfClipPrecision = clippres;
593 logfont.lfQuality = quality;
594 logfont.lfPitchAndFamily = pitch;
596 if (name)
597 lstrcpynW(logfont.lfFaceName, name,
598 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
599 else
600 logfont.lfFaceName[0] = '\0';
602 return CreateFontIndirectW( &logfont );
605 #define ASSOC_CHARSET_OEM 1
606 #define ASSOC_CHARSET_ANSI 2
607 #define ASSOC_CHARSET_SYMBOL 4
609 static DWORD get_associated_charset_info(void)
611 static DWORD associated_charset = -1;
613 if (associated_charset == -1)
615 static const WCHAR assoc_charset_reg_keyW[] = {'S','y','s','t','e','m','\\',
616 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
617 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
618 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
619 static const WCHAR ansiW[] = {'A','N','S','I','(','0','0',')','\0'};
620 static const WCHAR oemW[] = {'O','E','M','(','F','F',')','\0'};
621 static const WCHAR symbolW[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
622 static const WCHAR yesW[] = {'Y','E','S','\0'};
623 HKEY hkey;
624 WCHAR dataW[32];
625 DWORD type, data_len;
627 associated_charset = 0;
629 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
630 assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS)
631 return 0;
633 data_len = sizeof(dataW);
634 if (!RegQueryValueExW(hkey, ansiW, NULL, &type, (LPBYTE)dataW, &data_len) &&
635 type == REG_SZ && !strcmpiW(dataW, yesW))
636 associated_charset |= ASSOC_CHARSET_ANSI;
638 data_len = sizeof(dataW);
639 if (!RegQueryValueExW(hkey, oemW, NULL, &type, (LPBYTE)dataW, &data_len) &&
640 type == REG_SZ && !strcmpiW(dataW, yesW))
641 associated_charset |= ASSOC_CHARSET_OEM;
643 data_len = sizeof(dataW);
644 if (!RegQueryValueExW(hkey, symbolW, NULL, &type, (LPBYTE)dataW, &data_len) &&
645 type == REG_SZ && !strcmpiW(dataW, yesW))
646 associated_charset |= ASSOC_CHARSET_SYMBOL;
648 RegCloseKey(hkey);
650 TRACE("associated_charset = %d\n", associated_charset);
653 return associated_charset;
656 static void update_font_code_page( DC *dc, HANDLE font )
658 CHARSETINFO csi;
659 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
660 LOGFONTW lf;
662 GetObjectW( font, sizeof(lf), &lf );
664 if (charset == ANSI_CHARSET && !(lf.lfClipPrecision & CLIP_DFA_DISABLE) &&
665 get_associated_charset_info() & ASSOC_CHARSET_ANSI)
666 charset = DEFAULT_CHARSET;
668 /* Hmm, nicely designed api this one! */
669 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
670 dc->font_code_page = csi.ciACP;
671 else {
672 switch(charset) {
673 case OEM_CHARSET:
674 dc->font_code_page = GetOEMCP();
675 break;
676 case DEFAULT_CHARSET:
677 dc->font_code_page = GetACP();
678 break;
680 case VISCII_CHARSET:
681 case TCVN_CHARSET:
682 case KOI8_CHARSET:
683 case ISO3_CHARSET:
684 case ISO4_CHARSET:
685 case ISO10_CHARSET:
686 case CELTIC_CHARSET:
687 /* FIXME: These have no place here, but because x11drv
688 enumerates fonts with these (made up) charsets some apps
689 might use them and then the FIXME below would become
690 annoying. Now we could pick the intended codepage for
691 each of these, but since it's broken anyway we'll just
692 use CP_ACP and hope it'll go away...
694 dc->font_code_page = CP_ACP;
695 break;
697 default:
698 FIXME("Can't find codepage for charset %d\n", charset);
699 dc->font_code_page = CP_ACP;
700 break;
704 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
707 /***********************************************************************
708 * FONT_SelectObject
710 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
712 HGDIOBJ ret = 0;
713 DC *dc = get_dc_ptr( hdc );
714 PHYSDEV physdev;
715 UINT aa_flags = 0;
717 if (!dc) return 0;
719 if (!GDI_inc_ref_count( handle ))
721 release_dc_ptr( dc );
722 return 0;
725 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
726 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
728 ret = dc->hFont;
729 dc->hFont = handle;
730 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
731 update_font_code_page( dc, handle );
732 GDI_dec_ref_count( ret );
734 else GDI_dec_ref_count( handle );
736 release_dc_ptr( dc );
737 return ret;
741 /***********************************************************************
742 * FONT_GetObjectA
744 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
746 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
747 LOGFONTA lfA;
749 if (!font) return 0;
750 if (buffer)
752 FONT_LogFontWToA( &font->logfont, &lfA );
753 if (count > sizeof(lfA)) count = sizeof(lfA);
754 memcpy( buffer, &lfA, count );
756 else count = sizeof(lfA);
757 GDI_ReleaseObj( handle );
758 return count;
761 /***********************************************************************
762 * FONT_GetObjectW
764 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
766 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
768 if (!font) return 0;
769 if (buffer)
771 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
772 memcpy( buffer, &font->logfont, count );
774 else count = sizeof(LOGFONTW);
775 GDI_ReleaseObj( handle );
776 return count;
780 /***********************************************************************
781 * FONT_DeleteObject
783 static BOOL FONT_DeleteObject( HGDIOBJ handle )
785 FONTOBJ *obj;
787 if (!(obj = free_gdi_handle( handle ))) return FALSE;
788 return HeapFree( GetProcessHeap(), 0, obj );
792 /***********************************************************************
793 * nulldrv_SelectFont
795 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
797 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
798 'D','e','s','k','t','o','p',0 };
799 static int orientation = -1, smoothing = -1;
800 LOGFONTW lf;
801 HKEY key;
803 if (*aa_flags) return 0;
805 GetObjectW( font, sizeof(lf), &lf );
806 switch (lf.lfQuality)
808 case NONANTIALIASED_QUALITY:
809 *aa_flags = GGO_BITMAP;
810 break;
811 case ANTIALIASED_QUALITY:
812 *aa_flags = GGO_GRAY4_BITMAP;
813 break;
814 case CLEARTYPE_QUALITY:
815 case CLEARTYPE_NATURAL_QUALITY:
816 if (orientation == -1)
818 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
819 orientation = get_subpixel_orientation( key );
820 RegCloseKey( key );
822 *aa_flags = orientation;
823 break;
824 default:
825 if (smoothing == -1)
827 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
828 smoothing = get_default_smoothing( key );
829 RegCloseKey( key );
831 *aa_flags = smoothing;
832 break;
834 return 0;
838 /***********************************************************************
839 * FONT_EnumInstance
841 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
842 * We have to use other types because of the FONTENUMPROCW definition.
844 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
845 DWORD fType, LPARAM lp )
847 struct font_enum *pfe = (struct font_enum *)lp;
848 INT ret = 1;
850 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
851 if ((!pfe->lpLogFontParam ||
852 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
853 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
854 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
856 /* convert font metrics */
857 ENUMLOGFONTEXA logfont;
858 NEWTEXTMETRICEXA tmA;
860 if (!pfe->unicode)
862 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
863 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
864 plf = (LOGFONTW *)&logfont.elfLogFont;
865 ptm = (TEXTMETRICW *)&tmA;
867 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
868 pfe->retval = ret;
870 return ret;
873 /***********************************************************************
874 * FONT_EnumFontFamiliesEx
876 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
877 LPARAM lParam, BOOL unicode )
879 INT ret = 0;
880 DC *dc = get_dc_ptr( hDC );
881 struct font_enum fe;
883 if (dc)
885 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
887 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
888 fe.lpLogFontParam = plf;
889 fe.lpEnumFunc = efproc;
890 fe.lpData = lParam;
891 fe.unicode = unicode;
892 fe.hdc = hDC;
893 fe.retval = 1;
894 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
895 release_dc_ptr( dc );
897 return ret ? fe.retval : 0;
900 /***********************************************************************
901 * EnumFontFamiliesExW (GDI32.@)
903 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
904 FONTENUMPROCW efproc,
905 LPARAM lParam, DWORD dwFlags )
907 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
910 /***********************************************************************
911 * EnumFontFamiliesExA (GDI32.@)
913 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
914 FONTENUMPROCA efproc,
915 LPARAM lParam, DWORD dwFlags)
917 LOGFONTW lfW, *plfW;
919 if (plf)
921 FONT_LogFontAToW( plf, &lfW );
922 plfW = &lfW;
924 else plfW = NULL;
926 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
929 /***********************************************************************
930 * EnumFontFamiliesA (GDI32.@)
932 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
933 FONTENUMPROCA efproc, LPARAM lpData )
935 LOGFONTA lf, *plf;
937 if (lpFamily)
939 if (!*lpFamily) return 1;
940 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
941 lf.lfCharSet = DEFAULT_CHARSET;
942 lf.lfPitchAndFamily = 0;
943 plf = &lf;
945 else plf = NULL;
947 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
950 /***********************************************************************
951 * EnumFontFamiliesW (GDI32.@)
953 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
954 FONTENUMPROCW efproc, LPARAM lpData )
956 LOGFONTW lf, *plf;
958 if (lpFamily)
960 if (!*lpFamily) return 1;
961 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
962 lf.lfCharSet = DEFAULT_CHARSET;
963 lf.lfPitchAndFamily = 0;
964 plf = &lf;
966 else plf = NULL;
968 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
971 /***********************************************************************
972 * EnumFontsA (GDI32.@)
974 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
975 LPARAM lpData )
977 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
980 /***********************************************************************
981 * EnumFontsW (GDI32.@)
983 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
984 LPARAM lpData )
986 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
990 /***********************************************************************
991 * GetTextCharacterExtra (GDI32.@)
993 INT WINAPI GetTextCharacterExtra( HDC hdc )
995 INT ret;
996 DC *dc = get_dc_ptr( hdc );
997 if (!dc) return 0x80000000;
998 ret = dc->charExtra;
999 release_dc_ptr( dc );
1000 return ret;
1004 /***********************************************************************
1005 * SetTextCharacterExtra (GDI32.@)
1007 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
1009 INT ret = 0x80000000;
1010 DC * dc = get_dc_ptr( hdc );
1012 if (dc)
1014 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
1015 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
1016 if (extra != 0x80000000)
1018 ret = dc->charExtra;
1019 dc->charExtra = extra;
1021 release_dc_ptr( dc );
1023 return ret;
1027 /***********************************************************************
1028 * SetTextJustification (GDI32.@)
1030 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1032 BOOL ret;
1033 PHYSDEV physdev;
1034 DC * dc = get_dc_ptr( hdc );
1036 if (!dc) return FALSE;
1038 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1039 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1040 if (ret)
1042 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
1043 if (!extra) breaks = 0;
1044 if (breaks)
1046 dc->breakExtra = extra / breaks;
1047 dc->breakRem = extra - (breaks * dc->breakExtra);
1049 else
1051 dc->breakExtra = 0;
1052 dc->breakRem = 0;
1055 release_dc_ptr( dc );
1056 return ret;
1060 /***********************************************************************
1061 * GetTextFaceA (GDI32.@)
1063 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1065 INT res = GetTextFaceW(hdc, 0, NULL);
1066 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1067 GetTextFaceW( hdc, res, nameW );
1069 if (name)
1071 if (count)
1073 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1074 if (res == 0)
1075 res = count;
1076 name[count-1] = 0;
1077 /* GetTextFaceA does NOT include the nul byte in the return count. */
1078 res--;
1080 else
1081 res = 0;
1083 else
1084 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1085 HeapFree( GetProcessHeap(), 0, nameW );
1086 return res;
1089 /***********************************************************************
1090 * GetTextFaceW (GDI32.@)
1092 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1094 PHYSDEV dev;
1095 INT ret;
1097 DC * dc = get_dc_ptr( hdc );
1098 if (!dc) return 0;
1100 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1101 ret = dev->funcs->pGetTextFace( dev, count, name );
1102 release_dc_ptr( dc );
1103 return ret;
1107 /***********************************************************************
1108 * GetTextExtentPoint32A (GDI32.@)
1110 * See GetTextExtentPoint32W.
1112 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1113 LPSIZE size )
1115 BOOL ret = FALSE;
1116 INT wlen;
1117 LPWSTR p;
1119 if (count < 0) return FALSE;
1121 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1123 if (p)
1125 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1126 HeapFree( GetProcessHeap(), 0, p );
1129 TRACE("(%p %s %d %p): returning %d x %d\n",
1130 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1131 return ret;
1135 /***********************************************************************
1136 * GetTextExtentPoint32W [GDI32.@]
1138 * Computes width/height for a string.
1140 * Computes width and height of the specified string.
1142 * RETURNS
1143 * Success: TRUE
1144 * Failure: FALSE
1146 BOOL WINAPI GetTextExtentPoint32W(
1147 HDC hdc, /* [in] Handle of device context */
1148 LPCWSTR str, /* [in] Address of text string */
1149 INT count, /* [in] Number of characters in string */
1150 LPSIZE size) /* [out] Address of structure for string size */
1152 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1155 /***********************************************************************
1156 * GetTextExtentExPointI [GDI32.@]
1158 * Computes width and height of the array of glyph indices.
1160 * PARAMS
1161 * hdc [I] Handle of device context.
1162 * indices [I] Glyph index array.
1163 * count [I] Number of glyphs in array.
1164 * max_ext [I] Maximum width in glyphs.
1165 * nfit [O] Maximum number of characters.
1166 * dxs [O] Partial string widths.
1167 * size [O] Returned string size.
1169 * RETURNS
1170 * Success: TRUE
1171 * Failure: FALSE
1173 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1174 LPINT nfit, LPINT dxs, LPSIZE size )
1176 DC *dc;
1177 int i;
1178 BOOL ret;
1179 INT buffer[256], *pos = dxs;
1181 if (count < 0) return FALSE;
1183 dc = get_dc_ptr( hdc );
1184 if (!dc) return FALSE;
1186 if (!dxs)
1188 pos = buffer;
1189 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1191 release_dc_ptr( dc );
1192 return FALSE;
1196 ret = get_char_positions_indices( dc, indices, count, pos, size );
1197 if (ret)
1199 if (dxs || nfit)
1201 for (i = 0; i < count; i++)
1203 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1204 if (nfit && dx > (unsigned int)max_ext) break;
1205 if (dxs) dxs[i] = dx;
1207 if (nfit) *nfit = i;
1210 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1211 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1214 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1215 release_dc_ptr( dc );
1217 TRACE("(%p %p %d %p): returning %d x %d\n",
1218 hdc, indices, count, size, size->cx, size->cy );
1219 return ret;
1222 /***********************************************************************
1223 * GetTextExtentPointI [GDI32.@]
1225 * Computes width and height of the array of glyph indices.
1227 * PARAMS
1228 * hdc [I] Handle of device context.
1229 * indices [I] Glyph index array.
1230 * count [I] Number of glyphs in array.
1231 * size [O] Returned string size.
1233 * RETURNS
1234 * Success: TRUE
1235 * Failure: FALSE
1237 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1239 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1243 /***********************************************************************
1244 * GetTextExtentPointA (GDI32.@)
1246 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1247 LPSIZE size )
1249 TRACE("not bug compatible.\n");
1250 return GetTextExtentPoint32A( hdc, str, count, size );
1253 /***********************************************************************
1254 * GetTextExtentPointW (GDI32.@)
1256 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1257 LPSIZE size )
1259 TRACE("not bug compatible.\n");
1260 return GetTextExtentPoint32W( hdc, str, count, size );
1264 /***********************************************************************
1265 * GetTextExtentExPointA (GDI32.@)
1267 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1268 INT maxExt, LPINT lpnFit,
1269 LPINT alpDx, LPSIZE size )
1271 BOOL ret;
1272 INT wlen;
1273 INT *walpDx = NULL;
1274 LPWSTR p = NULL;
1276 if (count < 0) return FALSE;
1277 if (maxExt < -1) return FALSE;
1279 if (alpDx)
1281 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1282 if (!walpDx) return FALSE;
1285 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1286 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1287 if (walpDx)
1289 INT n = lpnFit ? *lpnFit : wlen;
1290 INT i, j;
1291 for(i = 0, j = 0; i < n; i++, j++)
1293 alpDx[j] = walpDx[i];
1294 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1297 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1298 HeapFree( GetProcessHeap(), 0, p );
1299 HeapFree( GetProcessHeap(), 0, walpDx );
1300 return ret;
1304 /***********************************************************************
1305 * GetTextExtentExPointW (GDI32.@)
1307 * Return the size of the string as it would be if it was output properly by
1308 * e.g. TextOut.
1310 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1311 LPINT nfit, LPINT dxs, LPSIZE size )
1313 DC *dc;
1314 int i;
1315 BOOL ret;
1316 INT buffer[256], *pos = dxs;
1318 if (count < 0) return FALSE;
1320 dc = get_dc_ptr(hdc);
1321 if (!dc) return FALSE;
1323 if (!dxs)
1325 pos = buffer;
1326 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1328 release_dc_ptr( dc );
1329 return FALSE;
1333 ret = get_char_positions( dc, str, count, pos, size );
1334 if (ret)
1336 if (dxs || nfit)
1338 for (i = 0; i < count; i++)
1340 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1341 if (nfit && dx > (unsigned int)max_ext) break;
1342 if (dxs) dxs[i] = dx;
1344 if (nfit) *nfit = i;
1347 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1348 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1351 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1352 release_dc_ptr( dc );
1354 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1355 return ret;
1358 /***********************************************************************
1359 * GetTextMetricsA (GDI32.@)
1361 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1363 TEXTMETRICW tm32;
1365 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1366 FONT_TextMetricWToA( &tm32, metrics );
1367 return TRUE;
1370 /***********************************************************************
1371 * GetTextMetricsW (GDI32.@)
1373 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1375 PHYSDEV physdev;
1376 BOOL ret = FALSE;
1377 DC * dc = get_dc_ptr( hdc );
1378 if (!dc) return FALSE;
1380 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1381 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1383 if (ret)
1385 /* device layer returns values in device units
1386 * therefore we have to convert them to logical */
1388 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1389 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1390 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
1391 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
1392 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
1393 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
1394 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
1395 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
1396 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
1397 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
1398 ret = TRUE;
1400 TRACE("text metrics:\n"
1401 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1402 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1403 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1404 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1405 " PitchAndFamily = %02x\n"
1406 " --------------------\n"
1407 " InternalLeading = %i\n"
1408 " Ascent = %i\n"
1409 " Descent = %i\n"
1410 " Height = %i\n",
1411 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1412 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1413 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1414 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1415 metrics->tmPitchAndFamily,
1416 metrics->tmInternalLeading,
1417 metrics->tmAscent,
1418 metrics->tmDescent,
1419 metrics->tmHeight );
1421 release_dc_ptr( dc );
1422 return ret;
1426 /***********************************************************************
1427 * GetOutlineTextMetricsA (GDI32.@)
1428 * Gets metrics for TrueType fonts.
1430 * NOTES
1431 * If the supplied buffer isn't big enough Windows partially fills it up to
1432 * its given length and returns that length.
1434 * RETURNS
1435 * Success: Non-zero or size of required buffer
1436 * Failure: 0
1438 UINT WINAPI GetOutlineTextMetricsA(
1439 HDC hdc, /* [in] Handle of device context */
1440 UINT cbData, /* [in] Size of metric data array */
1441 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1443 char buf[512], *ptr;
1444 UINT ret, needed;
1445 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1446 OUTLINETEXTMETRICA *output = lpOTM;
1447 INT left, len;
1449 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1450 return 0;
1451 if(ret > sizeof(buf))
1452 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1453 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1455 needed = sizeof(OUTLINETEXTMETRICA);
1456 if(lpOTMW->otmpFamilyName)
1457 needed += WideCharToMultiByte(CP_ACP, 0,
1458 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1459 NULL, 0, NULL, NULL);
1460 if(lpOTMW->otmpFaceName)
1461 needed += WideCharToMultiByte(CP_ACP, 0,
1462 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1463 NULL, 0, NULL, NULL);
1464 if(lpOTMW->otmpStyleName)
1465 needed += WideCharToMultiByte(CP_ACP, 0,
1466 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1467 NULL, 0, NULL, NULL);
1468 if(lpOTMW->otmpFullName)
1469 needed += WideCharToMultiByte(CP_ACP, 0,
1470 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1471 NULL, 0, NULL, NULL);
1473 if(!lpOTM) {
1474 ret = needed;
1475 goto end;
1478 TRACE("needed = %d\n", needed);
1479 if(needed > cbData)
1480 /* Since the supplied buffer isn't big enough, we'll alloc one
1481 that is and memcpy the first cbData bytes into the lpOTM at
1482 the end. */
1483 output = HeapAlloc(GetProcessHeap(), 0, needed);
1485 ret = output->otmSize = min(needed, cbData);
1486 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1487 output->otmFiller = 0;
1488 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1489 output->otmfsSelection = lpOTMW->otmfsSelection;
1490 output->otmfsType = lpOTMW->otmfsType;
1491 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1492 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1493 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1494 output->otmEMSquare = lpOTMW->otmEMSquare;
1495 output->otmAscent = lpOTMW->otmAscent;
1496 output->otmDescent = lpOTMW->otmDescent;
1497 output->otmLineGap = lpOTMW->otmLineGap;
1498 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1499 output->otmsXHeight = lpOTMW->otmsXHeight;
1500 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1501 output->otmMacAscent = lpOTMW->otmMacAscent;
1502 output->otmMacDescent = lpOTMW->otmMacDescent;
1503 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1504 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1505 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1506 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1507 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1508 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1509 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1510 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1511 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1512 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1515 ptr = (char*)(output + 1);
1516 left = needed - sizeof(*output);
1518 if(lpOTMW->otmpFamilyName) {
1519 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1520 len = WideCharToMultiByte(CP_ACP, 0,
1521 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1522 ptr, left, NULL, NULL);
1523 left -= len;
1524 ptr += len;
1525 } else
1526 output->otmpFamilyName = 0;
1528 if(lpOTMW->otmpFaceName) {
1529 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1530 len = WideCharToMultiByte(CP_ACP, 0,
1531 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1532 ptr, left, NULL, NULL);
1533 left -= len;
1534 ptr += len;
1535 } else
1536 output->otmpFaceName = 0;
1538 if(lpOTMW->otmpStyleName) {
1539 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1540 len = WideCharToMultiByte(CP_ACP, 0,
1541 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1542 ptr, left, NULL, NULL);
1543 left -= len;
1544 ptr += len;
1545 } else
1546 output->otmpStyleName = 0;
1548 if(lpOTMW->otmpFullName) {
1549 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1550 len = WideCharToMultiByte(CP_ACP, 0,
1551 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1552 ptr, left, NULL, NULL);
1553 left -= len;
1554 } else
1555 output->otmpFullName = 0;
1557 assert(left == 0);
1559 if(output != lpOTM) {
1560 memcpy(lpOTM, output, cbData);
1561 HeapFree(GetProcessHeap(), 0, output);
1563 /* check if the string offsets really fit into the provided size */
1564 /* FIXME: should we check string length as well? */
1565 /* make sure that we don't read/write beyond the provided buffer */
1566 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1568 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1569 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1572 /* make sure that we don't read/write beyond the provided buffer */
1573 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1575 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1576 lpOTM->otmpFaceName = 0; /* doesn't fit */
1579 /* make sure that we don't read/write beyond the provided buffer */
1580 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1582 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1583 lpOTM->otmpStyleName = 0; /* doesn't fit */
1586 /* make sure that we don't read/write beyond the provided buffer */
1587 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1589 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1590 lpOTM->otmpFullName = 0; /* doesn't fit */
1594 end:
1595 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1596 HeapFree(GetProcessHeap(), 0, lpOTMW);
1598 return ret;
1602 /***********************************************************************
1603 * GetOutlineTextMetricsW [GDI32.@]
1605 UINT WINAPI GetOutlineTextMetricsW(
1606 HDC hdc, /* [in] Handle of device context */
1607 UINT cbData, /* [in] Size of metric data array */
1608 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1610 DC *dc = get_dc_ptr( hdc );
1611 OUTLINETEXTMETRICW *output = lpOTM;
1612 PHYSDEV dev;
1613 UINT ret;
1615 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1616 if(!dc) return 0;
1618 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1619 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1621 if (lpOTM && ret > cbData)
1623 output = HeapAlloc(GetProcessHeap(), 0, ret);
1624 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1627 if (lpOTM && ret)
1629 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1630 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1631 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
1632 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
1633 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
1634 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
1635 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
1636 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
1637 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
1638 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
1639 output->otmAscent = height_to_LP( dc, output->otmAscent);
1640 output->otmDescent = height_to_LP( dc, output->otmDescent);
1641 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1642 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1643 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1644 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
1645 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
1646 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
1647 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
1648 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
1649 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
1650 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1651 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
1652 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
1653 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
1654 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
1655 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
1656 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
1657 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
1658 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
1659 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1660 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
1661 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
1662 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
1663 #undef WDPTOLP
1664 #undef HDPTOLP
1665 if(output != lpOTM)
1667 memcpy(lpOTM, output, cbData);
1668 HeapFree(GetProcessHeap(), 0, output);
1669 ret = cbData;
1672 release_dc_ptr(dc);
1673 return ret;
1676 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1678 INT i, count = lastChar - firstChar + 1;
1679 UINT mbcp;
1680 UINT c;
1681 LPSTR str;
1683 if (count <= 0)
1684 return NULL;
1686 mbcp = GdiGetCodePage(hdc);
1687 switch (mbcp)
1689 case 932:
1690 case 936:
1691 case 949:
1692 case 950:
1693 case 1361:
1694 if (lastChar > 0xffff)
1695 return NULL;
1696 if ((firstChar ^ lastChar) > 0xff)
1697 return NULL;
1698 break;
1699 default:
1700 if (lastChar > 0xff)
1701 return NULL;
1702 mbcp = 0;
1703 break;
1706 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1707 if (str == NULL)
1708 return NULL;
1710 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1712 if (mbcp) {
1713 if (c > 0xff)
1714 str[i++] = (BYTE)(c >> 8);
1715 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1716 str[i] = 0x1f; /* FIXME: use default character */
1717 else
1718 str[i] = (BYTE)c;
1720 else
1721 str[i] = (BYTE)c;
1723 str[i] = '\0';
1725 *pByteLen = i;
1727 return str;
1730 /***********************************************************************
1731 * GetCharWidthW (GDI32.@)
1732 * GetCharWidth32W (GDI32.@)
1734 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1735 LPINT buffer )
1737 UINT i;
1738 BOOL ret;
1739 PHYSDEV dev;
1740 DC * dc = get_dc_ptr( hdc );
1742 if (!dc) return FALSE;
1744 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1745 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1747 if (ret)
1749 /* convert device units to logical */
1750 for( i = firstChar; i <= lastChar; i++, buffer++ )
1751 *buffer = width_to_LP( dc, *buffer );
1753 release_dc_ptr( dc );
1754 return ret;
1758 /***********************************************************************
1759 * GetCharWidthA (GDI32.@)
1760 * GetCharWidth32A (GDI32.@)
1762 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1763 LPINT buffer )
1765 INT i, wlen;
1766 LPSTR str;
1767 LPWSTR wstr;
1768 BOOL ret = TRUE;
1770 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1771 if(str == NULL)
1772 return FALSE;
1774 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1776 for(i = 0; i < wlen; i++)
1778 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1780 ret = FALSE;
1781 break;
1783 buffer++;
1786 HeapFree(GetProcessHeap(), 0, str);
1787 HeapFree(GetProcessHeap(), 0, wstr);
1789 return ret;
1793 /* helper for nulldrv_ExtTextOut */
1794 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1795 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1797 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1798 UINT indices[3] = {0, 0, 0x20};
1799 unsigned int i;
1800 DWORD ret, size;
1801 int stride;
1803 indices[0] = index;
1804 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1806 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1808 index = indices[i];
1809 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1810 if (ret != GDI_ERROR) break;
1813 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1814 if (!image) return ERROR_SUCCESS;
1816 image->ptr = NULL;
1817 image->free = NULL;
1818 if (!ret) /* empty glyph */
1820 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
1821 return ERROR_SUCCESS;
1824 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1825 size = metrics->gmBlackBoxY * stride;
1827 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1828 image->is_copy = TRUE;
1829 image->free = free_heap_bits;
1831 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1832 if (ret == GDI_ERROR)
1834 HeapFree( GetProcessHeap(), 0, image->ptr );
1835 return ERROR_NOT_FOUND;
1837 return ERROR_SUCCESS;
1840 /* helper for nulldrv_ExtTextOut */
1841 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1842 LPCWSTR str, UINT count, const INT *dx )
1844 UINT i;
1845 RECT rect, bounds;
1847 reset_bounds( &bounds );
1848 for (i = 0; i < count; i++)
1850 GLYPHMETRICS metrics;
1852 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1854 rect.left = x + metrics.gmptGlyphOrigin.x;
1855 rect.top = y - metrics.gmptGlyphOrigin.y;
1856 rect.right = rect.left + metrics.gmBlackBoxX;
1857 rect.bottom = rect.top + metrics.gmBlackBoxY;
1858 add_bounds_rect( &bounds, &rect );
1860 if (dx)
1862 if (flags & ETO_PDY)
1864 x += dx[ i * 2 ];
1865 y += dx[ i * 2 + 1];
1867 else x += dx[ i ];
1869 else
1871 x += metrics.gmCellIncX;
1872 y += metrics.gmCellIncY;
1875 return bounds;
1878 /* helper for nulldrv_ExtTextOut */
1879 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1880 const struct gdi_image_bits *image, const RECT *clip )
1882 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1883 UINT i, count, max_count;
1884 LONG x, y;
1885 BYTE *ptr = image->ptr;
1886 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1887 POINT *pts;
1888 RECT rect, clipped_rect;
1890 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1891 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1892 rect.right = rect.left + metrics->gmBlackBoxX;
1893 rect.bottom = rect.top + metrics->gmBlackBoxY;
1894 if (!clip) clipped_rect = rect;
1895 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1897 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1898 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1899 if (!pts) return;
1901 count = 0;
1902 ptr += (clipped_rect.top - rect.top) * stride;
1903 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1905 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1907 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1908 pts[count].x = rect.left + x;
1909 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1910 pts[count + 1].x = rect.left + x;
1911 if (pts[count + 1].x > pts[count].x)
1913 pts[count].y = pts[count + 1].y = y;
1914 count += 2;
1918 assert( count <= max_count );
1919 DPtoLP( hdc, pts, count );
1920 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1921 HeapFree( GetProcessHeap(), 0, pts );
1924 /***********************************************************************
1925 * nulldrv_ExtTextOut
1927 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1928 LPCWSTR str, UINT count, const INT *dx )
1930 DC *dc = get_nulldrv_dc( dev );
1931 UINT i;
1932 DWORD err;
1933 HGDIOBJ orig;
1934 HPEN pen;
1936 if (flags & ETO_OPAQUE)
1938 RECT rc = *rect;
1939 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1941 if (brush)
1943 orig = SelectObject( dev->hdc, brush );
1944 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1945 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1946 SelectObject( dev->hdc, orig );
1947 DeleteObject( brush );
1951 if (!count) return TRUE;
1953 if (dc->aa_flags != GGO_BITMAP)
1955 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1956 BITMAPINFO *info = (BITMAPINFO *)buffer;
1957 struct gdi_image_bits bits;
1958 struct bitblt_coords src, dst;
1959 PHYSDEV dst_dev;
1960 /* FIXME Subpixel modes */
1961 UINT aa_flags = GGO_GRAY4_BITMAP;
1963 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1964 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1965 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1966 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1968 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1969 src.x = src.visrect.left;
1970 src.y = src.visrect.top;
1971 src.width = src.visrect.right - src.visrect.left;
1972 src.height = src.visrect.bottom - src.visrect.top;
1973 dst = src;
1974 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1975 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1977 /* we can avoid the GetImage, just query the needed format */
1978 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1979 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1980 info->bmiHeader.biWidth = src.width;
1981 info->bmiHeader.biHeight = -src.height;
1982 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1983 if (!err || err == ERROR_BAD_FORMAT)
1985 /* make the source rectangle relative to the source bits */
1986 src.x = src.y = 0;
1987 src.visrect.left = src.visrect.top = 0;
1988 src.visrect.right = src.width;
1989 src.visrect.bottom = src.height;
1991 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1992 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1993 bits.is_copy = TRUE;
1994 bits.free = free_heap_bits;
1995 err = ERROR_SUCCESS;
1998 else
2000 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
2001 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
2002 if (!err && !bits.is_copy)
2004 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
2005 if (!ptr)
2007 if (bits.free) bits.free( &bits );
2008 return ERROR_OUTOFMEMORY;
2010 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
2011 if (bits.free) bits.free( &bits );
2012 bits.ptr = ptr;
2013 bits.is_copy = TRUE;
2014 bits.free = free_heap_bits;
2017 if (!err)
2019 /* make x,y relative to the image bits */
2020 x += src.visrect.left - dst.visrect.left;
2021 y += src.visrect.top - dst.visrect.top;
2022 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
2023 aa_flags, str, count, dx );
2024 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2025 if (bits.free) bits.free( &bits );
2026 return !err;
2030 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
2031 orig = SelectObject( dev->hdc, pen );
2033 for (i = 0; i < count; i++)
2035 GLYPHMETRICS metrics;
2036 struct gdi_image_bits image;
2038 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2039 if (err) continue;
2041 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2042 if (image.free) image.free( &image );
2044 if (dx)
2046 if (flags & ETO_PDY)
2048 x += dx[ i * 2 ];
2049 y += dx[ i * 2 + 1];
2051 else x += dx[ i ];
2053 else
2055 x += metrics.gmCellIncX;
2056 y += metrics.gmCellIncY;
2060 SelectObject( dev->hdc, orig );
2061 DeleteObject( pen );
2062 return TRUE;
2066 /***********************************************************************
2067 * ExtTextOutA (GDI32.@)
2069 * See ExtTextOutW.
2071 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2072 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2074 INT wlen;
2075 UINT codepage;
2076 LPWSTR p;
2077 BOOL ret;
2078 LPINT lpDxW = NULL;
2080 if (flags & ETO_GLYPH_INDEX)
2081 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2083 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2085 if (lpDx) {
2086 unsigned int i = 0, j = 0;
2088 /* allocate enough for a ETO_PDY */
2089 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2090 while(i < count) {
2091 if(IsDBCSLeadByteEx(codepage, str[i]))
2093 if(flags & ETO_PDY)
2095 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2096 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2098 else
2099 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2100 i = i + 2;
2102 else
2104 if(flags & ETO_PDY)
2106 lpDxW[j++] = lpDx[i * 2];
2107 lpDxW[j++] = lpDx[i * 2 + 1];
2109 else
2110 lpDxW[j++] = lpDx[i];
2111 i = i + 1;
2116 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2118 HeapFree( GetProcessHeap(), 0, p );
2119 HeapFree( GetProcessHeap(), 0, lpDxW );
2120 return ret;
2124 /***********************************************************************
2125 * ExtTextOutW (GDI32.@)
2127 * Draws text using the currently selected font, background color, and text color.
2130 * PARAMS
2131 * x,y [I] coordinates of string
2132 * flags [I]
2133 * ETO_GRAYED - undocumented on MSDN
2134 * ETO_OPAQUE - use background color for fill the rectangle
2135 * ETO_CLIPPED - clipping text to the rectangle
2136 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2137 * than encoded characters. Implies ETO_IGNORELANGUAGE
2138 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2139 * Affects BiDi ordering
2140 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2141 * ETO_PDY - unimplemented
2142 * ETO_NUMERICSLATIN - unimplemented always assumed -
2143 * do not translate numbers into locale representations
2144 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2145 * lprect [I] dimensions for clipping or/and opaquing
2146 * str [I] text string
2147 * count [I] number of symbols in string
2148 * lpDx [I] optional parameter with distance between drawing characters
2150 * RETURNS
2151 * Success: TRUE
2152 * Failure: FALSE
2154 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2155 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2157 BOOL ret = FALSE;
2158 LPWSTR reordered_str = (LPWSTR)str;
2159 WORD *glyphs = NULL;
2160 UINT align = GetTextAlign( hdc );
2161 DWORD layout = GetLayout( hdc );
2162 POINT pt;
2163 TEXTMETRICW tm;
2164 LOGFONTW lf;
2165 double cosEsc, sinEsc;
2166 INT char_extra;
2167 SIZE sz;
2168 RECT rc;
2169 POINT *deltas = NULL, width = {0, 0};
2170 DWORD type;
2171 DC * dc = get_dc_ptr( hdc );
2172 PHYSDEV physdev;
2173 INT breakRem;
2174 static int quietfixme = 0;
2176 if (!dc) return FALSE;
2178 breakRem = dc->breakRem;
2180 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2182 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2183 quietfixme = 1;
2186 update_dc( dc );
2187 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2188 type = GetObjectType(hdc);
2189 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2191 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2192 release_dc_ptr( dc );
2193 return ret;
2196 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2197 if (layout & LAYOUT_RTL)
2199 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2200 align ^= TA_RTLREADING;
2203 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2205 INT cGlyphs;
2206 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2208 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2209 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2210 reordered_str, count, NULL, &glyphs, &cGlyphs);
2212 flags |= ETO_IGNORELANGUAGE;
2213 if (glyphs)
2215 flags |= ETO_GLYPH_INDEX;
2216 if (cGlyphs != count)
2217 count = cGlyphs;
2220 else if(flags & ETO_GLYPH_INDEX)
2221 glyphs = reordered_str;
2223 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2224 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2225 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2227 if(align & TA_UPDATECP)
2229 GetCurrentPositionEx( hdc, &pt );
2230 x = pt.x;
2231 y = pt.y;
2234 GetTextMetricsW(hdc, &tm);
2235 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2237 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2238 lf.lfEscapement = 0;
2240 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2241 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2243 lf.lfEscapement = -lf.lfEscapement;
2246 if(lf.lfEscapement != 0)
2248 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2249 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2251 else
2253 cosEsc = 1;
2254 sinEsc = 0;
2257 if (lprect)
2259 rc = *lprect;
2260 LPtoDP(hdc, (POINT*)&rc, 2);
2261 order_rect( &rc );
2262 if (flags & ETO_OPAQUE)
2263 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2265 else flags &= ~ETO_CLIPPED;
2267 if(count == 0)
2269 ret = TRUE;
2270 goto done;
2273 pt.x = x;
2274 pt.y = y;
2275 LPtoDP(hdc, &pt, 1);
2276 x = pt.x;
2277 y = pt.y;
2279 char_extra = GetTextCharacterExtra(hdc);
2280 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2281 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2283 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2285 UINT i;
2286 POINT total = {0, 0}, desired[2];
2288 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2289 if (lpDx)
2291 if (flags & ETO_PDY)
2293 for (i = 0; i < count; i++)
2295 deltas[i].x = lpDx[i * 2] + char_extra;
2296 deltas[i].y = -lpDx[i * 2 + 1];
2299 else
2301 for (i = 0; i < count; i++)
2303 deltas[i].x = lpDx[i] + char_extra;
2304 deltas[i].y = 0;
2308 else
2310 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2312 if (flags & ETO_GLYPH_INDEX)
2313 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2314 else
2315 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2317 deltas[0].x = dx[0];
2318 deltas[0].y = 0;
2319 for (i = 1; i < count; i++)
2321 deltas[i].x = dx[i] - dx[i - 1];
2322 deltas[i].y = 0;
2324 HeapFree( GetProcessHeap(), 0, dx );
2327 for(i = 0; i < count; i++)
2329 total.x += deltas[i].x;
2330 total.y += deltas[i].y;
2332 desired[0].x = desired[0].y = 0;
2334 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2335 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2337 LPtoDP(hdc, desired, 2);
2338 desired[1].x -= desired[0].x;
2339 desired[1].y -= desired[0].y;
2341 if (dc->GraphicsMode == GM_COMPATIBLE)
2343 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2344 desired[1].x = -desired[1].x;
2345 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2346 desired[1].y = -desired[1].y;
2349 deltas[i].x = desired[1].x - width.x;
2350 deltas[i].y = desired[1].y - width.y;
2352 width = desired[1];
2354 flags |= ETO_PDY;
2356 else
2358 POINT desired[2];
2360 if(flags & ETO_GLYPH_INDEX)
2361 GetTextExtentPointI(hdc, glyphs, count, &sz);
2362 else
2363 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2364 desired[0].x = desired[0].y = 0;
2365 desired[1].x = sz.cx;
2366 desired[1].y = 0;
2367 LPtoDP(hdc, desired, 2);
2368 desired[1].x -= desired[0].x;
2369 desired[1].y -= desired[0].y;
2371 if (dc->GraphicsMode == GM_COMPATIBLE)
2373 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2374 desired[1].x = -desired[1].x;
2375 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2376 desired[1].y = -desired[1].y;
2378 width = desired[1];
2381 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2382 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2383 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2385 case TA_LEFT:
2386 if (align & TA_UPDATECP)
2388 pt.x = x + width.x;
2389 pt.y = y + width.y;
2390 DPtoLP(hdc, &pt, 1);
2391 MoveToEx(hdc, pt.x, pt.y, NULL);
2393 break;
2395 case TA_CENTER:
2396 x -= width.x / 2;
2397 y -= width.y / 2;
2398 break;
2400 case TA_RIGHT:
2401 x -= width.x;
2402 y -= width.y;
2403 if (align & TA_UPDATECP)
2405 pt.x = x;
2406 pt.y = y;
2407 DPtoLP(hdc, &pt, 1);
2408 MoveToEx(hdc, pt.x, pt.y, NULL);
2410 break;
2413 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2415 case TA_TOP:
2416 y += tm.tmAscent * cosEsc;
2417 x += tm.tmAscent * sinEsc;
2418 break;
2420 case TA_BOTTOM:
2421 y -= tm.tmDescent * cosEsc;
2422 x -= tm.tmDescent * sinEsc;
2423 break;
2425 case TA_BASELINE:
2426 break;
2429 if (GetBkMode(hdc) != TRANSPARENT)
2431 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2433 if(!(flags & ETO_OPAQUE) || !lprect ||
2434 x < rc.left || x + width.x >= rc.right ||
2435 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2437 RECT text_box;
2438 text_box.left = x;
2439 text_box.right = x + width.x;
2440 text_box.top = y - tm.tmAscent;
2441 text_box.bottom = y + tm.tmDescent;
2443 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2444 if (!is_rect_empty( &text_box ))
2445 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2450 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2451 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2453 done:
2454 HeapFree(GetProcessHeap(), 0, deltas);
2455 if(glyphs != reordered_str)
2456 HeapFree(GetProcessHeap(), 0, glyphs);
2457 if(reordered_str != str)
2458 HeapFree(GetProcessHeap(), 0, reordered_str);
2460 release_dc_ptr( dc );
2462 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2464 int underlinePos, strikeoutPos;
2465 int underlineWidth, strikeoutWidth;
2466 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2467 OUTLINETEXTMETRICW* otm = NULL;
2468 POINT pts[5];
2469 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2470 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2472 hbrush = SelectObject(hdc, hbrush);
2474 if(!size)
2476 underlinePos = 0;
2477 underlineWidth = tm.tmAscent / 20 + 1;
2478 strikeoutPos = tm.tmAscent / 2;
2479 strikeoutWidth = underlineWidth;
2481 else
2483 otm = HeapAlloc(GetProcessHeap(), 0, size);
2484 GetOutlineTextMetricsW(hdc, size, otm);
2485 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2486 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2487 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2488 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2489 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2490 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2491 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2492 HeapFree(GetProcessHeap(), 0, otm);
2496 if (lf.lfUnderline)
2498 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2499 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2500 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2501 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2502 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2503 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2504 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2505 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2506 pts[4].x = pts[0].x;
2507 pts[4].y = pts[0].y;
2508 DPtoLP(hdc, pts, 5);
2509 Polygon(hdc, pts, 5);
2512 if (lf.lfStrikeOut)
2514 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2515 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2516 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2517 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2518 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2519 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2520 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2521 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2522 pts[4].x = pts[0].x;
2523 pts[4].y = pts[0].y;
2524 DPtoLP(hdc, pts, 5);
2525 Polygon(hdc, pts, 5);
2528 SelectObject(hdc, hpen);
2529 hbrush = SelectObject(hdc, hbrush);
2530 DeleteObject(hbrush);
2533 return ret;
2537 /***********************************************************************
2538 * TextOutA (GDI32.@)
2540 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2542 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2546 /***********************************************************************
2547 * TextOutW (GDI32.@)
2549 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2551 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2555 /***********************************************************************
2556 * PolyTextOutA (GDI32.@)
2558 * See PolyTextOutW.
2560 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2562 for (; cStrings>0; cStrings--, pptxt++)
2563 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2564 return FALSE;
2565 return TRUE;
2570 /***********************************************************************
2571 * PolyTextOutW (GDI32.@)
2573 * Draw several Strings
2575 * RETURNS
2576 * TRUE: Success.
2577 * FALSE: Failure.
2579 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2581 for (; cStrings>0; cStrings--, pptxt++)
2582 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2583 return FALSE;
2584 return TRUE;
2588 /***********************************************************************
2589 * SetMapperFlags (GDI32.@)
2591 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2593 DC *dc = get_dc_ptr( hdc );
2594 DWORD ret = GDI_ERROR;
2596 if (dc)
2598 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2599 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2600 if (flags != GDI_ERROR)
2602 ret = dc->mapperFlags;
2603 dc->mapperFlags = flags;
2605 release_dc_ptr( dc );
2607 return ret;
2610 /***********************************************************************
2611 * GetAspectRatioFilterEx (GDI32.@)
2613 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2615 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2616 return FALSE;
2620 /***********************************************************************
2621 * GetCharABCWidthsA (GDI32.@)
2623 * See GetCharABCWidthsW.
2625 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2626 LPABC abc )
2628 INT i, wlen;
2629 LPSTR str;
2630 LPWSTR wstr;
2631 BOOL ret = TRUE;
2633 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2634 if (str == NULL)
2635 return FALSE;
2637 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2638 if (wstr == NULL)
2640 HeapFree(GetProcessHeap(), 0, str);
2641 return FALSE;
2644 for(i = 0; i < wlen; i++)
2646 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2648 ret = FALSE;
2649 break;
2651 abc++;
2654 HeapFree(GetProcessHeap(), 0, str);
2655 HeapFree(GetProcessHeap(), 0, wstr);
2657 return ret;
2661 /******************************************************************************
2662 * GetCharABCWidthsW [GDI32.@]
2664 * Retrieves widths of characters in range.
2666 * PARAMS
2667 * hdc [I] Handle of device context
2668 * firstChar [I] First character in range to query
2669 * lastChar [I] Last character in range to query
2670 * abc [O] Address of character-width structure
2672 * NOTES
2673 * Only works with TrueType fonts
2675 * RETURNS
2676 * Success: TRUE
2677 * Failure: FALSE
2679 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2680 LPABC abc )
2682 DC *dc = get_dc_ptr(hdc);
2683 PHYSDEV dev;
2684 unsigned int i;
2685 BOOL ret;
2686 TEXTMETRICW tm;
2688 if (!dc) return FALSE;
2690 if (!abc)
2692 release_dc_ptr( dc );
2693 return FALSE;
2696 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2697 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2698 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2700 release_dc_ptr( dc );
2701 return FALSE;
2704 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2705 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2706 if (ret)
2708 /* convert device units to logical */
2709 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2710 abc->abcA = width_to_LP(dc, abc->abcA);
2711 abc->abcB = width_to_LP(dc, abc->abcB);
2712 abc->abcC = width_to_LP(dc, abc->abcC);
2716 release_dc_ptr( dc );
2717 return ret;
2721 /******************************************************************************
2722 * GetCharABCWidthsI [GDI32.@]
2724 * Retrieves widths of characters in range.
2726 * PARAMS
2727 * hdc [I] Handle of device context
2728 * firstChar [I] First glyphs in range to query
2729 * count [I] Last glyphs in range to query
2730 * pgi [i] Array of glyphs to query
2731 * abc [O] Address of character-width structure
2733 * NOTES
2734 * Only works with TrueType fonts
2736 * RETURNS
2737 * Success: TRUE
2738 * Failure: FALSE
2740 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2741 LPWORD pgi, LPABC abc)
2743 DC *dc = get_dc_ptr(hdc);
2744 PHYSDEV dev;
2745 unsigned int i;
2746 BOOL ret;
2748 if (!dc) return FALSE;
2750 if (!abc)
2752 release_dc_ptr( dc );
2753 return FALSE;
2756 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2757 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2758 if (ret)
2760 /* convert device units to logical */
2761 for( i = 0; i < count; i++, abc++ ) {
2762 abc->abcA = width_to_LP(dc, abc->abcA);
2763 abc->abcB = width_to_LP(dc, abc->abcB);
2764 abc->abcC = width_to_LP(dc, abc->abcC);
2768 release_dc_ptr( dc );
2769 return ret;
2773 /***********************************************************************
2774 * GetGlyphOutlineA (GDI32.@)
2776 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2777 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2778 LPVOID lpBuffer, const MAT2 *lpmat2 )
2780 if (!lpmat2) return GDI_ERROR;
2782 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2783 UINT cp;
2784 int len;
2785 char mbchs[2];
2787 cp = GdiGetCodePage(hdc);
2788 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2789 len = 2;
2790 mbchs[0] = (uChar & 0xff00) >> 8;
2791 mbchs[1] = (uChar & 0xff);
2792 } else {
2793 len = 1;
2794 mbchs[0] = (uChar & 0xff);
2796 uChar = 0;
2797 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2800 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2801 lpmat2);
2804 /***********************************************************************
2805 * GetGlyphOutlineW (GDI32.@)
2807 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2808 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2809 LPVOID lpBuffer, const MAT2 *lpmat2 )
2811 DC *dc;
2812 DWORD ret;
2813 PHYSDEV dev;
2815 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2816 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2818 if (!lpmat2) return GDI_ERROR;
2820 dc = get_dc_ptr(hdc);
2821 if(!dc) return GDI_ERROR;
2823 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2824 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2825 release_dc_ptr( dc );
2826 return ret;
2830 /***********************************************************************
2831 * CreateScalableFontResourceA (GDI32.@)
2833 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2834 LPCSTR lpszResourceFile,
2835 LPCSTR lpszFontFile,
2836 LPCSTR lpszCurrentPath )
2838 LPWSTR lpszResourceFileW = NULL;
2839 LPWSTR lpszFontFileW = NULL;
2840 LPWSTR lpszCurrentPathW = NULL;
2841 int len;
2842 BOOL ret;
2844 if (lpszResourceFile)
2846 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2847 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2848 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2851 if (lpszFontFile)
2853 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2854 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2855 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2858 if (lpszCurrentPath)
2860 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2861 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2862 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2865 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2866 lpszFontFileW, lpszCurrentPathW);
2868 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2869 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2870 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2872 return ret;
2875 /***********************************************************************
2876 * CreateScalableFontResourceW (GDI32.@)
2878 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2879 LPCWSTR font_file, LPCWSTR font_path )
2881 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2882 debugstr_w(font_file), debugstr_w(font_path) );
2884 return WineEngCreateScalableFontResource( hidden, resource_file,
2885 font_file, font_path );
2888 /*************************************************************************
2889 * GetKerningPairsA (GDI32.@)
2891 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2892 LPKERNINGPAIR kern_pairA )
2894 UINT cp;
2895 CPINFO cpi;
2896 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2897 KERNINGPAIR *kern_pairW;
2899 if (!cPairs && kern_pairA)
2901 SetLastError(ERROR_INVALID_PARAMETER);
2902 return 0;
2905 cp = GdiGetCodePage(hDC);
2907 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2908 * to fail on an invalid character for CP_SYMBOL.
2910 cpi.DefaultChar[0] = 0;
2911 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2913 FIXME("Can't find codepage %u info\n", cp);
2914 return 0;
2917 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2918 if (!total_kern_pairs) return 0;
2920 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2921 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2923 for (i = 0; i < total_kern_pairs; i++)
2925 char first, second;
2927 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2928 continue;
2930 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2931 continue;
2933 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2934 continue;
2936 if (kern_pairA)
2938 if (kern_pairs_copied >= cPairs) break;
2940 kern_pairA->wFirst = (BYTE)first;
2941 kern_pairA->wSecond = (BYTE)second;
2942 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2943 kern_pairA++;
2945 kern_pairs_copied++;
2948 HeapFree(GetProcessHeap(), 0, kern_pairW);
2950 return kern_pairs_copied;
2953 /*************************************************************************
2954 * GetKerningPairsW (GDI32.@)
2956 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2957 LPKERNINGPAIR lpKerningPairs )
2959 DC *dc;
2960 DWORD ret;
2961 PHYSDEV dev;
2963 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2965 if (!cPairs && lpKerningPairs)
2967 SetLastError(ERROR_INVALID_PARAMETER);
2968 return 0;
2971 dc = get_dc_ptr(hDC);
2972 if (!dc) return 0;
2974 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2975 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2976 release_dc_ptr( dc );
2977 return ret;
2980 /*************************************************************************
2981 * TranslateCharsetInfo [GDI32.@]
2983 * Fills a CHARSETINFO structure for a character set, code page, or
2984 * font. This allows making the correspondence between different labels
2985 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2986 * of the same encoding.
2988 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2989 * only one codepage should be set in *lpSrc.
2991 * RETURNS
2992 * TRUE on success, FALSE on failure.
2995 BOOL WINAPI TranslateCharsetInfo(
2996 LPDWORD lpSrc, /* [in]
2997 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2998 if flags == TCI_SRCCHARSET: a character set value
2999 if flags == TCI_SRCCODEPAGE: a code page value
3001 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
3002 DWORD flags /* [in] determines interpretation of lpSrc */)
3004 int index = 0;
3005 switch (flags) {
3006 case TCI_SRCFONTSIG:
3007 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3008 break;
3009 case TCI_SRCCODEPAGE:
3010 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3011 break;
3012 case TCI_SRCCHARSET:
3013 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3014 break;
3015 default:
3016 return FALSE;
3018 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3019 *lpCs = FONT_tci[index];
3020 return TRUE;
3023 /*************************************************************************
3024 * GetFontLanguageInfo (GDI32.@)
3026 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3028 FONTSIGNATURE fontsig;
3029 static const DWORD GCP_DBCS_MASK=FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB,
3030 GCP_DIACRITIC_MASK=0x00000000,
3031 FLI_GLYPHS_MASK=0x00000000,
3032 GCP_GLYPHSHAPE_MASK=FS_ARABIC,
3033 GCP_KASHIDA_MASK=0x00000000,
3034 GCP_LIGATE_MASK=0x00000000,
3035 GCP_USEKERNING_MASK=0x00000000,
3036 GCP_REORDER_MASK=FS_HEBREW|FS_ARABIC;
3038 DWORD result=0;
3040 GetTextCharsetInfo( hdc, &fontsig, 0 );
3041 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3043 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3044 result|=GCP_DBCS;
3046 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3047 result|=GCP_DIACRITIC;
3049 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3050 result|=FLI_GLYPHS;
3052 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3053 result|=GCP_GLYPHSHAPE;
3055 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3056 result|=GCP_KASHIDA;
3058 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3059 result|=GCP_LIGATE;
3061 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3062 result|=GCP_USEKERNING;
3064 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3065 if( GetTextAlign( hdc) & TA_RTLREADING )
3066 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3067 result|=GCP_REORDER;
3069 return result;
3073 /*************************************************************************
3074 * GetFontData [GDI32.@]
3076 * Retrieve data for TrueType font.
3078 * RETURNS
3080 * success: Number of bytes returned
3081 * failure: GDI_ERROR
3083 * NOTES
3085 * Calls SetLastError()
3088 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3089 LPVOID buffer, DWORD length)
3091 DC *dc = get_dc_ptr(hdc);
3092 PHYSDEV dev;
3093 DWORD ret;
3095 if(!dc) return GDI_ERROR;
3097 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3098 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3099 release_dc_ptr( dc );
3100 return ret;
3103 /*************************************************************************
3104 * GetGlyphIndicesA [GDI32.@]
3106 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3107 LPWORD pgi, DWORD flags)
3109 DWORD ret;
3110 WCHAR *lpstrW;
3111 INT countW;
3113 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3114 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3116 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3117 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3118 HeapFree(GetProcessHeap(), 0, lpstrW);
3120 return ret;
3123 /*************************************************************************
3124 * GetGlyphIndicesW [GDI32.@]
3126 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3127 LPWORD pgi, DWORD flags)
3129 DC *dc = get_dc_ptr(hdc);
3130 PHYSDEV dev;
3131 DWORD ret;
3133 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3134 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3136 if(!dc) return GDI_ERROR;
3138 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3139 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3140 release_dc_ptr( dc );
3141 return ret;
3144 /*************************************************************************
3145 * GetCharacterPlacementA [GDI32.@]
3147 * See GetCharacterPlacementW.
3149 * NOTES:
3150 * the web browser control of ie4 calls this with dwFlags=0
3152 DWORD WINAPI
3153 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3154 INT nMaxExtent, GCP_RESULTSA *lpResults,
3155 DWORD dwFlags)
3157 WCHAR *lpStringW;
3158 INT uCountW;
3159 GCP_RESULTSW resultsW;
3160 DWORD ret;
3161 UINT font_cp;
3163 TRACE("%s, %d, %d, 0x%08x\n",
3164 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3166 /* both structs are equal in size */
3167 memcpy(&resultsW, lpResults, sizeof(resultsW));
3169 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3170 if(lpResults->lpOutString)
3171 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3173 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3175 lpResults->nGlyphs = resultsW.nGlyphs;
3176 lpResults->nMaxFit = resultsW.nMaxFit;
3178 if(lpResults->lpOutString) {
3179 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3180 lpResults->lpOutString, uCount, NULL, NULL );
3183 HeapFree(GetProcessHeap(), 0, lpStringW);
3184 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3186 return ret;
3189 /*************************************************************************
3190 * GetCharacterPlacementW [GDI32.@]
3192 * Retrieve information about a string. This includes the width, reordering,
3193 * Glyphing and so on.
3195 * RETURNS
3197 * The width and height of the string if successful, 0 if failed.
3199 * BUGS
3201 * All flags except GCP_REORDER are not yet implemented.
3202 * Reordering is not 100% compliant to the Windows BiDi method.
3203 * Caret positioning is not yet implemented for BiDi.
3204 * Classes are not yet implemented.
3207 DWORD WINAPI
3208 GetCharacterPlacementW(
3209 HDC hdc, /* [in] Device context for which the rendering is to be done */
3210 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3211 INT uCount, /* [in] Number of WORDS in string. */
3212 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3213 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3214 DWORD dwFlags /* [in] Flags specifying how to process the string */
3217 DWORD ret=0;
3218 SIZE size;
3219 UINT i, nSet;
3221 TRACE("%s, %d, %d, 0x%08x\n",
3222 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3224 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3225 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3226 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3227 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3228 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3230 if(dwFlags&(~GCP_REORDER))
3231 FIXME("flags 0x%08x ignored\n", dwFlags);
3232 if(lpResults->lpClass)
3233 FIXME("classes not implemented\n");
3234 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3235 FIXME("Caret positions for complex scripts not implemented\n");
3237 nSet = (UINT)uCount;
3238 if(nSet > lpResults->nGlyphs)
3239 nSet = lpResults->nGlyphs;
3241 /* return number of initialized fields */
3242 lpResults->nGlyphs = nSet;
3244 if((dwFlags&GCP_REORDER)==0 )
3246 /* Treat the case where no special handling was requested in a fastpath way */
3247 /* copy will do if the GCP_REORDER flag is not set */
3248 if(lpResults->lpOutString)
3249 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3251 if(lpResults->lpOrder)
3253 for(i = 0; i < nSet; i++)
3254 lpResults->lpOrder[i] = i;
3257 else
3259 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3260 nSet, lpResults->lpOrder, NULL, NULL );
3263 /* FIXME: Will use the placement chars */
3264 if (lpResults->lpDx)
3266 int c;
3267 for (i = 0; i < nSet; i++)
3269 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3270 lpResults->lpDx[i]= c;
3274 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3276 int pos = 0;
3278 lpResults->lpCaretPos[0] = 0;
3279 for (i = 1; i < nSet; i++)
3280 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3281 lpResults->lpCaretPos[i] = (pos += size.cx);
3284 if(lpResults->lpGlyphs)
3285 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3287 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3288 ret = MAKELONG(size.cx, size.cy);
3290 return ret;
3293 /*************************************************************************
3294 * GetCharABCWidthsFloatA [GDI32.@]
3296 * See GetCharABCWidthsFloatW.
3298 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3300 INT i, wlen;
3301 LPSTR str;
3302 LPWSTR wstr;
3303 BOOL ret = TRUE;
3305 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3306 if (str == NULL)
3307 return FALSE;
3309 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3311 for (i = 0; i < wlen; i++)
3313 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3315 ret = FALSE;
3316 break;
3318 abcf++;
3321 HeapFree( GetProcessHeap(), 0, str );
3322 HeapFree( GetProcessHeap(), 0, wstr );
3324 return ret;
3327 /*************************************************************************
3328 * GetCharABCWidthsFloatW [GDI32.@]
3330 * Retrieves widths of a range of characters.
3332 * PARAMS
3333 * hdc [I] Handle to device context.
3334 * first [I] First character in range to query.
3335 * last [I] Last character in range to query.
3336 * abcf [O] Array of LPABCFLOAT structures.
3338 * RETURNS
3339 * Success: TRUE
3340 * Failure: FALSE
3342 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3344 UINT i;
3345 ABC *abc;
3346 PHYSDEV dev;
3347 BOOL ret = FALSE;
3348 DC *dc = get_dc_ptr( hdc );
3350 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3352 if (!dc) return FALSE;
3354 if (!abcf) goto done;
3355 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3357 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3358 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3359 if (ret)
3361 /* convert device units to logical */
3362 FLOAT scale = fabs( dc->xformVport2World.eM11 );
3363 for (i = first; i <= last; i++, abcf++)
3365 abcf->abcfA = abc[i - first].abcA * scale;
3366 abcf->abcfB = abc[i - first].abcB * scale;
3367 abcf->abcfC = abc[i - first].abcC * scale;
3370 HeapFree( GetProcessHeap(), 0, abc );
3372 done:
3373 release_dc_ptr( dc );
3374 return ret;
3377 /*************************************************************************
3378 * GetCharWidthFloatA [GDI32.@]
3380 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3381 UINT iLastChar, PFLOAT pxBuffer)
3383 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3384 return FALSE;
3387 /*************************************************************************
3388 * GetCharWidthFloatW [GDI32.@]
3390 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3391 UINT iLastChar, PFLOAT pxBuffer)
3393 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3394 return FALSE;
3398 /***********************************************************************
3400 * Font Resource API *
3402 ***********************************************************************/
3404 /***********************************************************************
3405 * AddFontResourceA (GDI32.@)
3407 INT WINAPI AddFontResourceA( LPCSTR str )
3409 return AddFontResourceExA( str, 0, NULL);
3412 /***********************************************************************
3413 * AddFontResourceW (GDI32.@)
3415 INT WINAPI AddFontResourceW( LPCWSTR str )
3417 return AddFontResourceExW(str, 0, NULL);
3421 /***********************************************************************
3422 * AddFontResourceExA (GDI32.@)
3424 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3426 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3427 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3428 INT ret;
3430 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3431 ret = AddFontResourceExW(strW, fl, pdv);
3432 HeapFree(GetProcessHeap(), 0, strW);
3433 return ret;
3436 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3438 HRSRC rsrc = FindResourceW(hModule, name, type);
3439 HGLOBAL hMem = LoadResource(hModule, rsrc);
3440 LPVOID *pMem = LockResource(hMem);
3441 int *num_total = (int *)lParam;
3442 DWORD num_in_res;
3444 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3445 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3447 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3448 return FALSE;
3451 *num_total += num_in_res;
3452 return TRUE;
3455 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3457 HANDLE file, mapping;
3458 void *ptr;
3460 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3461 if (file == INVALID_HANDLE_VALUE) return NULL;
3463 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3465 CloseHandle( file );
3466 return NULL;
3469 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3470 CloseHandle( file );
3471 if (!mapping) return NULL;
3473 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3474 CloseHandle( mapping );
3476 return ptr;
3479 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3481 WORD align, type_id, count;
3482 DWORD res_off;
3484 if (size < rsrc_off + 10) return NULL;
3485 align = *(WORD *)(ptr + rsrc_off);
3486 rsrc_off += 2;
3487 type_id = *(WORD *)(ptr + rsrc_off);
3488 while (type_id && type_id != type)
3490 count = *(WORD *)(ptr + rsrc_off + 2);
3491 rsrc_off += 8 + count * 12;
3492 if (size < rsrc_off + 8) return NULL;
3493 type_id = *(WORD *)(ptr + rsrc_off);
3495 if (!type_id) return NULL;
3496 count = *(WORD *)(ptr + rsrc_off + 2);
3497 if (size < rsrc_off + 8 + count * 12) return NULL;
3498 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3499 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3500 if (size < res_off + *len) return NULL;
3501 return ptr + res_off;
3504 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3506 LARGE_INTEGER size;
3507 BYTE *ptr = map_file( res, &size );
3508 const IMAGE_DOS_HEADER *dos;
3509 const IMAGE_OS2_HEADER *ne;
3510 WORD *fontdir;
3511 char *data;
3512 WCHAR *name = NULL;
3513 DWORD len;
3515 if (!ptr) return NULL;
3517 if (size.u.LowPart < sizeof( *dos )) goto fail;
3518 dos = (const IMAGE_DOS_HEADER *)ptr;
3519 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3520 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3521 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3523 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3524 if (!fontdir) goto fail;
3525 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3527 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3528 if (!data) goto fail;
3529 if (!memchr( data, 0, len )) goto fail;
3531 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3532 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3533 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3535 fail:
3536 UnmapViewOfFile( ptr );
3537 return name;
3540 /***********************************************************************
3541 * AddFontResourceExW (GDI32.@)
3543 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3545 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3546 WCHAR *filename;
3547 BOOL hidden;
3549 if (ret == 0)
3551 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3552 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3553 if (hModule != NULL)
3555 int num_resources = 0;
3556 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3558 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3559 wine_dbgstr_w(str));
3560 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3561 ret = num_resources;
3562 FreeLibrary(hModule);
3564 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3566 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3567 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3568 HeapFree( GetProcessHeap(), 0, filename );
3571 return ret;
3574 /***********************************************************************
3575 * RemoveFontResourceA (GDI32.@)
3577 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3579 return RemoveFontResourceExA(str, 0, 0);
3582 /***********************************************************************
3583 * RemoveFontResourceW (GDI32.@)
3585 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3587 return RemoveFontResourceExW(str, 0, 0);
3590 /***********************************************************************
3591 * AddFontMemResourceEx (GDI32.@)
3593 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3595 HANDLE ret;
3596 DWORD num_fonts;
3598 if (!pbFont || !cbFont || !pcFonts)
3600 SetLastError(ERROR_INVALID_PARAMETER);
3601 return NULL;
3604 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3605 if (ret)
3607 __TRY
3609 *pcFonts = num_fonts;
3611 __EXCEPT_PAGE_FAULT
3613 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3614 RemoveFontMemResourceEx(ret);
3615 ret = 0;
3617 __ENDTRY
3619 return ret;
3622 /***********************************************************************
3623 * RemoveFontMemResourceEx (GDI32.@)
3625 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3627 FIXME("(%p) stub\n", fh);
3628 return TRUE;
3631 /***********************************************************************
3632 * RemoveFontResourceExA (GDI32.@)
3634 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3636 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3637 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3638 INT ret;
3640 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3641 ret = RemoveFontResourceExW(strW, fl, pdv);
3642 HeapFree(GetProcessHeap(), 0, strW);
3643 return ret;
3646 /***********************************************************************
3647 * RemoveFontResourceExW (GDI32.@)
3649 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3651 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3652 WCHAR *filename;
3653 BOOL hidden;
3655 if (ret == 0)
3657 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3658 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3659 if (hModule != NULL)
3661 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3662 FreeLibrary(hModule);
3664 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3666 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3667 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3668 HeapFree( GetProcessHeap(), 0, filename );
3671 return ret;
3674 /***********************************************************************
3675 * GetFontResourceInfoW (GDI32.@)
3677 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3679 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3680 return FALSE;
3683 /***********************************************************************
3684 * GetTextCharset (GDI32.@)
3686 UINT WINAPI GetTextCharset(HDC hdc)
3688 /* MSDN docs say this is equivalent */
3689 return GetTextCharsetInfo(hdc, NULL, 0);
3692 /***********************************************************************
3693 * GetTextCharsetInfo (GDI32.@)
3695 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3697 UINT ret = DEFAULT_CHARSET;
3698 DC *dc = get_dc_ptr(hdc);
3699 PHYSDEV dev;
3701 if (dc)
3703 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3704 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3705 release_dc_ptr( dc );
3708 if (ret == DEFAULT_CHARSET && fs)
3709 memset(fs, 0, sizeof(FONTSIGNATURE));
3710 return ret;
3713 /***********************************************************************
3714 * GdiGetCharDimensions (GDI32.@)
3716 * Gets the average width of the characters in the English alphabet.
3718 * PARAMS
3719 * hdc [I] Handle to the device context to measure on.
3720 * lptm [O] Pointer to memory to store the text metrics into.
3721 * height [O] On exit, the maximum height of characters in the English alphabet.
3723 * RETURNS
3724 * The average width of characters in the English alphabet.
3726 * NOTES
3727 * This function is used by the dialog manager to get the size of a dialog
3728 * unit. It should also be used by other pieces of code that need to know
3729 * the size of a dialog unit in logical units without having access to the
3730 * window handle of the dialog.
3731 * Windows caches the font metrics from this function, but we don't and
3732 * there doesn't appear to be an immediate advantage to do so.
3734 * SEE ALSO
3735 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3737 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3739 SIZE sz;
3740 static const WCHAR alphabet[] = {
3741 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3742 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3743 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3745 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3747 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3749 if (height) *height = sz.cy;
3750 return (sz.cx / 26 + 1) / 2;
3753 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3755 FIXME("(%d): stub\n", fEnableEUDC);
3756 return FALSE;
3759 /***********************************************************************
3760 * GetCharWidthI (GDI32.@)
3762 * Retrieve widths of characters.
3764 * PARAMS
3765 * hdc [I] Handle to a device context.
3766 * first [I] First glyph in range to query.
3767 * count [I] Number of glyph indices to query.
3768 * glyphs [I] Array of glyphs to query.
3769 * buffer [O] Buffer to receive character widths.
3771 * NOTES
3772 * Only works with TrueType fonts.
3774 * RETURNS
3775 * Success: TRUE
3776 * Failure: FALSE
3778 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3780 ABC *abc;
3781 unsigned int i;
3783 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3785 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3786 return FALSE;
3788 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3790 HeapFree(GetProcessHeap(), 0, abc);
3791 return FALSE;
3794 for (i = 0; i < count; i++)
3795 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3797 HeapFree(GetProcessHeap(), 0, abc);
3798 return TRUE;
3801 /***********************************************************************
3802 * GetFontUnicodeRanges (GDI32.@)
3804 * Retrieve a list of supported Unicode characters in a font.
3806 * PARAMS
3807 * hdc [I] Handle to a device context.
3808 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3810 * RETURNS
3811 * Success: Number of bytes written to the buffer pointed to by lpgs.
3812 * Failure: 0
3815 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3817 DWORD ret;
3818 PHYSDEV dev;
3819 DC *dc = get_dc_ptr(hdc);
3821 TRACE("(%p, %p)\n", hdc, lpgs);
3823 if (!dc) return 0;
3825 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3826 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3827 release_dc_ptr(dc);
3828 return ret;
3832 /*************************************************************
3833 * FontIsLinked (GDI32.@)
3835 BOOL WINAPI FontIsLinked(HDC hdc)
3837 DC *dc = get_dc_ptr(hdc);
3838 PHYSDEV dev;
3839 BOOL ret;
3841 if (!dc) return FALSE;
3842 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3843 ret = dev->funcs->pFontIsLinked( dev );
3844 release_dc_ptr(dc);
3845 TRACE("returning %d\n", ret);
3846 return ret;
3849 /*************************************************************
3850 * GdiRealizationInfo (GDI32.@)
3852 * Returns a structure that contains some font information.
3854 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3856 DC *dc = get_dc_ptr(hdc);
3857 PHYSDEV dev;
3858 BOOL ret;
3860 if (!dc) return FALSE;
3861 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3862 ret = dev->funcs->pGdiRealizationInfo( dev, info );
3863 release_dc_ptr(dc);
3864 return ret;