msvcrt: Don't define type_info structures as const so we can set demangled class...
[wine.git] / dlls / gdi32 / font.c
blob3b3f0b50516c7c7df6bda8285228316be948d266
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 lp_to_dp(dc, 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 * get_text_charset_info
412 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
414 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
416 UINT ret = DEFAULT_CHARSET;
417 PHYSDEV dev;
419 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
420 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
422 if (ret == DEFAULT_CHARSET && fs)
423 memset(fs, 0, sizeof(FONTSIGNATURE));
424 return ret;
427 /***********************************************************************
428 * GetTextCharsetInfo (GDI32.@)
430 UINT WINAPI GetTextCharsetInfo(HDC hdc, FONTSIGNATURE *fs, DWORD flags)
432 UINT ret = DEFAULT_CHARSET;
433 DC *dc = get_dc_ptr(hdc);
435 if (dc)
437 ret = get_text_charset_info( dc, fs, flags );
438 release_dc_ptr( dc );
440 return ret;
443 /***********************************************************************
444 * FONT_mbtowc
446 * Returns a Unicode translation of str using the charset of the
447 * currently selected font in hdc. If count is -1 then str is assumed
448 * to be '\0' terminated, otherwise it contains the number of bytes to
449 * convert. If plenW is non-NULL, on return it will point to the
450 * number of WCHARs that have been written. If pCP is non-NULL, on
451 * return it will point to the codepage used in the conversion. The
452 * caller should free the returned LPWSTR from the process heap
453 * itself.
455 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
457 UINT cp;
458 INT lenW;
459 LPWSTR strW;
461 cp = GdiGetCodePage( hdc );
463 if(count == -1) count = strlen(str);
464 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
465 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
466 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
467 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
468 if(plenW) *plenW = lenW;
469 if(pCP) *pCP = cp;
470 return strW;
473 /***********************************************************************
474 * CreateFontIndirectExA (GDI32.@)
476 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
478 ENUMLOGFONTEXDVW enumexW;
480 if (!penumexA) return 0;
482 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
483 enumexW.elfDesignVector = penumexA->elfDesignVector;
484 return CreateFontIndirectExW( &enumexW );
487 /***********************************************************************
488 * CreateFontIndirectExW (GDI32.@)
490 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
492 HFONT hFont;
493 FONTOBJ *fontPtr;
494 const LOGFONTW *plf;
496 if (!penumex) return 0;
498 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
499 penumex->elfEnumLogfontEx.elfStyle[0] ||
500 penumex->elfEnumLogfontEx.elfScript[0])
502 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
503 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
504 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
505 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
508 plf = &penumex->elfEnumLogfontEx.elfLogFont;
509 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
511 fontPtr->logfont = *plf;
513 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
515 HeapFree( GetProcessHeap(), 0, fontPtr );
516 return 0;
519 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
520 plf->lfHeight, plf->lfWidth,
521 plf->lfEscapement, plf->lfOrientation,
522 plf->lfPitchAndFamily,
523 plf->lfOutPrecision, plf->lfClipPrecision,
524 plf->lfQuality, plf->lfCharSet,
525 debugstr_w(plf->lfFaceName),
526 plf->lfWeight > 400 ? "Bold" : "",
527 plf->lfItalic ? "Italic" : "",
528 plf->lfUnderline ? "Underline" : "", hFont);
530 return hFont;
533 /***********************************************************************
534 * CreateFontIndirectA (GDI32.@)
536 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
538 LOGFONTW lfW;
540 if (!plfA) return 0;
542 FONT_LogFontAToW( plfA, &lfW );
543 return CreateFontIndirectW( &lfW );
546 /***********************************************************************
547 * CreateFontIndirectW (GDI32.@)
549 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
551 ENUMLOGFONTEXDVW exdv;
553 if (!plf) return 0;
555 exdv.elfEnumLogfontEx.elfLogFont = *plf;
556 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
557 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
558 exdv.elfEnumLogfontEx.elfScript[0] = 0;
559 return CreateFontIndirectExW( &exdv );
562 /*************************************************************************
563 * CreateFontA (GDI32.@)
565 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
566 INT orient, INT weight, DWORD italic,
567 DWORD underline, DWORD strikeout, DWORD charset,
568 DWORD outpres, DWORD clippres, DWORD quality,
569 DWORD pitch, LPCSTR name )
571 LOGFONTA logfont;
573 logfont.lfHeight = height;
574 logfont.lfWidth = width;
575 logfont.lfEscapement = esc;
576 logfont.lfOrientation = orient;
577 logfont.lfWeight = weight;
578 logfont.lfItalic = italic;
579 logfont.lfUnderline = underline;
580 logfont.lfStrikeOut = strikeout;
581 logfont.lfCharSet = charset;
582 logfont.lfOutPrecision = outpres;
583 logfont.lfClipPrecision = clippres;
584 logfont.lfQuality = quality;
585 logfont.lfPitchAndFamily = pitch;
587 if (name)
588 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
589 else
590 logfont.lfFaceName[0] = '\0';
592 return CreateFontIndirectA( &logfont );
595 /*************************************************************************
596 * CreateFontW (GDI32.@)
598 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
599 INT orient, INT weight, DWORD italic,
600 DWORD underline, DWORD strikeout, DWORD charset,
601 DWORD outpres, DWORD clippres, DWORD quality,
602 DWORD pitch, LPCWSTR name )
604 LOGFONTW logfont;
606 logfont.lfHeight = height;
607 logfont.lfWidth = width;
608 logfont.lfEscapement = esc;
609 logfont.lfOrientation = orient;
610 logfont.lfWeight = weight;
611 logfont.lfItalic = italic;
612 logfont.lfUnderline = underline;
613 logfont.lfStrikeOut = strikeout;
614 logfont.lfCharSet = charset;
615 logfont.lfOutPrecision = outpres;
616 logfont.lfClipPrecision = clippres;
617 logfont.lfQuality = quality;
618 logfont.lfPitchAndFamily = pitch;
620 if (name)
621 lstrcpynW(logfont.lfFaceName, name,
622 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
623 else
624 logfont.lfFaceName[0] = '\0';
626 return CreateFontIndirectW( &logfont );
629 #define ASSOC_CHARSET_OEM 1
630 #define ASSOC_CHARSET_ANSI 2
631 #define ASSOC_CHARSET_SYMBOL 4
633 static DWORD get_associated_charset_info(void)
635 static DWORD associated_charset = -1;
637 if (associated_charset == -1)
639 static const WCHAR assoc_charset_reg_keyW[] = {'S','y','s','t','e','m','\\',
640 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
641 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
642 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
643 static const WCHAR ansiW[] = {'A','N','S','I','(','0','0',')','\0'};
644 static const WCHAR oemW[] = {'O','E','M','(','F','F',')','\0'};
645 static const WCHAR symbolW[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
646 static const WCHAR yesW[] = {'Y','E','S','\0'};
647 HKEY hkey;
648 WCHAR dataW[32];
649 DWORD type, data_len;
651 associated_charset = 0;
653 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
654 assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS)
655 return 0;
657 data_len = sizeof(dataW);
658 if (!RegQueryValueExW(hkey, ansiW, NULL, &type, (LPBYTE)dataW, &data_len) &&
659 type == REG_SZ && !strcmpiW(dataW, yesW))
660 associated_charset |= ASSOC_CHARSET_ANSI;
662 data_len = sizeof(dataW);
663 if (!RegQueryValueExW(hkey, oemW, NULL, &type, (LPBYTE)dataW, &data_len) &&
664 type == REG_SZ && !strcmpiW(dataW, yesW))
665 associated_charset |= ASSOC_CHARSET_OEM;
667 data_len = sizeof(dataW);
668 if (!RegQueryValueExW(hkey, symbolW, NULL, &type, (LPBYTE)dataW, &data_len) &&
669 type == REG_SZ && !strcmpiW(dataW, yesW))
670 associated_charset |= ASSOC_CHARSET_SYMBOL;
672 RegCloseKey(hkey);
674 TRACE("associated_charset = %d\n", associated_charset);
677 return associated_charset;
680 static void update_font_code_page( DC *dc, HANDLE font )
682 CHARSETINFO csi;
683 int charset = get_text_charset_info( dc, NULL, 0 );
685 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
687 LOGFONTW lf;
689 GetObjectW( font, sizeof(lf), &lf );
690 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
691 charset = DEFAULT_CHARSET;
694 /* Hmm, nicely designed api this one! */
695 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
696 dc->font_code_page = csi.ciACP;
697 else {
698 switch(charset) {
699 case OEM_CHARSET:
700 dc->font_code_page = GetOEMCP();
701 break;
702 case DEFAULT_CHARSET:
703 dc->font_code_page = GetACP();
704 break;
706 case VISCII_CHARSET:
707 case TCVN_CHARSET:
708 case KOI8_CHARSET:
709 case ISO3_CHARSET:
710 case ISO4_CHARSET:
711 case ISO10_CHARSET:
712 case CELTIC_CHARSET:
713 /* FIXME: These have no place here, but because x11drv
714 enumerates fonts with these (made up) charsets some apps
715 might use them and then the FIXME below would become
716 annoying. Now we could pick the intended codepage for
717 each of these, but since it's broken anyway we'll just
718 use CP_ACP and hope it'll go away...
720 dc->font_code_page = CP_ACP;
721 break;
723 default:
724 FIXME("Can't find codepage for charset %d\n", charset);
725 dc->font_code_page = CP_ACP;
726 break;
730 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
733 /***********************************************************************
734 * FONT_SelectObject
736 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
738 HGDIOBJ ret = 0;
739 DC *dc = get_dc_ptr( hdc );
740 PHYSDEV physdev;
741 UINT aa_flags = 0;
743 if (!dc) return 0;
745 if (!GDI_inc_ref_count( handle ))
747 release_dc_ptr( dc );
748 return 0;
751 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
752 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
754 ret = dc->hFont;
755 dc->hFont = handle;
756 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
757 update_font_code_page( dc, handle );
758 GDI_dec_ref_count( ret );
760 else GDI_dec_ref_count( handle );
762 release_dc_ptr( dc );
763 return ret;
767 /***********************************************************************
768 * FONT_GetObjectA
770 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
772 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
773 LOGFONTA lfA;
775 if (!font) return 0;
776 if (buffer)
778 FONT_LogFontWToA( &font->logfont, &lfA );
779 if (count > sizeof(lfA)) count = sizeof(lfA);
780 memcpy( buffer, &lfA, count );
782 else count = sizeof(lfA);
783 GDI_ReleaseObj( handle );
784 return count;
787 /***********************************************************************
788 * FONT_GetObjectW
790 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
792 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
794 if (!font) return 0;
795 if (buffer)
797 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
798 memcpy( buffer, &font->logfont, count );
800 else count = sizeof(LOGFONTW);
801 GDI_ReleaseObj( handle );
802 return count;
806 /***********************************************************************
807 * FONT_DeleteObject
809 static BOOL FONT_DeleteObject( HGDIOBJ handle )
811 FONTOBJ *obj;
813 if (!(obj = free_gdi_handle( handle ))) return FALSE;
814 return HeapFree( GetProcessHeap(), 0, obj );
818 /***********************************************************************
819 * nulldrv_SelectFont
821 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
823 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
824 'D','e','s','k','t','o','p',0 };
825 static int orientation = -1, smoothing = -1;
826 LOGFONTW lf;
827 HKEY key;
829 if (*aa_flags) return 0;
831 GetObjectW( font, sizeof(lf), &lf );
832 switch (lf.lfQuality)
834 case NONANTIALIASED_QUALITY:
835 *aa_flags = GGO_BITMAP;
836 break;
837 case ANTIALIASED_QUALITY:
838 *aa_flags = GGO_GRAY4_BITMAP;
839 break;
840 case CLEARTYPE_QUALITY:
841 case CLEARTYPE_NATURAL_QUALITY:
842 if (orientation == -1)
844 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
845 orientation = get_subpixel_orientation( key );
846 RegCloseKey( key );
848 *aa_flags = orientation;
849 break;
850 default:
851 if (smoothing == -1)
853 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
854 smoothing = get_default_smoothing( key );
855 RegCloseKey( key );
857 *aa_flags = smoothing;
858 break;
860 return 0;
864 /***********************************************************************
865 * FONT_EnumInstance
867 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
868 * We have to use other types because of the FONTENUMPROCW definition.
870 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
871 DWORD fType, LPARAM lp )
873 struct font_enum *pfe = (struct font_enum *)lp;
874 INT ret = 1;
876 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
877 if ((!pfe->lpLogFontParam ||
878 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
879 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
880 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
882 /* convert font metrics */
883 ENUMLOGFONTEXA logfont;
884 NEWTEXTMETRICEXA tmA;
886 if (!pfe->unicode)
888 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
889 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
890 plf = (LOGFONTW *)&logfont.elfLogFont;
891 ptm = (TEXTMETRICW *)&tmA;
893 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
894 pfe->retval = ret;
896 return ret;
899 /***********************************************************************
900 * FONT_EnumFontFamiliesEx
902 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
903 LPARAM lParam, BOOL unicode )
905 INT ret = 0;
906 DC *dc = get_dc_ptr( hDC );
907 struct font_enum fe;
909 if (dc)
911 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
913 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
914 fe.lpLogFontParam = plf;
915 fe.lpEnumFunc = efproc;
916 fe.lpData = lParam;
917 fe.unicode = unicode;
918 fe.hdc = hDC;
919 fe.retval = 1;
920 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
921 release_dc_ptr( dc );
923 return ret ? fe.retval : 0;
926 /***********************************************************************
927 * EnumFontFamiliesExW (GDI32.@)
929 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
930 FONTENUMPROCW efproc,
931 LPARAM lParam, DWORD dwFlags )
933 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
936 /***********************************************************************
937 * EnumFontFamiliesExA (GDI32.@)
939 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
940 FONTENUMPROCA efproc,
941 LPARAM lParam, DWORD dwFlags)
943 LOGFONTW lfW, *plfW;
945 if (plf)
947 FONT_LogFontAToW( plf, &lfW );
948 plfW = &lfW;
950 else plfW = NULL;
952 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
955 /***********************************************************************
956 * EnumFontFamiliesA (GDI32.@)
958 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
959 FONTENUMPROCA efproc, LPARAM lpData )
961 LOGFONTA lf, *plf;
963 if (lpFamily)
965 if (!*lpFamily) return 1;
966 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
967 lf.lfCharSet = DEFAULT_CHARSET;
968 lf.lfPitchAndFamily = 0;
969 plf = &lf;
971 else plf = NULL;
973 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
976 /***********************************************************************
977 * EnumFontFamiliesW (GDI32.@)
979 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
980 FONTENUMPROCW efproc, LPARAM lpData )
982 LOGFONTW lf, *plf;
984 if (lpFamily)
986 if (!*lpFamily) return 1;
987 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
988 lf.lfCharSet = DEFAULT_CHARSET;
989 lf.lfPitchAndFamily = 0;
990 plf = &lf;
992 else plf = NULL;
994 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
997 /***********************************************************************
998 * EnumFontsA (GDI32.@)
1000 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
1001 LPARAM lpData )
1003 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
1006 /***********************************************************************
1007 * EnumFontsW (GDI32.@)
1009 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
1010 LPARAM lpData )
1012 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
1016 /***********************************************************************
1017 * GetTextCharacterExtra (GDI32.@)
1019 INT WINAPI GetTextCharacterExtra( HDC hdc )
1021 INT ret;
1022 DC *dc = get_dc_ptr( hdc );
1023 if (!dc) return 0x80000000;
1024 ret = dc->charExtra;
1025 release_dc_ptr( dc );
1026 return ret;
1030 /***********************************************************************
1031 * SetTextCharacterExtra (GDI32.@)
1033 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
1035 INT ret = 0x80000000;
1036 DC * dc = get_dc_ptr( hdc );
1038 if (dc)
1040 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
1041 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
1042 if (extra != 0x80000000)
1044 ret = dc->charExtra;
1045 dc->charExtra = extra;
1047 release_dc_ptr( dc );
1049 return ret;
1053 /***********************************************************************
1054 * SetTextJustification (GDI32.@)
1056 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1058 BOOL ret;
1059 PHYSDEV physdev;
1060 DC * dc = get_dc_ptr( hdc );
1062 if (!dc) return FALSE;
1064 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1065 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1066 if (ret)
1068 extra = abs((extra * dc->vport_ext.cx + dc->wnd_ext.cx / 2) / dc->wnd_ext.cx);
1069 if (!extra) breaks = 0;
1070 if (breaks)
1072 dc->breakExtra = extra / breaks;
1073 dc->breakRem = extra - (breaks * dc->breakExtra);
1075 else
1077 dc->breakExtra = 0;
1078 dc->breakRem = 0;
1081 release_dc_ptr( dc );
1082 return ret;
1086 /***********************************************************************
1087 * GetTextFaceA (GDI32.@)
1089 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1091 INT res = GetTextFaceW(hdc, 0, NULL);
1092 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1093 GetTextFaceW( hdc, res, nameW );
1095 if (name)
1097 if (count)
1099 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1100 if (res == 0)
1101 res = count;
1102 name[count-1] = 0;
1103 /* GetTextFaceA does NOT include the nul byte in the return count. */
1104 res--;
1106 else
1107 res = 0;
1109 else
1110 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1111 HeapFree( GetProcessHeap(), 0, nameW );
1112 return res;
1115 /***********************************************************************
1116 * GetTextFaceW (GDI32.@)
1118 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1120 PHYSDEV dev;
1121 INT ret;
1123 DC * dc = get_dc_ptr( hdc );
1124 if (!dc) return 0;
1126 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1127 ret = dev->funcs->pGetTextFace( dev, count, name );
1128 release_dc_ptr( dc );
1129 return ret;
1133 /***********************************************************************
1134 * GetTextExtentPoint32A (GDI32.@)
1136 * See GetTextExtentPoint32W.
1138 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1139 LPSIZE size )
1141 BOOL ret = FALSE;
1142 INT wlen;
1143 LPWSTR p;
1145 if (count < 0) return FALSE;
1147 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1149 if (p)
1151 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1152 HeapFree( GetProcessHeap(), 0, p );
1155 TRACE("(%p %s %d %p): returning %d x %d\n",
1156 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1157 return ret;
1161 /***********************************************************************
1162 * GetTextExtentPoint32W [GDI32.@]
1164 * Computes width/height for a string.
1166 * Computes width and height of the specified string.
1168 * RETURNS
1169 * Success: TRUE
1170 * Failure: FALSE
1172 BOOL WINAPI GetTextExtentPoint32W(
1173 HDC hdc, /* [in] Handle of device context */
1174 LPCWSTR str, /* [in] Address of text string */
1175 INT count, /* [in] Number of characters in string */
1176 LPSIZE size) /* [out] Address of structure for string size */
1178 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1181 /***********************************************************************
1182 * GetTextExtentExPointI [GDI32.@]
1184 * Computes width and height of the array of glyph indices.
1186 * PARAMS
1187 * hdc [I] Handle of device context.
1188 * indices [I] Glyph index array.
1189 * count [I] Number of glyphs in array.
1190 * max_ext [I] Maximum width in glyphs.
1191 * nfit [O] Maximum number of characters.
1192 * dxs [O] Partial string widths.
1193 * size [O] Returned string size.
1195 * RETURNS
1196 * Success: TRUE
1197 * Failure: FALSE
1199 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1200 LPINT nfit, LPINT dxs, LPSIZE size )
1202 DC *dc;
1203 int i;
1204 BOOL ret;
1205 INT buffer[256], *pos = dxs;
1207 if (count < 0) return FALSE;
1209 dc = get_dc_ptr( hdc );
1210 if (!dc) return FALSE;
1212 if (!dxs)
1214 pos = buffer;
1215 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1217 release_dc_ptr( dc );
1218 return FALSE;
1222 ret = get_char_positions_indices( dc, indices, count, pos, size );
1223 if (ret)
1225 if (dxs || nfit)
1227 for (i = 0; i < count; i++)
1229 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1230 if (nfit && dx > (unsigned int)max_ext) break;
1231 if (dxs) dxs[i] = dx;
1233 if (nfit) *nfit = i;
1236 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1237 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1240 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1241 release_dc_ptr( dc );
1243 TRACE("(%p %p %d %p): returning %d x %d\n",
1244 hdc, indices, count, size, size->cx, size->cy );
1245 return ret;
1248 /***********************************************************************
1249 * GetTextExtentPointI [GDI32.@]
1251 * Computes width and height of the array of glyph indices.
1253 * PARAMS
1254 * hdc [I] Handle of device context.
1255 * indices [I] Glyph index array.
1256 * count [I] Number of glyphs in array.
1257 * size [O] Returned string size.
1259 * RETURNS
1260 * Success: TRUE
1261 * Failure: FALSE
1263 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1265 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1269 /***********************************************************************
1270 * GetTextExtentPointA (GDI32.@)
1272 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1273 LPSIZE size )
1275 TRACE("not bug compatible.\n");
1276 return GetTextExtentPoint32A( hdc, str, count, size );
1279 /***********************************************************************
1280 * GetTextExtentPointW (GDI32.@)
1282 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1283 LPSIZE size )
1285 TRACE("not bug compatible.\n");
1286 return GetTextExtentPoint32W( hdc, str, count, size );
1290 /***********************************************************************
1291 * GetTextExtentExPointA (GDI32.@)
1293 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1294 INT maxExt, LPINT lpnFit,
1295 LPINT alpDx, LPSIZE size )
1297 BOOL ret;
1298 INT wlen;
1299 INT *walpDx = NULL;
1300 LPWSTR p = NULL;
1302 if (count < 0) return FALSE;
1303 if (maxExt < -1) return FALSE;
1305 if (alpDx)
1307 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1308 if (!walpDx) return FALSE;
1311 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1312 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1313 if (walpDx)
1315 INT n = lpnFit ? *lpnFit : wlen;
1316 INT i, j;
1317 for(i = 0, j = 0; i < n; i++, j++)
1319 alpDx[j] = walpDx[i];
1320 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1323 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1324 HeapFree( GetProcessHeap(), 0, p );
1325 HeapFree( GetProcessHeap(), 0, walpDx );
1326 return ret;
1330 /***********************************************************************
1331 * GetTextExtentExPointW (GDI32.@)
1333 * Return the size of the string as it would be if it was output properly by
1334 * e.g. TextOut.
1336 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1337 LPINT nfit, LPINT dxs, LPSIZE size )
1339 DC *dc;
1340 int i;
1341 BOOL ret;
1342 INT buffer[256], *pos = dxs;
1344 if (count < 0) return FALSE;
1346 dc = get_dc_ptr(hdc);
1347 if (!dc) return FALSE;
1349 if (!dxs)
1351 pos = buffer;
1352 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1354 release_dc_ptr( dc );
1355 return FALSE;
1359 ret = get_char_positions( dc, str, count, pos, size );
1360 if (ret)
1362 if (dxs || nfit)
1364 for (i = 0; i < count; i++)
1366 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1367 if (nfit && dx > (unsigned int)max_ext) break;
1368 if (dxs) dxs[i] = dx;
1370 if (nfit) *nfit = i;
1373 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1374 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1377 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1378 release_dc_ptr( dc );
1380 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1381 return ret;
1384 /***********************************************************************
1385 * GetTextMetricsA (GDI32.@)
1387 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1389 TEXTMETRICW tm32;
1391 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1392 FONT_TextMetricWToA( &tm32, metrics );
1393 return TRUE;
1396 /***********************************************************************
1397 * GetTextMetricsW (GDI32.@)
1399 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1401 PHYSDEV physdev;
1402 BOOL ret = FALSE;
1403 DC * dc = get_dc_ptr( hdc );
1404 if (!dc) return FALSE;
1406 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1407 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1409 if (ret)
1411 /* device layer returns values in device units
1412 * therefore we have to convert them to logical */
1414 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1415 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1416 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
1417 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
1418 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
1419 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
1420 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
1421 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
1422 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
1423 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
1424 ret = TRUE;
1426 TRACE("text metrics:\n"
1427 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1428 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1429 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1430 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1431 " PitchAndFamily = %02x\n"
1432 " --------------------\n"
1433 " InternalLeading = %i\n"
1434 " Ascent = %i\n"
1435 " Descent = %i\n"
1436 " Height = %i\n",
1437 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1438 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1439 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1440 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1441 metrics->tmPitchAndFamily,
1442 metrics->tmInternalLeading,
1443 metrics->tmAscent,
1444 metrics->tmDescent,
1445 metrics->tmHeight );
1447 release_dc_ptr( dc );
1448 return ret;
1452 /***********************************************************************
1453 * GetOutlineTextMetricsA (GDI32.@)
1454 * Gets metrics for TrueType fonts.
1456 * NOTES
1457 * If the supplied buffer isn't big enough Windows partially fills it up to
1458 * its given length and returns that length.
1460 * RETURNS
1461 * Success: Non-zero or size of required buffer
1462 * Failure: 0
1464 UINT WINAPI GetOutlineTextMetricsA(
1465 HDC hdc, /* [in] Handle of device context */
1466 UINT cbData, /* [in] Size of metric data array */
1467 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1469 char buf[512], *ptr;
1470 UINT ret, needed;
1471 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1472 OUTLINETEXTMETRICA *output = lpOTM;
1473 INT left, len;
1475 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1476 return 0;
1477 if(ret > sizeof(buf))
1478 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1479 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1481 needed = sizeof(OUTLINETEXTMETRICA);
1482 if(lpOTMW->otmpFamilyName)
1483 needed += WideCharToMultiByte(CP_ACP, 0,
1484 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1485 NULL, 0, NULL, NULL);
1486 if(lpOTMW->otmpFaceName)
1487 needed += WideCharToMultiByte(CP_ACP, 0,
1488 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1489 NULL, 0, NULL, NULL);
1490 if(lpOTMW->otmpStyleName)
1491 needed += WideCharToMultiByte(CP_ACP, 0,
1492 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1493 NULL, 0, NULL, NULL);
1494 if(lpOTMW->otmpFullName)
1495 needed += WideCharToMultiByte(CP_ACP, 0,
1496 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1497 NULL, 0, NULL, NULL);
1499 if(!lpOTM) {
1500 ret = needed;
1501 goto end;
1504 TRACE("needed = %d\n", needed);
1505 if(needed > cbData)
1506 /* Since the supplied buffer isn't big enough, we'll alloc one
1507 that is and memcpy the first cbData bytes into the lpOTM at
1508 the end. */
1509 output = HeapAlloc(GetProcessHeap(), 0, needed);
1511 ret = output->otmSize = min(needed, cbData);
1512 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1513 output->otmFiller = 0;
1514 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1515 output->otmfsSelection = lpOTMW->otmfsSelection;
1516 output->otmfsType = lpOTMW->otmfsType;
1517 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1518 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1519 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1520 output->otmEMSquare = lpOTMW->otmEMSquare;
1521 output->otmAscent = lpOTMW->otmAscent;
1522 output->otmDescent = lpOTMW->otmDescent;
1523 output->otmLineGap = lpOTMW->otmLineGap;
1524 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1525 output->otmsXHeight = lpOTMW->otmsXHeight;
1526 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1527 output->otmMacAscent = lpOTMW->otmMacAscent;
1528 output->otmMacDescent = lpOTMW->otmMacDescent;
1529 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1530 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1531 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1532 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1533 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1534 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1535 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1536 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1537 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1538 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1541 ptr = (char*)(output + 1);
1542 left = needed - sizeof(*output);
1544 if(lpOTMW->otmpFamilyName) {
1545 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1546 len = WideCharToMultiByte(CP_ACP, 0,
1547 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1548 ptr, left, NULL, NULL);
1549 left -= len;
1550 ptr += len;
1551 } else
1552 output->otmpFamilyName = 0;
1554 if(lpOTMW->otmpFaceName) {
1555 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1556 len = WideCharToMultiByte(CP_ACP, 0,
1557 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1558 ptr, left, NULL, NULL);
1559 left -= len;
1560 ptr += len;
1561 } else
1562 output->otmpFaceName = 0;
1564 if(lpOTMW->otmpStyleName) {
1565 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1566 len = WideCharToMultiByte(CP_ACP, 0,
1567 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1568 ptr, left, NULL, NULL);
1569 left -= len;
1570 ptr += len;
1571 } else
1572 output->otmpStyleName = 0;
1574 if(lpOTMW->otmpFullName) {
1575 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1576 len = WideCharToMultiByte(CP_ACP, 0,
1577 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1578 ptr, left, NULL, NULL);
1579 left -= len;
1580 } else
1581 output->otmpFullName = 0;
1583 assert(left == 0);
1585 if(output != lpOTM) {
1586 memcpy(lpOTM, output, cbData);
1587 HeapFree(GetProcessHeap(), 0, output);
1589 /* check if the string offsets really fit into the provided size */
1590 /* FIXME: should we check string length as well? */
1591 /* make sure that we don't read/write beyond the provided buffer */
1592 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1594 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1595 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1598 /* make sure that we don't read/write beyond the provided buffer */
1599 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1601 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1602 lpOTM->otmpFaceName = 0; /* doesn't fit */
1605 /* make sure that we don't read/write beyond the provided buffer */
1606 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1608 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1609 lpOTM->otmpStyleName = 0; /* doesn't fit */
1612 /* make sure that we don't read/write beyond the provided buffer */
1613 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1615 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1616 lpOTM->otmpFullName = 0; /* doesn't fit */
1620 end:
1621 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1622 HeapFree(GetProcessHeap(), 0, lpOTMW);
1624 return ret;
1628 /***********************************************************************
1629 * GetOutlineTextMetricsW [GDI32.@]
1631 UINT WINAPI GetOutlineTextMetricsW(
1632 HDC hdc, /* [in] Handle of device context */
1633 UINT cbData, /* [in] Size of metric data array */
1634 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1636 DC *dc = get_dc_ptr( hdc );
1637 OUTLINETEXTMETRICW *output = lpOTM;
1638 PHYSDEV dev;
1639 UINT ret;
1641 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1642 if(!dc) return 0;
1644 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1645 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1647 if (lpOTM && ret > cbData)
1649 output = HeapAlloc(GetProcessHeap(), 0, ret);
1650 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1653 if (lpOTM && ret)
1655 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1656 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1657 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
1658 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
1659 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
1660 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
1661 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
1662 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
1663 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
1664 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
1665 output->otmAscent = height_to_LP( dc, output->otmAscent);
1666 output->otmDescent = height_to_LP( dc, output->otmDescent);
1667 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1668 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1669 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1670 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
1671 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
1672 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
1673 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
1674 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
1675 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
1676 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1677 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
1678 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
1679 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
1680 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
1681 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
1682 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
1683 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
1684 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
1685 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1686 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
1687 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
1688 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
1690 if(output != lpOTM)
1692 memcpy(lpOTM, output, cbData);
1693 HeapFree(GetProcessHeap(), 0, output);
1694 ret = cbData;
1697 release_dc_ptr(dc);
1698 return ret;
1701 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1703 INT i, count = lastChar - firstChar + 1;
1704 UINT mbcp;
1705 UINT c;
1706 LPSTR str;
1708 if (count <= 0)
1709 return NULL;
1711 mbcp = GdiGetCodePage(hdc);
1712 switch (mbcp)
1714 case 932:
1715 case 936:
1716 case 949:
1717 case 950:
1718 case 1361:
1719 if (lastChar > 0xffff)
1720 return NULL;
1721 if ((firstChar ^ lastChar) > 0xff)
1722 return NULL;
1723 break;
1724 default:
1725 if (lastChar > 0xff)
1726 return NULL;
1727 mbcp = 0;
1728 break;
1731 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1732 if (str == NULL)
1733 return NULL;
1735 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1737 if (mbcp) {
1738 if (c > 0xff)
1739 str[i++] = (BYTE)(c >> 8);
1740 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1741 str[i] = 0x1f; /* FIXME: use default character */
1742 else
1743 str[i] = (BYTE)c;
1745 else
1746 str[i] = (BYTE)c;
1748 str[i] = '\0';
1750 *pByteLen = i;
1752 return str;
1755 /***********************************************************************
1756 * GetCharWidthW (GDI32.@)
1757 * GetCharWidth32W (GDI32.@)
1759 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1760 LPINT buffer )
1762 UINT i;
1763 BOOL ret;
1764 PHYSDEV dev;
1765 DC * dc = get_dc_ptr( hdc );
1767 if (!dc) return FALSE;
1769 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1770 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1772 if (ret)
1774 /* convert device units to logical */
1775 for( i = firstChar; i <= lastChar; i++, buffer++ )
1776 *buffer = width_to_LP( dc, *buffer );
1778 release_dc_ptr( dc );
1779 return ret;
1783 /***********************************************************************
1784 * GetCharWidthA (GDI32.@)
1785 * GetCharWidth32A (GDI32.@)
1787 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1788 LPINT buffer )
1790 INT i, wlen;
1791 LPSTR str;
1792 LPWSTR wstr;
1793 BOOL ret = TRUE;
1795 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1796 if(str == NULL)
1797 return FALSE;
1799 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1801 for(i = 0; i < wlen; i++)
1803 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1805 ret = FALSE;
1806 break;
1808 buffer++;
1811 HeapFree(GetProcessHeap(), 0, str);
1812 HeapFree(GetProcessHeap(), 0, wstr);
1814 return ret;
1818 /* helper for nulldrv_ExtTextOut */
1819 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1820 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1822 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1823 UINT indices[3] = {0, 0, 0x20};
1824 unsigned int i;
1825 DWORD ret, size;
1826 int stride;
1828 indices[0] = index;
1829 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1831 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1833 index = indices[i];
1834 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1835 if (ret != GDI_ERROR) break;
1838 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1839 if (!image) return ERROR_SUCCESS;
1841 image->ptr = NULL;
1842 image->free = NULL;
1843 if (!ret) /* empty glyph */
1845 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
1846 return ERROR_SUCCESS;
1849 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1850 size = metrics->gmBlackBoxY * stride;
1852 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1853 image->is_copy = TRUE;
1854 image->free = free_heap_bits;
1856 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1857 if (ret == GDI_ERROR)
1859 HeapFree( GetProcessHeap(), 0, image->ptr );
1860 return ERROR_NOT_FOUND;
1862 return ERROR_SUCCESS;
1865 /* helper for nulldrv_ExtTextOut */
1866 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1867 LPCWSTR str, UINT count, const INT *dx )
1869 UINT i;
1870 RECT rect, bounds;
1872 reset_bounds( &bounds );
1873 for (i = 0; i < count; i++)
1875 GLYPHMETRICS metrics;
1877 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1879 rect.left = x + metrics.gmptGlyphOrigin.x;
1880 rect.top = y - metrics.gmptGlyphOrigin.y;
1881 rect.right = rect.left + metrics.gmBlackBoxX;
1882 rect.bottom = rect.top + metrics.gmBlackBoxY;
1883 add_bounds_rect( &bounds, &rect );
1885 if (dx)
1887 if (flags & ETO_PDY)
1889 x += dx[ i * 2 ];
1890 y += dx[ i * 2 + 1];
1892 else x += dx[ i ];
1894 else
1896 x += metrics.gmCellIncX;
1897 y += metrics.gmCellIncY;
1900 return bounds;
1903 /* helper for nulldrv_ExtTextOut */
1904 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1905 const struct gdi_image_bits *image, const RECT *clip )
1907 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1908 UINT i, count, max_count;
1909 LONG x, y;
1910 BYTE *ptr = image->ptr;
1911 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1912 POINT *pts;
1913 RECT rect, clipped_rect;
1915 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1916 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1917 rect.right = rect.left + metrics->gmBlackBoxX;
1918 rect.bottom = rect.top + metrics->gmBlackBoxY;
1919 if (!clip) clipped_rect = rect;
1920 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1922 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1923 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1924 if (!pts) return;
1926 count = 0;
1927 ptr += (clipped_rect.top - rect.top) * stride;
1928 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1930 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1932 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1933 pts[count].x = rect.left + x;
1934 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1935 pts[count + 1].x = rect.left + x;
1936 if (pts[count + 1].x > pts[count].x)
1938 pts[count].y = pts[count + 1].y = y;
1939 count += 2;
1943 assert( count <= max_count );
1944 dp_to_lp( dc, pts, count );
1945 for (i = 0; i < count; i += 2) Polyline( dc->hSelf, pts + i, 2 );
1946 HeapFree( GetProcessHeap(), 0, pts );
1949 /***********************************************************************
1950 * nulldrv_ExtTextOut
1952 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1953 LPCWSTR str, UINT count, const INT *dx )
1955 DC *dc = get_nulldrv_dc( dev );
1956 UINT i;
1957 DWORD err;
1958 HGDIOBJ orig;
1959 HPEN pen;
1961 if (flags & ETO_OPAQUE)
1963 RECT rc = *rect;
1964 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, dc->backgroundColor ) );
1966 if (brush)
1968 orig = SelectObject( dev->hdc, brush );
1969 dp_to_lp( dc, (POINT *)&rc, 2 );
1970 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1971 SelectObject( dev->hdc, orig );
1972 DeleteObject( brush );
1976 if (!count) return TRUE;
1978 if (dc->aa_flags != GGO_BITMAP)
1980 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1981 BITMAPINFO *info = (BITMAPINFO *)buffer;
1982 struct gdi_image_bits bits;
1983 struct bitblt_coords src, dst;
1984 PHYSDEV dst_dev;
1985 /* FIXME Subpixel modes */
1986 UINT aa_flags = GGO_GRAY4_BITMAP;
1988 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1989 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1990 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1991 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1993 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1994 src.x = src.visrect.left;
1995 src.y = src.visrect.top;
1996 src.width = src.visrect.right - src.visrect.left;
1997 src.height = src.visrect.bottom - src.visrect.top;
1998 dst = src;
1999 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
2000 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
2002 /* we can avoid the GetImage, just query the needed format */
2003 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
2004 info->bmiHeader.biSize = sizeof(info->bmiHeader);
2005 info->bmiHeader.biWidth = src.width;
2006 info->bmiHeader.biHeight = -src.height;
2007 info->bmiHeader.biSizeImage = get_dib_image_size( info );
2008 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
2009 if (!err || err == ERROR_BAD_FORMAT)
2011 /* make the source rectangle relative to the source bits */
2012 src.x = src.y = 0;
2013 src.visrect.left = src.visrect.top = 0;
2014 src.visrect.right = src.width;
2015 src.visrect.bottom = src.height;
2017 bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
2018 if (!bits.ptr) return ERROR_OUTOFMEMORY;
2019 bits.is_copy = TRUE;
2020 bits.free = free_heap_bits;
2021 err = ERROR_SUCCESS;
2024 else
2026 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
2027 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
2028 if (!err && !bits.is_copy)
2030 void *ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
2031 if (!ptr)
2033 if (bits.free) bits.free( &bits );
2034 return ERROR_OUTOFMEMORY;
2036 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
2037 if (bits.free) bits.free( &bits );
2038 bits.ptr = ptr;
2039 bits.is_copy = TRUE;
2040 bits.free = free_heap_bits;
2043 if (!err)
2045 /* make x,y relative to the image bits */
2046 x += src.visrect.left - dst.visrect.left;
2047 y += src.visrect.top - dst.visrect.top;
2048 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
2049 aa_flags, str, count, dx );
2050 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2051 if (bits.free) bits.free( &bits );
2052 return !err;
2056 pen = CreatePen( PS_SOLID, 1, dc->textColor );
2057 orig = SelectObject( dev->hdc, pen );
2059 for (i = 0; i < count; i++)
2061 GLYPHMETRICS metrics;
2062 struct gdi_image_bits image;
2064 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2065 if (err) continue;
2067 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2068 if (image.free) image.free( &image );
2070 if (dx)
2072 if (flags & ETO_PDY)
2074 x += dx[ i * 2 ];
2075 y += dx[ i * 2 + 1];
2077 else x += dx[ i ];
2079 else
2081 x += metrics.gmCellIncX;
2082 y += metrics.gmCellIncY;
2086 SelectObject( dev->hdc, orig );
2087 DeleteObject( pen );
2088 return TRUE;
2092 /***********************************************************************
2093 * ExtTextOutA (GDI32.@)
2095 * See ExtTextOutW.
2097 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2098 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2100 INT wlen;
2101 UINT codepage;
2102 LPWSTR p;
2103 BOOL ret;
2104 LPINT lpDxW = NULL;
2106 if (flags & ETO_GLYPH_INDEX)
2107 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2109 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2111 if (lpDx) {
2112 unsigned int i = 0, j = 0;
2114 /* allocate enough for a ETO_PDY */
2115 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2116 while(i < count) {
2117 if(IsDBCSLeadByteEx(codepage, str[i]))
2119 if(flags & ETO_PDY)
2121 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2122 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2124 else
2125 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2126 i = i + 2;
2128 else
2130 if(flags & ETO_PDY)
2132 lpDxW[j++] = lpDx[i * 2];
2133 lpDxW[j++] = lpDx[i * 2 + 1];
2135 else
2136 lpDxW[j++] = lpDx[i];
2137 i = i + 1;
2142 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2144 HeapFree( GetProcessHeap(), 0, p );
2145 HeapFree( GetProcessHeap(), 0, lpDxW );
2146 return ret;
2149 /***********************************************************************
2150 * get_line_width
2152 * Scale the underline / strikeout line width.
2154 static inline int get_line_width( DC *dc, int metric_size )
2156 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
2157 if (width == 0) width = 1;
2158 if (metric_size < 0) width = -width;
2159 return width;
2162 /***********************************************************************
2163 * ExtTextOutW (GDI32.@)
2165 * Draws text using the currently selected font, background color, and text color.
2168 * PARAMS
2169 * x,y [I] coordinates of string
2170 * flags [I]
2171 * ETO_GRAYED - undocumented on MSDN
2172 * ETO_OPAQUE - use background color for fill the rectangle
2173 * ETO_CLIPPED - clipping text to the rectangle
2174 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2175 * than encoded characters. Implies ETO_IGNORELANGUAGE
2176 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2177 * Affects BiDi ordering
2178 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2179 * ETO_PDY - unimplemented
2180 * ETO_NUMERICSLATIN - unimplemented always assumed -
2181 * do not translate numbers into locale representations
2182 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2183 * lprect [I] dimensions for clipping or/and opaquing
2184 * str [I] text string
2185 * count [I] number of symbols in string
2186 * lpDx [I] optional parameter with distance between drawing characters
2188 * RETURNS
2189 * Success: TRUE
2190 * Failure: FALSE
2192 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2193 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2195 BOOL ret = FALSE;
2196 LPWSTR reordered_str = (LPWSTR)str;
2197 WORD *glyphs = NULL;
2198 UINT align;
2199 DWORD layout;
2200 POINT pt;
2201 TEXTMETRICW tm;
2202 LOGFONTW lf;
2203 double cosEsc, sinEsc;
2204 INT char_extra;
2205 SIZE sz;
2206 RECT rc;
2207 POINT *deltas = NULL, width = {0, 0};
2208 DWORD type;
2209 DC * dc = get_dc_ptr( hdc );
2210 PHYSDEV physdev;
2211 INT breakRem;
2212 static int quietfixme = 0;
2214 if (!dc) return FALSE;
2216 align = dc->textAlign;
2217 breakRem = dc->breakRem;
2218 layout = dc->layout;
2220 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2222 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2223 quietfixme = 1;
2226 update_dc( dc );
2227 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2228 type = GetObjectType(hdc);
2229 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2231 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2232 release_dc_ptr( dc );
2233 return ret;
2236 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2237 if (layout & LAYOUT_RTL)
2239 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2240 align ^= TA_RTLREADING;
2243 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2245 INT cGlyphs;
2246 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2248 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2249 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2250 reordered_str, count, NULL, &glyphs, &cGlyphs);
2252 flags |= ETO_IGNORELANGUAGE;
2253 if (glyphs)
2255 flags |= ETO_GLYPH_INDEX;
2256 if (cGlyphs != count)
2257 count = cGlyphs;
2260 else if(flags & ETO_GLYPH_INDEX)
2261 glyphs = reordered_str;
2263 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2264 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2265 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->backgroundMode, dc->MapMode);
2267 if(align & TA_UPDATECP)
2269 pt = dc->cur_pos;
2270 x = pt.x;
2271 y = pt.y;
2274 GetTextMetricsW(hdc, &tm);
2275 GetObjectW(dc->hFont, sizeof(lf), &lf);
2277 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2278 lf.lfEscapement = 0;
2280 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2281 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2283 lf.lfEscapement = -lf.lfEscapement;
2286 if(lf.lfEscapement != 0)
2288 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2289 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2291 else
2293 cosEsc = 1;
2294 sinEsc = 0;
2297 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
2299 rc = *lprect;
2300 lp_to_dp(dc, (POINT*)&rc, 2);
2301 order_rect( &rc );
2302 if (flags & ETO_OPAQUE)
2303 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2305 else flags &= ~ETO_CLIPPED;
2307 if(count == 0)
2309 ret = TRUE;
2310 goto done;
2313 pt.x = x;
2314 pt.y = y;
2315 lp_to_dp(dc, &pt, 1);
2316 x = pt.x;
2317 y = pt.y;
2319 char_extra = GetTextCharacterExtra(hdc);
2320 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2321 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2323 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2325 UINT i;
2326 POINT total = {0, 0}, desired[2];
2328 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2329 if (lpDx)
2331 if (flags & ETO_PDY)
2333 for (i = 0; i < count; i++)
2335 deltas[i].x = lpDx[i * 2] + char_extra;
2336 deltas[i].y = -lpDx[i * 2 + 1];
2339 else
2341 for (i = 0; i < count; i++)
2343 deltas[i].x = lpDx[i] + char_extra;
2344 deltas[i].y = 0;
2348 else
2350 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2352 if (flags & ETO_GLYPH_INDEX)
2353 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2354 else
2355 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2357 deltas[0].x = dx[0];
2358 deltas[0].y = 0;
2359 for (i = 1; i < count; i++)
2361 deltas[i].x = dx[i] - dx[i - 1];
2362 deltas[i].y = 0;
2364 HeapFree( GetProcessHeap(), 0, dx );
2367 for(i = 0; i < count; i++)
2369 total.x += deltas[i].x;
2370 total.y += deltas[i].y;
2372 desired[0].x = desired[0].y = 0;
2374 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2375 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2377 lp_to_dp(dc, desired, 2);
2378 desired[1].x -= desired[0].x;
2379 desired[1].y -= desired[0].y;
2381 if (dc->GraphicsMode == GM_COMPATIBLE)
2383 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2384 desired[1].x = -desired[1].x;
2385 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2386 desired[1].y = -desired[1].y;
2389 deltas[i].x = desired[1].x - width.x;
2390 deltas[i].y = desired[1].y - width.y;
2392 width = desired[1];
2394 flags |= ETO_PDY;
2396 else
2398 POINT desired[2];
2400 if(flags & ETO_GLYPH_INDEX)
2401 GetTextExtentPointI(hdc, glyphs, count, &sz);
2402 else
2403 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2404 desired[0].x = desired[0].y = 0;
2405 desired[1].x = sz.cx;
2406 desired[1].y = 0;
2407 lp_to_dp(dc, desired, 2);
2408 desired[1].x -= desired[0].x;
2409 desired[1].y -= desired[0].y;
2411 if (dc->GraphicsMode == GM_COMPATIBLE)
2413 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2414 desired[1].x = -desired[1].x;
2415 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2416 desired[1].y = -desired[1].y;
2418 width = desired[1];
2421 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2422 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2423 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2425 case TA_LEFT:
2426 if (align & TA_UPDATECP)
2428 pt.x = x + width.x;
2429 pt.y = y + width.y;
2430 dp_to_lp(dc, &pt, 1);
2431 MoveToEx(hdc, pt.x, pt.y, NULL);
2433 break;
2435 case TA_CENTER:
2436 x -= width.x / 2;
2437 y -= width.y / 2;
2438 break;
2440 case TA_RIGHT:
2441 x -= width.x;
2442 y -= width.y;
2443 if (align & TA_UPDATECP)
2445 pt.x = x;
2446 pt.y = y;
2447 dp_to_lp(dc, &pt, 1);
2448 MoveToEx(hdc, pt.x, pt.y, NULL);
2450 break;
2453 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2455 case TA_TOP:
2456 y += tm.tmAscent * cosEsc;
2457 x += tm.tmAscent * sinEsc;
2458 break;
2460 case TA_BOTTOM:
2461 y -= tm.tmDescent * cosEsc;
2462 x -= tm.tmDescent * sinEsc;
2463 break;
2465 case TA_BASELINE:
2466 break;
2469 if (dc->backgroundMode != TRANSPARENT)
2471 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2473 if(!(flags & ETO_OPAQUE) || !lprect ||
2474 x < rc.left || x + width.x >= rc.right ||
2475 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2477 RECT text_box;
2478 text_box.left = x;
2479 text_box.right = x + width.x;
2480 text_box.top = y - tm.tmAscent;
2481 text_box.bottom = y + tm.tmDescent;
2483 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2484 if (!is_rect_empty( &text_box ))
2485 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2490 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2491 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2493 done:
2494 HeapFree(GetProcessHeap(), 0, deltas);
2495 if(glyphs != reordered_str)
2496 HeapFree(GetProcessHeap(), 0, glyphs);
2497 if(reordered_str != str)
2498 HeapFree(GetProcessHeap(), 0, reordered_str);
2500 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2502 int underlinePos, strikeoutPos;
2503 int underlineWidth, strikeoutWidth;
2504 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2505 OUTLINETEXTMETRICW* otm = NULL;
2506 POINT pts[5];
2507 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2508 HBRUSH hbrush = CreateSolidBrush(dc->textColor);
2510 hbrush = SelectObject(hdc, hbrush);
2512 if(!size)
2514 underlinePos = 0;
2515 underlineWidth = tm.tmAscent / 20 + 1;
2516 strikeoutPos = tm.tmAscent / 2;
2517 strikeoutWidth = underlineWidth;
2519 else
2521 otm = HeapAlloc(GetProcessHeap(), 0, size);
2522 GetOutlineTextMetricsW(hdc, size, otm);
2523 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2524 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2525 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
2526 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2527 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2528 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
2529 HeapFree(GetProcessHeap(), 0, otm);
2533 if (lf.lfUnderline)
2535 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2536 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2537 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2538 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2539 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2540 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2541 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2542 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2543 pts[4].x = pts[0].x;
2544 pts[4].y = pts[0].y;
2545 dp_to_lp(dc, pts, 5);
2546 Polygon(hdc, pts, 5);
2549 if (lf.lfStrikeOut)
2551 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2552 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2553 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2554 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2555 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2556 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2557 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2558 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2559 pts[4].x = pts[0].x;
2560 pts[4].y = pts[0].y;
2561 dp_to_lp(dc, pts, 5);
2562 Polygon(hdc, pts, 5);
2565 SelectObject(hdc, hpen);
2566 hbrush = SelectObject(hdc, hbrush);
2567 DeleteObject(hbrush);
2570 release_dc_ptr( dc );
2572 return ret;
2576 /***********************************************************************
2577 * TextOutA (GDI32.@)
2579 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2581 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2585 /***********************************************************************
2586 * TextOutW (GDI32.@)
2588 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2590 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2594 /***********************************************************************
2595 * PolyTextOutA (GDI32.@)
2597 * See PolyTextOutW.
2599 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2601 for (; cStrings>0; cStrings--, pptxt++)
2602 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2603 return FALSE;
2604 return TRUE;
2609 /***********************************************************************
2610 * PolyTextOutW (GDI32.@)
2612 * Draw several Strings
2614 * RETURNS
2615 * TRUE: Success.
2616 * FALSE: Failure.
2618 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2620 for (; cStrings>0; cStrings--, pptxt++)
2621 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2622 return FALSE;
2623 return TRUE;
2627 /***********************************************************************
2628 * SetMapperFlags (GDI32.@)
2630 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2632 DC *dc = get_dc_ptr( hdc );
2633 DWORD ret = GDI_ERROR;
2635 if (dc)
2637 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2638 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2639 if (flags != GDI_ERROR)
2641 ret = dc->mapperFlags;
2642 dc->mapperFlags = flags;
2644 release_dc_ptr( dc );
2646 return ret;
2649 /***********************************************************************
2650 * GetAspectRatioFilterEx (GDI32.@)
2652 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2654 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2655 return FALSE;
2659 /***********************************************************************
2660 * GetCharABCWidthsA (GDI32.@)
2662 * See GetCharABCWidthsW.
2664 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2665 LPABC abc )
2667 INT i, wlen;
2668 LPSTR str;
2669 LPWSTR wstr;
2670 BOOL ret = TRUE;
2672 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2673 if (str == NULL)
2674 return FALSE;
2676 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2677 if (wstr == NULL)
2679 HeapFree(GetProcessHeap(), 0, str);
2680 return FALSE;
2683 for(i = 0; i < wlen; i++)
2685 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2687 ret = FALSE;
2688 break;
2690 abc++;
2693 HeapFree(GetProcessHeap(), 0, str);
2694 HeapFree(GetProcessHeap(), 0, wstr);
2696 return ret;
2700 /******************************************************************************
2701 * GetCharABCWidthsW [GDI32.@]
2703 * Retrieves widths of characters in range.
2705 * PARAMS
2706 * hdc [I] Handle of device context
2707 * firstChar [I] First character in range to query
2708 * lastChar [I] Last character in range to query
2709 * abc [O] Address of character-width structure
2711 * NOTES
2712 * Only works with TrueType fonts
2714 * RETURNS
2715 * Success: TRUE
2716 * Failure: FALSE
2718 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2719 LPABC abc )
2721 DC *dc = get_dc_ptr(hdc);
2722 PHYSDEV dev;
2723 unsigned int i;
2724 BOOL ret;
2725 TEXTMETRICW tm;
2727 if (!dc) return FALSE;
2729 if (!abc)
2731 release_dc_ptr( dc );
2732 return FALSE;
2735 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2736 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2737 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2739 release_dc_ptr( dc );
2740 return FALSE;
2743 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2744 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2745 if (ret)
2747 /* convert device units to logical */
2748 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2749 abc->abcA = width_to_LP(dc, abc->abcA);
2750 abc->abcB = width_to_LP(dc, abc->abcB);
2751 abc->abcC = width_to_LP(dc, abc->abcC);
2755 release_dc_ptr( dc );
2756 return ret;
2760 /******************************************************************************
2761 * GetCharABCWidthsI [GDI32.@]
2763 * Retrieves widths of characters in range.
2765 * PARAMS
2766 * hdc [I] Handle of device context
2767 * firstChar [I] First glyphs in range to query
2768 * count [I] Last glyphs in range to query
2769 * pgi [i] Array of glyphs to query
2770 * abc [O] Address of character-width structure
2772 * NOTES
2773 * Only works with TrueType fonts
2775 * RETURNS
2776 * Success: TRUE
2777 * Failure: FALSE
2779 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2780 LPWORD pgi, LPABC abc)
2782 DC *dc = get_dc_ptr(hdc);
2783 PHYSDEV dev;
2784 unsigned int i;
2785 BOOL ret;
2787 if (!dc) return FALSE;
2789 if (!abc)
2791 release_dc_ptr( dc );
2792 return FALSE;
2795 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2796 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2797 if (ret)
2799 /* convert device units to logical */
2800 for( i = 0; i < count; i++, abc++ ) {
2801 abc->abcA = width_to_LP(dc, abc->abcA);
2802 abc->abcB = width_to_LP(dc, abc->abcB);
2803 abc->abcC = width_to_LP(dc, abc->abcC);
2807 release_dc_ptr( dc );
2808 return ret;
2812 /***********************************************************************
2813 * GetGlyphOutlineA (GDI32.@)
2815 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2816 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2817 LPVOID lpBuffer, const MAT2 *lpmat2 )
2819 if (!lpmat2) return GDI_ERROR;
2821 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2822 UINT cp;
2823 int len;
2824 char mbchs[2];
2826 cp = GdiGetCodePage(hdc);
2827 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2828 len = 2;
2829 mbchs[0] = (uChar & 0xff00) >> 8;
2830 mbchs[1] = (uChar & 0xff);
2831 } else {
2832 len = 1;
2833 mbchs[0] = (uChar & 0xff);
2835 uChar = 0;
2836 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2839 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2840 lpmat2);
2843 /***********************************************************************
2844 * GetGlyphOutlineW (GDI32.@)
2846 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2847 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2848 LPVOID lpBuffer, const MAT2 *lpmat2 )
2850 DC *dc;
2851 DWORD ret;
2852 PHYSDEV dev;
2854 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2855 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2857 if (!lpmat2) return GDI_ERROR;
2859 dc = get_dc_ptr(hdc);
2860 if(!dc) return GDI_ERROR;
2862 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2863 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2864 release_dc_ptr( dc );
2865 return ret;
2869 /***********************************************************************
2870 * CreateScalableFontResourceA (GDI32.@)
2872 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2873 LPCSTR lpszResourceFile,
2874 LPCSTR lpszFontFile,
2875 LPCSTR lpszCurrentPath )
2877 LPWSTR lpszResourceFileW = NULL;
2878 LPWSTR lpszFontFileW = NULL;
2879 LPWSTR lpszCurrentPathW = NULL;
2880 int len;
2881 BOOL ret;
2883 if (lpszResourceFile)
2885 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2886 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2887 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2890 if (lpszFontFile)
2892 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2893 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2894 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2897 if (lpszCurrentPath)
2899 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2900 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2901 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2904 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2905 lpszFontFileW, lpszCurrentPathW);
2907 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2908 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2909 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2911 return ret;
2914 /***********************************************************************
2915 * CreateScalableFontResourceW (GDI32.@)
2917 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2918 LPCWSTR font_file, LPCWSTR font_path )
2920 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2921 debugstr_w(font_file), debugstr_w(font_path) );
2923 return WineEngCreateScalableFontResource( hidden, resource_file,
2924 font_file, font_path );
2927 /*************************************************************************
2928 * GetKerningPairsA (GDI32.@)
2930 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2931 LPKERNINGPAIR kern_pairA )
2933 UINT cp;
2934 CPINFO cpi;
2935 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2936 KERNINGPAIR *kern_pairW;
2938 if (!cPairs && kern_pairA)
2940 SetLastError(ERROR_INVALID_PARAMETER);
2941 return 0;
2944 cp = GdiGetCodePage(hDC);
2946 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2947 * to fail on an invalid character for CP_SYMBOL.
2949 cpi.DefaultChar[0] = 0;
2950 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2952 FIXME("Can't find codepage %u info\n", cp);
2953 return 0;
2956 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2957 if (!total_kern_pairs) return 0;
2959 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2960 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2962 for (i = 0; i < total_kern_pairs; i++)
2964 char first, second;
2966 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2967 continue;
2969 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2970 continue;
2972 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2973 continue;
2975 if (kern_pairA)
2977 if (kern_pairs_copied >= cPairs) break;
2979 kern_pairA->wFirst = (BYTE)first;
2980 kern_pairA->wSecond = (BYTE)second;
2981 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2982 kern_pairA++;
2984 kern_pairs_copied++;
2987 HeapFree(GetProcessHeap(), 0, kern_pairW);
2989 return kern_pairs_copied;
2992 /*************************************************************************
2993 * GetKerningPairsW (GDI32.@)
2995 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2996 LPKERNINGPAIR lpKerningPairs )
2998 DC *dc;
2999 DWORD ret;
3000 PHYSDEV dev;
3002 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
3004 if (!cPairs && lpKerningPairs)
3006 SetLastError(ERROR_INVALID_PARAMETER);
3007 return 0;
3010 dc = get_dc_ptr(hDC);
3011 if (!dc) return 0;
3013 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
3014 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
3015 release_dc_ptr( dc );
3016 return ret;
3019 /*************************************************************************
3020 * TranslateCharsetInfo [GDI32.@]
3022 * Fills a CHARSETINFO structure for a character set, code page, or
3023 * font. This allows making the correspondence between different labels
3024 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
3025 * of the same encoding.
3027 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
3028 * only one codepage should be set in *lpSrc.
3030 * RETURNS
3031 * TRUE on success, FALSE on failure.
3034 BOOL WINAPI TranslateCharsetInfo(
3035 LPDWORD lpSrc, /* [in]
3036 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
3037 if flags == TCI_SRCCHARSET: a character set value
3038 if flags == TCI_SRCCODEPAGE: a code page value
3040 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
3041 DWORD flags /* [in] determines interpretation of lpSrc */)
3043 int index = 0;
3044 switch (flags) {
3045 case TCI_SRCFONTSIG:
3046 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3047 break;
3048 case TCI_SRCCODEPAGE:
3049 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3050 break;
3051 case TCI_SRCCHARSET:
3052 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3053 break;
3054 default:
3055 return FALSE;
3057 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3058 *lpCs = FONT_tci[index];
3059 return TRUE;
3062 /*************************************************************************
3063 * GetFontLanguageInfo (GDI32.@)
3065 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3067 FONTSIGNATURE fontsig;
3068 static const DWORD GCP_DBCS_MASK=FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB,
3069 GCP_DIACRITIC_MASK=0x00000000,
3070 FLI_GLYPHS_MASK=0x00000000,
3071 GCP_GLYPHSHAPE_MASK=FS_ARABIC,
3072 GCP_KASHIDA_MASK=0x00000000,
3073 GCP_LIGATE_MASK=0x00000000,
3074 GCP_REORDER_MASK=FS_HEBREW|FS_ARABIC;
3076 DWORD result=0;
3078 GetTextCharsetInfo( hdc, &fontsig, 0 );
3079 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3081 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3082 result|=GCP_DBCS;
3084 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3085 result|=GCP_DIACRITIC;
3087 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3088 result|=FLI_GLYPHS;
3090 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3091 result|=GCP_GLYPHSHAPE;
3093 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3094 result|=GCP_KASHIDA;
3096 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3097 result|=GCP_LIGATE;
3099 if( GetKerningPairsW( hdc, 0, NULL ) )
3100 result|=GCP_USEKERNING;
3102 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3103 if( GetTextAlign( hdc) & TA_RTLREADING )
3104 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3105 result|=GCP_REORDER;
3107 return result;
3111 /*************************************************************************
3112 * GetFontData [GDI32.@]
3114 * Retrieve data for TrueType font.
3116 * RETURNS
3118 * success: Number of bytes returned
3119 * failure: GDI_ERROR
3121 * NOTES
3123 * Calls SetLastError()
3126 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3127 LPVOID buffer, DWORD length)
3129 DC *dc = get_dc_ptr(hdc);
3130 PHYSDEV dev;
3131 DWORD ret;
3133 if(!dc) return GDI_ERROR;
3135 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3136 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3137 release_dc_ptr( dc );
3138 return ret;
3141 /*************************************************************************
3142 * GetGlyphIndicesA [GDI32.@]
3144 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3145 LPWORD pgi, DWORD flags)
3147 DWORD ret;
3148 WCHAR *lpstrW;
3149 INT countW;
3151 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3152 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3154 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3155 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3156 HeapFree(GetProcessHeap(), 0, lpstrW);
3158 return ret;
3161 /*************************************************************************
3162 * GetGlyphIndicesW [GDI32.@]
3164 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3165 LPWORD pgi, DWORD flags)
3167 DC *dc = get_dc_ptr(hdc);
3168 PHYSDEV dev;
3169 DWORD ret;
3171 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3172 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3174 if(!dc) return GDI_ERROR;
3176 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3177 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3178 release_dc_ptr( dc );
3179 return ret;
3182 /*************************************************************************
3183 * GetCharacterPlacementA [GDI32.@]
3185 * See GetCharacterPlacementW.
3187 * NOTES:
3188 * the web browser control of ie4 calls this with dwFlags=0
3190 DWORD WINAPI
3191 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3192 INT nMaxExtent, GCP_RESULTSA *lpResults,
3193 DWORD dwFlags)
3195 WCHAR *lpStringW;
3196 INT uCountW;
3197 GCP_RESULTSW resultsW;
3198 DWORD ret;
3199 UINT font_cp;
3201 TRACE("%s, %d, %d, 0x%08x\n",
3202 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3204 /* both structs are equal in size */
3205 memcpy(&resultsW, lpResults, sizeof(resultsW));
3207 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3208 if(lpResults->lpOutString)
3209 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3211 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3213 lpResults->nGlyphs = resultsW.nGlyphs;
3214 lpResults->nMaxFit = resultsW.nMaxFit;
3216 if(lpResults->lpOutString) {
3217 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3218 lpResults->lpOutString, uCount, NULL, NULL );
3221 HeapFree(GetProcessHeap(), 0, lpStringW);
3222 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3224 return ret;
3227 /*************************************************************************
3228 * GetCharacterPlacementW [GDI32.@]
3230 * Retrieve information about a string. This includes the width, reordering,
3231 * Glyphing and so on.
3233 * RETURNS
3235 * The width and height of the string if successful, 0 if failed.
3237 * BUGS
3239 * All flags except GCP_REORDER are not yet implemented.
3240 * Reordering is not 100% compliant to the Windows BiDi method.
3241 * Caret positioning is not yet implemented for BiDi.
3242 * Classes are not yet implemented.
3245 DWORD WINAPI
3246 GetCharacterPlacementW(
3247 HDC hdc, /* [in] Device context for which the rendering is to be done */
3248 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3249 INT uCount, /* [in] Number of WORDS in string. */
3250 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3251 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3252 DWORD dwFlags /* [in] Flags specifying how to process the string */
3255 DWORD ret=0;
3256 SIZE size;
3257 UINT i, nSet;
3259 TRACE("%s, %d, %d, 0x%08x\n",
3260 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3262 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3263 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3264 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3265 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3266 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3268 if(dwFlags&(~GCP_REORDER))
3269 FIXME("flags 0x%08x ignored\n", dwFlags);
3270 if(lpResults->lpClass)
3271 FIXME("classes not implemented\n");
3272 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3273 FIXME("Caret positions for complex scripts not implemented\n");
3275 nSet = (UINT)uCount;
3276 if(nSet > lpResults->nGlyphs)
3277 nSet = lpResults->nGlyphs;
3279 /* return number of initialized fields */
3280 lpResults->nGlyphs = nSet;
3282 if((dwFlags&GCP_REORDER)==0 )
3284 /* Treat the case where no special handling was requested in a fastpath way */
3285 /* copy will do if the GCP_REORDER flag is not set */
3286 if(lpResults->lpOutString)
3287 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3289 if(lpResults->lpOrder)
3291 for(i = 0; i < nSet; i++)
3292 lpResults->lpOrder[i] = i;
3295 else
3297 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3298 nSet, lpResults->lpOrder, NULL, NULL );
3301 /* FIXME: Will use the placement chars */
3302 if (lpResults->lpDx)
3304 int c;
3305 for (i = 0; i < nSet; i++)
3307 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3308 lpResults->lpDx[i]= c;
3312 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3314 int pos = 0;
3316 lpResults->lpCaretPos[0] = 0;
3317 for (i = 1; i < nSet; i++)
3318 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3319 lpResults->lpCaretPos[i] = (pos += size.cx);
3322 if(lpResults->lpGlyphs)
3323 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3325 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3326 ret = MAKELONG(size.cx, size.cy);
3328 return ret;
3331 /*************************************************************************
3332 * GetCharABCWidthsFloatA [GDI32.@]
3334 * See GetCharABCWidthsFloatW.
3336 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3338 INT i, wlen;
3339 LPSTR str;
3340 LPWSTR wstr;
3341 BOOL ret = TRUE;
3343 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3344 if (str == NULL)
3345 return FALSE;
3347 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3349 for (i = 0; i < wlen; i++)
3351 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3353 ret = FALSE;
3354 break;
3356 abcf++;
3359 HeapFree( GetProcessHeap(), 0, str );
3360 HeapFree( GetProcessHeap(), 0, wstr );
3362 return ret;
3365 /*************************************************************************
3366 * GetCharABCWidthsFloatW [GDI32.@]
3368 * Retrieves widths of a range of characters.
3370 * PARAMS
3371 * hdc [I] Handle to device context.
3372 * first [I] First character in range to query.
3373 * last [I] Last character in range to query.
3374 * abcf [O] Array of LPABCFLOAT structures.
3376 * RETURNS
3377 * Success: TRUE
3378 * Failure: FALSE
3380 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3382 UINT i;
3383 ABC *abc;
3384 PHYSDEV dev;
3385 BOOL ret = FALSE;
3386 DC *dc = get_dc_ptr( hdc );
3388 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3390 if (!dc) return FALSE;
3392 if (!abcf) goto done;
3393 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3395 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3396 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3397 if (ret)
3399 /* convert device units to logical */
3400 FLOAT scale = fabs( dc->xformVport2World.eM11 );
3401 for (i = first; i <= last; i++, abcf++)
3403 abcf->abcfA = abc[i - first].abcA * scale;
3404 abcf->abcfB = abc[i - first].abcB * scale;
3405 abcf->abcfC = abc[i - first].abcC * scale;
3408 HeapFree( GetProcessHeap(), 0, abc );
3410 done:
3411 release_dc_ptr( dc );
3412 return ret;
3415 /*************************************************************************
3416 * GetCharWidthFloatA [GDI32.@]
3418 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3419 UINT iLastChar, PFLOAT pxBuffer)
3421 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3422 return FALSE;
3425 /*************************************************************************
3426 * GetCharWidthFloatW [GDI32.@]
3428 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3429 UINT iLastChar, PFLOAT pxBuffer)
3431 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3432 return FALSE;
3436 /***********************************************************************
3438 * Font Resource API *
3440 ***********************************************************************/
3442 /***********************************************************************
3443 * AddFontResourceA (GDI32.@)
3445 INT WINAPI AddFontResourceA( LPCSTR str )
3447 return AddFontResourceExA( str, 0, NULL);
3450 /***********************************************************************
3451 * AddFontResourceW (GDI32.@)
3453 INT WINAPI AddFontResourceW( LPCWSTR str )
3455 return AddFontResourceExW(str, 0, NULL);
3459 /***********************************************************************
3460 * AddFontResourceExA (GDI32.@)
3462 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3464 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3465 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3466 INT ret;
3468 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3469 ret = AddFontResourceExW(strW, fl, pdv);
3470 HeapFree(GetProcessHeap(), 0, strW);
3471 return ret;
3474 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3476 HRSRC rsrc = FindResourceW(hModule, name, type);
3477 HGLOBAL hMem = LoadResource(hModule, rsrc);
3478 LPVOID *pMem = LockResource(hMem);
3479 int *num_total = (int *)lParam;
3480 DWORD num_in_res;
3482 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3483 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3485 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3486 return FALSE;
3489 *num_total += num_in_res;
3490 return TRUE;
3493 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3495 HANDLE file, mapping;
3496 void *ptr;
3498 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3499 if (file == INVALID_HANDLE_VALUE) return NULL;
3501 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3503 CloseHandle( file );
3504 return NULL;
3507 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3508 CloseHandle( file );
3509 if (!mapping) return NULL;
3511 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3512 CloseHandle( mapping );
3514 return ptr;
3517 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3519 WORD align, type_id, count;
3520 DWORD res_off;
3522 if (size < rsrc_off + 10) return NULL;
3523 align = *(WORD *)(ptr + rsrc_off);
3524 rsrc_off += 2;
3525 type_id = *(WORD *)(ptr + rsrc_off);
3526 while (type_id && type_id != type)
3528 count = *(WORD *)(ptr + rsrc_off + 2);
3529 rsrc_off += 8 + count * 12;
3530 if (size < rsrc_off + 8) return NULL;
3531 type_id = *(WORD *)(ptr + rsrc_off);
3533 if (!type_id) return NULL;
3534 count = *(WORD *)(ptr + rsrc_off + 2);
3535 if (size < rsrc_off + 8 + count * 12) return NULL;
3536 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3537 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3538 if (size < res_off + *len) return NULL;
3539 return ptr + res_off;
3542 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3544 LARGE_INTEGER size;
3545 BYTE *ptr = map_file( res, &size );
3546 const IMAGE_DOS_HEADER *dos;
3547 const IMAGE_OS2_HEADER *ne;
3548 WORD *fontdir;
3549 char *data;
3550 WCHAR *name = NULL;
3551 DWORD len;
3553 if (!ptr) return NULL;
3555 if (size.u.LowPart < sizeof( *dos )) goto fail;
3556 dos = (const IMAGE_DOS_HEADER *)ptr;
3557 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3558 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3559 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3561 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3562 if (!fontdir) goto fail;
3563 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3565 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3566 if (!data) goto fail;
3567 if (!memchr( data, 0, len )) goto fail;
3569 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3570 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3571 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3573 fail:
3574 UnmapViewOfFile( ptr );
3575 return name;
3578 /***********************************************************************
3579 * AddFontResourceExW (GDI32.@)
3581 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3583 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3584 WCHAR *filename;
3585 BOOL hidden;
3587 if (ret == 0)
3589 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3590 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3591 if (hModule != NULL)
3593 int num_resources = 0;
3594 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3596 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3597 wine_dbgstr_w(str));
3598 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3599 ret = num_resources;
3600 FreeLibrary(hModule);
3602 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3604 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3605 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3606 HeapFree( GetProcessHeap(), 0, filename );
3609 return ret;
3612 /***********************************************************************
3613 * RemoveFontResourceA (GDI32.@)
3615 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3617 return RemoveFontResourceExA(str, 0, 0);
3620 /***********************************************************************
3621 * RemoveFontResourceW (GDI32.@)
3623 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3625 return RemoveFontResourceExW(str, 0, 0);
3628 /***********************************************************************
3629 * AddFontMemResourceEx (GDI32.@)
3631 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3633 HANDLE ret;
3634 DWORD num_fonts;
3636 if (!pbFont || !cbFont || !pcFonts)
3638 SetLastError(ERROR_INVALID_PARAMETER);
3639 return NULL;
3642 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3643 if (ret)
3645 __TRY
3647 *pcFonts = num_fonts;
3649 __EXCEPT_PAGE_FAULT
3651 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3652 RemoveFontMemResourceEx(ret);
3653 ret = 0;
3655 __ENDTRY
3657 return ret;
3660 /***********************************************************************
3661 * RemoveFontMemResourceEx (GDI32.@)
3663 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3665 FIXME("(%p) stub\n", fh);
3666 return TRUE;
3669 /***********************************************************************
3670 * RemoveFontResourceExA (GDI32.@)
3672 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3674 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3675 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3676 INT ret;
3678 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3679 ret = RemoveFontResourceExW(strW, fl, pdv);
3680 HeapFree(GetProcessHeap(), 0, strW);
3681 return ret;
3684 /***********************************************************************
3685 * RemoveFontResourceExW (GDI32.@)
3687 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3689 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3690 WCHAR *filename;
3691 BOOL hidden;
3693 if (ret == 0)
3695 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3696 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3697 if (hModule != NULL)
3699 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3700 FreeLibrary(hModule);
3702 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3704 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3705 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3706 HeapFree( GetProcessHeap(), 0, filename );
3709 return ret;
3712 /***********************************************************************
3713 * GetFontResourceInfoW (GDI32.@)
3715 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3717 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3718 return FALSE;
3721 /***********************************************************************
3722 * GetTextCharset (GDI32.@)
3724 UINT WINAPI GetTextCharset(HDC hdc)
3726 /* MSDN docs say this is equivalent */
3727 return GetTextCharsetInfo(hdc, NULL, 0);
3730 /***********************************************************************
3731 * GdiGetCharDimensions (GDI32.@)
3733 * Gets the average width of the characters in the English alphabet.
3735 * PARAMS
3736 * hdc [I] Handle to the device context to measure on.
3737 * lptm [O] Pointer to memory to store the text metrics into.
3738 * height [O] On exit, the maximum height of characters in the English alphabet.
3740 * RETURNS
3741 * The average width of characters in the English alphabet.
3743 * NOTES
3744 * This function is used by the dialog manager to get the size of a dialog
3745 * unit. It should also be used by other pieces of code that need to know
3746 * the size of a dialog unit in logical units without having access to the
3747 * window handle of the dialog.
3748 * Windows caches the font metrics from this function, but we don't and
3749 * there doesn't appear to be an immediate advantage to do so.
3751 * SEE ALSO
3752 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3754 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3756 SIZE sz;
3757 static const WCHAR alphabet[] = {
3758 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3759 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3760 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3762 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3764 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3766 if (height) *height = sz.cy;
3767 return (sz.cx / 26 + 1) / 2;
3770 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3772 FIXME("(%d): stub\n", fEnableEUDC);
3773 return FALSE;
3776 /***********************************************************************
3777 * GetCharWidthI (GDI32.@)
3779 * Retrieve widths of characters.
3781 * PARAMS
3782 * hdc [I] Handle to a device context.
3783 * first [I] First glyph in range to query.
3784 * count [I] Number of glyph indices to query.
3785 * glyphs [I] Array of glyphs to query.
3786 * buffer [O] Buffer to receive character widths.
3788 * NOTES
3789 * Only works with TrueType fonts.
3791 * RETURNS
3792 * Success: TRUE
3793 * Failure: FALSE
3795 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3797 ABC *abc;
3798 unsigned int i;
3800 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3802 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3803 return FALSE;
3805 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3807 HeapFree(GetProcessHeap(), 0, abc);
3808 return FALSE;
3811 for (i = 0; i < count; i++)
3812 buffer[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
3814 HeapFree(GetProcessHeap(), 0, abc);
3815 return TRUE;
3818 /***********************************************************************
3819 * GetFontUnicodeRanges (GDI32.@)
3821 * Retrieve a list of supported Unicode characters in a font.
3823 * PARAMS
3824 * hdc [I] Handle to a device context.
3825 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3827 * RETURNS
3828 * Success: Number of bytes written to the buffer pointed to by lpgs.
3829 * Failure: 0
3832 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3834 DWORD ret;
3835 PHYSDEV dev;
3836 DC *dc = get_dc_ptr(hdc);
3838 TRACE("(%p, %p)\n", hdc, lpgs);
3840 if (!dc) return 0;
3842 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3843 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3844 release_dc_ptr(dc);
3845 return ret;
3849 /*************************************************************
3850 * FontIsLinked (GDI32.@)
3852 BOOL WINAPI FontIsLinked(HDC hdc)
3854 DC *dc = get_dc_ptr(hdc);
3855 PHYSDEV dev;
3856 BOOL ret;
3858 if (!dc) return FALSE;
3859 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3860 ret = dev->funcs->pFontIsLinked( dev );
3861 release_dc_ptr(dc);
3862 TRACE("returning %d\n", ret);
3863 return ret;
3866 /*************************************************************
3867 * GetFontRealizationInfo (GDI32.@)
3869 BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info)
3871 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, unk);
3872 PHYSDEV dev;
3873 BOOL ret;
3874 DC *dc;
3876 if (info->size != sizeof(*info) && !is_v0)
3877 return FALSE;
3879 dc = get_dc_ptr(hdc);
3880 if (!dc) return FALSE;
3881 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
3882 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
3883 release_dc_ptr(dc);
3884 return ret;
3887 struct realization_info
3889 DWORD flags; /* 1 for bitmap fonts, 3 for scalable fonts */
3890 DWORD cache_num; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
3891 DWORD instance_id; /* identifies a realized font instance */
3894 /*************************************************************
3895 * GdiRealizationInfo (GDI32.@)
3897 * Returns a structure that contains some font information.
3899 BOOL WINAPI GdiRealizationInfo(HDC hdc, struct realization_info *info)
3901 struct font_realization_info ri;
3902 BOOL ret;
3904 ri.size = sizeof(ri);
3905 ret = GetFontRealizationInfo( hdc, &ri );
3906 if (ret)
3908 info->flags = ri.flags;
3909 info->cache_num = ri.cache_num;
3910 info->instance_id = ri.instance_id;
3913 return ret;