advapi32/tests: Allow ERROR_ACCESS_DENIED for newer Win10.
[wine.git] / dlls / gdi32 / font.c
blobc4b7cfb141f11be4112b2cb1b5ea263314d5fa4c
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 HeapFree( GetProcessHeap(), 0, obj );
815 return TRUE;
819 /***********************************************************************
820 * nulldrv_SelectFont
822 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
824 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
825 'D','e','s','k','t','o','p',0 };
826 static int orientation = -1, smoothing = -1;
827 LOGFONTW lf;
828 HKEY key;
830 if (*aa_flags) return 0;
832 GetObjectW( font, sizeof(lf), &lf );
833 switch (lf.lfQuality)
835 case NONANTIALIASED_QUALITY:
836 *aa_flags = GGO_BITMAP;
837 break;
838 case ANTIALIASED_QUALITY:
839 *aa_flags = GGO_GRAY4_BITMAP;
840 break;
841 case CLEARTYPE_QUALITY:
842 case CLEARTYPE_NATURAL_QUALITY:
843 if (orientation == -1)
845 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
846 orientation = get_subpixel_orientation( key );
847 RegCloseKey( key );
849 *aa_flags = orientation;
850 break;
851 default:
852 if (smoothing == -1)
854 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
855 smoothing = get_default_smoothing( key );
856 RegCloseKey( key );
858 *aa_flags = smoothing;
859 break;
861 return 0;
865 /***********************************************************************
866 * FONT_EnumInstance
868 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
869 * We have to use other types because of the FONTENUMPROCW definition.
871 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
872 DWORD fType, LPARAM lp )
874 struct font_enum *pfe = (struct font_enum *)lp;
875 INT ret = 1;
877 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
878 if ((!pfe->lpLogFontParam ||
879 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
880 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
881 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
883 /* convert font metrics */
884 ENUMLOGFONTEXA logfont;
885 NEWTEXTMETRICEXA tmA;
887 if (!pfe->unicode)
889 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
890 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
891 plf = (LOGFONTW *)&logfont.elfLogFont;
892 ptm = (TEXTMETRICW *)&tmA;
894 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
895 pfe->retval = ret;
897 return ret;
900 /***********************************************************************
901 * FONT_EnumFontFamiliesEx
903 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
904 LPARAM lParam, BOOL unicode )
906 INT ret = 0;
907 DC *dc = get_dc_ptr( hDC );
908 struct font_enum fe;
910 if (dc)
912 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
914 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
915 fe.lpLogFontParam = plf;
916 fe.lpEnumFunc = efproc;
917 fe.lpData = lParam;
918 fe.unicode = unicode;
919 fe.hdc = hDC;
920 fe.retval = 1;
921 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
922 release_dc_ptr( dc );
924 return ret ? fe.retval : 0;
927 /***********************************************************************
928 * EnumFontFamiliesExW (GDI32.@)
930 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
931 FONTENUMPROCW efproc,
932 LPARAM lParam, DWORD dwFlags )
934 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
937 /***********************************************************************
938 * EnumFontFamiliesExA (GDI32.@)
940 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
941 FONTENUMPROCA efproc,
942 LPARAM lParam, DWORD dwFlags)
944 LOGFONTW lfW, *plfW;
946 if (plf)
948 FONT_LogFontAToW( plf, &lfW );
949 plfW = &lfW;
951 else plfW = NULL;
953 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
956 /***********************************************************************
957 * EnumFontFamiliesA (GDI32.@)
959 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
960 FONTENUMPROCA efproc, LPARAM lpData )
962 LOGFONTA lf, *plf;
964 if (lpFamily)
966 if (!*lpFamily) return 1;
967 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
968 lf.lfCharSet = DEFAULT_CHARSET;
969 lf.lfPitchAndFamily = 0;
970 plf = &lf;
972 else plf = NULL;
974 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
977 /***********************************************************************
978 * EnumFontFamiliesW (GDI32.@)
980 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
981 FONTENUMPROCW efproc, LPARAM lpData )
983 LOGFONTW lf, *plf;
985 if (lpFamily)
987 if (!*lpFamily) return 1;
988 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
989 lf.lfCharSet = DEFAULT_CHARSET;
990 lf.lfPitchAndFamily = 0;
991 plf = &lf;
993 else plf = NULL;
995 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
998 /***********************************************************************
999 * EnumFontsA (GDI32.@)
1001 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
1002 LPARAM lpData )
1004 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
1007 /***********************************************************************
1008 * EnumFontsW (GDI32.@)
1010 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
1011 LPARAM lpData )
1013 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
1017 /***********************************************************************
1018 * GetTextCharacterExtra (GDI32.@)
1020 INT WINAPI GetTextCharacterExtra( HDC hdc )
1022 INT ret;
1023 DC *dc = get_dc_ptr( hdc );
1024 if (!dc) return 0x80000000;
1025 ret = dc->charExtra;
1026 release_dc_ptr( dc );
1027 return ret;
1031 /***********************************************************************
1032 * SetTextCharacterExtra (GDI32.@)
1034 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
1036 INT ret = 0x80000000;
1037 DC * dc = get_dc_ptr( hdc );
1039 if (dc)
1041 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
1042 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
1043 if (extra != 0x80000000)
1045 ret = dc->charExtra;
1046 dc->charExtra = extra;
1048 release_dc_ptr( dc );
1050 return ret;
1054 /***********************************************************************
1055 * SetTextJustification (GDI32.@)
1057 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1059 BOOL ret;
1060 PHYSDEV physdev;
1061 DC * dc = get_dc_ptr( hdc );
1063 if (!dc) return FALSE;
1065 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1066 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1067 if (ret)
1069 extra = abs((extra * dc->vport_ext.cx + dc->wnd_ext.cx / 2) / dc->wnd_ext.cx);
1070 if (!extra) breaks = 0;
1071 if (breaks)
1073 dc->breakExtra = extra / breaks;
1074 dc->breakRem = extra - (breaks * dc->breakExtra);
1076 else
1078 dc->breakExtra = 0;
1079 dc->breakRem = 0;
1082 release_dc_ptr( dc );
1083 return ret;
1087 /***********************************************************************
1088 * GetTextFaceA (GDI32.@)
1090 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1092 INT res = GetTextFaceW(hdc, 0, NULL);
1093 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1094 GetTextFaceW( hdc, res, nameW );
1096 if (name)
1098 if (count)
1100 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1101 if (res == 0)
1102 res = count;
1103 name[count-1] = 0;
1104 /* GetTextFaceA does NOT include the nul byte in the return count. */
1105 res--;
1107 else
1108 res = 0;
1110 else
1111 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1112 HeapFree( GetProcessHeap(), 0, nameW );
1113 return res;
1116 /***********************************************************************
1117 * GetTextFaceW (GDI32.@)
1119 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1121 PHYSDEV dev;
1122 INT ret;
1124 DC * dc = get_dc_ptr( hdc );
1125 if (!dc) return 0;
1127 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1128 ret = dev->funcs->pGetTextFace( dev, count, name );
1129 release_dc_ptr( dc );
1130 return ret;
1134 /***********************************************************************
1135 * GetTextExtentPoint32A (GDI32.@)
1137 * See GetTextExtentPoint32W.
1139 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1140 LPSIZE size )
1142 BOOL ret = FALSE;
1143 INT wlen;
1144 LPWSTR p;
1146 if (count < 0) return FALSE;
1148 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1150 if (p)
1152 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1153 HeapFree( GetProcessHeap(), 0, p );
1156 TRACE("(%p %s %d %p): returning %d x %d\n",
1157 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1158 return ret;
1162 /***********************************************************************
1163 * GetTextExtentPoint32W [GDI32.@]
1165 * Computes width/height for a string.
1167 * Computes width and height of the specified string.
1169 * RETURNS
1170 * Success: TRUE
1171 * Failure: FALSE
1173 BOOL WINAPI GetTextExtentPoint32W(
1174 HDC hdc, /* [in] Handle of device context */
1175 LPCWSTR str, /* [in] Address of text string */
1176 INT count, /* [in] Number of characters in string */
1177 LPSIZE size) /* [out] Address of structure for string size */
1179 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1182 /***********************************************************************
1183 * GetTextExtentExPointI [GDI32.@]
1185 * Computes width and height of the array of glyph indices.
1187 * PARAMS
1188 * hdc [I] Handle of device context.
1189 * indices [I] Glyph index array.
1190 * count [I] Number of glyphs in array.
1191 * max_ext [I] Maximum width in glyphs.
1192 * nfit [O] Maximum number of characters.
1193 * dxs [O] Partial string widths.
1194 * size [O] Returned string size.
1196 * RETURNS
1197 * Success: TRUE
1198 * Failure: FALSE
1200 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1201 LPINT nfit, LPINT dxs, LPSIZE size )
1203 DC *dc;
1204 int i;
1205 BOOL ret;
1206 INT buffer[256], *pos = dxs;
1208 if (count < 0) return FALSE;
1210 dc = get_dc_ptr( hdc );
1211 if (!dc) return FALSE;
1213 if (!dxs)
1215 pos = buffer;
1216 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1218 release_dc_ptr( dc );
1219 return FALSE;
1223 ret = get_char_positions_indices( dc, indices, count, pos, size );
1224 if (ret)
1226 if (dxs || nfit)
1228 for (i = 0; i < count; i++)
1230 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1231 if (nfit && dx > (unsigned int)max_ext) break;
1232 if (dxs) dxs[i] = dx;
1234 if (nfit) *nfit = i;
1237 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1238 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1241 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1242 release_dc_ptr( dc );
1244 TRACE("(%p %p %d %p): returning %d x %d\n",
1245 hdc, indices, count, size, size->cx, size->cy );
1246 return ret;
1249 /***********************************************************************
1250 * GetTextExtentPointI [GDI32.@]
1252 * Computes width and height of the array of glyph indices.
1254 * PARAMS
1255 * hdc [I] Handle of device context.
1256 * indices [I] Glyph index array.
1257 * count [I] Number of glyphs in array.
1258 * size [O] Returned string size.
1260 * RETURNS
1261 * Success: TRUE
1262 * Failure: FALSE
1264 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1266 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1270 /***********************************************************************
1271 * GetTextExtentPointA (GDI32.@)
1273 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1274 LPSIZE size )
1276 TRACE("not bug compatible.\n");
1277 return GetTextExtentPoint32A( hdc, str, count, size );
1280 /***********************************************************************
1281 * GetTextExtentPointW (GDI32.@)
1283 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1284 LPSIZE size )
1286 TRACE("not bug compatible.\n");
1287 return GetTextExtentPoint32W( hdc, str, count, size );
1291 /***********************************************************************
1292 * GetTextExtentExPointA (GDI32.@)
1294 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1295 INT maxExt, LPINT lpnFit,
1296 LPINT alpDx, LPSIZE size )
1298 BOOL ret;
1299 INT wlen;
1300 INT *walpDx = NULL;
1301 LPWSTR p = NULL;
1303 if (count < 0) return FALSE;
1304 if (maxExt < -1) return FALSE;
1306 if (alpDx)
1308 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1309 if (!walpDx) return FALSE;
1312 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1313 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1314 if (walpDx)
1316 INT n = lpnFit ? *lpnFit : wlen;
1317 INT i, j;
1318 for(i = 0, j = 0; i < n; i++, j++)
1320 alpDx[j] = walpDx[i];
1321 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1324 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1325 HeapFree( GetProcessHeap(), 0, p );
1326 HeapFree( GetProcessHeap(), 0, walpDx );
1327 return ret;
1331 /***********************************************************************
1332 * GetTextExtentExPointW (GDI32.@)
1334 * Return the size of the string as it would be if it was output properly by
1335 * e.g. TextOut.
1337 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1338 LPINT nfit, LPINT dxs, LPSIZE size )
1340 DC *dc;
1341 int i;
1342 BOOL ret;
1343 INT buffer[256], *pos = dxs;
1345 if (count < 0) return FALSE;
1347 dc = get_dc_ptr(hdc);
1348 if (!dc) return FALSE;
1350 if (!dxs)
1352 pos = buffer;
1353 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1355 release_dc_ptr( dc );
1356 return FALSE;
1360 ret = get_char_positions( dc, str, count, pos, size );
1361 if (ret)
1363 if (dxs || nfit)
1365 for (i = 0; i < count; i++)
1367 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1368 if (nfit && dx > (unsigned int)max_ext) break;
1369 if (dxs) dxs[i] = dx;
1371 if (nfit) *nfit = i;
1374 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1375 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1378 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1379 release_dc_ptr( dc );
1381 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1382 return ret;
1385 /***********************************************************************
1386 * GetTextMetricsA (GDI32.@)
1388 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1390 TEXTMETRICW tm32;
1392 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1393 FONT_TextMetricWToA( &tm32, metrics );
1394 return TRUE;
1397 /***********************************************************************
1398 * GetTextMetricsW (GDI32.@)
1400 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1402 PHYSDEV physdev;
1403 BOOL ret = FALSE;
1404 DC * dc = get_dc_ptr( hdc );
1405 if (!dc) return FALSE;
1407 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1408 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1410 if (ret)
1412 /* device layer returns values in device units
1413 * therefore we have to convert them to logical */
1415 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1416 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1417 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
1418 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
1419 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
1420 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
1421 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
1422 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
1423 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
1424 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
1425 ret = TRUE;
1427 TRACE("text metrics:\n"
1428 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1429 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1430 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1431 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1432 " PitchAndFamily = %02x\n"
1433 " --------------------\n"
1434 " InternalLeading = %i\n"
1435 " Ascent = %i\n"
1436 " Descent = %i\n"
1437 " Height = %i\n",
1438 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1439 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1440 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1441 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1442 metrics->tmPitchAndFamily,
1443 metrics->tmInternalLeading,
1444 metrics->tmAscent,
1445 metrics->tmDescent,
1446 metrics->tmHeight );
1448 release_dc_ptr( dc );
1449 return ret;
1453 /***********************************************************************
1454 * GetOutlineTextMetricsA (GDI32.@)
1455 * Gets metrics for TrueType fonts.
1457 * NOTES
1458 * If the supplied buffer isn't big enough Windows partially fills it up to
1459 * its given length and returns that length.
1461 * RETURNS
1462 * Success: Non-zero or size of required buffer
1463 * Failure: 0
1465 UINT WINAPI GetOutlineTextMetricsA(
1466 HDC hdc, /* [in] Handle of device context */
1467 UINT cbData, /* [in] Size of metric data array */
1468 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1470 char buf[512], *ptr;
1471 UINT ret, needed;
1472 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1473 OUTLINETEXTMETRICA *output = lpOTM;
1474 INT left, len;
1476 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1477 return 0;
1478 if(ret > sizeof(buf))
1479 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1480 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1482 needed = sizeof(OUTLINETEXTMETRICA);
1483 if(lpOTMW->otmpFamilyName)
1484 needed += WideCharToMultiByte(CP_ACP, 0,
1485 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1486 NULL, 0, NULL, NULL);
1487 if(lpOTMW->otmpFaceName)
1488 needed += WideCharToMultiByte(CP_ACP, 0,
1489 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1490 NULL, 0, NULL, NULL);
1491 if(lpOTMW->otmpStyleName)
1492 needed += WideCharToMultiByte(CP_ACP, 0,
1493 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1494 NULL, 0, NULL, NULL);
1495 if(lpOTMW->otmpFullName)
1496 needed += WideCharToMultiByte(CP_ACP, 0,
1497 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1498 NULL, 0, NULL, NULL);
1500 if(!lpOTM) {
1501 ret = needed;
1502 goto end;
1505 TRACE("needed = %d\n", needed);
1506 if(needed > cbData)
1507 /* Since the supplied buffer isn't big enough, we'll alloc one
1508 that is and memcpy the first cbData bytes into the lpOTM at
1509 the end. */
1510 output = HeapAlloc(GetProcessHeap(), 0, needed);
1512 ret = output->otmSize = min(needed, cbData);
1513 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1514 output->otmFiller = 0;
1515 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1516 output->otmfsSelection = lpOTMW->otmfsSelection;
1517 output->otmfsType = lpOTMW->otmfsType;
1518 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1519 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1520 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1521 output->otmEMSquare = lpOTMW->otmEMSquare;
1522 output->otmAscent = lpOTMW->otmAscent;
1523 output->otmDescent = lpOTMW->otmDescent;
1524 output->otmLineGap = lpOTMW->otmLineGap;
1525 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1526 output->otmsXHeight = lpOTMW->otmsXHeight;
1527 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1528 output->otmMacAscent = lpOTMW->otmMacAscent;
1529 output->otmMacDescent = lpOTMW->otmMacDescent;
1530 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1531 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1532 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1533 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1534 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1535 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1536 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1537 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1538 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1539 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1542 ptr = (char*)(output + 1);
1543 left = needed - sizeof(*output);
1545 if(lpOTMW->otmpFamilyName) {
1546 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1547 len = WideCharToMultiByte(CP_ACP, 0,
1548 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1549 ptr, left, NULL, NULL);
1550 left -= len;
1551 ptr += len;
1552 } else
1553 output->otmpFamilyName = 0;
1555 if(lpOTMW->otmpFaceName) {
1556 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1557 len = WideCharToMultiByte(CP_ACP, 0,
1558 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1559 ptr, left, NULL, NULL);
1560 left -= len;
1561 ptr += len;
1562 } else
1563 output->otmpFaceName = 0;
1565 if(lpOTMW->otmpStyleName) {
1566 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1567 len = WideCharToMultiByte(CP_ACP, 0,
1568 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1569 ptr, left, NULL, NULL);
1570 left -= len;
1571 ptr += len;
1572 } else
1573 output->otmpStyleName = 0;
1575 if(lpOTMW->otmpFullName) {
1576 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1577 len = WideCharToMultiByte(CP_ACP, 0,
1578 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1579 ptr, left, NULL, NULL);
1580 left -= len;
1581 } else
1582 output->otmpFullName = 0;
1584 assert(left == 0);
1586 if(output != lpOTM) {
1587 memcpy(lpOTM, output, cbData);
1588 HeapFree(GetProcessHeap(), 0, output);
1590 /* check if the string offsets really fit into the provided size */
1591 /* FIXME: should we check string length as well? */
1592 /* make sure that we don't read/write beyond the provided buffer */
1593 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1595 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1596 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1599 /* make sure that we don't read/write beyond the provided buffer */
1600 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1602 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1603 lpOTM->otmpFaceName = 0; /* doesn't fit */
1606 /* make sure that we don't read/write beyond the provided buffer */
1607 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1609 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1610 lpOTM->otmpStyleName = 0; /* doesn't fit */
1613 /* make sure that we don't read/write beyond the provided buffer */
1614 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1616 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1617 lpOTM->otmpFullName = 0; /* doesn't fit */
1621 end:
1622 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1623 HeapFree(GetProcessHeap(), 0, lpOTMW);
1625 return ret;
1629 /***********************************************************************
1630 * GetOutlineTextMetricsW [GDI32.@]
1632 UINT WINAPI GetOutlineTextMetricsW(
1633 HDC hdc, /* [in] Handle of device context */
1634 UINT cbData, /* [in] Size of metric data array */
1635 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1637 DC *dc = get_dc_ptr( hdc );
1638 OUTLINETEXTMETRICW *output = lpOTM;
1639 PHYSDEV dev;
1640 UINT ret;
1642 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1643 if(!dc) return 0;
1645 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1646 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1648 if (lpOTM && ret > cbData)
1650 output = HeapAlloc(GetProcessHeap(), 0, ret);
1651 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1654 if (lpOTM && ret)
1656 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1657 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1658 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
1659 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
1660 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
1661 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
1662 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
1663 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
1664 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
1665 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
1666 output->otmAscent = height_to_LP( dc, output->otmAscent);
1667 output->otmDescent = height_to_LP( dc, output->otmDescent);
1668 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
1669 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
1670 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
1671 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
1672 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
1673 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
1674 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
1675 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
1676 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
1677 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
1678 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
1679 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
1680 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
1681 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
1682 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
1683 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
1684 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
1685 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
1686 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
1687 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
1688 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
1689 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
1691 if(output != lpOTM)
1693 memcpy(lpOTM, output, cbData);
1694 HeapFree(GetProcessHeap(), 0, output);
1695 ret = cbData;
1698 release_dc_ptr(dc);
1699 return ret;
1702 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1704 INT i, count = lastChar - firstChar + 1;
1705 UINT mbcp;
1706 UINT c;
1707 LPSTR str;
1709 if (count <= 0)
1710 return NULL;
1712 mbcp = GdiGetCodePage(hdc);
1713 switch (mbcp)
1715 case 932:
1716 case 936:
1717 case 949:
1718 case 950:
1719 case 1361:
1720 if (lastChar > 0xffff)
1721 return NULL;
1722 if ((firstChar ^ lastChar) > 0xff)
1723 return NULL;
1724 break;
1725 default:
1726 if (lastChar > 0xff)
1727 return NULL;
1728 mbcp = 0;
1729 break;
1732 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1733 if (str == NULL)
1734 return NULL;
1736 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1738 if (mbcp) {
1739 if (c > 0xff)
1740 str[i++] = (BYTE)(c >> 8);
1741 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1742 str[i] = 0x1f; /* FIXME: use default character */
1743 else
1744 str[i] = (BYTE)c;
1746 else
1747 str[i] = (BYTE)c;
1749 str[i] = '\0';
1751 *pByteLen = i;
1753 return str;
1756 /***********************************************************************
1757 * GetCharWidthW (GDI32.@)
1758 * GetCharWidth32W (GDI32.@)
1760 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1761 LPINT buffer )
1763 UINT i;
1764 BOOL ret;
1765 PHYSDEV dev;
1766 DC * dc = get_dc_ptr( hdc );
1768 if (!dc) return FALSE;
1770 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1771 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1773 if (ret)
1775 /* convert device units to logical */
1776 for( i = firstChar; i <= lastChar; i++, buffer++ )
1777 *buffer = width_to_LP( dc, *buffer );
1779 release_dc_ptr( dc );
1780 return ret;
1784 /***********************************************************************
1785 * GetCharWidthA (GDI32.@)
1786 * GetCharWidth32A (GDI32.@)
1788 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1789 LPINT buffer )
1791 INT i, wlen;
1792 LPSTR str;
1793 LPWSTR wstr;
1794 BOOL ret = TRUE;
1796 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1797 if(str == NULL)
1798 return FALSE;
1800 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1802 for(i = 0; i < wlen; i++)
1804 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1806 ret = FALSE;
1807 break;
1809 buffer++;
1812 HeapFree(GetProcessHeap(), 0, str);
1813 HeapFree(GetProcessHeap(), 0, wstr);
1815 return ret;
1819 /* helper for nulldrv_ExtTextOut */
1820 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1821 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1823 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1824 UINT indices[3] = {0, 0, 0x20};
1825 unsigned int i;
1826 DWORD ret, size;
1827 int stride;
1829 indices[0] = index;
1830 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1832 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1834 index = indices[i];
1835 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1836 if (ret != GDI_ERROR) break;
1839 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1840 if (!image) return ERROR_SUCCESS;
1842 image->ptr = NULL;
1843 image->free = NULL;
1844 if (!ret) /* empty glyph */
1846 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
1847 return ERROR_SUCCESS;
1850 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1851 size = metrics->gmBlackBoxY * stride;
1853 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1854 image->is_copy = TRUE;
1855 image->free = free_heap_bits;
1857 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1858 if (ret == GDI_ERROR)
1860 HeapFree( GetProcessHeap(), 0, image->ptr );
1861 return ERROR_NOT_FOUND;
1863 return ERROR_SUCCESS;
1866 /* helper for nulldrv_ExtTextOut */
1867 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1868 LPCWSTR str, UINT count, const INT *dx )
1870 UINT i;
1871 RECT rect, bounds;
1873 reset_bounds( &bounds );
1874 for (i = 0; i < count; i++)
1876 GLYPHMETRICS metrics;
1878 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1880 rect.left = x + metrics.gmptGlyphOrigin.x;
1881 rect.top = y - metrics.gmptGlyphOrigin.y;
1882 rect.right = rect.left + metrics.gmBlackBoxX;
1883 rect.bottom = rect.top + metrics.gmBlackBoxY;
1884 add_bounds_rect( &bounds, &rect );
1886 if (dx)
1888 if (flags & ETO_PDY)
1890 x += dx[ i * 2 ];
1891 y += dx[ i * 2 + 1];
1893 else x += dx[ i ];
1895 else
1897 x += metrics.gmCellIncX;
1898 y += metrics.gmCellIncY;
1901 return bounds;
1904 /* helper for nulldrv_ExtTextOut */
1905 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1906 const struct gdi_image_bits *image, const RECT *clip )
1908 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1909 UINT i, count, max_count;
1910 LONG x, y;
1911 BYTE *ptr = image->ptr;
1912 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1913 POINT *pts;
1914 RECT rect, clipped_rect;
1916 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1917 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1918 rect.right = rect.left + metrics->gmBlackBoxX;
1919 rect.bottom = rect.top + metrics->gmBlackBoxY;
1920 if (!clip) clipped_rect = rect;
1921 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1923 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1924 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1925 if (!pts) return;
1927 count = 0;
1928 ptr += (clipped_rect.top - rect.top) * stride;
1929 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1931 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1933 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1934 pts[count].x = rect.left + x;
1935 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1936 pts[count + 1].x = rect.left + x;
1937 if (pts[count + 1].x > pts[count].x)
1939 pts[count].y = pts[count + 1].y = y;
1940 count += 2;
1944 assert( count <= max_count );
1945 dp_to_lp( dc, pts, count );
1946 for (i = 0; i < count; i += 2) Polyline( dc->hSelf, pts + i, 2 );
1947 HeapFree( GetProcessHeap(), 0, pts );
1950 /***********************************************************************
1951 * nulldrv_ExtTextOut
1953 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1954 LPCWSTR str, UINT count, const INT *dx )
1956 DC *dc = get_nulldrv_dc( dev );
1957 UINT i;
1958 DWORD err;
1959 HGDIOBJ orig;
1960 HPEN pen;
1962 if (flags & ETO_OPAQUE)
1964 RECT rc = *rect;
1965 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, dc->backgroundColor ) );
1967 if (brush)
1969 orig = SelectObject( dev->hdc, brush );
1970 dp_to_lp( dc, (POINT *)&rc, 2 );
1971 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1972 SelectObject( dev->hdc, orig );
1973 DeleteObject( brush );
1977 if (!count) return TRUE;
1979 if (dc->aa_flags != GGO_BITMAP)
1981 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1982 BITMAPINFO *info = (BITMAPINFO *)buffer;
1983 struct gdi_image_bits bits;
1984 struct bitblt_coords src, dst;
1985 PHYSDEV dst_dev;
1986 /* FIXME Subpixel modes */
1987 UINT aa_flags = GGO_GRAY4_BITMAP;
1989 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1990 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1991 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1992 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1994 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1995 src.x = src.visrect.left;
1996 src.y = src.visrect.top;
1997 src.width = src.visrect.right - src.visrect.left;
1998 src.height = src.visrect.bottom - src.visrect.top;
1999 dst = src;
2000 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
2001 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
2003 /* we can avoid the GetImage, just query the needed format */
2004 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
2005 info->bmiHeader.biSize = sizeof(info->bmiHeader);
2006 info->bmiHeader.biWidth = src.width;
2007 info->bmiHeader.biHeight = -src.height;
2008 info->bmiHeader.biSizeImage = get_dib_image_size( info );
2009 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
2010 if (!err || err == ERROR_BAD_FORMAT)
2012 /* make the source rectangle relative to the source bits */
2013 src.x = src.y = 0;
2014 src.visrect.left = src.visrect.top = 0;
2015 src.visrect.right = src.width;
2016 src.visrect.bottom = src.height;
2018 bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
2019 if (!bits.ptr) return ERROR_OUTOFMEMORY;
2020 bits.is_copy = TRUE;
2021 bits.free = free_heap_bits;
2022 err = ERROR_SUCCESS;
2025 else
2027 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
2028 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
2029 if (!err && !bits.is_copy)
2031 void *ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
2032 if (!ptr)
2034 if (bits.free) bits.free( &bits );
2035 return ERROR_OUTOFMEMORY;
2037 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
2038 if (bits.free) bits.free( &bits );
2039 bits.ptr = ptr;
2040 bits.is_copy = TRUE;
2041 bits.free = free_heap_bits;
2044 if (!err)
2046 /* make x,y relative to the image bits */
2047 x += src.visrect.left - dst.visrect.left;
2048 y += src.visrect.top - dst.visrect.top;
2049 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
2050 aa_flags, str, count, dx );
2051 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2052 if (bits.free) bits.free( &bits );
2053 return !err;
2057 pen = CreatePen( PS_SOLID, 1, dc->textColor );
2058 orig = SelectObject( dev->hdc, pen );
2060 for (i = 0; i < count; i++)
2062 GLYPHMETRICS metrics;
2063 struct gdi_image_bits image;
2065 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2066 if (err) continue;
2068 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2069 if (image.free) image.free( &image );
2071 if (dx)
2073 if (flags & ETO_PDY)
2075 x += dx[ i * 2 ];
2076 y += dx[ i * 2 + 1];
2078 else x += dx[ i ];
2080 else
2082 x += metrics.gmCellIncX;
2083 y += metrics.gmCellIncY;
2087 SelectObject( dev->hdc, orig );
2088 DeleteObject( pen );
2089 return TRUE;
2093 /***********************************************************************
2094 * ExtTextOutA (GDI32.@)
2096 * See ExtTextOutW.
2098 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2099 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2101 INT wlen;
2102 UINT codepage;
2103 LPWSTR p;
2104 BOOL ret;
2105 LPINT lpDxW = NULL;
2107 if (flags & ETO_GLYPH_INDEX)
2108 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2110 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2112 if (lpDx) {
2113 unsigned int i = 0, j = 0;
2115 /* allocate enough for a ETO_PDY */
2116 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2117 while(i < count) {
2118 if(IsDBCSLeadByteEx(codepage, str[i]))
2120 if(flags & ETO_PDY)
2122 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2123 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2125 else
2126 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2127 i = i + 2;
2129 else
2131 if(flags & ETO_PDY)
2133 lpDxW[j++] = lpDx[i * 2];
2134 lpDxW[j++] = lpDx[i * 2 + 1];
2136 else
2137 lpDxW[j++] = lpDx[i];
2138 i = i + 1;
2143 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2145 HeapFree( GetProcessHeap(), 0, p );
2146 HeapFree( GetProcessHeap(), 0, lpDxW );
2147 return ret;
2150 /***********************************************************************
2151 * get_line_width
2153 * Scale the underline / strikeout line width.
2155 static inline int get_line_width( DC *dc, int metric_size )
2157 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
2158 if (width == 0) width = 1;
2159 if (metric_size < 0) width = -width;
2160 return width;
2163 /***********************************************************************
2164 * ExtTextOutW (GDI32.@)
2166 * Draws text using the currently selected font, background color, and text color.
2169 * PARAMS
2170 * x,y [I] coordinates of string
2171 * flags [I]
2172 * ETO_GRAYED - undocumented on MSDN
2173 * ETO_OPAQUE - use background color for fill the rectangle
2174 * ETO_CLIPPED - clipping text to the rectangle
2175 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2176 * than encoded characters. Implies ETO_IGNORELANGUAGE
2177 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2178 * Affects BiDi ordering
2179 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2180 * ETO_PDY - unimplemented
2181 * ETO_NUMERICSLATIN - unimplemented always assumed -
2182 * do not translate numbers into locale representations
2183 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2184 * lprect [I] dimensions for clipping or/and opaquing
2185 * str [I] text string
2186 * count [I] number of symbols in string
2187 * lpDx [I] optional parameter with distance between drawing characters
2189 * RETURNS
2190 * Success: TRUE
2191 * Failure: FALSE
2193 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2194 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2196 BOOL ret = FALSE;
2197 LPWSTR reordered_str = (LPWSTR)str;
2198 WORD *glyphs = NULL;
2199 UINT align;
2200 DWORD layout;
2201 POINT pt;
2202 TEXTMETRICW tm;
2203 LOGFONTW lf;
2204 double cosEsc, sinEsc;
2205 INT char_extra;
2206 SIZE sz;
2207 RECT rc;
2208 POINT *deltas = NULL, width = {0, 0};
2209 DWORD type;
2210 DC * dc = get_dc_ptr( hdc );
2211 PHYSDEV physdev;
2212 INT breakRem;
2213 static int quietfixme = 0;
2215 if (!dc) return FALSE;
2217 align = dc->textAlign;
2218 breakRem = dc->breakRem;
2219 layout = dc->layout;
2221 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2223 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2224 quietfixme = 1;
2227 update_dc( dc );
2228 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2229 type = GetObjectType(hdc);
2230 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2232 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2233 release_dc_ptr( dc );
2234 return ret;
2237 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2238 if (layout & LAYOUT_RTL)
2240 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2241 align ^= TA_RTLREADING;
2244 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2246 INT cGlyphs;
2247 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2249 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2250 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2251 reordered_str, count, NULL, &glyphs, &cGlyphs);
2253 flags |= ETO_IGNORELANGUAGE;
2254 if (glyphs)
2256 flags |= ETO_GLYPH_INDEX;
2257 if (cGlyphs != count)
2258 count = cGlyphs;
2261 else if(flags & ETO_GLYPH_INDEX)
2262 glyphs = reordered_str;
2264 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2265 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2266 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->backgroundMode, dc->MapMode);
2268 if(align & TA_UPDATECP)
2270 pt = dc->cur_pos;
2271 x = pt.x;
2272 y = pt.y;
2275 GetTextMetricsW(hdc, &tm);
2276 GetObjectW(dc->hFont, sizeof(lf), &lf);
2278 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2279 lf.lfEscapement = 0;
2281 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2282 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2284 lf.lfEscapement = -lf.lfEscapement;
2287 if(lf.lfEscapement != 0)
2289 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2290 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2292 else
2294 cosEsc = 1;
2295 sinEsc = 0;
2298 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
2300 rc = *lprect;
2301 lp_to_dp(dc, (POINT*)&rc, 2);
2302 order_rect( &rc );
2303 if (flags & ETO_OPAQUE)
2304 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2306 else flags &= ~ETO_CLIPPED;
2308 if(count == 0)
2310 ret = TRUE;
2311 goto done;
2314 pt.x = x;
2315 pt.y = y;
2316 lp_to_dp(dc, &pt, 1);
2317 x = pt.x;
2318 y = pt.y;
2320 char_extra = GetTextCharacterExtra(hdc);
2321 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2322 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2324 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2326 UINT i;
2327 POINT total = {0, 0}, desired[2];
2329 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2330 if (lpDx)
2332 if (flags & ETO_PDY)
2334 for (i = 0; i < count; i++)
2336 deltas[i].x = lpDx[i * 2] + char_extra;
2337 deltas[i].y = -lpDx[i * 2 + 1];
2340 else
2342 for (i = 0; i < count; i++)
2344 deltas[i].x = lpDx[i] + char_extra;
2345 deltas[i].y = 0;
2349 else
2351 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2353 if (flags & ETO_GLYPH_INDEX)
2354 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2355 else
2356 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2358 deltas[0].x = dx[0];
2359 deltas[0].y = 0;
2360 for (i = 1; i < count; i++)
2362 deltas[i].x = dx[i] - dx[i - 1];
2363 deltas[i].y = 0;
2365 HeapFree( GetProcessHeap(), 0, dx );
2368 for(i = 0; i < count; i++)
2370 total.x += deltas[i].x;
2371 total.y += deltas[i].y;
2373 desired[0].x = desired[0].y = 0;
2375 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2376 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2378 lp_to_dp(dc, desired, 2);
2379 desired[1].x -= desired[0].x;
2380 desired[1].y -= desired[0].y;
2382 if (dc->GraphicsMode == GM_COMPATIBLE)
2384 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2385 desired[1].x = -desired[1].x;
2386 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2387 desired[1].y = -desired[1].y;
2390 deltas[i].x = desired[1].x - width.x;
2391 deltas[i].y = desired[1].y - width.y;
2393 width = desired[1];
2395 flags |= ETO_PDY;
2397 else
2399 POINT desired[2];
2401 if(flags & ETO_GLYPH_INDEX)
2402 GetTextExtentPointI(hdc, glyphs, count, &sz);
2403 else
2404 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2405 desired[0].x = desired[0].y = 0;
2406 desired[1].x = sz.cx;
2407 desired[1].y = 0;
2408 lp_to_dp(dc, desired, 2);
2409 desired[1].x -= desired[0].x;
2410 desired[1].y -= desired[0].y;
2412 if (dc->GraphicsMode == GM_COMPATIBLE)
2414 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2415 desired[1].x = -desired[1].x;
2416 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2417 desired[1].y = -desired[1].y;
2419 width = desired[1];
2422 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2423 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2424 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2426 case TA_LEFT:
2427 if (align & TA_UPDATECP)
2429 pt.x = x + width.x;
2430 pt.y = y + width.y;
2431 dp_to_lp(dc, &pt, 1);
2432 MoveToEx(hdc, pt.x, pt.y, NULL);
2434 break;
2436 case TA_CENTER:
2437 x -= width.x / 2;
2438 y -= width.y / 2;
2439 break;
2441 case TA_RIGHT:
2442 x -= width.x;
2443 y -= width.y;
2444 if (align & TA_UPDATECP)
2446 pt.x = x;
2447 pt.y = y;
2448 dp_to_lp(dc, &pt, 1);
2449 MoveToEx(hdc, pt.x, pt.y, NULL);
2451 break;
2454 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2456 case TA_TOP:
2457 y += tm.tmAscent * cosEsc;
2458 x += tm.tmAscent * sinEsc;
2459 break;
2461 case TA_BOTTOM:
2462 y -= tm.tmDescent * cosEsc;
2463 x -= tm.tmDescent * sinEsc;
2464 break;
2466 case TA_BASELINE:
2467 break;
2470 if (dc->backgroundMode != TRANSPARENT)
2472 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2474 if(!(flags & ETO_OPAQUE) || !lprect ||
2475 x < rc.left || x + width.x >= rc.right ||
2476 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2478 RECT text_box;
2479 text_box.left = x;
2480 text_box.right = x + width.x;
2481 text_box.top = y - tm.tmAscent;
2482 text_box.bottom = y + tm.tmDescent;
2484 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2485 if (!is_rect_empty( &text_box ))
2486 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2491 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2492 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2494 done:
2495 HeapFree(GetProcessHeap(), 0, deltas);
2496 if(glyphs != reordered_str)
2497 HeapFree(GetProcessHeap(), 0, glyphs);
2498 if(reordered_str != str)
2499 HeapFree(GetProcessHeap(), 0, reordered_str);
2501 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2503 int underlinePos, strikeoutPos;
2504 int underlineWidth, strikeoutWidth;
2505 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2506 OUTLINETEXTMETRICW* otm = NULL;
2507 POINT pts[5];
2508 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2509 HBRUSH hbrush = CreateSolidBrush(dc->textColor);
2511 hbrush = SelectObject(hdc, hbrush);
2513 if(!size)
2515 underlinePos = 0;
2516 underlineWidth = tm.tmAscent / 20 + 1;
2517 strikeoutPos = tm.tmAscent / 2;
2518 strikeoutWidth = underlineWidth;
2520 else
2522 otm = HeapAlloc(GetProcessHeap(), 0, size);
2523 GetOutlineTextMetricsW(hdc, size, otm);
2524 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2525 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2526 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
2527 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2528 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2529 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
2530 HeapFree(GetProcessHeap(), 0, otm);
2534 if (lf.lfUnderline)
2536 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2537 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2538 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2539 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2540 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2541 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2542 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2543 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2544 pts[4].x = pts[0].x;
2545 pts[4].y = pts[0].y;
2546 dp_to_lp(dc, pts, 5);
2547 Polygon(hdc, pts, 5);
2550 if (lf.lfStrikeOut)
2552 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2553 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2554 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2555 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2556 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2557 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2558 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2559 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2560 pts[4].x = pts[0].x;
2561 pts[4].y = pts[0].y;
2562 dp_to_lp(dc, pts, 5);
2563 Polygon(hdc, pts, 5);
2566 SelectObject(hdc, hpen);
2567 hbrush = SelectObject(hdc, hbrush);
2568 DeleteObject(hbrush);
2571 release_dc_ptr( dc );
2573 return ret;
2577 /***********************************************************************
2578 * TextOutA (GDI32.@)
2580 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2582 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2586 /***********************************************************************
2587 * TextOutW (GDI32.@)
2589 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2591 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2595 /***********************************************************************
2596 * PolyTextOutA (GDI32.@)
2598 * See PolyTextOutW.
2600 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2602 for (; cStrings>0; cStrings--, pptxt++)
2603 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2604 return FALSE;
2605 return TRUE;
2610 /***********************************************************************
2611 * PolyTextOutW (GDI32.@)
2613 * Draw several Strings
2615 * RETURNS
2616 * TRUE: Success.
2617 * FALSE: Failure.
2619 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2621 for (; cStrings>0; cStrings--, pptxt++)
2622 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2623 return FALSE;
2624 return TRUE;
2628 /***********************************************************************
2629 * SetMapperFlags (GDI32.@)
2631 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2633 DC *dc = get_dc_ptr( hdc );
2634 DWORD ret = GDI_ERROR;
2636 if (dc)
2638 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2639 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2640 if (flags != GDI_ERROR)
2642 ret = dc->mapperFlags;
2643 dc->mapperFlags = flags;
2645 release_dc_ptr( dc );
2647 return ret;
2650 /***********************************************************************
2651 * GetAspectRatioFilterEx (GDI32.@)
2653 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2655 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2656 return FALSE;
2660 /***********************************************************************
2661 * GetCharABCWidthsA (GDI32.@)
2663 * See GetCharABCWidthsW.
2665 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2666 LPABC abc )
2668 INT i, wlen;
2669 LPSTR str;
2670 LPWSTR wstr;
2671 BOOL ret = TRUE;
2673 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2674 if (str == NULL)
2675 return FALSE;
2677 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2678 if (wstr == NULL)
2680 HeapFree(GetProcessHeap(), 0, str);
2681 return FALSE;
2684 for(i = 0; i < wlen; i++)
2686 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2688 ret = FALSE;
2689 break;
2691 abc++;
2694 HeapFree(GetProcessHeap(), 0, str);
2695 HeapFree(GetProcessHeap(), 0, wstr);
2697 return ret;
2701 /******************************************************************************
2702 * GetCharABCWidthsW [GDI32.@]
2704 * Retrieves widths of characters in range.
2706 * PARAMS
2707 * hdc [I] Handle of device context
2708 * firstChar [I] First character in range to query
2709 * lastChar [I] Last character in range to query
2710 * abc [O] Address of character-width structure
2712 * NOTES
2713 * Only works with TrueType fonts
2715 * RETURNS
2716 * Success: TRUE
2717 * Failure: FALSE
2719 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2720 LPABC abc )
2722 DC *dc = get_dc_ptr(hdc);
2723 PHYSDEV dev;
2724 unsigned int i;
2725 BOOL ret;
2726 TEXTMETRICW tm;
2728 if (!dc) return FALSE;
2730 if (!abc)
2732 release_dc_ptr( dc );
2733 return FALSE;
2736 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2737 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2738 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2740 release_dc_ptr( dc );
2741 return FALSE;
2744 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2745 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2746 if (ret)
2748 /* convert device units to logical */
2749 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2750 abc->abcA = width_to_LP(dc, abc->abcA);
2751 abc->abcB = width_to_LP(dc, abc->abcB);
2752 abc->abcC = width_to_LP(dc, abc->abcC);
2756 release_dc_ptr( dc );
2757 return ret;
2761 /******************************************************************************
2762 * GetCharABCWidthsI [GDI32.@]
2764 * Retrieves widths of characters in range.
2766 * PARAMS
2767 * hdc [I] Handle of device context
2768 * firstChar [I] First glyphs in range to query
2769 * count [I] Last glyphs in range to query
2770 * pgi [i] Array of glyphs to query
2771 * abc [O] Address of character-width structure
2773 * NOTES
2774 * Only works with TrueType fonts
2776 * RETURNS
2777 * Success: TRUE
2778 * Failure: FALSE
2780 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2781 LPWORD pgi, LPABC abc)
2783 DC *dc = get_dc_ptr(hdc);
2784 PHYSDEV dev;
2785 unsigned int i;
2786 BOOL ret;
2788 if (!dc) return FALSE;
2790 if (!abc)
2792 release_dc_ptr( dc );
2793 return FALSE;
2796 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2797 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2798 if (ret)
2800 /* convert device units to logical */
2801 for( i = 0; i < count; i++, abc++ ) {
2802 abc->abcA = width_to_LP(dc, abc->abcA);
2803 abc->abcB = width_to_LP(dc, abc->abcB);
2804 abc->abcC = width_to_LP(dc, abc->abcC);
2808 release_dc_ptr( dc );
2809 return ret;
2813 /***********************************************************************
2814 * GetGlyphOutlineA (GDI32.@)
2816 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2817 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2818 LPVOID lpBuffer, const MAT2 *lpmat2 )
2820 if (!lpmat2) return GDI_ERROR;
2822 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2823 UINT cp;
2824 int len;
2825 char mbchs[2];
2826 WCHAR wChar;
2828 cp = GdiGetCodePage(hdc);
2829 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2830 len = 2;
2831 mbchs[0] = (uChar & 0xff00) >> 8;
2832 mbchs[1] = (uChar & 0xff);
2833 } else {
2834 len = 1;
2835 mbchs[0] = (uChar & 0xff);
2837 wChar = 0;
2838 MultiByteToWideChar(cp, 0, mbchs, len, &wChar, 1);
2839 uChar = wChar;
2842 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2843 lpmat2);
2846 /***********************************************************************
2847 * GetGlyphOutlineW (GDI32.@)
2849 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2850 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2851 LPVOID lpBuffer, const MAT2 *lpmat2 )
2853 DC *dc;
2854 DWORD ret;
2855 PHYSDEV dev;
2857 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2858 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2860 if (!lpmat2) return GDI_ERROR;
2862 dc = get_dc_ptr(hdc);
2863 if(!dc) return GDI_ERROR;
2865 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2866 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2867 release_dc_ptr( dc );
2868 return ret;
2872 /***********************************************************************
2873 * CreateScalableFontResourceA (GDI32.@)
2875 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2876 LPCSTR lpszResourceFile,
2877 LPCSTR lpszFontFile,
2878 LPCSTR lpszCurrentPath )
2880 LPWSTR lpszResourceFileW = NULL;
2881 LPWSTR lpszFontFileW = NULL;
2882 LPWSTR lpszCurrentPathW = NULL;
2883 int len;
2884 BOOL ret;
2886 if (lpszResourceFile)
2888 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2889 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2890 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2893 if (lpszFontFile)
2895 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2896 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2897 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2900 if (lpszCurrentPath)
2902 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2903 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2904 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2907 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2908 lpszFontFileW, lpszCurrentPathW);
2910 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2911 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2912 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2914 return ret;
2917 /***********************************************************************
2918 * CreateScalableFontResourceW (GDI32.@)
2920 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2921 LPCWSTR font_file, LPCWSTR font_path )
2923 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2924 debugstr_w(font_file), debugstr_w(font_path) );
2926 return WineEngCreateScalableFontResource( hidden, resource_file,
2927 font_file, font_path );
2930 /*************************************************************************
2931 * GetKerningPairsA (GDI32.@)
2933 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2934 LPKERNINGPAIR kern_pairA )
2936 UINT cp;
2937 CPINFO cpi;
2938 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2939 KERNINGPAIR *kern_pairW;
2941 if (!cPairs && kern_pairA)
2943 SetLastError(ERROR_INVALID_PARAMETER);
2944 return 0;
2947 cp = GdiGetCodePage(hDC);
2949 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2950 * to fail on an invalid character for CP_SYMBOL.
2952 cpi.DefaultChar[0] = 0;
2953 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2955 FIXME("Can't find codepage %u info\n", cp);
2956 return 0;
2959 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2960 if (!total_kern_pairs) return 0;
2962 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2963 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2965 for (i = 0; i < total_kern_pairs; i++)
2967 char first, second;
2969 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2970 continue;
2972 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2973 continue;
2975 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2976 continue;
2978 if (kern_pairA)
2980 if (kern_pairs_copied >= cPairs) break;
2982 kern_pairA->wFirst = (BYTE)first;
2983 kern_pairA->wSecond = (BYTE)second;
2984 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2985 kern_pairA++;
2987 kern_pairs_copied++;
2990 HeapFree(GetProcessHeap(), 0, kern_pairW);
2992 return kern_pairs_copied;
2995 /*************************************************************************
2996 * GetKerningPairsW (GDI32.@)
2998 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2999 LPKERNINGPAIR lpKerningPairs )
3001 DC *dc;
3002 DWORD ret;
3003 PHYSDEV dev;
3005 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
3007 if (!cPairs && lpKerningPairs)
3009 SetLastError(ERROR_INVALID_PARAMETER);
3010 return 0;
3013 dc = get_dc_ptr(hDC);
3014 if (!dc) return 0;
3016 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
3017 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
3018 release_dc_ptr( dc );
3019 return ret;
3022 /*************************************************************************
3023 * TranslateCharsetInfo [GDI32.@]
3025 * Fills a CHARSETINFO structure for a character set, code page, or
3026 * font. This allows making the correspondence between different labels
3027 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
3028 * of the same encoding.
3030 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
3031 * only one codepage should be set in *lpSrc.
3033 * RETURNS
3034 * TRUE on success, FALSE on failure.
3037 BOOL WINAPI TranslateCharsetInfo(
3038 LPDWORD lpSrc, /* [in]
3039 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
3040 if flags == TCI_SRCCHARSET: a character set value
3041 if flags == TCI_SRCCODEPAGE: a code page value
3043 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
3044 DWORD flags /* [in] determines interpretation of lpSrc */)
3046 int index = 0;
3047 switch (flags) {
3048 case TCI_SRCFONTSIG:
3049 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3050 break;
3051 case TCI_SRCCODEPAGE:
3052 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3053 break;
3054 case TCI_SRCCHARSET:
3055 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3056 break;
3057 default:
3058 return FALSE;
3060 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3061 *lpCs = FONT_tci[index];
3062 return TRUE;
3065 /*************************************************************************
3066 * GetFontLanguageInfo (GDI32.@)
3068 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3070 FONTSIGNATURE fontsig;
3071 static const DWORD GCP_DBCS_MASK=FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB,
3072 GCP_DIACRITIC_MASK=0x00000000,
3073 FLI_GLYPHS_MASK=0x00000000,
3074 GCP_GLYPHSHAPE_MASK=FS_ARABIC,
3075 GCP_KASHIDA_MASK=0x00000000,
3076 GCP_LIGATE_MASK=0x00000000,
3077 GCP_REORDER_MASK=FS_HEBREW|FS_ARABIC;
3079 DWORD result=0;
3081 GetTextCharsetInfo( hdc, &fontsig, 0 );
3082 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3084 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3085 result|=GCP_DBCS;
3087 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3088 result|=GCP_DIACRITIC;
3090 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3091 result|=FLI_GLYPHS;
3093 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3094 result|=GCP_GLYPHSHAPE;
3096 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3097 result|=GCP_KASHIDA;
3099 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3100 result|=GCP_LIGATE;
3102 if( GetKerningPairsW( hdc, 0, NULL ) )
3103 result|=GCP_USEKERNING;
3105 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3106 if( GetTextAlign( hdc) & TA_RTLREADING )
3107 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3108 result|=GCP_REORDER;
3110 return result;
3114 /*************************************************************************
3115 * GetFontData [GDI32.@]
3117 * Retrieve data for TrueType font.
3119 * RETURNS
3121 * success: Number of bytes returned
3122 * failure: GDI_ERROR
3124 * NOTES
3126 * Calls SetLastError()
3129 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3130 LPVOID buffer, DWORD length)
3132 DC *dc = get_dc_ptr(hdc);
3133 PHYSDEV dev;
3134 DWORD ret;
3136 if(!dc) return GDI_ERROR;
3138 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3139 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3140 release_dc_ptr( dc );
3141 return ret;
3144 /*************************************************************************
3145 * GetGlyphIndicesA [GDI32.@]
3147 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3148 LPWORD pgi, DWORD flags)
3150 DWORD ret;
3151 WCHAR *lpstrW;
3152 INT countW;
3154 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3155 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3157 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3158 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3159 HeapFree(GetProcessHeap(), 0, lpstrW);
3161 return ret;
3164 /*************************************************************************
3165 * GetGlyphIndicesW [GDI32.@]
3167 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3168 LPWORD pgi, DWORD flags)
3170 DC *dc = get_dc_ptr(hdc);
3171 PHYSDEV dev;
3172 DWORD ret;
3174 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3175 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3177 if(!dc) return GDI_ERROR;
3179 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3180 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3181 release_dc_ptr( dc );
3182 return ret;
3185 /*************************************************************************
3186 * GetCharacterPlacementA [GDI32.@]
3188 * See GetCharacterPlacementW.
3190 * NOTES:
3191 * the web browser control of ie4 calls this with dwFlags=0
3193 DWORD WINAPI
3194 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3195 INT nMaxExtent, GCP_RESULTSA *lpResults,
3196 DWORD dwFlags)
3198 WCHAR *lpStringW;
3199 INT uCountW;
3200 GCP_RESULTSW resultsW;
3201 DWORD ret;
3202 UINT font_cp;
3204 TRACE("%s, %d, %d, 0x%08x\n",
3205 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3207 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3209 if (!lpResults)
3211 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, NULL, dwFlags);
3212 HeapFree(GetProcessHeap(), 0, lpStringW);
3213 return ret;
3216 /* both structs are equal in size */
3217 memcpy(&resultsW, lpResults, sizeof(resultsW));
3219 if(lpResults->lpOutString)
3220 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3222 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3224 lpResults->nGlyphs = resultsW.nGlyphs;
3225 lpResults->nMaxFit = resultsW.nMaxFit;
3227 if(lpResults->lpOutString) {
3228 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3229 lpResults->lpOutString, uCount, NULL, NULL );
3232 HeapFree(GetProcessHeap(), 0, lpStringW);
3233 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3235 return ret;
3238 /*************************************************************************
3239 * GetCharacterPlacementW [GDI32.@]
3241 * Retrieve information about a string. This includes the width, reordering,
3242 * Glyphing and so on.
3244 * RETURNS
3246 * The width and height of the string if successful, 0 if failed.
3248 * BUGS
3250 * All flags except GCP_REORDER are not yet implemented.
3251 * Reordering is not 100% compliant to the Windows BiDi method.
3252 * Caret positioning is not yet implemented for BiDi.
3253 * Classes are not yet implemented.
3256 DWORD WINAPI
3257 GetCharacterPlacementW(
3258 HDC hdc, /* [in] Device context for which the rendering is to be done */
3259 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3260 INT uCount, /* [in] Number of WORDS in string. */
3261 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3262 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3263 DWORD dwFlags /* [in] Flags specifying how to process the string */
3266 DWORD ret=0;
3267 SIZE size;
3268 UINT i, nSet;
3270 TRACE("%s, %d, %d, 0x%08x\n",
3271 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3273 if (!lpResults)
3274 return GetTextExtentPoint32W(hdc, lpString, uCount, &size) ? MAKELONG(size.cx, size.cy) : 0;
3276 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3277 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3278 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3279 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3280 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3282 if(dwFlags&(~GCP_REORDER))
3283 FIXME("flags 0x%08x ignored\n", dwFlags);
3284 if(lpResults->lpClass)
3285 FIXME("classes not implemented\n");
3286 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3287 FIXME("Caret positions for complex scripts not implemented\n");
3289 nSet = (UINT)uCount;
3290 if(nSet > lpResults->nGlyphs)
3291 nSet = lpResults->nGlyphs;
3293 /* return number of initialized fields */
3294 lpResults->nGlyphs = nSet;
3296 if((dwFlags&GCP_REORDER)==0 )
3298 /* Treat the case where no special handling was requested in a fastpath way */
3299 /* copy will do if the GCP_REORDER flag is not set */
3300 if(lpResults->lpOutString)
3301 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3303 if(lpResults->lpOrder)
3305 for(i = 0; i < nSet; i++)
3306 lpResults->lpOrder[i] = i;
3309 else
3311 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3312 nSet, lpResults->lpOrder, NULL, NULL );
3315 /* FIXME: Will use the placement chars */
3316 if (lpResults->lpDx)
3318 int c;
3319 for (i = 0; i < nSet; i++)
3321 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3322 lpResults->lpDx[i]= c;
3326 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3328 int pos = 0;
3330 lpResults->lpCaretPos[0] = 0;
3331 for (i = 1; i < nSet; i++)
3332 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3333 lpResults->lpCaretPos[i] = (pos += size.cx);
3336 if(lpResults->lpGlyphs)
3337 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3339 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3340 ret = MAKELONG(size.cx, size.cy);
3342 return ret;
3345 /*************************************************************************
3346 * GetCharABCWidthsFloatA [GDI32.@]
3348 * See GetCharABCWidthsFloatW.
3350 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3352 INT i, wlen;
3353 LPSTR str;
3354 LPWSTR wstr;
3355 BOOL ret = TRUE;
3357 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3358 if (str == NULL)
3359 return FALSE;
3361 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3363 for (i = 0; i < wlen; i++)
3365 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3367 ret = FALSE;
3368 break;
3370 abcf++;
3373 HeapFree( GetProcessHeap(), 0, str );
3374 HeapFree( GetProcessHeap(), 0, wstr );
3376 return ret;
3379 /*************************************************************************
3380 * GetCharABCWidthsFloatW [GDI32.@]
3382 * Retrieves widths of a range of characters.
3384 * PARAMS
3385 * hdc [I] Handle to device context.
3386 * first [I] First character in range to query.
3387 * last [I] Last character in range to query.
3388 * abcf [O] Array of LPABCFLOAT structures.
3390 * RETURNS
3391 * Success: TRUE
3392 * Failure: FALSE
3394 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3396 UINT i;
3397 ABC *abc;
3398 PHYSDEV dev;
3399 BOOL ret = FALSE;
3400 DC *dc = get_dc_ptr( hdc );
3402 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3404 if (!dc) return FALSE;
3406 if (!abcf) goto done;
3407 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3409 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3410 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3411 if (ret)
3413 /* convert device units to logical */
3414 FLOAT scale = fabs( dc->xformVport2World.eM11 );
3415 for (i = first; i <= last; i++, abcf++)
3417 abcf->abcfA = abc[i - first].abcA * scale;
3418 abcf->abcfB = abc[i - first].abcB * scale;
3419 abcf->abcfC = abc[i - first].abcC * scale;
3422 HeapFree( GetProcessHeap(), 0, abc );
3424 done:
3425 release_dc_ptr( dc );
3426 return ret;
3429 /*************************************************************************
3430 * GetCharWidthFloatA [GDI32.@]
3432 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3433 UINT iLastChar, PFLOAT pxBuffer)
3435 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3436 return FALSE;
3439 /*************************************************************************
3440 * GetCharWidthFloatW [GDI32.@]
3442 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3443 UINT iLastChar, PFLOAT pxBuffer)
3445 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3446 return FALSE;
3450 /***********************************************************************
3452 * Font Resource API *
3454 ***********************************************************************/
3456 /***********************************************************************
3457 * AddFontResourceA (GDI32.@)
3459 INT WINAPI AddFontResourceA( LPCSTR str )
3461 return AddFontResourceExA( str, 0, NULL);
3464 /***********************************************************************
3465 * AddFontResourceW (GDI32.@)
3467 INT WINAPI AddFontResourceW( LPCWSTR str )
3469 return AddFontResourceExW(str, 0, NULL);
3473 /***********************************************************************
3474 * AddFontResourceExA (GDI32.@)
3476 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3478 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3479 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3480 INT ret;
3482 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3483 ret = AddFontResourceExW(strW, fl, pdv);
3484 HeapFree(GetProcessHeap(), 0, strW);
3485 return ret;
3488 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3490 HRSRC rsrc = FindResourceW(hModule, name, type);
3491 HGLOBAL hMem = LoadResource(hModule, rsrc);
3492 LPVOID *pMem = LockResource(hMem);
3493 int *num_total = (int *)lParam;
3494 DWORD num_in_res;
3496 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3497 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3499 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3500 return FALSE;
3503 *num_total += num_in_res;
3504 return TRUE;
3507 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3509 HANDLE file, mapping;
3510 void *ptr;
3512 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3513 if (file == INVALID_HANDLE_VALUE) return NULL;
3515 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3517 CloseHandle( file );
3518 return NULL;
3521 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3522 CloseHandle( file );
3523 if (!mapping) return NULL;
3525 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3526 CloseHandle( mapping );
3528 return ptr;
3531 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3533 WORD align, type_id, count;
3534 DWORD res_off;
3536 if (size < rsrc_off + 10) return NULL;
3537 align = *(WORD *)(ptr + rsrc_off);
3538 rsrc_off += 2;
3539 type_id = *(WORD *)(ptr + rsrc_off);
3540 while (type_id && type_id != type)
3542 count = *(WORD *)(ptr + rsrc_off + 2);
3543 rsrc_off += 8 + count * 12;
3544 if (size < rsrc_off + 8) return NULL;
3545 type_id = *(WORD *)(ptr + rsrc_off);
3547 if (!type_id) return NULL;
3548 count = *(WORD *)(ptr + rsrc_off + 2);
3549 if (size < rsrc_off + 8 + count * 12) return NULL;
3550 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3551 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3552 if (size < res_off + *len) return NULL;
3553 return ptr + res_off;
3556 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3558 LARGE_INTEGER size;
3559 BYTE *ptr = map_file( res, &size );
3560 const IMAGE_DOS_HEADER *dos;
3561 const IMAGE_OS2_HEADER *ne;
3562 WORD *fontdir;
3563 char *data;
3564 WCHAR *name = NULL;
3565 DWORD len;
3567 if (!ptr) return NULL;
3569 if (size.u.LowPart < sizeof( *dos )) goto fail;
3570 dos = (const IMAGE_DOS_HEADER *)ptr;
3571 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3572 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3573 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3575 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3576 if (!fontdir) goto fail;
3577 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3579 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3580 if (!data) goto fail;
3581 if (!memchr( data, 0, len )) goto fail;
3583 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3584 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3585 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3587 fail:
3588 UnmapViewOfFile( ptr );
3589 return name;
3592 /***********************************************************************
3593 * AddFontResourceExW (GDI32.@)
3595 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3597 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3598 WCHAR *filename;
3599 BOOL hidden;
3601 if (ret == 0)
3603 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3604 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3605 if (hModule != NULL)
3607 int num_resources = 0;
3608 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3610 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3611 wine_dbgstr_w(str));
3612 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3613 ret = num_resources;
3614 FreeLibrary(hModule);
3616 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3618 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3619 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3620 HeapFree( GetProcessHeap(), 0, filename );
3623 return ret;
3626 /***********************************************************************
3627 * RemoveFontResourceA (GDI32.@)
3629 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3631 return RemoveFontResourceExA(str, 0, 0);
3634 /***********************************************************************
3635 * RemoveFontResourceW (GDI32.@)
3637 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3639 return RemoveFontResourceExW(str, 0, 0);
3642 /***********************************************************************
3643 * AddFontMemResourceEx (GDI32.@)
3645 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3647 HANDLE ret;
3648 DWORD num_fonts;
3650 if (!pbFont || !cbFont || !pcFonts)
3652 SetLastError(ERROR_INVALID_PARAMETER);
3653 return NULL;
3656 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3657 if (ret)
3659 __TRY
3661 *pcFonts = num_fonts;
3663 __EXCEPT_PAGE_FAULT
3665 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3666 RemoveFontMemResourceEx(ret);
3667 ret = 0;
3669 __ENDTRY
3671 return ret;
3674 /***********************************************************************
3675 * RemoveFontMemResourceEx (GDI32.@)
3677 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3679 FIXME("(%p) stub\n", fh);
3680 return TRUE;
3683 /***********************************************************************
3684 * RemoveFontResourceExA (GDI32.@)
3686 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3688 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3689 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3690 INT ret;
3692 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3693 ret = RemoveFontResourceExW(strW, fl, pdv);
3694 HeapFree(GetProcessHeap(), 0, strW);
3695 return ret;
3698 /***********************************************************************
3699 * RemoveFontResourceExW (GDI32.@)
3701 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3703 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3704 WCHAR *filename;
3705 BOOL hidden;
3707 if (ret == 0)
3709 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3710 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3711 if (hModule != NULL)
3713 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3714 FreeLibrary(hModule);
3716 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3718 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3719 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3720 HeapFree( GetProcessHeap(), 0, filename );
3723 return ret;
3726 /***********************************************************************
3727 * GetFontResourceInfoW (GDI32.@)
3729 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3731 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3732 return FALSE;
3735 /***********************************************************************
3736 * GetTextCharset (GDI32.@)
3738 UINT WINAPI GetTextCharset(HDC hdc)
3740 /* MSDN docs say this is equivalent */
3741 return GetTextCharsetInfo(hdc, NULL, 0);
3744 /***********************************************************************
3745 * GdiGetCharDimensions (GDI32.@)
3747 * Gets the average width of the characters in the English alphabet.
3749 * PARAMS
3750 * hdc [I] Handle to the device context to measure on.
3751 * lptm [O] Pointer to memory to store the text metrics into.
3752 * height [O] On exit, the maximum height of characters in the English alphabet.
3754 * RETURNS
3755 * The average width of characters in the English alphabet.
3757 * NOTES
3758 * This function is used by the dialog manager to get the size of a dialog
3759 * unit. It should also be used by other pieces of code that need to know
3760 * the size of a dialog unit in logical units without having access to the
3761 * window handle of the dialog.
3762 * Windows caches the font metrics from this function, but we don't and
3763 * there doesn't appear to be an immediate advantage to do so.
3765 * SEE ALSO
3766 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3768 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3770 SIZE sz;
3771 static const WCHAR alphabet[] = {
3772 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3773 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3774 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3776 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3778 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3780 if (height) *height = sz.cy;
3781 return (sz.cx / 26 + 1) / 2;
3784 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3786 FIXME("(%d): stub\n", fEnableEUDC);
3787 return FALSE;
3790 /***********************************************************************
3791 * GetCharWidthI (GDI32.@)
3793 * Retrieve widths of characters.
3795 * PARAMS
3796 * hdc [I] Handle to a device context.
3797 * first [I] First glyph in range to query.
3798 * count [I] Number of glyph indices to query.
3799 * glyphs [I] Array of glyphs to query.
3800 * buffer [O] Buffer to receive character widths.
3802 * NOTES
3803 * Only works with TrueType fonts.
3805 * RETURNS
3806 * Success: TRUE
3807 * Failure: FALSE
3809 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3811 ABC *abc;
3812 unsigned int i;
3814 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3816 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3817 return FALSE;
3819 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3821 HeapFree(GetProcessHeap(), 0, abc);
3822 return FALSE;
3825 for (i = 0; i < count; i++)
3826 buffer[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
3828 HeapFree(GetProcessHeap(), 0, abc);
3829 return TRUE;
3832 /***********************************************************************
3833 * GetFontUnicodeRanges (GDI32.@)
3835 * Retrieve a list of supported Unicode characters in a font.
3837 * PARAMS
3838 * hdc [I] Handle to a device context.
3839 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3841 * RETURNS
3842 * Success: Number of bytes written to the buffer pointed to by lpgs.
3843 * Failure: 0
3846 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3848 DWORD ret;
3849 PHYSDEV dev;
3850 DC *dc = get_dc_ptr(hdc);
3852 TRACE("(%p, %p)\n", hdc, lpgs);
3854 if (!dc) return 0;
3856 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3857 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3858 release_dc_ptr(dc);
3859 return ret;
3863 /*************************************************************
3864 * FontIsLinked (GDI32.@)
3866 BOOL WINAPI FontIsLinked(HDC hdc)
3868 DC *dc = get_dc_ptr(hdc);
3869 PHYSDEV dev;
3870 BOOL ret;
3872 if (!dc) return FALSE;
3873 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3874 ret = dev->funcs->pFontIsLinked( dev );
3875 release_dc_ptr(dc);
3876 TRACE("returning %d\n", ret);
3877 return ret;
3880 /*************************************************************
3881 * GetFontRealizationInfo (GDI32.@)
3883 BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info)
3885 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, unk);
3886 PHYSDEV dev;
3887 BOOL ret;
3888 DC *dc;
3890 if (info->size != sizeof(*info) && !is_v0)
3891 return FALSE;
3893 dc = get_dc_ptr(hdc);
3894 if (!dc) return FALSE;
3895 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
3896 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
3897 release_dc_ptr(dc);
3898 return ret;
3901 struct realization_info
3903 DWORD flags; /* 1 for bitmap fonts, 3 for scalable fonts */
3904 DWORD cache_num; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
3905 DWORD instance_id; /* identifies a realized font instance */
3908 /*************************************************************
3909 * GdiRealizationInfo (GDI32.@)
3911 * Returns a structure that contains some font information.
3913 BOOL WINAPI GdiRealizationInfo(HDC hdc, struct realization_info *info)
3915 struct font_realization_info ri;
3916 BOOL ret;
3918 ri.size = sizeof(ri);
3919 ret = GetFontRealizationInfo( hdc, &ri );
3920 if (ret)
3922 info->flags = ri.flags;
3923 info->cache_num = ri.cache_num;
3924 info->instance_id = ri.instance_id;
3927 return ret;