gdiplus: Get rid of no longer needed path and region fields.
[wine.git] / dlls / gdi32 / font.c
bloba025d172b6160fb83a338c2905bea2b1932287d2
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <limits.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include "winerror.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "winreg.h"
37 #include "gdi_private.h"
38 #include "wine/exception.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(font);
44 /* Device -> World size conversion */
46 /* Performs a device to world transformation on the specified width (which
47 * is in integer format).
49 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
51 double floatWidth;
53 /* Perform operation with floating point */
54 floatWidth = (double)width * dc->xformVport2World.eM11;
55 /* Round to integers */
56 return GDI_ROUND(floatWidth);
59 /* Performs a device to world transformation on the specified size (which
60 * is in integer format).
62 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
64 double floatHeight;
66 /* Perform operation with floating point */
67 floatHeight = (double)height * dc->xformVport2World.eM22;
68 /* Round to integers */
69 return GDI_ROUND(floatHeight);
72 /* scale width and height but don't mirror them */
74 static inline INT width_to_LP( DC *dc, INT width )
76 return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
79 static inline INT height_to_LP( DC *dc, INT height )
81 return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
84 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
86 POINT pt[2];
87 pt[0].x = pt[0].y = 0;
88 pt[1].x = width;
89 pt[1].y = 0;
90 LPtoDP(dc->hSelf, pt, 2);
91 return pt[1].x - pt[0].x;
94 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
96 POINT pt[2];
97 pt[0].x = pt[0].y = 0;
98 pt[1].x = 0;
99 pt[1].y = height;
100 LPtoDP(dc->hSelf, pt, 2);
101 return pt[1].y - pt[0].y;
104 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
105 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
106 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
107 static BOOL FONT_DeleteObject( HGDIOBJ handle );
109 static const struct gdi_obj_funcs font_funcs =
111 FONT_SelectObject, /* pSelectObject */
112 FONT_GetObjectA, /* pGetObjectA */
113 FONT_GetObjectW, /* pGetObjectW */
114 NULL, /* pUnrealizeObject */
115 FONT_DeleteObject /* pDeleteObject */
118 typedef struct
120 LOGFONTW logfont;
121 } FONTOBJ;
123 struct font_enum
125 LPLOGFONTW lpLogFontParam;
126 FONTENUMPROCW lpEnumFunc;
127 LPARAM lpData;
128 BOOL unicode;
129 HDC hdc;
130 INT retval;
134 * For TranslateCharsetInfo
136 #define MAXTCIINDEX 32
137 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
138 /* ANSI */
139 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
140 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
141 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
142 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
143 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
144 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
145 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
146 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
147 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
148 /* reserved by ANSI */
149 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
150 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
151 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 /* ANSI and OEM */
157 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
158 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
159 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
160 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
161 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
162 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
163 /* reserved for alternate ANSI and OEM */
164 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
165 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
166 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
167 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
168 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
169 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
170 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
171 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
172 /* reserved for system */
173 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
174 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
177 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
179 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
180 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
181 LF_FACESIZE);
182 fontW->lfFaceName[LF_FACESIZE-1] = 0;
185 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
187 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
188 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
189 LF_FACESIZE, NULL, NULL);
190 fontA->lfFaceName[LF_FACESIZE-1] = 0;
193 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
195 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
197 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
198 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
199 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
200 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
201 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
202 fontA->elfStyle[LF_FACESIZE-1] = '\0';
203 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
204 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
205 fontA->elfScript[LF_FACESIZE-1] = '\0';
208 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
210 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
212 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
213 fontW->elfFullName, LF_FULLFACESIZE );
214 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
215 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
216 fontW->elfStyle, LF_FACESIZE );
217 fontW->elfStyle[LF_FACESIZE-1] = '\0';
218 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
219 fontW->elfScript, LF_FACESIZE );
220 fontW->elfScript[LF_FACESIZE-1] = '\0';
223 /***********************************************************************
224 * TEXTMETRIC conversion functions.
226 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
228 ptmA->tmHeight = ptmW->tmHeight;
229 ptmA->tmAscent = ptmW->tmAscent;
230 ptmA->tmDescent = ptmW->tmDescent;
231 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
232 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
233 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
234 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
235 ptmA->tmWeight = ptmW->tmWeight;
236 ptmA->tmOverhang = ptmW->tmOverhang;
237 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
238 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
239 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
240 if (ptmW->tmCharSet == SYMBOL_CHARSET)
242 ptmA->tmFirstChar = 0x1e;
243 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
245 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
247 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
248 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
250 else
252 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
253 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
255 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
256 ptmA->tmBreakChar = ptmW->tmBreakChar;
257 ptmA->tmItalic = ptmW->tmItalic;
258 ptmA->tmUnderlined = ptmW->tmUnderlined;
259 ptmA->tmStruckOut = ptmW->tmStruckOut;
260 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
261 ptmA->tmCharSet = ptmW->tmCharSet;
265 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
267 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
268 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
269 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
270 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
271 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
272 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
275 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
277 WCHAR buf[12];
278 DWORD count = sizeof(buf), type, err;
280 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
281 if (!err)
283 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
284 else *value = atoiW( buf );
286 return err;
289 static UINT get_subpixel_orientation( HKEY key )
291 static const WCHAR smoothing_orientation[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
292 'O','r','i','e','n','t','a','t','i','o','n',0};
293 DWORD orient;
295 /* FIXME: handle vertical orientations even though Windows doesn't */
296 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
298 switch (orient)
300 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
301 return WINE_GGO_HBGR_BITMAP;
302 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
303 return WINE_GGO_HRGB_BITMAP;
305 return GGO_GRAY4_BITMAP;
308 static UINT get_default_smoothing( HKEY key )
310 static const WCHAR smoothing[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
311 static const WCHAR smoothing_type[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
312 DWORD enabled, type;
314 if (get_key_value( key, smoothing, &enabled )) return 0;
315 if (!enabled) return GGO_BITMAP;
317 if (!get_key_value( key, smoothing_type, &type ) && type == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
318 return get_subpixel_orientation( key );
320 return GGO_GRAY4_BITMAP;
323 /* compute positions for text rendering, in device coords */
324 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
326 TEXTMETRICW tm;
327 PHYSDEV dev;
329 size->cx = size->cy = 0;
330 if (!count) return TRUE;
332 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
333 dev->funcs->pGetTextMetrics( dev, &tm );
335 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
336 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
338 if (dc->breakExtra || dc->breakRem)
340 int i, space = 0, rem = dc->breakRem;
342 for (i = 0; i < count; i++)
344 if (str[i] == tm.tmBreakChar)
346 space += dc->breakExtra;
347 if (rem > 0)
349 space++;
350 rem--;
353 dx[i] += space;
356 size->cx = dx[count - 1];
357 size->cy = tm.tmHeight;
358 return TRUE;
361 /* compute positions for text rendering, in device coords */
362 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
364 TEXTMETRICW tm;
365 PHYSDEV dev;
367 size->cx = size->cy = 0;
368 if (!count) return TRUE;
370 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
371 dev->funcs->pGetTextMetrics( dev, &tm );
373 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
374 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
376 if (dc->breakExtra || dc->breakRem)
378 WORD space_index;
379 int i, space = 0, rem = dc->breakRem;
381 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
382 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
384 for (i = 0; i < count; i++)
386 if (indices[i] == space_index)
388 space += dc->breakExtra;
389 if (rem > 0)
391 space++;
392 rem--;
395 dx[i] += space;
398 size->cx = dx[count - 1];
399 size->cy = tm.tmHeight;
400 return TRUE;
403 /***********************************************************************
404 * GdiGetCodePage (GDI32.@)
406 DWORD WINAPI GdiGetCodePage( HDC hdc )
408 UINT cp = CP_ACP;
409 DC *dc = get_dc_ptr( hdc );
411 if (dc)
413 cp = dc->font_code_page;
414 release_dc_ptr( dc );
416 return cp;
419 /***********************************************************************
420 * FONT_mbtowc
422 * Returns a Unicode translation of str using the charset of the
423 * currently selected font in hdc. If count is -1 then str is assumed
424 * to be '\0' terminated, otherwise it contains the number of bytes to
425 * convert. If plenW is non-NULL, on return it will point to the
426 * number of WCHARs that have been written. If pCP is non-NULL, on
427 * return it will point to the codepage used in the conversion. The
428 * caller should free the returned LPWSTR from the process heap
429 * itself.
431 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
433 UINT cp;
434 INT lenW;
435 LPWSTR strW;
437 cp = GdiGetCodePage( hdc );
439 if(count == -1) count = strlen(str);
440 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
441 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
442 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
443 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
444 if(plenW) *plenW = lenW;
445 if(pCP) *pCP = cp;
446 return strW;
449 /***********************************************************************
450 * CreateFontIndirectExA (GDI32.@)
452 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
454 ENUMLOGFONTEXDVW enumexW;
456 if (!penumexA) return 0;
458 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
459 enumexW.elfDesignVector = penumexA->elfDesignVector;
460 return CreateFontIndirectExW( &enumexW );
463 /***********************************************************************
464 * CreateFontIndirectExW (GDI32.@)
466 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
468 HFONT hFont;
469 FONTOBJ *fontPtr;
470 const LOGFONTW *plf;
472 if (!penumex) return 0;
474 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
475 penumex->elfEnumLogfontEx.elfStyle[0] ||
476 penumex->elfEnumLogfontEx.elfScript[0])
478 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
479 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
480 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
481 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
484 plf = &penumex->elfEnumLogfontEx.elfLogFont;
485 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
487 fontPtr->logfont = *plf;
489 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
491 HeapFree( GetProcessHeap(), 0, fontPtr );
492 return 0;
495 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
496 plf->lfHeight, plf->lfWidth,
497 plf->lfEscapement, plf->lfOrientation,
498 plf->lfPitchAndFamily,
499 plf->lfOutPrecision, plf->lfClipPrecision,
500 plf->lfQuality, plf->lfCharSet,
501 debugstr_w(plf->lfFaceName),
502 plf->lfWeight > 400 ? "Bold" : "",
503 plf->lfItalic ? "Italic" : "",
504 plf->lfUnderline ? "Underline" : "", hFont);
506 return hFont;
509 /***********************************************************************
510 * CreateFontIndirectA (GDI32.@)
512 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
514 LOGFONTW lfW;
516 if (!plfA) return 0;
518 FONT_LogFontAToW( plfA, &lfW );
519 return CreateFontIndirectW( &lfW );
522 /***********************************************************************
523 * CreateFontIndirectW (GDI32.@)
525 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
527 ENUMLOGFONTEXDVW exdv;
529 if (!plf) return 0;
531 exdv.elfEnumLogfontEx.elfLogFont = *plf;
532 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
533 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
534 exdv.elfEnumLogfontEx.elfScript[0] = 0;
535 return CreateFontIndirectExW( &exdv );
538 /*************************************************************************
539 * CreateFontA (GDI32.@)
541 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
542 INT orient, INT weight, DWORD italic,
543 DWORD underline, DWORD strikeout, DWORD charset,
544 DWORD outpres, DWORD clippres, DWORD quality,
545 DWORD pitch, LPCSTR name )
547 LOGFONTA logfont;
549 logfont.lfHeight = height;
550 logfont.lfWidth = width;
551 logfont.lfEscapement = esc;
552 logfont.lfOrientation = orient;
553 logfont.lfWeight = weight;
554 logfont.lfItalic = italic;
555 logfont.lfUnderline = underline;
556 logfont.lfStrikeOut = strikeout;
557 logfont.lfCharSet = charset;
558 logfont.lfOutPrecision = outpres;
559 logfont.lfClipPrecision = clippres;
560 logfont.lfQuality = quality;
561 logfont.lfPitchAndFamily = pitch;
563 if (name)
564 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
565 else
566 logfont.lfFaceName[0] = '\0';
568 return CreateFontIndirectA( &logfont );
571 /*************************************************************************
572 * CreateFontW (GDI32.@)
574 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
575 INT orient, INT weight, DWORD italic,
576 DWORD underline, DWORD strikeout, DWORD charset,
577 DWORD outpres, DWORD clippres, DWORD quality,
578 DWORD pitch, LPCWSTR name )
580 LOGFONTW logfont;
582 logfont.lfHeight = height;
583 logfont.lfWidth = width;
584 logfont.lfEscapement = esc;
585 logfont.lfOrientation = orient;
586 logfont.lfWeight = weight;
587 logfont.lfItalic = italic;
588 logfont.lfUnderline = underline;
589 logfont.lfStrikeOut = strikeout;
590 logfont.lfCharSet = charset;
591 logfont.lfOutPrecision = outpres;
592 logfont.lfClipPrecision = clippres;
593 logfont.lfQuality = quality;
594 logfont.lfPitchAndFamily = pitch;
596 if (name)
597 lstrcpynW(logfont.lfFaceName, name,
598 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
599 else
600 logfont.lfFaceName[0] = '\0';
602 return CreateFontIndirectW( &logfont );
605 #define ASSOC_CHARSET_OEM 1
606 #define ASSOC_CHARSET_ANSI 2
607 #define ASSOC_CHARSET_SYMBOL 4
609 static DWORD get_associated_charset_info(void)
611 static DWORD associated_charset = -1;
613 if (associated_charset == -1)
615 static const WCHAR assoc_charset_reg_keyW[] = {'S','y','s','t','e','m','\\',
616 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
617 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
618 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
619 static const WCHAR ansiW[] = {'A','N','S','I','(','0','0',')','\0'};
620 static const WCHAR oemW[] = {'O','E','M','(','F','F',')','\0'};
621 static const WCHAR symbolW[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
622 static const WCHAR yesW[] = {'Y','E','S','\0'};
623 HKEY hkey;
624 WCHAR dataW[32];
625 DWORD type, data_len;
627 associated_charset = 0;
629 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
630 assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS)
631 return 0;
633 data_len = sizeof(dataW);
634 if (!RegQueryValueExW(hkey, ansiW, NULL, &type, (LPBYTE)dataW, &data_len) &&
635 type == REG_SZ && !strcmpiW(dataW, yesW))
636 associated_charset |= ASSOC_CHARSET_ANSI;
638 data_len = sizeof(dataW);
639 if (!RegQueryValueExW(hkey, oemW, NULL, &type, (LPBYTE)dataW, &data_len) &&
640 type == REG_SZ && !strcmpiW(dataW, yesW))
641 associated_charset |= ASSOC_CHARSET_OEM;
643 data_len = sizeof(dataW);
644 if (!RegQueryValueExW(hkey, symbolW, NULL, &type, (LPBYTE)dataW, &data_len) &&
645 type == REG_SZ && !strcmpiW(dataW, yesW))
646 associated_charset |= ASSOC_CHARSET_SYMBOL;
648 RegCloseKey(hkey);
650 TRACE("associated_charset = %d\n", associated_charset);
653 return associated_charset;
656 static void update_font_code_page( DC *dc )
658 CHARSETINFO csi;
659 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
661 if (charset == ANSI_CHARSET &&
662 get_associated_charset_info() & ASSOC_CHARSET_ANSI)
663 charset = DEFAULT_CHARSET;
665 /* Hmm, nicely designed api this one! */
666 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
667 dc->font_code_page = csi.ciACP;
668 else {
669 switch(charset) {
670 case OEM_CHARSET:
671 dc->font_code_page = GetOEMCP();
672 break;
673 case DEFAULT_CHARSET:
674 dc->font_code_page = GetACP();
675 break;
677 case VISCII_CHARSET:
678 case TCVN_CHARSET:
679 case KOI8_CHARSET:
680 case ISO3_CHARSET:
681 case ISO4_CHARSET:
682 case ISO10_CHARSET:
683 case CELTIC_CHARSET:
684 /* FIXME: These have no place here, but because x11drv
685 enumerates fonts with these (made up) charsets some apps
686 might use them and then the FIXME below would become
687 annoying. Now we could pick the intended codepage for
688 each of these, but since it's broken anyway we'll just
689 use CP_ACP and hope it'll go away...
691 dc->font_code_page = CP_ACP;
692 break;
694 default:
695 FIXME("Can't find codepage for charset %d\n", charset);
696 dc->font_code_page = CP_ACP;
697 break;
701 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
704 /***********************************************************************
705 * FONT_SelectObject
707 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
709 HGDIOBJ ret = 0;
710 DC *dc = get_dc_ptr( hdc );
711 PHYSDEV physdev;
712 UINT aa_flags = 0;
714 if (!dc) return 0;
716 if (!GDI_inc_ref_count( handle ))
718 release_dc_ptr( dc );
719 return 0;
722 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
723 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
725 ret = dc->hFont;
726 dc->hFont = handle;
727 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
728 update_font_code_page( dc );
729 GDI_dec_ref_count( ret );
731 else GDI_dec_ref_count( handle );
733 release_dc_ptr( dc );
734 return ret;
738 /***********************************************************************
739 * FONT_GetObjectA
741 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
743 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
744 LOGFONTA lfA;
746 if (!font) return 0;
747 if (buffer)
749 FONT_LogFontWToA( &font->logfont, &lfA );
750 if (count > sizeof(lfA)) count = sizeof(lfA);
751 memcpy( buffer, &lfA, count );
753 else count = sizeof(lfA);
754 GDI_ReleaseObj( handle );
755 return count;
758 /***********************************************************************
759 * FONT_GetObjectW
761 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
763 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
765 if (!font) return 0;
766 if (buffer)
768 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
769 memcpy( buffer, &font->logfont, count );
771 else count = sizeof(LOGFONTW);
772 GDI_ReleaseObj( handle );
773 return count;
777 /***********************************************************************
778 * FONT_DeleteObject
780 static BOOL FONT_DeleteObject( HGDIOBJ handle )
782 FONTOBJ *obj;
784 if (!(obj = free_gdi_handle( handle ))) return FALSE;
785 return HeapFree( GetProcessHeap(), 0, obj );
789 /***********************************************************************
790 * nulldrv_SelectFont
792 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
794 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
795 'D','e','s','k','t','o','p',0 };
796 static int orientation = -1, smoothing = -1;
797 LOGFONTW lf;
798 HKEY key;
800 if (*aa_flags) return 0;
802 GetObjectW( font, sizeof(lf), &lf );
803 switch (lf.lfQuality)
805 case NONANTIALIASED_QUALITY:
806 *aa_flags = GGO_BITMAP;
807 break;
808 case ANTIALIASED_QUALITY:
809 *aa_flags = GGO_GRAY4_BITMAP;
810 break;
811 case CLEARTYPE_QUALITY:
812 case CLEARTYPE_NATURAL_QUALITY:
813 if (orientation == -1)
815 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
816 orientation = get_subpixel_orientation( key );
817 RegCloseKey( key );
819 *aa_flags = orientation;
820 break;
821 default:
822 if (smoothing == -1)
824 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
825 smoothing = get_default_smoothing( key );
826 RegCloseKey( key );
828 *aa_flags = smoothing;
829 break;
831 return 0;
835 /***********************************************************************
836 * FONT_EnumInstance
838 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
839 * We have to use other types because of the FONTENUMPROCW definition.
841 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
842 DWORD fType, LPARAM lp )
844 struct font_enum *pfe = (struct font_enum *)lp;
845 INT ret = 1;
847 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
848 if ((!pfe->lpLogFontParam ||
849 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
850 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
851 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
853 /* convert font metrics */
854 ENUMLOGFONTEXA logfont;
855 NEWTEXTMETRICEXA tmA;
857 if (!pfe->unicode)
859 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
860 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
861 plf = (LOGFONTW *)&logfont.elfLogFont;
862 ptm = (TEXTMETRICW *)&tmA;
864 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
865 pfe->retval = ret;
867 return ret;
870 /***********************************************************************
871 * FONT_EnumFontFamiliesEx
873 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
874 LPARAM lParam, BOOL unicode )
876 INT ret = 0;
877 DC *dc = get_dc_ptr( hDC );
878 struct font_enum fe;
880 if (dc)
882 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
884 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
885 fe.lpLogFontParam = plf;
886 fe.lpEnumFunc = efproc;
887 fe.lpData = lParam;
888 fe.unicode = unicode;
889 fe.hdc = hDC;
890 fe.retval = 1;
891 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
892 release_dc_ptr( dc );
894 return ret ? fe.retval : 0;
897 /***********************************************************************
898 * EnumFontFamiliesExW (GDI32.@)
900 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
901 FONTENUMPROCW efproc,
902 LPARAM lParam, DWORD dwFlags )
904 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
907 /***********************************************************************
908 * EnumFontFamiliesExA (GDI32.@)
910 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
911 FONTENUMPROCA efproc,
912 LPARAM lParam, DWORD dwFlags)
914 LOGFONTW lfW, *plfW;
916 if (plf)
918 FONT_LogFontAToW( plf, &lfW );
919 plfW = &lfW;
921 else plfW = NULL;
923 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
926 /***********************************************************************
927 * EnumFontFamiliesA (GDI32.@)
929 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
930 FONTENUMPROCA efproc, LPARAM lpData )
932 LOGFONTA lf, *plf;
934 if (lpFamily)
936 if (!*lpFamily) return 1;
937 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
938 lf.lfCharSet = DEFAULT_CHARSET;
939 lf.lfPitchAndFamily = 0;
940 plf = &lf;
942 else plf = NULL;
944 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
947 /***********************************************************************
948 * EnumFontFamiliesW (GDI32.@)
950 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
951 FONTENUMPROCW efproc, LPARAM lpData )
953 LOGFONTW lf, *plf;
955 if (lpFamily)
957 if (!*lpFamily) return 1;
958 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
959 lf.lfCharSet = DEFAULT_CHARSET;
960 lf.lfPitchAndFamily = 0;
961 plf = &lf;
963 else plf = NULL;
965 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
968 /***********************************************************************
969 * EnumFontsA (GDI32.@)
971 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
972 LPARAM lpData )
974 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
977 /***********************************************************************
978 * EnumFontsW (GDI32.@)
980 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
981 LPARAM lpData )
983 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
987 /***********************************************************************
988 * GetTextCharacterExtra (GDI32.@)
990 INT WINAPI GetTextCharacterExtra( HDC hdc )
992 INT ret;
993 DC *dc = get_dc_ptr( hdc );
994 if (!dc) return 0x80000000;
995 ret = dc->charExtra;
996 release_dc_ptr( dc );
997 return ret;
1001 /***********************************************************************
1002 * SetTextCharacterExtra (GDI32.@)
1004 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
1006 INT ret = 0x80000000;
1007 DC * dc = get_dc_ptr( hdc );
1009 if (dc)
1011 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
1012 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
1013 if (extra != 0x80000000)
1015 ret = dc->charExtra;
1016 dc->charExtra = extra;
1018 release_dc_ptr( dc );
1020 return ret;
1024 /***********************************************************************
1025 * SetTextJustification (GDI32.@)
1027 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1029 BOOL ret;
1030 PHYSDEV physdev;
1031 DC * dc = get_dc_ptr( hdc );
1033 if (!dc) return FALSE;
1035 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1036 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1037 if (ret)
1039 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
1040 if (!extra) breaks = 0;
1041 if (breaks)
1043 dc->breakExtra = extra / breaks;
1044 dc->breakRem = extra - (breaks * dc->breakExtra);
1046 else
1048 dc->breakExtra = 0;
1049 dc->breakRem = 0;
1052 release_dc_ptr( dc );
1053 return ret;
1057 /***********************************************************************
1058 * GetTextFaceA (GDI32.@)
1060 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1062 INT res = GetTextFaceW(hdc, 0, NULL);
1063 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1064 GetTextFaceW( hdc, res, nameW );
1066 if (name)
1068 if (count)
1070 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1071 if (res == 0)
1072 res = count;
1073 name[count-1] = 0;
1074 /* GetTextFaceA does NOT include the nul byte in the return count. */
1075 res--;
1077 else
1078 res = 0;
1080 else
1081 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1082 HeapFree( GetProcessHeap(), 0, nameW );
1083 return res;
1086 /***********************************************************************
1087 * GetTextFaceW (GDI32.@)
1089 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1091 PHYSDEV dev;
1092 INT ret;
1094 DC * dc = get_dc_ptr( hdc );
1095 if (!dc) return 0;
1097 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1098 ret = dev->funcs->pGetTextFace( dev, count, name );
1099 release_dc_ptr( dc );
1100 return ret;
1104 /***********************************************************************
1105 * GetTextExtentPoint32A (GDI32.@)
1107 * See GetTextExtentPoint32W.
1109 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1110 LPSIZE size )
1112 BOOL ret = FALSE;
1113 INT wlen;
1114 LPWSTR p;
1116 if (count < 0) return FALSE;
1118 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1120 if (p)
1122 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1123 HeapFree( GetProcessHeap(), 0, p );
1126 TRACE("(%p %s %d %p): returning %d x %d\n",
1127 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1128 return ret;
1132 /***********************************************************************
1133 * GetTextExtentPoint32W [GDI32.@]
1135 * Computes width/height for a string.
1137 * Computes width and height of the specified string.
1139 * RETURNS
1140 * Success: TRUE
1141 * Failure: FALSE
1143 BOOL WINAPI GetTextExtentPoint32W(
1144 HDC hdc, /* [in] Handle of device context */
1145 LPCWSTR str, /* [in] Address of text string */
1146 INT count, /* [in] Number of characters in string */
1147 LPSIZE size) /* [out] Address of structure for string size */
1149 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1152 /***********************************************************************
1153 * GetTextExtentExPointI [GDI32.@]
1155 * Computes width and height of the array of glyph indices.
1157 * PARAMS
1158 * hdc [I] Handle of device context.
1159 * indices [I] Glyph index array.
1160 * count [I] Number of glyphs in array.
1161 * max_ext [I] Maximum width in glyphs.
1162 * nfit [O] Maximum number of characters.
1163 * dxs [O] Partial string widths.
1164 * size [O] Returned string size.
1166 * RETURNS
1167 * Success: TRUE
1168 * Failure: FALSE
1170 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1171 LPINT nfit, LPINT dxs, LPSIZE size )
1173 DC *dc;
1174 int i;
1175 BOOL ret;
1176 INT buffer[256], *pos = dxs;
1178 if (count < 0) return FALSE;
1180 dc = get_dc_ptr( hdc );
1181 if (!dc) return FALSE;
1183 if (!dxs)
1185 pos = buffer;
1186 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1188 release_dc_ptr( dc );
1189 return FALSE;
1193 ret = get_char_positions_indices( dc, indices, count, pos, size );
1194 if (ret)
1196 if (dxs || nfit)
1198 for (i = 0; i < count; i++)
1200 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1201 if (nfit && dx > (unsigned int)max_ext) break;
1202 if (dxs) dxs[i] = dx;
1204 if (nfit) *nfit = i;
1207 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1208 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1211 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1212 release_dc_ptr( dc );
1214 TRACE("(%p %p %d %p): returning %d x %d\n",
1215 hdc, indices, count, size, size->cx, size->cy );
1216 return ret;
1219 /***********************************************************************
1220 * GetTextExtentPointI [GDI32.@]
1222 * Computes width and height of the array of glyph indices.
1224 * PARAMS
1225 * hdc [I] Handle of device context.
1226 * indices [I] Glyph index array.
1227 * count [I] Number of glyphs in array.
1228 * size [O] Returned string size.
1230 * RETURNS
1231 * Success: TRUE
1232 * Failure: FALSE
1234 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1236 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1240 /***********************************************************************
1241 * GetTextExtentPointA (GDI32.@)
1243 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1244 LPSIZE size )
1246 TRACE("not bug compatible.\n");
1247 return GetTextExtentPoint32A( hdc, str, count, size );
1250 /***********************************************************************
1251 * GetTextExtentPointW (GDI32.@)
1253 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1254 LPSIZE size )
1256 TRACE("not bug compatible.\n");
1257 return GetTextExtentPoint32W( hdc, str, count, size );
1261 /***********************************************************************
1262 * GetTextExtentExPointA (GDI32.@)
1264 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1265 INT maxExt, LPINT lpnFit,
1266 LPINT alpDx, LPSIZE size )
1268 BOOL ret;
1269 INT wlen;
1270 INT *walpDx = NULL;
1271 LPWSTR p = NULL;
1273 if (count < 0) return FALSE;
1274 if (maxExt < -1) return FALSE;
1276 if (alpDx)
1278 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1279 if (!walpDx) return FALSE;
1282 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1283 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1284 if (walpDx)
1286 INT n = lpnFit ? *lpnFit : wlen;
1287 INT i, j;
1288 for(i = 0, j = 0; i < n; i++, j++)
1290 alpDx[j] = walpDx[i];
1291 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1294 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1295 HeapFree( GetProcessHeap(), 0, p );
1296 HeapFree( GetProcessHeap(), 0, walpDx );
1297 return ret;
1301 /***********************************************************************
1302 * GetTextExtentExPointW (GDI32.@)
1304 * Return the size of the string as it would be if it was output properly by
1305 * e.g. TextOut.
1307 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1308 LPINT nfit, LPINT dxs, LPSIZE size )
1310 DC *dc;
1311 int i;
1312 BOOL ret;
1313 INT buffer[256], *pos = dxs;
1315 if (count < 0) return FALSE;
1317 dc = get_dc_ptr(hdc);
1318 if (!dc) return FALSE;
1320 if (!dxs)
1322 pos = buffer;
1323 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1325 release_dc_ptr( dc );
1326 return FALSE;
1330 ret = get_char_positions( dc, str, count, pos, size );
1331 if (ret)
1333 if (dxs || nfit)
1335 for (i = 0; i < count; i++)
1337 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1338 if (nfit && dx > (unsigned int)max_ext) break;
1339 if (dxs) dxs[i] = dx;
1341 if (nfit) *nfit = i;
1344 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1345 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1348 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1349 release_dc_ptr( dc );
1351 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1352 return ret;
1355 /***********************************************************************
1356 * GetTextMetricsA (GDI32.@)
1358 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1360 TEXTMETRICW tm32;
1362 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1363 FONT_TextMetricWToA( &tm32, metrics );
1364 return TRUE;
1367 /***********************************************************************
1368 * GetTextMetricsW (GDI32.@)
1370 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1372 PHYSDEV physdev;
1373 BOOL ret = FALSE;
1374 DC * dc = get_dc_ptr( hdc );
1375 if (!dc) return FALSE;
1377 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1378 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1380 if (ret)
1382 /* device layer returns values in device units
1383 * therefore we have to convert them to logical */
1385 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1386 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1387 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
1388 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
1389 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
1390 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
1391 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
1392 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
1393 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
1394 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
1395 ret = TRUE;
1397 TRACE("text metrics:\n"
1398 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1399 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1400 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1401 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1402 " PitchAndFamily = %02x\n"
1403 " --------------------\n"
1404 " InternalLeading = %i\n"
1405 " Ascent = %i\n"
1406 " Descent = %i\n"
1407 " Height = %i\n",
1408 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1409 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1410 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1411 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1412 metrics->tmPitchAndFamily,
1413 metrics->tmInternalLeading,
1414 metrics->tmAscent,
1415 metrics->tmDescent,
1416 metrics->tmHeight );
1418 release_dc_ptr( dc );
1419 return ret;
1423 /***********************************************************************
1424 * GetOutlineTextMetricsA (GDI32.@)
1425 * Gets metrics for TrueType fonts.
1427 * NOTES
1428 * If the supplied buffer isn't big enough Windows partially fills it up to
1429 * its given length and returns that length.
1431 * RETURNS
1432 * Success: Non-zero or size of required buffer
1433 * Failure: 0
1435 UINT WINAPI GetOutlineTextMetricsA(
1436 HDC hdc, /* [in] Handle of device context */
1437 UINT cbData, /* [in] Size of metric data array */
1438 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1440 char buf[512], *ptr;
1441 UINT ret, needed;
1442 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1443 OUTLINETEXTMETRICA *output = lpOTM;
1444 INT left, len;
1446 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1447 return 0;
1448 if(ret > sizeof(buf))
1449 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1450 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1452 needed = sizeof(OUTLINETEXTMETRICA);
1453 if(lpOTMW->otmpFamilyName)
1454 needed += WideCharToMultiByte(CP_ACP, 0,
1455 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1456 NULL, 0, NULL, NULL);
1457 if(lpOTMW->otmpFaceName)
1458 needed += WideCharToMultiByte(CP_ACP, 0,
1459 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1460 NULL, 0, NULL, NULL);
1461 if(lpOTMW->otmpStyleName)
1462 needed += WideCharToMultiByte(CP_ACP, 0,
1463 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1464 NULL, 0, NULL, NULL);
1465 if(lpOTMW->otmpFullName)
1466 needed += WideCharToMultiByte(CP_ACP, 0,
1467 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1468 NULL, 0, NULL, NULL);
1470 if(!lpOTM) {
1471 ret = needed;
1472 goto end;
1475 TRACE("needed = %d\n", needed);
1476 if(needed > cbData)
1477 /* Since the supplied buffer isn't big enough, we'll alloc one
1478 that is and memcpy the first cbData bytes into the lpOTM at
1479 the end. */
1480 output = HeapAlloc(GetProcessHeap(), 0, needed);
1482 ret = output->otmSize = min(needed, cbData);
1483 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1484 output->otmFiller = 0;
1485 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1486 output->otmfsSelection = lpOTMW->otmfsSelection;
1487 output->otmfsType = lpOTMW->otmfsType;
1488 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1489 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1490 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1491 output->otmEMSquare = lpOTMW->otmEMSquare;
1492 output->otmAscent = lpOTMW->otmAscent;
1493 output->otmDescent = lpOTMW->otmDescent;
1494 output->otmLineGap = lpOTMW->otmLineGap;
1495 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1496 output->otmsXHeight = lpOTMW->otmsXHeight;
1497 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1498 output->otmMacAscent = lpOTMW->otmMacAscent;
1499 output->otmMacDescent = lpOTMW->otmMacDescent;
1500 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1501 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1502 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1503 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1504 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1505 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1506 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1507 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1508 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1509 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1512 ptr = (char*)(output + 1);
1513 left = needed - sizeof(*output);
1515 if(lpOTMW->otmpFamilyName) {
1516 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1517 len = WideCharToMultiByte(CP_ACP, 0,
1518 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1519 ptr, left, NULL, NULL);
1520 left -= len;
1521 ptr += len;
1522 } else
1523 output->otmpFamilyName = 0;
1525 if(lpOTMW->otmpFaceName) {
1526 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1527 len = WideCharToMultiByte(CP_ACP, 0,
1528 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1529 ptr, left, NULL, NULL);
1530 left -= len;
1531 ptr += len;
1532 } else
1533 output->otmpFaceName = 0;
1535 if(lpOTMW->otmpStyleName) {
1536 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1537 len = WideCharToMultiByte(CP_ACP, 0,
1538 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1539 ptr, left, NULL, NULL);
1540 left -= len;
1541 ptr += len;
1542 } else
1543 output->otmpStyleName = 0;
1545 if(lpOTMW->otmpFullName) {
1546 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1547 len = WideCharToMultiByte(CP_ACP, 0,
1548 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1549 ptr, left, NULL, NULL);
1550 left -= len;
1551 } else
1552 output->otmpFullName = 0;
1554 assert(left == 0);
1556 if(output != lpOTM) {
1557 memcpy(lpOTM, output, cbData);
1558 HeapFree(GetProcessHeap(), 0, output);
1560 /* check if the string offsets really fit into the provided size */
1561 /* FIXME: should we check string length as well? */
1562 /* make sure that we don't read/write beyond the provided buffer */
1563 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1565 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1566 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1569 /* make sure that we don't read/write beyond the provided buffer */
1570 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1572 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1573 lpOTM->otmpFaceName = 0; /* doesn't fit */
1576 /* make sure that we don't read/write beyond the provided buffer */
1577 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1579 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1580 lpOTM->otmpStyleName = 0; /* doesn't fit */
1583 /* make sure that we don't read/write beyond the provided buffer */
1584 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1586 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1587 lpOTM->otmpFullName = 0; /* doesn't fit */
1591 end:
1592 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1593 HeapFree(GetProcessHeap(), 0, lpOTMW);
1595 return ret;
1599 /***********************************************************************
1600 * GetOutlineTextMetricsW [GDI32.@]
1602 UINT WINAPI GetOutlineTextMetricsW(
1603 HDC hdc, /* [in] Handle of device context */
1604 UINT cbData, /* [in] Size of metric data array */
1605 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1607 DC *dc = get_dc_ptr( hdc );
1608 OUTLINETEXTMETRICW *output = lpOTM;
1609 PHYSDEV dev;
1610 UINT ret;
1612 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1613 if(!dc) return 0;
1615 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1616 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1618 if (lpOTM && ret > cbData)
1620 output = HeapAlloc(GetProcessHeap(), 0, ret);
1621 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1624 if (lpOTM && ret)
1626 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1627 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1628 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
1629 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
1630 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
1631 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
1632 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
1633 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
1634 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
1635 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
1636 output->otmAscent = height_to_LP( dc, output->otmAscent);
1637 output->otmDescent = height_to_LP( dc, output->otmDescent);
1638 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1639 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1640 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1641 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
1642 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
1643 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
1644 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
1645 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
1646 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
1647 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1648 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
1649 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
1650 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
1651 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
1652 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
1653 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
1654 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
1655 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
1656 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1657 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
1658 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
1659 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
1660 #undef WDPTOLP
1661 #undef HDPTOLP
1662 if(output != lpOTM)
1664 memcpy(lpOTM, output, cbData);
1665 HeapFree(GetProcessHeap(), 0, output);
1666 ret = cbData;
1669 release_dc_ptr(dc);
1670 return ret;
1673 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1675 INT i, count = lastChar - firstChar + 1;
1676 UINT mbcp;
1677 UINT c;
1678 LPSTR str;
1680 if (count <= 0)
1681 return NULL;
1683 mbcp = GdiGetCodePage(hdc);
1684 switch (mbcp)
1686 case 932:
1687 case 936:
1688 case 949:
1689 case 950:
1690 case 1361:
1691 if (lastChar > 0xffff)
1692 return NULL;
1693 if ((firstChar ^ lastChar) > 0xff)
1694 return NULL;
1695 break;
1696 default:
1697 if (lastChar > 0xff)
1698 return NULL;
1699 mbcp = 0;
1700 break;
1703 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1704 if (str == NULL)
1705 return NULL;
1707 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1709 if (mbcp) {
1710 if (c > 0xff)
1711 str[i++] = (BYTE)(c >> 8);
1712 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1713 str[i] = 0x1f; /* FIXME: use default character */
1714 else
1715 str[i] = (BYTE)c;
1717 else
1718 str[i] = (BYTE)c;
1720 str[i] = '\0';
1722 *pByteLen = i;
1724 return str;
1727 /***********************************************************************
1728 * GetCharWidthW (GDI32.@)
1729 * GetCharWidth32W (GDI32.@)
1731 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1732 LPINT buffer )
1734 UINT i;
1735 BOOL ret;
1736 PHYSDEV dev;
1737 DC * dc = get_dc_ptr( hdc );
1739 if (!dc) return FALSE;
1741 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1742 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1744 if (ret)
1746 /* convert device units to logical */
1747 for( i = firstChar; i <= lastChar; i++, buffer++ )
1748 *buffer = width_to_LP( dc, *buffer );
1750 release_dc_ptr( dc );
1751 return ret;
1755 /***********************************************************************
1756 * GetCharWidthA (GDI32.@)
1757 * GetCharWidth32A (GDI32.@)
1759 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1760 LPINT buffer )
1762 INT i, wlen;
1763 LPSTR str;
1764 LPWSTR wstr;
1765 BOOL ret = TRUE;
1767 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1768 if(str == NULL)
1769 return FALSE;
1771 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1773 for(i = 0; i < wlen; i++)
1775 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1777 ret = FALSE;
1778 break;
1780 buffer++;
1783 HeapFree(GetProcessHeap(), 0, str);
1784 HeapFree(GetProcessHeap(), 0, wstr);
1786 return ret;
1790 /* helper for nulldrv_ExtTextOut */
1791 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1792 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1794 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1795 UINT indices[3] = {0, 0, 0x20};
1796 unsigned int i;
1797 DWORD ret, size;
1798 int stride;
1800 indices[0] = index;
1801 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1803 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1805 index = indices[i];
1806 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1807 if (ret != GDI_ERROR) break;
1810 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1811 if (!image) return ERROR_SUCCESS;
1813 image->ptr = NULL;
1814 image->free = NULL;
1815 if (!ret) /* empty glyph */
1817 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
1818 return ERROR_SUCCESS;
1821 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1822 size = metrics->gmBlackBoxY * stride;
1824 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1825 image->is_copy = TRUE;
1826 image->free = free_heap_bits;
1828 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1829 if (ret == GDI_ERROR)
1831 HeapFree( GetProcessHeap(), 0, image->ptr );
1832 return ERROR_NOT_FOUND;
1834 return ERROR_SUCCESS;
1837 /* helper for nulldrv_ExtTextOut */
1838 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1839 LPCWSTR str, UINT count, const INT *dx )
1841 UINT i;
1842 RECT rect, bounds;
1844 reset_bounds( &bounds );
1845 for (i = 0; i < count; i++)
1847 GLYPHMETRICS metrics;
1849 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1851 rect.left = x + metrics.gmptGlyphOrigin.x;
1852 rect.top = y - metrics.gmptGlyphOrigin.y;
1853 rect.right = rect.left + metrics.gmBlackBoxX;
1854 rect.bottom = rect.top + metrics.gmBlackBoxY;
1855 add_bounds_rect( &bounds, &rect );
1857 if (dx)
1859 if (flags & ETO_PDY)
1861 x += dx[ i * 2 ];
1862 y += dx[ i * 2 + 1];
1864 else x += dx[ i ];
1866 else
1868 x += metrics.gmCellIncX;
1869 y += metrics.gmCellIncY;
1872 return bounds;
1875 /* helper for nulldrv_ExtTextOut */
1876 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1877 const struct gdi_image_bits *image, const RECT *clip )
1879 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1880 UINT i, count, max_count;
1881 LONG x, y;
1882 BYTE *ptr = image->ptr;
1883 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1884 POINT *pts;
1885 RECT rect, clipped_rect;
1887 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1888 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1889 rect.right = rect.left + metrics->gmBlackBoxX;
1890 rect.bottom = rect.top + metrics->gmBlackBoxY;
1891 if (!clip) clipped_rect = rect;
1892 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1894 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1895 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1896 if (!pts) return;
1898 count = 0;
1899 ptr += (clipped_rect.top - rect.top) * stride;
1900 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1902 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1904 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1905 pts[count].x = rect.left + x;
1906 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1907 pts[count + 1].x = rect.left + x;
1908 if (pts[count + 1].x > pts[count].x)
1910 pts[count].y = pts[count + 1].y = y;
1911 count += 2;
1915 assert( count <= max_count );
1916 DPtoLP( hdc, pts, count );
1917 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1918 HeapFree( GetProcessHeap(), 0, pts );
1921 /***********************************************************************
1922 * nulldrv_ExtTextOut
1924 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1925 LPCWSTR str, UINT count, const INT *dx )
1927 DC *dc = get_nulldrv_dc( dev );
1928 UINT i;
1929 DWORD err;
1930 HGDIOBJ orig;
1931 HPEN pen;
1933 if (flags & ETO_OPAQUE)
1935 RECT rc = *rect;
1936 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1938 if (brush)
1940 orig = SelectObject( dev->hdc, brush );
1941 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1942 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1943 SelectObject( dev->hdc, orig );
1944 DeleteObject( brush );
1948 if (!count) return TRUE;
1950 if (dc->aa_flags != GGO_BITMAP)
1952 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1953 BITMAPINFO *info = (BITMAPINFO *)buffer;
1954 struct gdi_image_bits bits;
1955 struct bitblt_coords src, dst;
1956 PHYSDEV dst_dev;
1957 /* FIXME Subpixel modes */
1958 UINT aa_flags = GGO_GRAY4_BITMAP;
1960 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1961 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1962 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1963 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1965 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1966 src.x = src.visrect.left;
1967 src.y = src.visrect.top;
1968 src.width = src.visrect.right - src.visrect.left;
1969 src.height = src.visrect.bottom - src.visrect.top;
1970 dst = src;
1971 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1972 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1974 /* we can avoid the GetImage, just query the needed format */
1975 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1976 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1977 info->bmiHeader.biWidth = src.width;
1978 info->bmiHeader.biHeight = -src.height;
1979 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1980 if (!err || err == ERROR_BAD_FORMAT)
1982 /* make the source rectangle relative to the source bits */
1983 src.x = src.y = 0;
1984 src.visrect.left = src.visrect.top = 0;
1985 src.visrect.right = src.width;
1986 src.visrect.bottom = src.height;
1988 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1989 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1990 bits.is_copy = TRUE;
1991 bits.free = free_heap_bits;
1992 err = ERROR_SUCCESS;
1995 else
1997 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1998 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1999 if (!err && !bits.is_copy)
2001 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
2002 if (!ptr)
2004 if (bits.free) bits.free( &bits );
2005 return ERROR_OUTOFMEMORY;
2007 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
2008 if (bits.free) bits.free( &bits );
2009 bits.ptr = ptr;
2010 bits.is_copy = TRUE;
2011 bits.free = free_heap_bits;
2014 if (!err)
2016 /* make x,y relative to the image bits */
2017 x += src.visrect.left - dst.visrect.left;
2018 y += src.visrect.top - dst.visrect.top;
2019 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
2020 aa_flags, str, count, dx );
2021 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2022 if (bits.free) bits.free( &bits );
2023 return !err;
2027 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
2028 orig = SelectObject( dev->hdc, pen );
2030 for (i = 0; i < count; i++)
2032 GLYPHMETRICS metrics;
2033 struct gdi_image_bits image;
2035 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2036 if (err) continue;
2038 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2039 if (image.free) image.free( &image );
2041 if (dx)
2043 if (flags & ETO_PDY)
2045 x += dx[ i * 2 ];
2046 y += dx[ i * 2 + 1];
2048 else x += dx[ i ];
2050 else
2052 x += metrics.gmCellIncX;
2053 y += metrics.gmCellIncY;
2057 SelectObject( dev->hdc, orig );
2058 DeleteObject( pen );
2059 return TRUE;
2063 /***********************************************************************
2064 * ExtTextOutA (GDI32.@)
2066 * See ExtTextOutW.
2068 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2069 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2071 INT wlen;
2072 UINT codepage;
2073 LPWSTR p;
2074 BOOL ret;
2075 LPINT lpDxW = NULL;
2077 if (flags & ETO_GLYPH_INDEX)
2078 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2080 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2082 if (lpDx) {
2083 unsigned int i = 0, j = 0;
2085 /* allocate enough for a ETO_PDY */
2086 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2087 while(i < count) {
2088 if(IsDBCSLeadByteEx(codepage, str[i]))
2090 if(flags & ETO_PDY)
2092 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2093 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2095 else
2096 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2097 i = i + 2;
2099 else
2101 if(flags & ETO_PDY)
2103 lpDxW[j++] = lpDx[i * 2];
2104 lpDxW[j++] = lpDx[i * 2 + 1];
2106 else
2107 lpDxW[j++] = lpDx[i];
2108 i = i + 1;
2113 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2115 HeapFree( GetProcessHeap(), 0, p );
2116 HeapFree( GetProcessHeap(), 0, lpDxW );
2117 return ret;
2121 /***********************************************************************
2122 * ExtTextOutW (GDI32.@)
2124 * Draws text using the currently selected font, background color, and text color.
2127 * PARAMS
2128 * x,y [I] coordinates of string
2129 * flags [I]
2130 * ETO_GRAYED - undocumented on MSDN
2131 * ETO_OPAQUE - use background color for fill the rectangle
2132 * ETO_CLIPPED - clipping text to the rectangle
2133 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2134 * than encoded characters. Implies ETO_IGNORELANGUAGE
2135 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2136 * Affects BiDi ordering
2137 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2138 * ETO_PDY - unimplemented
2139 * ETO_NUMERICSLATIN - unimplemented always assumed -
2140 * do not translate numbers into locale representations
2141 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2142 * lprect [I] dimensions for clipping or/and opaquing
2143 * str [I] text string
2144 * count [I] number of symbols in string
2145 * lpDx [I] optional parameter with distance between drawing characters
2147 * RETURNS
2148 * Success: TRUE
2149 * Failure: FALSE
2151 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2152 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2154 BOOL ret = FALSE;
2155 LPWSTR reordered_str = (LPWSTR)str;
2156 WORD *glyphs = NULL;
2157 UINT align = GetTextAlign( hdc );
2158 DWORD layout = GetLayout( hdc );
2159 POINT pt;
2160 TEXTMETRICW tm;
2161 LOGFONTW lf;
2162 double cosEsc, sinEsc;
2163 INT char_extra;
2164 SIZE sz;
2165 RECT rc;
2166 POINT *deltas = NULL, width = {0, 0};
2167 DWORD type;
2168 DC * dc = get_dc_ptr( hdc );
2169 PHYSDEV physdev;
2170 INT breakRem;
2171 static int quietfixme = 0;
2173 if (!dc) return FALSE;
2175 breakRem = dc->breakRem;
2177 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2179 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2180 quietfixme = 1;
2183 update_dc( dc );
2184 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2185 type = GetObjectType(hdc);
2186 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2188 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2189 release_dc_ptr( dc );
2190 return ret;
2193 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2194 if (layout & LAYOUT_RTL)
2196 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2197 align ^= TA_RTLREADING;
2200 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2202 INT cGlyphs;
2203 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2205 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2206 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2207 reordered_str, count, NULL, &glyphs, &cGlyphs);
2209 flags |= ETO_IGNORELANGUAGE;
2210 if (glyphs)
2212 flags |= ETO_GLYPH_INDEX;
2213 if (cGlyphs != count)
2214 count = cGlyphs;
2217 else if(flags & ETO_GLYPH_INDEX)
2218 glyphs = reordered_str;
2220 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2221 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2222 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2224 if(align & TA_UPDATECP)
2226 GetCurrentPositionEx( hdc, &pt );
2227 x = pt.x;
2228 y = pt.y;
2231 GetTextMetricsW(hdc, &tm);
2232 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2234 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2235 lf.lfEscapement = 0;
2237 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2238 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2240 lf.lfEscapement = -lf.lfEscapement;
2243 if(lf.lfEscapement != 0)
2245 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2246 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2248 else
2250 cosEsc = 1;
2251 sinEsc = 0;
2254 if (lprect)
2256 rc = *lprect;
2257 LPtoDP(hdc, (POINT*)&rc, 2);
2258 order_rect( &rc );
2259 if (flags & ETO_OPAQUE)
2260 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2262 else flags &= ~ETO_CLIPPED;
2264 if(count == 0)
2266 ret = TRUE;
2267 goto done;
2270 pt.x = x;
2271 pt.y = y;
2272 LPtoDP(hdc, &pt, 1);
2273 x = pt.x;
2274 y = pt.y;
2276 char_extra = GetTextCharacterExtra(hdc);
2277 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2278 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2280 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2282 UINT i;
2283 POINT total = {0, 0}, desired[2];
2285 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2286 if (lpDx)
2288 if (flags & ETO_PDY)
2290 for (i = 0; i < count; i++)
2292 deltas[i].x = lpDx[i * 2] + char_extra;
2293 deltas[i].y = -lpDx[i * 2 + 1];
2296 else
2298 for (i = 0; i < count; i++)
2300 deltas[i].x = lpDx[i] + char_extra;
2301 deltas[i].y = 0;
2305 else
2307 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2309 if (flags & ETO_GLYPH_INDEX)
2310 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2311 else
2312 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2314 deltas[0].x = dx[0];
2315 deltas[0].y = 0;
2316 for (i = 1; i < count; i++)
2318 deltas[i].x = dx[i] - dx[i - 1];
2319 deltas[i].y = 0;
2321 HeapFree( GetProcessHeap(), 0, dx );
2324 for(i = 0; i < count; i++)
2326 total.x += deltas[i].x;
2327 total.y += deltas[i].y;
2329 desired[0].x = desired[0].y = 0;
2331 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2332 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2334 LPtoDP(hdc, desired, 2);
2335 desired[1].x -= desired[0].x;
2336 desired[1].y -= desired[0].y;
2338 if (dc->GraphicsMode == GM_COMPATIBLE)
2340 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2341 desired[1].x = -desired[1].x;
2342 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2343 desired[1].y = -desired[1].y;
2346 deltas[i].x = desired[1].x - width.x;
2347 deltas[i].y = desired[1].y - width.y;
2349 width = desired[1];
2351 flags |= ETO_PDY;
2353 else
2355 POINT desired[2];
2357 if(flags & ETO_GLYPH_INDEX)
2358 GetTextExtentPointI(hdc, glyphs, count, &sz);
2359 else
2360 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2361 desired[0].x = desired[0].y = 0;
2362 desired[1].x = sz.cx;
2363 desired[1].y = 0;
2364 LPtoDP(hdc, desired, 2);
2365 desired[1].x -= desired[0].x;
2366 desired[1].y -= desired[0].y;
2368 if (dc->GraphicsMode == GM_COMPATIBLE)
2370 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2371 desired[1].x = -desired[1].x;
2372 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2373 desired[1].y = -desired[1].y;
2375 width = desired[1];
2378 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2379 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2380 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2382 case TA_LEFT:
2383 if (align & TA_UPDATECP)
2385 pt.x = x + width.x;
2386 pt.y = y + width.y;
2387 DPtoLP(hdc, &pt, 1);
2388 MoveToEx(hdc, pt.x, pt.y, NULL);
2390 break;
2392 case TA_CENTER:
2393 x -= width.x / 2;
2394 y -= width.y / 2;
2395 break;
2397 case TA_RIGHT:
2398 x -= width.x;
2399 y -= width.y;
2400 if (align & TA_UPDATECP)
2402 pt.x = x;
2403 pt.y = y;
2404 DPtoLP(hdc, &pt, 1);
2405 MoveToEx(hdc, pt.x, pt.y, NULL);
2407 break;
2410 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2412 case TA_TOP:
2413 y += tm.tmAscent * cosEsc;
2414 x += tm.tmAscent * sinEsc;
2415 break;
2417 case TA_BOTTOM:
2418 y -= tm.tmDescent * cosEsc;
2419 x -= tm.tmDescent * sinEsc;
2420 break;
2422 case TA_BASELINE:
2423 break;
2426 if (GetBkMode(hdc) != TRANSPARENT)
2428 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2430 if(!(flags & ETO_OPAQUE) || !lprect ||
2431 x < rc.left || x + width.x >= rc.right ||
2432 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2434 RECT text_box;
2435 text_box.left = x;
2436 text_box.right = x + width.x;
2437 text_box.top = y - tm.tmAscent;
2438 text_box.bottom = y + tm.tmDescent;
2440 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2441 if (!is_rect_empty( &text_box ))
2442 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2447 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2448 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2450 done:
2451 HeapFree(GetProcessHeap(), 0, deltas);
2452 if(glyphs != reordered_str)
2453 HeapFree(GetProcessHeap(), 0, glyphs);
2454 if(reordered_str != str)
2455 HeapFree(GetProcessHeap(), 0, reordered_str);
2457 release_dc_ptr( dc );
2459 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2461 int underlinePos, strikeoutPos;
2462 int underlineWidth, strikeoutWidth;
2463 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2464 OUTLINETEXTMETRICW* otm = NULL;
2465 POINT pts[5];
2466 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2467 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2469 hbrush = SelectObject(hdc, hbrush);
2471 if(!size)
2473 underlinePos = 0;
2474 underlineWidth = tm.tmAscent / 20 + 1;
2475 strikeoutPos = tm.tmAscent / 2;
2476 strikeoutWidth = underlineWidth;
2478 else
2480 otm = HeapAlloc(GetProcessHeap(), 0, size);
2481 GetOutlineTextMetricsW(hdc, size, otm);
2482 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2483 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2484 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2485 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2486 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2487 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2488 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2489 HeapFree(GetProcessHeap(), 0, otm);
2493 if (lf.lfUnderline)
2495 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2496 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2497 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2498 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2499 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2500 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2501 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2502 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2503 pts[4].x = pts[0].x;
2504 pts[4].y = pts[0].y;
2505 DPtoLP(hdc, pts, 5);
2506 Polygon(hdc, pts, 5);
2509 if (lf.lfStrikeOut)
2511 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2512 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2513 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2514 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2515 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2516 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2517 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2518 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2519 pts[4].x = pts[0].x;
2520 pts[4].y = pts[0].y;
2521 DPtoLP(hdc, pts, 5);
2522 Polygon(hdc, pts, 5);
2525 SelectObject(hdc, hpen);
2526 hbrush = SelectObject(hdc, hbrush);
2527 DeleteObject(hbrush);
2530 return ret;
2534 /***********************************************************************
2535 * TextOutA (GDI32.@)
2537 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2539 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2543 /***********************************************************************
2544 * TextOutW (GDI32.@)
2546 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2548 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2552 /***********************************************************************
2553 * PolyTextOutA (GDI32.@)
2555 * See PolyTextOutW.
2557 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2559 for (; cStrings>0; cStrings--, pptxt++)
2560 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2561 return FALSE;
2562 return TRUE;
2567 /***********************************************************************
2568 * PolyTextOutW (GDI32.@)
2570 * Draw several Strings
2572 * RETURNS
2573 * TRUE: Success.
2574 * FALSE: Failure.
2576 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2578 for (; cStrings>0; cStrings--, pptxt++)
2579 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2580 return FALSE;
2581 return TRUE;
2585 /***********************************************************************
2586 * SetMapperFlags (GDI32.@)
2588 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2590 DC *dc = get_dc_ptr( hdc );
2591 DWORD ret = GDI_ERROR;
2593 if (dc)
2595 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2596 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2597 if (flags != GDI_ERROR)
2599 ret = dc->mapperFlags;
2600 dc->mapperFlags = flags;
2602 release_dc_ptr( dc );
2604 return ret;
2607 /***********************************************************************
2608 * GetAspectRatioFilterEx (GDI32.@)
2610 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2612 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2613 return FALSE;
2617 /***********************************************************************
2618 * GetCharABCWidthsA (GDI32.@)
2620 * See GetCharABCWidthsW.
2622 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2623 LPABC abc )
2625 INT i, wlen;
2626 LPSTR str;
2627 LPWSTR wstr;
2628 BOOL ret = TRUE;
2630 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2631 if (str == NULL)
2632 return FALSE;
2634 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2635 if (wstr == NULL)
2637 HeapFree(GetProcessHeap(), 0, str);
2638 return FALSE;
2641 for(i = 0; i < wlen; i++)
2643 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2645 ret = FALSE;
2646 break;
2648 abc++;
2651 HeapFree(GetProcessHeap(), 0, str);
2652 HeapFree(GetProcessHeap(), 0, wstr);
2654 return ret;
2658 /******************************************************************************
2659 * GetCharABCWidthsW [GDI32.@]
2661 * Retrieves widths of characters in range.
2663 * PARAMS
2664 * hdc [I] Handle of device context
2665 * firstChar [I] First character in range to query
2666 * lastChar [I] Last character in range to query
2667 * abc [O] Address of character-width structure
2669 * NOTES
2670 * Only works with TrueType fonts
2672 * RETURNS
2673 * Success: TRUE
2674 * Failure: FALSE
2676 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2677 LPABC abc )
2679 DC *dc = get_dc_ptr(hdc);
2680 PHYSDEV dev;
2681 unsigned int i;
2682 BOOL ret;
2683 TEXTMETRICW tm;
2685 if (!dc) return FALSE;
2687 if (!abc)
2689 release_dc_ptr( dc );
2690 return FALSE;
2693 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2694 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2695 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2697 release_dc_ptr( dc );
2698 return FALSE;
2701 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2702 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2703 if (ret)
2705 /* convert device units to logical */
2706 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2707 abc->abcA = width_to_LP(dc, abc->abcA);
2708 abc->abcB = width_to_LP(dc, abc->abcB);
2709 abc->abcC = width_to_LP(dc, abc->abcC);
2713 release_dc_ptr( dc );
2714 return ret;
2718 /******************************************************************************
2719 * GetCharABCWidthsI [GDI32.@]
2721 * Retrieves widths of characters in range.
2723 * PARAMS
2724 * hdc [I] Handle of device context
2725 * firstChar [I] First glyphs in range to query
2726 * count [I] Last glyphs in range to query
2727 * pgi [i] Array of glyphs to query
2728 * abc [O] Address of character-width structure
2730 * NOTES
2731 * Only works with TrueType fonts
2733 * RETURNS
2734 * Success: TRUE
2735 * Failure: FALSE
2737 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2738 LPWORD pgi, LPABC abc)
2740 DC *dc = get_dc_ptr(hdc);
2741 PHYSDEV dev;
2742 unsigned int i;
2743 BOOL ret;
2745 if (!dc) return FALSE;
2747 if (!abc)
2749 release_dc_ptr( dc );
2750 return FALSE;
2753 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2754 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2755 if (ret)
2757 /* convert device units to logical */
2758 for( i = 0; i < count; i++, abc++ ) {
2759 abc->abcA = width_to_LP(dc, abc->abcA);
2760 abc->abcB = width_to_LP(dc, abc->abcB);
2761 abc->abcC = width_to_LP(dc, abc->abcC);
2765 release_dc_ptr( dc );
2766 return ret;
2770 /***********************************************************************
2771 * GetGlyphOutlineA (GDI32.@)
2773 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2774 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2775 LPVOID lpBuffer, const MAT2 *lpmat2 )
2777 if (!lpmat2) return GDI_ERROR;
2779 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2780 UINT cp;
2781 int len;
2782 char mbchs[2];
2784 cp = GdiGetCodePage(hdc);
2785 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2786 len = 2;
2787 mbchs[0] = (uChar & 0xff00) >> 8;
2788 mbchs[1] = (uChar & 0xff);
2789 } else {
2790 len = 1;
2791 mbchs[0] = (uChar & 0xff);
2793 uChar = 0;
2794 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2797 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2798 lpmat2);
2801 /***********************************************************************
2802 * GetGlyphOutlineW (GDI32.@)
2804 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2805 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2806 LPVOID lpBuffer, const MAT2 *lpmat2 )
2808 DC *dc;
2809 DWORD ret;
2810 PHYSDEV dev;
2812 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2813 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2815 if (!lpmat2) return GDI_ERROR;
2817 dc = get_dc_ptr(hdc);
2818 if(!dc) return GDI_ERROR;
2820 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2821 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2822 release_dc_ptr( dc );
2823 return ret;
2827 /***********************************************************************
2828 * CreateScalableFontResourceA (GDI32.@)
2830 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2831 LPCSTR lpszResourceFile,
2832 LPCSTR lpszFontFile,
2833 LPCSTR lpszCurrentPath )
2835 LPWSTR lpszResourceFileW = NULL;
2836 LPWSTR lpszFontFileW = NULL;
2837 LPWSTR lpszCurrentPathW = NULL;
2838 int len;
2839 BOOL ret;
2841 if (lpszResourceFile)
2843 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2844 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2845 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2848 if (lpszFontFile)
2850 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2851 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2852 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2855 if (lpszCurrentPath)
2857 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2858 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2859 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2862 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2863 lpszFontFileW, lpszCurrentPathW);
2865 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2866 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2867 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2869 return ret;
2872 /***********************************************************************
2873 * CreateScalableFontResourceW (GDI32.@)
2875 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2876 LPCWSTR font_file, LPCWSTR font_path )
2878 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2879 debugstr_w(font_file), debugstr_w(font_path) );
2881 return WineEngCreateScalableFontResource( hidden, resource_file,
2882 font_file, font_path );
2885 /*************************************************************************
2886 * GetKerningPairsA (GDI32.@)
2888 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2889 LPKERNINGPAIR kern_pairA )
2891 UINT cp;
2892 CPINFO cpi;
2893 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2894 KERNINGPAIR *kern_pairW;
2896 if (!cPairs && kern_pairA)
2898 SetLastError(ERROR_INVALID_PARAMETER);
2899 return 0;
2902 cp = GdiGetCodePage(hDC);
2904 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2905 * to fail on an invalid character for CP_SYMBOL.
2907 cpi.DefaultChar[0] = 0;
2908 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2910 FIXME("Can't find codepage %u info\n", cp);
2911 return 0;
2914 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2915 if (!total_kern_pairs) return 0;
2917 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2918 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2920 for (i = 0; i < total_kern_pairs; i++)
2922 char first, second;
2924 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2925 continue;
2927 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2928 continue;
2930 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2931 continue;
2933 if (kern_pairA)
2935 if (kern_pairs_copied >= cPairs) break;
2937 kern_pairA->wFirst = (BYTE)first;
2938 kern_pairA->wSecond = (BYTE)second;
2939 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2940 kern_pairA++;
2942 kern_pairs_copied++;
2945 HeapFree(GetProcessHeap(), 0, kern_pairW);
2947 return kern_pairs_copied;
2950 /*************************************************************************
2951 * GetKerningPairsW (GDI32.@)
2953 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2954 LPKERNINGPAIR lpKerningPairs )
2956 DC *dc;
2957 DWORD ret;
2958 PHYSDEV dev;
2960 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2962 if (!cPairs && lpKerningPairs)
2964 SetLastError(ERROR_INVALID_PARAMETER);
2965 return 0;
2968 dc = get_dc_ptr(hDC);
2969 if (!dc) return 0;
2971 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2972 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2973 release_dc_ptr( dc );
2974 return ret;
2977 /*************************************************************************
2978 * TranslateCharsetInfo [GDI32.@]
2980 * Fills a CHARSETINFO structure for a character set, code page, or
2981 * font. This allows making the correspondence between different labels
2982 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2983 * of the same encoding.
2985 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2986 * only one codepage should be set in *lpSrc.
2988 * RETURNS
2989 * TRUE on success, FALSE on failure.
2992 BOOL WINAPI TranslateCharsetInfo(
2993 LPDWORD lpSrc, /* [in]
2994 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2995 if flags == TCI_SRCCHARSET: a character set value
2996 if flags == TCI_SRCCODEPAGE: a code page value
2998 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2999 DWORD flags /* [in] determines interpretation of lpSrc */)
3001 int index = 0;
3002 switch (flags) {
3003 case TCI_SRCFONTSIG:
3004 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3005 break;
3006 case TCI_SRCCODEPAGE:
3007 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3008 break;
3009 case TCI_SRCCHARSET:
3010 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3011 break;
3012 default:
3013 return FALSE;
3015 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3016 *lpCs = FONT_tci[index];
3017 return TRUE;
3020 /*************************************************************************
3021 * GetFontLanguageInfo (GDI32.@)
3023 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3025 FONTSIGNATURE fontsig;
3026 static const DWORD GCP_DBCS_MASK=0x003F0000,
3027 GCP_DIACRITIC_MASK=0x00000000,
3028 FLI_GLYPHS_MASK=0x00000000,
3029 GCP_GLYPHSHAPE_MASK=0x00000040,
3030 GCP_KASHIDA_MASK=0x00000000,
3031 GCP_LIGATE_MASK=0x00000000,
3032 GCP_USEKERNING_MASK=0x00000000,
3033 GCP_REORDER_MASK=0x00000060;
3035 DWORD result=0;
3037 GetTextCharsetInfo( hdc, &fontsig, 0 );
3038 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3040 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3041 result|=GCP_DBCS;
3043 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3044 result|=GCP_DIACRITIC;
3046 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3047 result|=FLI_GLYPHS;
3049 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3050 result|=GCP_GLYPHSHAPE;
3052 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3053 result|=GCP_KASHIDA;
3055 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3056 result|=GCP_LIGATE;
3058 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3059 result|=GCP_USEKERNING;
3061 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3062 if( GetTextAlign( hdc) & TA_RTLREADING )
3063 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3064 result|=GCP_REORDER;
3066 return result;
3070 /*************************************************************************
3071 * GetFontData [GDI32.@]
3073 * Retrieve data for TrueType font.
3075 * RETURNS
3077 * success: Number of bytes returned
3078 * failure: GDI_ERROR
3080 * NOTES
3082 * Calls SetLastError()
3085 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3086 LPVOID buffer, DWORD length)
3088 DC *dc = get_dc_ptr(hdc);
3089 PHYSDEV dev;
3090 DWORD ret;
3092 if(!dc) return GDI_ERROR;
3094 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3095 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3096 release_dc_ptr( dc );
3097 return ret;
3100 /*************************************************************************
3101 * GetGlyphIndicesA [GDI32.@]
3103 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3104 LPWORD pgi, DWORD flags)
3106 DWORD ret;
3107 WCHAR *lpstrW;
3108 INT countW;
3110 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3111 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3113 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3114 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3115 HeapFree(GetProcessHeap(), 0, lpstrW);
3117 return ret;
3120 /*************************************************************************
3121 * GetGlyphIndicesW [GDI32.@]
3123 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3124 LPWORD pgi, DWORD flags)
3126 DC *dc = get_dc_ptr(hdc);
3127 PHYSDEV dev;
3128 DWORD ret;
3130 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3131 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3133 if(!dc) return GDI_ERROR;
3135 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3136 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3137 release_dc_ptr( dc );
3138 return ret;
3141 /*************************************************************************
3142 * GetCharacterPlacementA [GDI32.@]
3144 * See GetCharacterPlacementW.
3146 * NOTES:
3147 * the web browser control of ie4 calls this with dwFlags=0
3149 DWORD WINAPI
3150 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3151 INT nMaxExtent, GCP_RESULTSA *lpResults,
3152 DWORD dwFlags)
3154 WCHAR *lpStringW;
3155 INT uCountW;
3156 GCP_RESULTSW resultsW;
3157 DWORD ret;
3158 UINT font_cp;
3160 TRACE("%s, %d, %d, 0x%08x\n",
3161 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3163 /* both structs are equal in size */
3164 memcpy(&resultsW, lpResults, sizeof(resultsW));
3166 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3167 if(lpResults->lpOutString)
3168 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3170 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3172 lpResults->nGlyphs = resultsW.nGlyphs;
3173 lpResults->nMaxFit = resultsW.nMaxFit;
3175 if(lpResults->lpOutString) {
3176 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3177 lpResults->lpOutString, uCount, NULL, NULL );
3180 HeapFree(GetProcessHeap(), 0, lpStringW);
3181 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3183 return ret;
3186 /*************************************************************************
3187 * GetCharacterPlacementW [GDI32.@]
3189 * Retrieve information about a string. This includes the width, reordering,
3190 * Glyphing and so on.
3192 * RETURNS
3194 * The width and height of the string if successful, 0 if failed.
3196 * BUGS
3198 * All flags except GCP_REORDER are not yet implemented.
3199 * Reordering is not 100% compliant to the Windows BiDi method.
3200 * Caret positioning is not yet implemented for BiDi.
3201 * Classes are not yet implemented.
3204 DWORD WINAPI
3205 GetCharacterPlacementW(
3206 HDC hdc, /* [in] Device context for which the rendering is to be done */
3207 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3208 INT uCount, /* [in] Number of WORDS in string. */
3209 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3210 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3211 DWORD dwFlags /* [in] Flags specifying how to process the string */
3214 DWORD ret=0;
3215 SIZE size;
3216 UINT i, nSet;
3218 TRACE("%s, %d, %d, 0x%08x\n",
3219 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3221 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3222 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3223 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3224 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3225 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3227 if(dwFlags&(~GCP_REORDER))
3228 FIXME("flags 0x%08x ignored\n", dwFlags);
3229 if(lpResults->lpClass)
3230 FIXME("classes not implemented\n");
3231 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3232 FIXME("Caret positions for complex scripts not implemented\n");
3234 nSet = (UINT)uCount;
3235 if(nSet > lpResults->nGlyphs)
3236 nSet = lpResults->nGlyphs;
3238 /* return number of initialized fields */
3239 lpResults->nGlyphs = nSet;
3241 if((dwFlags&GCP_REORDER)==0 )
3243 /* Treat the case where no special handling was requested in a fastpath way */
3244 /* copy will do if the GCP_REORDER flag is not set */
3245 if(lpResults->lpOutString)
3246 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3248 if(lpResults->lpOrder)
3250 for(i = 0; i < nSet; i++)
3251 lpResults->lpOrder[i] = i;
3254 else
3256 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3257 nSet, lpResults->lpOrder, NULL, NULL );
3260 /* FIXME: Will use the placement chars */
3261 if (lpResults->lpDx)
3263 int c;
3264 for (i = 0; i < nSet; i++)
3266 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3267 lpResults->lpDx[i]= c;
3271 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3273 int pos = 0;
3275 lpResults->lpCaretPos[0] = 0;
3276 for (i = 1; i < nSet; i++)
3277 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3278 lpResults->lpCaretPos[i] = (pos += size.cx);
3281 if(lpResults->lpGlyphs)
3282 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3284 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3285 ret = MAKELONG(size.cx, size.cy);
3287 return ret;
3290 /*************************************************************************
3291 * GetCharABCWidthsFloatA [GDI32.@]
3293 * See GetCharABCWidthsFloatW.
3295 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3297 INT i, wlen;
3298 LPSTR str;
3299 LPWSTR wstr;
3300 BOOL ret = TRUE;
3302 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3303 if (str == NULL)
3304 return FALSE;
3306 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3308 for (i = 0; i < wlen; i++)
3310 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3312 ret = FALSE;
3313 break;
3315 abcf++;
3318 HeapFree( GetProcessHeap(), 0, str );
3319 HeapFree( GetProcessHeap(), 0, wstr );
3321 return ret;
3324 /*************************************************************************
3325 * GetCharABCWidthsFloatW [GDI32.@]
3327 * Retrieves widths of a range of characters.
3329 * PARAMS
3330 * hdc [I] Handle to device context.
3331 * first [I] First character in range to query.
3332 * last [I] Last character in range to query.
3333 * abcf [O] Array of LPABCFLOAT structures.
3335 * RETURNS
3336 * Success: TRUE
3337 * Failure: FALSE
3339 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3341 UINT i;
3342 ABC *abc;
3343 PHYSDEV dev;
3344 BOOL ret = FALSE;
3345 DC *dc = get_dc_ptr( hdc );
3347 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3349 if (!dc) return FALSE;
3351 if (!abcf) goto done;
3352 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3354 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3355 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3356 if (ret)
3358 /* convert device units to logical */
3359 FLOAT scale = fabs( dc->xformVport2World.eM11 );
3360 for (i = first; i <= last; i++, abcf++)
3362 abcf->abcfA = abc[i - first].abcA * scale;
3363 abcf->abcfB = abc[i - first].abcB * scale;
3364 abcf->abcfC = abc[i - first].abcC * scale;
3367 HeapFree( GetProcessHeap(), 0, abc );
3369 done:
3370 release_dc_ptr( dc );
3371 return ret;
3374 /*************************************************************************
3375 * GetCharWidthFloatA [GDI32.@]
3377 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3378 UINT iLastChar, PFLOAT pxBuffer)
3380 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3381 return 0;
3384 /*************************************************************************
3385 * GetCharWidthFloatW [GDI32.@]
3387 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3388 UINT iLastChar, PFLOAT pxBuffer)
3390 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3391 return 0;
3395 /***********************************************************************
3397 * Font Resource API *
3399 ***********************************************************************/
3401 /***********************************************************************
3402 * AddFontResourceA (GDI32.@)
3404 INT WINAPI AddFontResourceA( LPCSTR str )
3406 return AddFontResourceExA( str, 0, NULL);
3409 /***********************************************************************
3410 * AddFontResourceW (GDI32.@)
3412 INT WINAPI AddFontResourceW( LPCWSTR str )
3414 return AddFontResourceExW(str, 0, NULL);
3418 /***********************************************************************
3419 * AddFontResourceExA (GDI32.@)
3421 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3423 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3424 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3425 INT ret;
3427 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3428 ret = AddFontResourceExW(strW, fl, pdv);
3429 HeapFree(GetProcessHeap(), 0, strW);
3430 return ret;
3433 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3435 HRSRC rsrc = FindResourceW(hModule, name, type);
3436 HGLOBAL hMem = LoadResource(hModule, rsrc);
3437 LPVOID *pMem = LockResource(hMem);
3438 int *num_total = (int *)lParam;
3439 DWORD num_in_res;
3441 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3442 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3444 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3445 return FALSE;
3448 *num_total += num_in_res;
3449 return TRUE;
3452 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3454 HANDLE file, mapping;
3455 void *ptr;
3457 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3458 if (file == INVALID_HANDLE_VALUE) return NULL;
3460 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3462 CloseHandle( file );
3463 return NULL;
3466 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3467 CloseHandle( file );
3468 if (!mapping) return NULL;
3470 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3471 CloseHandle( mapping );
3473 return ptr;
3476 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3478 WORD align, type_id, count;
3479 DWORD res_off;
3481 if (size < rsrc_off + 10) return NULL;
3482 align = *(WORD *)(ptr + rsrc_off);
3483 rsrc_off += 2;
3484 type_id = *(WORD *)(ptr + rsrc_off);
3485 while (type_id && type_id != type)
3487 count = *(WORD *)(ptr + rsrc_off + 2);
3488 rsrc_off += 8 + count * 12;
3489 if (size < rsrc_off + 8) return NULL;
3490 type_id = *(WORD *)(ptr + rsrc_off);
3492 if (!type_id) return NULL;
3493 count = *(WORD *)(ptr + rsrc_off + 2);
3494 if (size < rsrc_off + 8 + count * 12) return NULL;
3495 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3496 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3497 if (size < res_off + *len) return NULL;
3498 return ptr + res_off;
3501 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3503 LARGE_INTEGER size;
3504 BYTE *ptr = map_file( res, &size );
3505 const IMAGE_DOS_HEADER *dos;
3506 const IMAGE_OS2_HEADER *ne;
3507 WORD *fontdir;
3508 char *data;
3509 WCHAR *name = NULL;
3510 DWORD len;
3512 if (!ptr) return NULL;
3514 if (size.u.LowPart < sizeof( *dos )) goto fail;
3515 dos = (const IMAGE_DOS_HEADER *)ptr;
3516 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3517 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3518 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3520 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3521 if (!fontdir) goto fail;
3522 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3524 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3525 if (!data) goto fail;
3526 if (!memchr( data, 0, len )) goto fail;
3528 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3529 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3530 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3532 fail:
3533 UnmapViewOfFile( ptr );
3534 return name;
3537 /***********************************************************************
3538 * AddFontResourceExW (GDI32.@)
3540 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3542 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3543 WCHAR *filename;
3544 BOOL hidden;
3546 if (ret == 0)
3548 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3549 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3550 if (hModule != NULL)
3552 int num_resources = 0;
3553 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3555 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3556 wine_dbgstr_w(str));
3557 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3558 ret = num_resources;
3559 FreeLibrary(hModule);
3561 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3563 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3564 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3565 HeapFree( GetProcessHeap(), 0, filename );
3568 return ret;
3571 /***********************************************************************
3572 * RemoveFontResourceA (GDI32.@)
3574 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3576 return RemoveFontResourceExA(str, 0, 0);
3579 /***********************************************************************
3580 * RemoveFontResourceW (GDI32.@)
3582 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3584 return RemoveFontResourceExW(str, 0, 0);
3587 /***********************************************************************
3588 * AddFontMemResourceEx (GDI32.@)
3590 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3592 HANDLE ret;
3593 DWORD num_fonts;
3595 if (!pbFont || !cbFont || !pcFonts)
3597 SetLastError(ERROR_INVALID_PARAMETER);
3598 return NULL;
3601 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3602 if (ret)
3604 __TRY
3606 *pcFonts = num_fonts;
3608 __EXCEPT_PAGE_FAULT
3610 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3611 RemoveFontMemResourceEx(ret);
3612 ret = 0;
3614 __ENDTRY
3616 return ret;
3619 /***********************************************************************
3620 * RemoveFontMemResourceEx (GDI32.@)
3622 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3624 FIXME("(%p) stub\n", fh);
3625 return TRUE;
3628 /***********************************************************************
3629 * RemoveFontResourceExA (GDI32.@)
3631 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3633 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3634 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3635 INT ret;
3637 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3638 ret = RemoveFontResourceExW(strW, fl, pdv);
3639 HeapFree(GetProcessHeap(), 0, strW);
3640 return ret;
3643 /***********************************************************************
3644 * RemoveFontResourceExW (GDI32.@)
3646 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3648 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3649 WCHAR *filename;
3650 BOOL hidden;
3652 if (ret == 0)
3654 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3655 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3656 if (hModule != NULL)
3658 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3659 FreeLibrary(hModule);
3661 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3663 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3664 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3665 HeapFree( GetProcessHeap(), 0, filename );
3668 return ret;
3671 /***********************************************************************
3672 * GetFontResourceInfoW (GDI32.@)
3674 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3676 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3677 return FALSE;
3680 /***********************************************************************
3681 * GetTextCharset (GDI32.@)
3683 UINT WINAPI GetTextCharset(HDC hdc)
3685 /* MSDN docs say this is equivalent */
3686 return GetTextCharsetInfo(hdc, NULL, 0);
3689 /***********************************************************************
3690 * GetTextCharsetInfo (GDI32.@)
3692 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3694 UINT ret = DEFAULT_CHARSET;
3695 DC *dc = get_dc_ptr(hdc);
3696 PHYSDEV dev;
3698 if (dc)
3700 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3701 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3702 release_dc_ptr( dc );
3705 if (ret == DEFAULT_CHARSET && fs)
3706 memset(fs, 0, sizeof(FONTSIGNATURE));
3707 return ret;
3710 /***********************************************************************
3711 * GdiGetCharDimensions (GDI32.@)
3713 * Gets the average width of the characters in the English alphabet.
3715 * PARAMS
3716 * hdc [I] Handle to the device context to measure on.
3717 * lptm [O] Pointer to memory to store the text metrics into.
3718 * height [O] On exit, the maximum height of characters in the English alphabet.
3720 * RETURNS
3721 * The average width of characters in the English alphabet.
3723 * NOTES
3724 * This function is used by the dialog manager to get the size of a dialog
3725 * unit. It should also be used by other pieces of code that need to know
3726 * the size of a dialog unit in logical units without having access to the
3727 * window handle of the dialog.
3728 * Windows caches the font metrics from this function, but we don't and
3729 * there doesn't appear to be an immediate advantage to do so.
3731 * SEE ALSO
3732 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3734 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3736 SIZE sz;
3737 static const WCHAR alphabet[] = {
3738 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3739 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3740 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3742 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3744 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3746 if (height) *height = sz.cy;
3747 return (sz.cx / 26 + 1) / 2;
3750 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3752 FIXME("(%d): stub\n", fEnableEUDC);
3753 return FALSE;
3756 /***********************************************************************
3757 * GetCharWidthI (GDI32.@)
3759 * Retrieve widths of characters.
3761 * PARAMS
3762 * hdc [I] Handle to a device context.
3763 * first [I] First glyph in range to query.
3764 * count [I] Number of glyph indices to query.
3765 * glyphs [I] Array of glyphs to query.
3766 * buffer [O] Buffer to receive character widths.
3768 * NOTES
3769 * Only works with TrueType fonts.
3771 * RETURNS
3772 * Success: TRUE
3773 * Failure: FALSE
3775 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3777 ABC *abc;
3778 unsigned int i;
3780 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3782 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3783 return FALSE;
3785 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3787 HeapFree(GetProcessHeap(), 0, abc);
3788 return FALSE;
3791 for (i = 0; i < count; i++)
3792 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3794 HeapFree(GetProcessHeap(), 0, abc);
3795 return TRUE;
3798 /***********************************************************************
3799 * GetFontUnicodeRanges (GDI32.@)
3801 * Retrieve a list of supported Unicode characters in a font.
3803 * PARAMS
3804 * hdc [I] Handle to a device context.
3805 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3807 * RETURNS
3808 * Success: Number of bytes written to the buffer pointed to by lpgs.
3809 * Failure: 0
3812 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3814 DWORD ret;
3815 PHYSDEV dev;
3816 DC *dc = get_dc_ptr(hdc);
3818 TRACE("(%p, %p)\n", hdc, lpgs);
3820 if (!dc) return 0;
3822 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3823 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3824 release_dc_ptr(dc);
3825 return ret;
3829 /*************************************************************
3830 * FontIsLinked (GDI32.@)
3832 BOOL WINAPI FontIsLinked(HDC hdc)
3834 DC *dc = get_dc_ptr(hdc);
3835 PHYSDEV dev;
3836 BOOL ret;
3838 if (!dc) return FALSE;
3839 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3840 ret = dev->funcs->pFontIsLinked( dev );
3841 release_dc_ptr(dc);
3842 TRACE("returning %d\n", ret);
3843 return ret;
3846 /*************************************************************
3847 * GdiRealizationInfo (GDI32.@)
3849 * Returns a structure that contains some font information.
3851 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3853 DC *dc = get_dc_ptr(hdc);
3854 PHYSDEV dev;
3855 BOOL ret;
3857 if (!dc) return FALSE;
3858 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3859 ret = dev->funcs->pGdiRealizationInfo( dev, info );
3860 release_dc_ptr(dc);
3861 return ret;