riched20: Implement IsEqual() for ranges.
[wine.git] / dlls / gdi32 / font.c
blob40ba7e72abe65204d2d60b409a2940aef2e89c6f
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_YWSTODS(DC *dc, INT height)
86 POINT pt[2];
87 pt[0].x = pt[0].y = 0;
88 pt[1].x = 0;
89 pt[1].y = height;
90 LPtoDP(dc->hSelf, pt, 2);
91 return pt[1].y - pt[0].y;
94 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
95 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
96 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
97 static BOOL FONT_DeleteObject( HGDIOBJ handle );
99 static const struct gdi_obj_funcs font_funcs =
101 FONT_SelectObject, /* pSelectObject */
102 FONT_GetObjectA, /* pGetObjectA */
103 FONT_GetObjectW, /* pGetObjectW */
104 NULL, /* pUnrealizeObject */
105 FONT_DeleteObject /* pDeleteObject */
108 typedef struct
110 LOGFONTW logfont;
111 } FONTOBJ;
113 struct font_enum
115 LPLOGFONTW lpLogFontParam;
116 FONTENUMPROCW lpEnumFunc;
117 LPARAM lpData;
118 BOOL unicode;
119 HDC hdc;
120 INT retval;
124 * For TranslateCharsetInfo
126 #define MAXTCIINDEX 32
127 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
128 /* ANSI */
129 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
130 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
131 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
132 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
133 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
134 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
135 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
136 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
137 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
138 /* reserved by ANSI */
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
145 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
146 /* ANSI and OEM */
147 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
148 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
149 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
150 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
151 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
152 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
153 /* reserved for alternate ANSI and OEM */
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 /* reserved for system */
163 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
164 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
167 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
169 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
170 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
171 LF_FACESIZE);
172 fontW->lfFaceName[LF_FACESIZE-1] = 0;
175 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
177 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
178 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
179 LF_FACESIZE, NULL, NULL);
180 fontA->lfFaceName[LF_FACESIZE-1] = 0;
183 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
185 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
187 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
188 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
189 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
190 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
191 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
192 fontA->elfStyle[LF_FACESIZE-1] = '\0';
193 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
194 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
195 fontA->elfScript[LF_FACESIZE-1] = '\0';
198 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
200 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
202 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
203 fontW->elfFullName, LF_FULLFACESIZE );
204 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
205 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
206 fontW->elfStyle, LF_FACESIZE );
207 fontW->elfStyle[LF_FACESIZE-1] = '\0';
208 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
209 fontW->elfScript, LF_FACESIZE );
210 fontW->elfScript[LF_FACESIZE-1] = '\0';
213 /***********************************************************************
214 * TEXTMETRIC conversion functions.
216 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
218 ptmA->tmHeight = ptmW->tmHeight;
219 ptmA->tmAscent = ptmW->tmAscent;
220 ptmA->tmDescent = ptmW->tmDescent;
221 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
222 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
223 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
224 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
225 ptmA->tmWeight = ptmW->tmWeight;
226 ptmA->tmOverhang = ptmW->tmOverhang;
227 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
228 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
229 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
230 if (ptmW->tmCharSet == SYMBOL_CHARSET)
232 ptmA->tmFirstChar = 0x1e;
233 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
235 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
237 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
238 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
240 else
242 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
243 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
245 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
246 ptmA->tmBreakChar = ptmW->tmBreakChar;
247 ptmA->tmItalic = ptmW->tmItalic;
248 ptmA->tmUnderlined = ptmW->tmUnderlined;
249 ptmA->tmStruckOut = ptmW->tmStruckOut;
250 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
251 ptmA->tmCharSet = ptmW->tmCharSet;
255 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
257 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
258 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
259 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
260 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
261 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
262 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
265 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
267 WCHAR buf[12];
268 DWORD count = sizeof(buf), type, err;
270 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
271 if (!err)
273 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
274 else *value = atoiW( buf );
276 return err;
279 static UINT get_subpixel_orientation( HKEY key )
281 static const WCHAR smoothing_orientation[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
282 'O','r','i','e','n','t','a','t','i','o','n',0};
283 DWORD orient;
285 /* FIXME: handle vertical orientations even though Windows doesn't */
286 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
288 switch (orient)
290 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
291 return WINE_GGO_HBGR_BITMAP;
292 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
293 return WINE_GGO_HRGB_BITMAP;
295 return GGO_GRAY4_BITMAP;
298 static UINT get_default_smoothing( HKEY key )
300 static const WCHAR smoothing[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
301 static const WCHAR smoothing_type[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
302 DWORD enabled, type;
304 if (get_key_value( key, smoothing, &enabled )) return 0;
305 if (!enabled) return GGO_BITMAP;
307 if (!get_key_value( key, smoothing_type, &type ) && type == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
308 return get_subpixel_orientation( key );
310 return GGO_GRAY4_BITMAP;
313 /* compute positions for text rendering, in device coords */
314 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
316 TEXTMETRICW tm;
317 PHYSDEV dev;
319 size->cx = size->cy = 0;
320 if (!count) return TRUE;
322 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
323 dev->funcs->pGetTextMetrics( dev, &tm );
325 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
326 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
328 if (dc->breakExtra || dc->breakRem)
330 int i, space = 0, rem = dc->breakRem;
332 for (i = 0; i < count; i++)
334 if (str[i] == tm.tmBreakChar)
336 space += dc->breakExtra;
337 if (rem > 0)
339 space++;
340 rem--;
343 dx[i] += space;
346 size->cx = dx[count - 1];
347 size->cy = tm.tmHeight;
348 return TRUE;
351 /* compute positions for text rendering, in device coords */
352 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
354 TEXTMETRICW tm;
355 PHYSDEV dev;
357 size->cx = size->cy = 0;
358 if (!count) return TRUE;
360 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
361 dev->funcs->pGetTextMetrics( dev, &tm );
363 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
364 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
366 if (dc->breakExtra || dc->breakRem)
368 WORD space_index;
369 int i, space = 0, rem = dc->breakRem;
371 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
372 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
374 for (i = 0; i < count; i++)
376 if (indices[i] == space_index)
378 space += dc->breakExtra;
379 if (rem > 0)
381 space++;
382 rem--;
385 dx[i] += space;
388 size->cx = dx[count - 1];
389 size->cy = tm.tmHeight;
390 return TRUE;
393 /***********************************************************************
394 * GdiGetCodePage (GDI32.@)
396 DWORD WINAPI GdiGetCodePage( HDC hdc )
398 UINT cp = CP_ACP;
399 DC *dc = get_dc_ptr( hdc );
401 if (dc)
403 cp = dc->font_code_page;
404 release_dc_ptr( dc );
406 return cp;
409 /***********************************************************************
410 * FONT_mbtowc
412 * Returns a Unicode translation of str using the charset of the
413 * currently selected font in hdc. If count is -1 then str is assumed
414 * to be '\0' terminated, otherwise it contains the number of bytes to
415 * convert. If plenW is non-NULL, on return it will point to the
416 * number of WCHARs that have been written. If pCP is non-NULL, on
417 * return it will point to the codepage used in the conversion. The
418 * caller should free the returned LPWSTR from the process heap
419 * itself.
421 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
423 UINT cp;
424 INT lenW;
425 LPWSTR strW;
427 cp = GdiGetCodePage( hdc );
429 if(count == -1) count = strlen(str);
430 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
431 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
432 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
433 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
434 if(plenW) *plenW = lenW;
435 if(pCP) *pCP = cp;
436 return strW;
439 /***********************************************************************
440 * CreateFontIndirectExA (GDI32.@)
442 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
444 ENUMLOGFONTEXDVW enumexW;
446 if (!penumexA) return 0;
448 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
449 enumexW.elfDesignVector = penumexA->elfDesignVector;
450 return CreateFontIndirectExW( &enumexW );
453 /***********************************************************************
454 * CreateFontIndirectExW (GDI32.@)
456 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
458 HFONT hFont;
459 FONTOBJ *fontPtr;
460 const LOGFONTW *plf;
462 if (!penumex) return 0;
464 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
465 penumex->elfEnumLogfontEx.elfStyle[0] ||
466 penumex->elfEnumLogfontEx.elfScript[0])
468 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
469 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
470 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
471 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
474 plf = &penumex->elfEnumLogfontEx.elfLogFont;
475 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
477 fontPtr->logfont = *plf;
479 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
481 HeapFree( GetProcessHeap(), 0, fontPtr );
482 return 0;
485 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
486 plf->lfHeight, plf->lfWidth,
487 plf->lfEscapement, plf->lfOrientation,
488 plf->lfPitchAndFamily,
489 plf->lfOutPrecision, plf->lfClipPrecision,
490 plf->lfQuality, plf->lfCharSet,
491 debugstr_w(plf->lfFaceName),
492 plf->lfWeight > 400 ? "Bold" : "",
493 plf->lfItalic ? "Italic" : "",
494 plf->lfUnderline ? "Underline" : "", hFont);
496 return hFont;
499 /***********************************************************************
500 * CreateFontIndirectA (GDI32.@)
502 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
504 LOGFONTW lfW;
506 if (!plfA) return 0;
508 FONT_LogFontAToW( plfA, &lfW );
509 return CreateFontIndirectW( &lfW );
512 /***********************************************************************
513 * CreateFontIndirectW (GDI32.@)
515 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
517 ENUMLOGFONTEXDVW exdv;
519 if (!plf) return 0;
521 exdv.elfEnumLogfontEx.elfLogFont = *plf;
522 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
523 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
524 exdv.elfEnumLogfontEx.elfScript[0] = 0;
525 return CreateFontIndirectExW( &exdv );
528 /*************************************************************************
529 * CreateFontA (GDI32.@)
531 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
532 INT orient, INT weight, DWORD italic,
533 DWORD underline, DWORD strikeout, DWORD charset,
534 DWORD outpres, DWORD clippres, DWORD quality,
535 DWORD pitch, LPCSTR name )
537 LOGFONTA logfont;
539 logfont.lfHeight = height;
540 logfont.lfWidth = width;
541 logfont.lfEscapement = esc;
542 logfont.lfOrientation = orient;
543 logfont.lfWeight = weight;
544 logfont.lfItalic = italic;
545 logfont.lfUnderline = underline;
546 logfont.lfStrikeOut = strikeout;
547 logfont.lfCharSet = charset;
548 logfont.lfOutPrecision = outpres;
549 logfont.lfClipPrecision = clippres;
550 logfont.lfQuality = quality;
551 logfont.lfPitchAndFamily = pitch;
553 if (name)
554 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
555 else
556 logfont.lfFaceName[0] = '\0';
558 return CreateFontIndirectA( &logfont );
561 /*************************************************************************
562 * CreateFontW (GDI32.@)
564 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
565 INT orient, INT weight, DWORD italic,
566 DWORD underline, DWORD strikeout, DWORD charset,
567 DWORD outpres, DWORD clippres, DWORD quality,
568 DWORD pitch, LPCWSTR name )
570 LOGFONTW logfont;
572 logfont.lfHeight = height;
573 logfont.lfWidth = width;
574 logfont.lfEscapement = esc;
575 logfont.lfOrientation = orient;
576 logfont.lfWeight = weight;
577 logfont.lfItalic = italic;
578 logfont.lfUnderline = underline;
579 logfont.lfStrikeOut = strikeout;
580 logfont.lfCharSet = charset;
581 logfont.lfOutPrecision = outpres;
582 logfont.lfClipPrecision = clippres;
583 logfont.lfQuality = quality;
584 logfont.lfPitchAndFamily = pitch;
586 if (name)
587 lstrcpynW(logfont.lfFaceName, name,
588 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
589 else
590 logfont.lfFaceName[0] = '\0';
592 return CreateFontIndirectW( &logfont );
595 #define ASSOC_CHARSET_OEM 1
596 #define ASSOC_CHARSET_ANSI 2
597 #define ASSOC_CHARSET_SYMBOL 4
599 static DWORD get_associated_charset_info(void)
601 static DWORD associated_charset = -1;
603 if (associated_charset == -1)
605 static const WCHAR assoc_charset_reg_keyW[] = {'S','y','s','t','e','m','\\',
606 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
607 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
608 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
609 static const WCHAR ansiW[] = {'A','N','S','I','(','0','0',')','\0'};
610 static const WCHAR oemW[] = {'O','E','M','(','F','F',')','\0'};
611 static const WCHAR symbolW[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
612 static const WCHAR yesW[] = {'Y','E','S','\0'};
613 HKEY hkey;
614 WCHAR dataW[32];
615 DWORD type, data_len;
617 associated_charset = 0;
619 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
620 assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS)
621 return 0;
623 data_len = sizeof(dataW);
624 if (!RegQueryValueExW(hkey, ansiW, NULL, &type, (LPBYTE)dataW, &data_len) &&
625 type == REG_SZ && !strcmpiW(dataW, yesW))
626 associated_charset |= ASSOC_CHARSET_ANSI;
628 data_len = sizeof(dataW);
629 if (!RegQueryValueExW(hkey, oemW, NULL, &type, (LPBYTE)dataW, &data_len) &&
630 type == REG_SZ && !strcmpiW(dataW, yesW))
631 associated_charset |= ASSOC_CHARSET_OEM;
633 data_len = sizeof(dataW);
634 if (!RegQueryValueExW(hkey, symbolW, NULL, &type, (LPBYTE)dataW, &data_len) &&
635 type == REG_SZ && !strcmpiW(dataW, yesW))
636 associated_charset |= ASSOC_CHARSET_SYMBOL;
638 RegCloseKey(hkey);
640 TRACE("associated_charset = %d\n", associated_charset);
643 return associated_charset;
646 static void update_font_code_page( DC *dc, HANDLE font )
648 CHARSETINFO csi;
649 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
650 LOGFONTW lf;
652 GetObjectW( font, sizeof(lf), &lf );
654 if (charset == ANSI_CHARSET && !(lf.lfClipPrecision & CLIP_DFA_DISABLE) &&
655 get_associated_charset_info() & ASSOC_CHARSET_ANSI)
656 charset = DEFAULT_CHARSET;
658 /* Hmm, nicely designed api this one! */
659 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
660 dc->font_code_page = csi.ciACP;
661 else {
662 switch(charset) {
663 case OEM_CHARSET:
664 dc->font_code_page = GetOEMCP();
665 break;
666 case DEFAULT_CHARSET:
667 dc->font_code_page = GetACP();
668 break;
670 case VISCII_CHARSET:
671 case TCVN_CHARSET:
672 case KOI8_CHARSET:
673 case ISO3_CHARSET:
674 case ISO4_CHARSET:
675 case ISO10_CHARSET:
676 case CELTIC_CHARSET:
677 /* FIXME: These have no place here, but because x11drv
678 enumerates fonts with these (made up) charsets some apps
679 might use them and then the FIXME below would become
680 annoying. Now we could pick the intended codepage for
681 each of these, but since it's broken anyway we'll just
682 use CP_ACP and hope it'll go away...
684 dc->font_code_page = CP_ACP;
685 break;
687 default:
688 FIXME("Can't find codepage for charset %d\n", charset);
689 dc->font_code_page = CP_ACP;
690 break;
694 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
697 /***********************************************************************
698 * FONT_SelectObject
700 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
702 HGDIOBJ ret = 0;
703 DC *dc = get_dc_ptr( hdc );
704 PHYSDEV physdev;
705 UINT aa_flags = 0;
707 if (!dc) return 0;
709 if (!GDI_inc_ref_count( handle ))
711 release_dc_ptr( dc );
712 return 0;
715 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
716 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
718 ret = dc->hFont;
719 dc->hFont = handle;
720 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
721 update_font_code_page( dc, handle );
722 GDI_dec_ref_count( ret );
724 else GDI_dec_ref_count( handle );
726 release_dc_ptr( dc );
727 return ret;
731 /***********************************************************************
732 * FONT_GetObjectA
734 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
736 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
737 LOGFONTA lfA;
739 if (!font) return 0;
740 if (buffer)
742 FONT_LogFontWToA( &font->logfont, &lfA );
743 if (count > sizeof(lfA)) count = sizeof(lfA);
744 memcpy( buffer, &lfA, count );
746 else count = sizeof(lfA);
747 GDI_ReleaseObj( handle );
748 return count;
751 /***********************************************************************
752 * FONT_GetObjectW
754 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
756 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
758 if (!font) return 0;
759 if (buffer)
761 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
762 memcpy( buffer, &font->logfont, count );
764 else count = sizeof(LOGFONTW);
765 GDI_ReleaseObj( handle );
766 return count;
770 /***********************************************************************
771 * FONT_DeleteObject
773 static BOOL FONT_DeleteObject( HGDIOBJ handle )
775 FONTOBJ *obj;
777 if (!(obj = free_gdi_handle( handle ))) return FALSE;
778 return HeapFree( GetProcessHeap(), 0, obj );
782 /***********************************************************************
783 * nulldrv_SelectFont
785 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
787 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
788 'D','e','s','k','t','o','p',0 };
789 static int orientation = -1, smoothing = -1;
790 LOGFONTW lf;
791 HKEY key;
793 if (*aa_flags) return 0;
795 GetObjectW( font, sizeof(lf), &lf );
796 switch (lf.lfQuality)
798 case NONANTIALIASED_QUALITY:
799 *aa_flags = GGO_BITMAP;
800 break;
801 case ANTIALIASED_QUALITY:
802 *aa_flags = GGO_GRAY4_BITMAP;
803 break;
804 case CLEARTYPE_QUALITY:
805 case CLEARTYPE_NATURAL_QUALITY:
806 if (orientation == -1)
808 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
809 orientation = get_subpixel_orientation( key );
810 RegCloseKey( key );
812 *aa_flags = orientation;
813 break;
814 default:
815 if (smoothing == -1)
817 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
818 smoothing = get_default_smoothing( key );
819 RegCloseKey( key );
821 *aa_flags = smoothing;
822 break;
824 return 0;
828 /***********************************************************************
829 * FONT_EnumInstance
831 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
832 * We have to use other types because of the FONTENUMPROCW definition.
834 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
835 DWORD fType, LPARAM lp )
837 struct font_enum *pfe = (struct font_enum *)lp;
838 INT ret = 1;
840 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
841 if ((!pfe->lpLogFontParam ||
842 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
843 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
844 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
846 /* convert font metrics */
847 ENUMLOGFONTEXA logfont;
848 NEWTEXTMETRICEXA tmA;
850 if (!pfe->unicode)
852 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
853 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
854 plf = (LOGFONTW *)&logfont.elfLogFont;
855 ptm = (TEXTMETRICW *)&tmA;
857 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
858 pfe->retval = ret;
860 return ret;
863 /***********************************************************************
864 * FONT_EnumFontFamiliesEx
866 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
867 LPARAM lParam, BOOL unicode )
869 INT ret = 0;
870 DC *dc = get_dc_ptr( hDC );
871 struct font_enum fe;
873 if (dc)
875 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
877 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
878 fe.lpLogFontParam = plf;
879 fe.lpEnumFunc = efproc;
880 fe.lpData = lParam;
881 fe.unicode = unicode;
882 fe.hdc = hDC;
883 fe.retval = 1;
884 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
885 release_dc_ptr( dc );
887 return ret ? fe.retval : 0;
890 /***********************************************************************
891 * EnumFontFamiliesExW (GDI32.@)
893 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
894 FONTENUMPROCW efproc,
895 LPARAM lParam, DWORD dwFlags )
897 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
900 /***********************************************************************
901 * EnumFontFamiliesExA (GDI32.@)
903 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
904 FONTENUMPROCA efproc,
905 LPARAM lParam, DWORD dwFlags)
907 LOGFONTW lfW, *plfW;
909 if (plf)
911 FONT_LogFontAToW( plf, &lfW );
912 plfW = &lfW;
914 else plfW = NULL;
916 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
919 /***********************************************************************
920 * EnumFontFamiliesA (GDI32.@)
922 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
923 FONTENUMPROCA efproc, LPARAM lpData )
925 LOGFONTA lf, *plf;
927 if (lpFamily)
929 if (!*lpFamily) return 1;
930 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
931 lf.lfCharSet = DEFAULT_CHARSET;
932 lf.lfPitchAndFamily = 0;
933 plf = &lf;
935 else plf = NULL;
937 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
940 /***********************************************************************
941 * EnumFontFamiliesW (GDI32.@)
943 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
944 FONTENUMPROCW efproc, LPARAM lpData )
946 LOGFONTW lf, *plf;
948 if (lpFamily)
950 if (!*lpFamily) return 1;
951 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
952 lf.lfCharSet = DEFAULT_CHARSET;
953 lf.lfPitchAndFamily = 0;
954 plf = &lf;
956 else plf = NULL;
958 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
961 /***********************************************************************
962 * EnumFontsA (GDI32.@)
964 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
965 LPARAM lpData )
967 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
970 /***********************************************************************
971 * EnumFontsW (GDI32.@)
973 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
974 LPARAM lpData )
976 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
980 /***********************************************************************
981 * GetTextCharacterExtra (GDI32.@)
983 INT WINAPI GetTextCharacterExtra( HDC hdc )
985 INT ret;
986 DC *dc = get_dc_ptr( hdc );
987 if (!dc) return 0x80000000;
988 ret = dc->charExtra;
989 release_dc_ptr( dc );
990 return ret;
994 /***********************************************************************
995 * SetTextCharacterExtra (GDI32.@)
997 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
999 INT ret = 0x80000000;
1000 DC * dc = get_dc_ptr( hdc );
1002 if (dc)
1004 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
1005 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
1006 if (extra != 0x80000000)
1008 ret = dc->charExtra;
1009 dc->charExtra = extra;
1011 release_dc_ptr( dc );
1013 return ret;
1017 /***********************************************************************
1018 * SetTextJustification (GDI32.@)
1020 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1022 BOOL ret;
1023 PHYSDEV physdev;
1024 DC * dc = get_dc_ptr( hdc );
1026 if (!dc) return FALSE;
1028 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1029 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1030 if (ret)
1032 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
1033 if (!extra) breaks = 0;
1034 if (breaks)
1036 dc->breakExtra = extra / breaks;
1037 dc->breakRem = extra - (breaks * dc->breakExtra);
1039 else
1041 dc->breakExtra = 0;
1042 dc->breakRem = 0;
1045 release_dc_ptr( dc );
1046 return ret;
1050 /***********************************************************************
1051 * GetTextFaceA (GDI32.@)
1053 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1055 INT res = GetTextFaceW(hdc, 0, NULL);
1056 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1057 GetTextFaceW( hdc, res, nameW );
1059 if (name)
1061 if (count)
1063 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1064 if (res == 0)
1065 res = count;
1066 name[count-1] = 0;
1067 /* GetTextFaceA does NOT include the nul byte in the return count. */
1068 res--;
1070 else
1071 res = 0;
1073 else
1074 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1075 HeapFree( GetProcessHeap(), 0, nameW );
1076 return res;
1079 /***********************************************************************
1080 * GetTextFaceW (GDI32.@)
1082 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1084 PHYSDEV dev;
1085 INT ret;
1087 DC * dc = get_dc_ptr( hdc );
1088 if (!dc) return 0;
1090 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1091 ret = dev->funcs->pGetTextFace( dev, count, name );
1092 release_dc_ptr( dc );
1093 return ret;
1097 /***********************************************************************
1098 * GetTextExtentPoint32A (GDI32.@)
1100 * See GetTextExtentPoint32W.
1102 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1103 LPSIZE size )
1105 BOOL ret = FALSE;
1106 INT wlen;
1107 LPWSTR p;
1109 if (count < 0) return FALSE;
1111 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1113 if (p)
1115 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1116 HeapFree( GetProcessHeap(), 0, p );
1119 TRACE("(%p %s %d %p): returning %d x %d\n",
1120 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1121 return ret;
1125 /***********************************************************************
1126 * GetTextExtentPoint32W [GDI32.@]
1128 * Computes width/height for a string.
1130 * Computes width and height of the specified string.
1132 * RETURNS
1133 * Success: TRUE
1134 * Failure: FALSE
1136 BOOL WINAPI GetTextExtentPoint32W(
1137 HDC hdc, /* [in] Handle of device context */
1138 LPCWSTR str, /* [in] Address of text string */
1139 INT count, /* [in] Number of characters in string */
1140 LPSIZE size) /* [out] Address of structure for string size */
1142 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1145 /***********************************************************************
1146 * GetTextExtentExPointI [GDI32.@]
1148 * Computes width and height of the array of glyph indices.
1150 * PARAMS
1151 * hdc [I] Handle of device context.
1152 * indices [I] Glyph index array.
1153 * count [I] Number of glyphs in array.
1154 * max_ext [I] Maximum width in glyphs.
1155 * nfit [O] Maximum number of characters.
1156 * dxs [O] Partial string widths.
1157 * size [O] Returned string size.
1159 * RETURNS
1160 * Success: TRUE
1161 * Failure: FALSE
1163 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1164 LPINT nfit, LPINT dxs, LPSIZE size )
1166 DC *dc;
1167 int i;
1168 BOOL ret;
1169 INT buffer[256], *pos = dxs;
1171 if (count < 0) return FALSE;
1173 dc = get_dc_ptr( hdc );
1174 if (!dc) return FALSE;
1176 if (!dxs)
1178 pos = buffer;
1179 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1181 release_dc_ptr( dc );
1182 return FALSE;
1186 ret = get_char_positions_indices( dc, indices, count, pos, size );
1187 if (ret)
1189 if (dxs || nfit)
1191 for (i = 0; i < count; i++)
1193 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1194 if (nfit && dx > (unsigned int)max_ext) break;
1195 if (dxs) dxs[i] = dx;
1197 if (nfit) *nfit = i;
1200 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1201 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1204 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1205 release_dc_ptr( dc );
1207 TRACE("(%p %p %d %p): returning %d x %d\n",
1208 hdc, indices, count, size, size->cx, size->cy );
1209 return ret;
1212 /***********************************************************************
1213 * GetTextExtentPointI [GDI32.@]
1215 * Computes width and height of the array of glyph indices.
1217 * PARAMS
1218 * hdc [I] Handle of device context.
1219 * indices [I] Glyph index array.
1220 * count [I] Number of glyphs in array.
1221 * size [O] Returned string size.
1223 * RETURNS
1224 * Success: TRUE
1225 * Failure: FALSE
1227 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1229 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1233 /***********************************************************************
1234 * GetTextExtentPointA (GDI32.@)
1236 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1237 LPSIZE size )
1239 TRACE("not bug compatible.\n");
1240 return GetTextExtentPoint32A( hdc, str, count, size );
1243 /***********************************************************************
1244 * GetTextExtentPointW (GDI32.@)
1246 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1247 LPSIZE size )
1249 TRACE("not bug compatible.\n");
1250 return GetTextExtentPoint32W( hdc, str, count, size );
1254 /***********************************************************************
1255 * GetTextExtentExPointA (GDI32.@)
1257 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1258 INT maxExt, LPINT lpnFit,
1259 LPINT alpDx, LPSIZE size )
1261 BOOL ret;
1262 INT wlen;
1263 INT *walpDx = NULL;
1264 LPWSTR p = NULL;
1266 if (count < 0) return FALSE;
1267 if (maxExt < -1) return FALSE;
1269 if (alpDx)
1271 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1272 if (!walpDx) return FALSE;
1275 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1276 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1277 if (walpDx)
1279 INT n = lpnFit ? *lpnFit : wlen;
1280 INT i, j;
1281 for(i = 0, j = 0; i < n; i++, j++)
1283 alpDx[j] = walpDx[i];
1284 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1287 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1288 HeapFree( GetProcessHeap(), 0, p );
1289 HeapFree( GetProcessHeap(), 0, walpDx );
1290 return ret;
1294 /***********************************************************************
1295 * GetTextExtentExPointW (GDI32.@)
1297 * Return the size of the string as it would be if it was output properly by
1298 * e.g. TextOut.
1300 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1301 LPINT nfit, LPINT dxs, LPSIZE size )
1303 DC *dc;
1304 int i;
1305 BOOL ret;
1306 INT buffer[256], *pos = dxs;
1308 if (count < 0) return FALSE;
1310 dc = get_dc_ptr(hdc);
1311 if (!dc) return FALSE;
1313 if (!dxs)
1315 pos = buffer;
1316 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1318 release_dc_ptr( dc );
1319 return FALSE;
1323 ret = get_char_positions( dc, str, count, pos, size );
1324 if (ret)
1326 if (dxs || nfit)
1328 for (i = 0; i < count; i++)
1330 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1331 if (nfit && dx > (unsigned int)max_ext) break;
1332 if (dxs) dxs[i] = dx;
1334 if (nfit) *nfit = i;
1337 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1338 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1341 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1342 release_dc_ptr( dc );
1344 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1345 return ret;
1348 /***********************************************************************
1349 * GetTextMetricsA (GDI32.@)
1351 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1353 TEXTMETRICW tm32;
1355 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1356 FONT_TextMetricWToA( &tm32, metrics );
1357 return TRUE;
1360 /***********************************************************************
1361 * GetTextMetricsW (GDI32.@)
1363 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1365 PHYSDEV physdev;
1366 BOOL ret = FALSE;
1367 DC * dc = get_dc_ptr( hdc );
1368 if (!dc) return FALSE;
1370 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1371 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1373 if (ret)
1375 /* device layer returns values in device units
1376 * therefore we have to convert them to logical */
1378 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1379 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1380 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
1381 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
1382 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
1383 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
1384 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
1385 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
1386 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
1387 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
1388 ret = TRUE;
1390 TRACE("text metrics:\n"
1391 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1392 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1393 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1394 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1395 " PitchAndFamily = %02x\n"
1396 " --------------------\n"
1397 " InternalLeading = %i\n"
1398 " Ascent = %i\n"
1399 " Descent = %i\n"
1400 " Height = %i\n",
1401 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1402 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1403 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1404 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1405 metrics->tmPitchAndFamily,
1406 metrics->tmInternalLeading,
1407 metrics->tmAscent,
1408 metrics->tmDescent,
1409 metrics->tmHeight );
1411 release_dc_ptr( dc );
1412 return ret;
1416 /***********************************************************************
1417 * GetOutlineTextMetricsA (GDI32.@)
1418 * Gets metrics for TrueType fonts.
1420 * NOTES
1421 * If the supplied buffer isn't big enough Windows partially fills it up to
1422 * its given length and returns that length.
1424 * RETURNS
1425 * Success: Non-zero or size of required buffer
1426 * Failure: 0
1428 UINT WINAPI GetOutlineTextMetricsA(
1429 HDC hdc, /* [in] Handle of device context */
1430 UINT cbData, /* [in] Size of metric data array */
1431 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1433 char buf[512], *ptr;
1434 UINT ret, needed;
1435 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1436 OUTLINETEXTMETRICA *output = lpOTM;
1437 INT left, len;
1439 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1440 return 0;
1441 if(ret > sizeof(buf))
1442 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1443 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1445 needed = sizeof(OUTLINETEXTMETRICA);
1446 if(lpOTMW->otmpFamilyName)
1447 needed += WideCharToMultiByte(CP_ACP, 0,
1448 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1449 NULL, 0, NULL, NULL);
1450 if(lpOTMW->otmpFaceName)
1451 needed += WideCharToMultiByte(CP_ACP, 0,
1452 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1453 NULL, 0, NULL, NULL);
1454 if(lpOTMW->otmpStyleName)
1455 needed += WideCharToMultiByte(CP_ACP, 0,
1456 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1457 NULL, 0, NULL, NULL);
1458 if(lpOTMW->otmpFullName)
1459 needed += WideCharToMultiByte(CP_ACP, 0,
1460 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1461 NULL, 0, NULL, NULL);
1463 if(!lpOTM) {
1464 ret = needed;
1465 goto end;
1468 TRACE("needed = %d\n", needed);
1469 if(needed > cbData)
1470 /* Since the supplied buffer isn't big enough, we'll alloc one
1471 that is and memcpy the first cbData bytes into the lpOTM at
1472 the end. */
1473 output = HeapAlloc(GetProcessHeap(), 0, needed);
1475 ret = output->otmSize = min(needed, cbData);
1476 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1477 output->otmFiller = 0;
1478 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1479 output->otmfsSelection = lpOTMW->otmfsSelection;
1480 output->otmfsType = lpOTMW->otmfsType;
1481 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1482 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1483 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1484 output->otmEMSquare = lpOTMW->otmEMSquare;
1485 output->otmAscent = lpOTMW->otmAscent;
1486 output->otmDescent = lpOTMW->otmDescent;
1487 output->otmLineGap = lpOTMW->otmLineGap;
1488 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1489 output->otmsXHeight = lpOTMW->otmsXHeight;
1490 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1491 output->otmMacAscent = lpOTMW->otmMacAscent;
1492 output->otmMacDescent = lpOTMW->otmMacDescent;
1493 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1494 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1495 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1496 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1497 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1498 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1499 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1500 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1501 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1502 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1505 ptr = (char*)(output + 1);
1506 left = needed - sizeof(*output);
1508 if(lpOTMW->otmpFamilyName) {
1509 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1510 len = WideCharToMultiByte(CP_ACP, 0,
1511 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1512 ptr, left, NULL, NULL);
1513 left -= len;
1514 ptr += len;
1515 } else
1516 output->otmpFamilyName = 0;
1518 if(lpOTMW->otmpFaceName) {
1519 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1520 len = WideCharToMultiByte(CP_ACP, 0,
1521 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1522 ptr, left, NULL, NULL);
1523 left -= len;
1524 ptr += len;
1525 } else
1526 output->otmpFaceName = 0;
1528 if(lpOTMW->otmpStyleName) {
1529 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1530 len = WideCharToMultiByte(CP_ACP, 0,
1531 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1532 ptr, left, NULL, NULL);
1533 left -= len;
1534 ptr += len;
1535 } else
1536 output->otmpStyleName = 0;
1538 if(lpOTMW->otmpFullName) {
1539 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1540 len = WideCharToMultiByte(CP_ACP, 0,
1541 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1542 ptr, left, NULL, NULL);
1543 left -= len;
1544 } else
1545 output->otmpFullName = 0;
1547 assert(left == 0);
1549 if(output != lpOTM) {
1550 memcpy(lpOTM, output, cbData);
1551 HeapFree(GetProcessHeap(), 0, output);
1553 /* check if the string offsets really fit into the provided size */
1554 /* FIXME: should we check string length as well? */
1555 /* make sure that we don't read/write beyond the provided buffer */
1556 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1558 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1559 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1562 /* make sure that we don't read/write beyond the provided buffer */
1563 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1565 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1566 lpOTM->otmpFaceName = 0; /* doesn't fit */
1569 /* make sure that we don't read/write beyond the provided buffer */
1570 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1572 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1573 lpOTM->otmpStyleName = 0; /* doesn't fit */
1576 /* make sure that we don't read/write beyond the provided buffer */
1577 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1579 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1580 lpOTM->otmpFullName = 0; /* doesn't fit */
1584 end:
1585 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1586 HeapFree(GetProcessHeap(), 0, lpOTMW);
1588 return ret;
1592 /***********************************************************************
1593 * GetOutlineTextMetricsW [GDI32.@]
1595 UINT WINAPI GetOutlineTextMetricsW(
1596 HDC hdc, /* [in] Handle of device context */
1597 UINT cbData, /* [in] Size of metric data array */
1598 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1600 DC *dc = get_dc_ptr( hdc );
1601 OUTLINETEXTMETRICW *output = lpOTM;
1602 PHYSDEV dev;
1603 UINT ret;
1605 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1606 if(!dc) return 0;
1608 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1609 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1611 if (lpOTM && ret > cbData)
1613 output = HeapAlloc(GetProcessHeap(), 0, ret);
1614 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1617 if (lpOTM && ret)
1619 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1620 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1621 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
1622 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
1623 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
1624 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
1625 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
1626 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
1627 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
1628 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
1629 output->otmAscent = height_to_LP( dc, output->otmAscent);
1630 output->otmDescent = height_to_LP( dc, output->otmDescent);
1631 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1632 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1633 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1634 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
1635 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
1636 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
1637 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
1638 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
1639 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
1640 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1641 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
1642 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
1643 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
1644 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
1645 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
1646 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
1647 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
1648 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
1649 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1650 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
1651 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
1652 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
1654 if(output != lpOTM)
1656 memcpy(lpOTM, output, cbData);
1657 HeapFree(GetProcessHeap(), 0, output);
1658 ret = cbData;
1661 release_dc_ptr(dc);
1662 return ret;
1665 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1667 INT i, count = lastChar - firstChar + 1;
1668 UINT mbcp;
1669 UINT c;
1670 LPSTR str;
1672 if (count <= 0)
1673 return NULL;
1675 mbcp = GdiGetCodePage(hdc);
1676 switch (mbcp)
1678 case 932:
1679 case 936:
1680 case 949:
1681 case 950:
1682 case 1361:
1683 if (lastChar > 0xffff)
1684 return NULL;
1685 if ((firstChar ^ lastChar) > 0xff)
1686 return NULL;
1687 break;
1688 default:
1689 if (lastChar > 0xff)
1690 return NULL;
1691 mbcp = 0;
1692 break;
1695 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1696 if (str == NULL)
1697 return NULL;
1699 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1701 if (mbcp) {
1702 if (c > 0xff)
1703 str[i++] = (BYTE)(c >> 8);
1704 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1705 str[i] = 0x1f; /* FIXME: use default character */
1706 else
1707 str[i] = (BYTE)c;
1709 else
1710 str[i] = (BYTE)c;
1712 str[i] = '\0';
1714 *pByteLen = i;
1716 return str;
1719 /***********************************************************************
1720 * GetCharWidthW (GDI32.@)
1721 * GetCharWidth32W (GDI32.@)
1723 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1724 LPINT buffer )
1726 UINT i;
1727 BOOL ret;
1728 PHYSDEV dev;
1729 DC * dc = get_dc_ptr( hdc );
1731 if (!dc) return FALSE;
1733 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1734 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1736 if (ret)
1738 /* convert device units to logical */
1739 for( i = firstChar; i <= lastChar; i++, buffer++ )
1740 *buffer = width_to_LP( dc, *buffer );
1742 release_dc_ptr( dc );
1743 return ret;
1747 /***********************************************************************
1748 * GetCharWidthA (GDI32.@)
1749 * GetCharWidth32A (GDI32.@)
1751 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1752 LPINT buffer )
1754 INT i, wlen;
1755 LPSTR str;
1756 LPWSTR wstr;
1757 BOOL ret = TRUE;
1759 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1760 if(str == NULL)
1761 return FALSE;
1763 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1765 for(i = 0; i < wlen; i++)
1767 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1769 ret = FALSE;
1770 break;
1772 buffer++;
1775 HeapFree(GetProcessHeap(), 0, str);
1776 HeapFree(GetProcessHeap(), 0, wstr);
1778 return ret;
1782 /* helper for nulldrv_ExtTextOut */
1783 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1784 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1786 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1787 UINT indices[3] = {0, 0, 0x20};
1788 unsigned int i;
1789 DWORD ret, size;
1790 int stride;
1792 indices[0] = index;
1793 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1795 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1797 index = indices[i];
1798 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1799 if (ret != GDI_ERROR) break;
1802 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1803 if (!image) return ERROR_SUCCESS;
1805 image->ptr = NULL;
1806 image->free = NULL;
1807 if (!ret) /* empty glyph */
1809 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
1810 return ERROR_SUCCESS;
1813 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1814 size = metrics->gmBlackBoxY * stride;
1816 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1817 image->is_copy = TRUE;
1818 image->free = free_heap_bits;
1820 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1821 if (ret == GDI_ERROR)
1823 HeapFree( GetProcessHeap(), 0, image->ptr );
1824 return ERROR_NOT_FOUND;
1826 return ERROR_SUCCESS;
1829 /* helper for nulldrv_ExtTextOut */
1830 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1831 LPCWSTR str, UINT count, const INT *dx )
1833 UINT i;
1834 RECT rect, bounds;
1836 reset_bounds( &bounds );
1837 for (i = 0; i < count; i++)
1839 GLYPHMETRICS metrics;
1841 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1843 rect.left = x + metrics.gmptGlyphOrigin.x;
1844 rect.top = y - metrics.gmptGlyphOrigin.y;
1845 rect.right = rect.left + metrics.gmBlackBoxX;
1846 rect.bottom = rect.top + metrics.gmBlackBoxY;
1847 add_bounds_rect( &bounds, &rect );
1849 if (dx)
1851 if (flags & ETO_PDY)
1853 x += dx[ i * 2 ];
1854 y += dx[ i * 2 + 1];
1856 else x += dx[ i ];
1858 else
1860 x += metrics.gmCellIncX;
1861 y += metrics.gmCellIncY;
1864 return bounds;
1867 /* helper for nulldrv_ExtTextOut */
1868 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1869 const struct gdi_image_bits *image, const RECT *clip )
1871 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1872 UINT i, count, max_count;
1873 LONG x, y;
1874 BYTE *ptr = image->ptr;
1875 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1876 POINT *pts;
1877 RECT rect, clipped_rect;
1879 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1880 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1881 rect.right = rect.left + metrics->gmBlackBoxX;
1882 rect.bottom = rect.top + metrics->gmBlackBoxY;
1883 if (!clip) clipped_rect = rect;
1884 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1886 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1887 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1888 if (!pts) return;
1890 count = 0;
1891 ptr += (clipped_rect.top - rect.top) * stride;
1892 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1894 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1896 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1897 pts[count].x = rect.left + x;
1898 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1899 pts[count + 1].x = rect.left + x;
1900 if (pts[count + 1].x > pts[count].x)
1902 pts[count].y = pts[count + 1].y = y;
1903 count += 2;
1907 assert( count <= max_count );
1908 DPtoLP( hdc, pts, count );
1909 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1910 HeapFree( GetProcessHeap(), 0, pts );
1913 /***********************************************************************
1914 * nulldrv_ExtTextOut
1916 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1917 LPCWSTR str, UINT count, const INT *dx )
1919 DC *dc = get_nulldrv_dc( dev );
1920 UINT i;
1921 DWORD err;
1922 HGDIOBJ orig;
1923 HPEN pen;
1925 if (flags & ETO_OPAQUE)
1927 RECT rc = *rect;
1928 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1930 if (brush)
1932 orig = SelectObject( dev->hdc, brush );
1933 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1934 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1935 SelectObject( dev->hdc, orig );
1936 DeleteObject( brush );
1940 if (!count) return TRUE;
1942 if (dc->aa_flags != GGO_BITMAP)
1944 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1945 BITMAPINFO *info = (BITMAPINFO *)buffer;
1946 struct gdi_image_bits bits;
1947 struct bitblt_coords src, dst;
1948 PHYSDEV dst_dev;
1949 /* FIXME Subpixel modes */
1950 UINT aa_flags = GGO_GRAY4_BITMAP;
1952 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1953 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1954 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1955 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1957 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1958 src.x = src.visrect.left;
1959 src.y = src.visrect.top;
1960 src.width = src.visrect.right - src.visrect.left;
1961 src.height = src.visrect.bottom - src.visrect.top;
1962 dst = src;
1963 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1964 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1966 /* we can avoid the GetImage, just query the needed format */
1967 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1968 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1969 info->bmiHeader.biWidth = src.width;
1970 info->bmiHeader.biHeight = -src.height;
1971 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1972 if (!err || err == ERROR_BAD_FORMAT)
1974 /* make the source rectangle relative to the source bits */
1975 src.x = src.y = 0;
1976 src.visrect.left = src.visrect.top = 0;
1977 src.visrect.right = src.width;
1978 src.visrect.bottom = src.height;
1980 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1981 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1982 bits.is_copy = TRUE;
1983 bits.free = free_heap_bits;
1984 err = ERROR_SUCCESS;
1987 else
1989 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1990 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1991 if (!err && !bits.is_copy)
1993 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1994 if (!ptr)
1996 if (bits.free) bits.free( &bits );
1997 return ERROR_OUTOFMEMORY;
1999 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
2000 if (bits.free) bits.free( &bits );
2001 bits.ptr = ptr;
2002 bits.is_copy = TRUE;
2003 bits.free = free_heap_bits;
2006 if (!err)
2008 /* make x,y relative to the image bits */
2009 x += src.visrect.left - dst.visrect.left;
2010 y += src.visrect.top - dst.visrect.top;
2011 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
2012 aa_flags, str, count, dx );
2013 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2014 if (bits.free) bits.free( &bits );
2015 return !err;
2019 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
2020 orig = SelectObject( dev->hdc, pen );
2022 for (i = 0; i < count; i++)
2024 GLYPHMETRICS metrics;
2025 struct gdi_image_bits image;
2027 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2028 if (err) continue;
2030 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2031 if (image.free) image.free( &image );
2033 if (dx)
2035 if (flags & ETO_PDY)
2037 x += dx[ i * 2 ];
2038 y += dx[ i * 2 + 1];
2040 else x += dx[ i ];
2042 else
2044 x += metrics.gmCellIncX;
2045 y += metrics.gmCellIncY;
2049 SelectObject( dev->hdc, orig );
2050 DeleteObject( pen );
2051 return TRUE;
2055 /***********************************************************************
2056 * ExtTextOutA (GDI32.@)
2058 * See ExtTextOutW.
2060 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2061 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2063 INT wlen;
2064 UINT codepage;
2065 LPWSTR p;
2066 BOOL ret;
2067 LPINT lpDxW = NULL;
2069 if (flags & ETO_GLYPH_INDEX)
2070 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2072 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2074 if (lpDx) {
2075 unsigned int i = 0, j = 0;
2077 /* allocate enough for a ETO_PDY */
2078 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2079 while(i < count) {
2080 if(IsDBCSLeadByteEx(codepage, str[i]))
2082 if(flags & ETO_PDY)
2084 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2085 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2087 else
2088 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2089 i = i + 2;
2091 else
2093 if(flags & ETO_PDY)
2095 lpDxW[j++] = lpDx[i * 2];
2096 lpDxW[j++] = lpDx[i * 2 + 1];
2098 else
2099 lpDxW[j++] = lpDx[i];
2100 i = i + 1;
2105 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2107 HeapFree( GetProcessHeap(), 0, p );
2108 HeapFree( GetProcessHeap(), 0, lpDxW );
2109 return ret;
2112 /***********************************************************************
2113 * get_line_width
2115 * Scale the underline / strikeout line width.
2117 static inline int get_line_width( DC *dc, int metric_size )
2119 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
2120 if (width == 0) width = 1;
2121 if (metric_size < 0) width = -width;
2122 return width;
2125 /***********************************************************************
2126 * ExtTextOutW (GDI32.@)
2128 * Draws text using the currently selected font, background color, and text color.
2131 * PARAMS
2132 * x,y [I] coordinates of string
2133 * flags [I]
2134 * ETO_GRAYED - undocumented on MSDN
2135 * ETO_OPAQUE - use background color for fill the rectangle
2136 * ETO_CLIPPED - clipping text to the rectangle
2137 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2138 * than encoded characters. Implies ETO_IGNORELANGUAGE
2139 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2140 * Affects BiDi ordering
2141 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2142 * ETO_PDY - unimplemented
2143 * ETO_NUMERICSLATIN - unimplemented always assumed -
2144 * do not translate numbers into locale representations
2145 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2146 * lprect [I] dimensions for clipping or/and opaquing
2147 * str [I] text string
2148 * count [I] number of symbols in string
2149 * lpDx [I] optional parameter with distance between drawing characters
2151 * RETURNS
2152 * Success: TRUE
2153 * Failure: FALSE
2155 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2156 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2158 BOOL ret = FALSE;
2159 LPWSTR reordered_str = (LPWSTR)str;
2160 WORD *glyphs = NULL;
2161 UINT align = GetTextAlign( hdc );
2162 DWORD layout = GetLayout( hdc );
2163 POINT pt;
2164 TEXTMETRICW tm;
2165 LOGFONTW lf;
2166 double cosEsc, sinEsc;
2167 INT char_extra;
2168 SIZE sz;
2169 RECT rc;
2170 POINT *deltas = NULL, width = {0, 0};
2171 DWORD type;
2172 DC * dc = get_dc_ptr( hdc );
2173 PHYSDEV physdev;
2174 INT breakRem;
2175 static int quietfixme = 0;
2177 if (!dc) return FALSE;
2179 breakRem = dc->breakRem;
2181 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2183 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2184 quietfixme = 1;
2187 update_dc( dc );
2188 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2189 type = GetObjectType(hdc);
2190 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2192 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2193 release_dc_ptr( dc );
2194 return ret;
2197 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2198 if (layout & LAYOUT_RTL)
2200 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2201 align ^= TA_RTLREADING;
2204 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2206 INT cGlyphs;
2207 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2209 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2210 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2211 reordered_str, count, NULL, &glyphs, &cGlyphs);
2213 flags |= ETO_IGNORELANGUAGE;
2214 if (glyphs)
2216 flags |= ETO_GLYPH_INDEX;
2217 if (cGlyphs != count)
2218 count = cGlyphs;
2221 else if(flags & ETO_GLYPH_INDEX)
2222 glyphs = reordered_str;
2224 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2225 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2226 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2228 if(align & TA_UPDATECP)
2230 GetCurrentPositionEx( hdc, &pt );
2231 x = pt.x;
2232 y = pt.y;
2235 GetTextMetricsW(hdc, &tm);
2236 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2238 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2239 lf.lfEscapement = 0;
2241 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2242 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2244 lf.lfEscapement = -lf.lfEscapement;
2247 if(lf.lfEscapement != 0)
2249 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2250 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2252 else
2254 cosEsc = 1;
2255 sinEsc = 0;
2258 if (lprect)
2260 rc = *lprect;
2261 LPtoDP(hdc, (POINT*)&rc, 2);
2262 order_rect( &rc );
2263 if (flags & ETO_OPAQUE)
2264 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2266 else flags &= ~ETO_CLIPPED;
2268 if(count == 0)
2270 ret = TRUE;
2271 goto done;
2274 pt.x = x;
2275 pt.y = y;
2276 LPtoDP(hdc, &pt, 1);
2277 x = pt.x;
2278 y = pt.y;
2280 char_extra = GetTextCharacterExtra(hdc);
2281 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2282 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2284 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2286 UINT i;
2287 POINT total = {0, 0}, desired[2];
2289 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2290 if (lpDx)
2292 if (flags & ETO_PDY)
2294 for (i = 0; i < count; i++)
2296 deltas[i].x = lpDx[i * 2] + char_extra;
2297 deltas[i].y = -lpDx[i * 2 + 1];
2300 else
2302 for (i = 0; i < count; i++)
2304 deltas[i].x = lpDx[i] + char_extra;
2305 deltas[i].y = 0;
2309 else
2311 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2313 if (flags & ETO_GLYPH_INDEX)
2314 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2315 else
2316 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2318 deltas[0].x = dx[0];
2319 deltas[0].y = 0;
2320 for (i = 1; i < count; i++)
2322 deltas[i].x = dx[i] - dx[i - 1];
2323 deltas[i].y = 0;
2325 HeapFree( GetProcessHeap(), 0, dx );
2328 for(i = 0; i < count; i++)
2330 total.x += deltas[i].x;
2331 total.y += deltas[i].y;
2333 desired[0].x = desired[0].y = 0;
2335 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2336 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2338 LPtoDP(hdc, desired, 2);
2339 desired[1].x -= desired[0].x;
2340 desired[1].y -= desired[0].y;
2342 if (dc->GraphicsMode == GM_COMPATIBLE)
2344 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2345 desired[1].x = -desired[1].x;
2346 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2347 desired[1].y = -desired[1].y;
2350 deltas[i].x = desired[1].x - width.x;
2351 deltas[i].y = desired[1].y - width.y;
2353 width = desired[1];
2355 flags |= ETO_PDY;
2357 else
2359 POINT desired[2];
2361 if(flags & ETO_GLYPH_INDEX)
2362 GetTextExtentPointI(hdc, glyphs, count, &sz);
2363 else
2364 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2365 desired[0].x = desired[0].y = 0;
2366 desired[1].x = sz.cx;
2367 desired[1].y = 0;
2368 LPtoDP(hdc, desired, 2);
2369 desired[1].x -= desired[0].x;
2370 desired[1].y -= desired[0].y;
2372 if (dc->GraphicsMode == GM_COMPATIBLE)
2374 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2375 desired[1].x = -desired[1].x;
2376 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2377 desired[1].y = -desired[1].y;
2379 width = desired[1];
2382 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2383 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2384 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2386 case TA_LEFT:
2387 if (align & TA_UPDATECP)
2389 pt.x = x + width.x;
2390 pt.y = y + width.y;
2391 DPtoLP(hdc, &pt, 1);
2392 MoveToEx(hdc, pt.x, pt.y, NULL);
2394 break;
2396 case TA_CENTER:
2397 x -= width.x / 2;
2398 y -= width.y / 2;
2399 break;
2401 case TA_RIGHT:
2402 x -= width.x;
2403 y -= width.y;
2404 if (align & TA_UPDATECP)
2406 pt.x = x;
2407 pt.y = y;
2408 DPtoLP(hdc, &pt, 1);
2409 MoveToEx(hdc, pt.x, pt.y, NULL);
2411 break;
2414 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2416 case TA_TOP:
2417 y += tm.tmAscent * cosEsc;
2418 x += tm.tmAscent * sinEsc;
2419 break;
2421 case TA_BOTTOM:
2422 y -= tm.tmDescent * cosEsc;
2423 x -= tm.tmDescent * sinEsc;
2424 break;
2426 case TA_BASELINE:
2427 break;
2430 if (GetBkMode(hdc) != TRANSPARENT)
2432 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2434 if(!(flags & ETO_OPAQUE) || !lprect ||
2435 x < rc.left || x + width.x >= rc.right ||
2436 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2438 RECT text_box;
2439 text_box.left = x;
2440 text_box.right = x + width.x;
2441 text_box.top = y - tm.tmAscent;
2442 text_box.bottom = y + tm.tmDescent;
2444 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2445 if (!is_rect_empty( &text_box ))
2446 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2451 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2452 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2454 done:
2455 HeapFree(GetProcessHeap(), 0, deltas);
2456 if(glyphs != reordered_str)
2457 HeapFree(GetProcessHeap(), 0, glyphs);
2458 if(reordered_str != str)
2459 HeapFree(GetProcessHeap(), 0, reordered_str);
2461 release_dc_ptr( dc );
2463 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2465 int underlinePos, strikeoutPos;
2466 int underlineWidth, strikeoutWidth;
2467 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2468 OUTLINETEXTMETRICW* otm = NULL;
2469 POINT pts[5];
2470 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2471 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2473 hbrush = SelectObject(hdc, hbrush);
2475 if(!size)
2477 underlinePos = 0;
2478 underlineWidth = tm.tmAscent / 20 + 1;
2479 strikeoutPos = tm.tmAscent / 2;
2480 strikeoutWidth = underlineWidth;
2482 else
2484 otm = HeapAlloc(GetProcessHeap(), 0, size);
2485 GetOutlineTextMetricsW(hdc, size, otm);
2486 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2487 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2488 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
2489 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2490 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2491 strikeoutWidth = get_line_width( 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;