quartz: Pass the matching filter count to IEnumRegFiltersImpl_Construct().
[wine.git] / dlls / gdi32 / font.c
blob8788426a2c2109e5be238316893bc9ad65f94069
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/heap.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(font);
45 /* Device -> World size conversion */
47 /* Performs a device to world transformation on the specified width (which
48 * is in integer format).
50 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
52 double floatWidth;
54 /* Perform operation with floating point */
55 floatWidth = (double)width * dc->xformVport2World.eM11;
56 /* Round to integers */
57 return GDI_ROUND(floatWidth);
60 /* Performs a device to world transformation on the specified size (which
61 * is in integer format).
63 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
65 double floatHeight;
67 /* Perform operation with floating point */
68 floatHeight = (double)height * dc->xformVport2World.eM22;
69 /* Round to integers */
70 return GDI_ROUND(floatHeight);
73 /* scale width and height but don't mirror them */
75 static inline INT width_to_LP( DC *dc, INT width )
77 return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
80 static inline INT height_to_LP( DC *dc, INT height )
82 return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
85 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
87 POINT pt[2];
88 pt[0].x = pt[0].y = 0;
89 pt[1].x = 0;
90 pt[1].y = height;
91 lp_to_dp(dc, pt, 2);
92 return pt[1].y - pt[0].y;
95 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
96 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
97 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
98 static BOOL FONT_DeleteObject( HGDIOBJ handle );
100 static const struct gdi_obj_funcs font_funcs =
102 FONT_SelectObject, /* pSelectObject */
103 FONT_GetObjectA, /* pGetObjectA */
104 FONT_GetObjectW, /* pGetObjectW */
105 NULL, /* pUnrealizeObject */
106 FONT_DeleteObject /* pDeleteObject */
109 typedef struct
111 LOGFONTW logfont;
112 } FONTOBJ;
114 struct font_enum
116 LPLOGFONTW lpLogFontParam;
117 FONTENUMPROCW lpEnumFunc;
118 LPARAM lpData;
119 BOOL unicode;
120 HDC hdc;
121 INT retval;
125 * For TranslateCharsetInfo
127 #define MAXTCIINDEX 32
128 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
129 /* ANSI */
130 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
131 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
132 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
133 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
134 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
135 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
136 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
137 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
138 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
139 /* reserved by ANSI */
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
145 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
146 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
147 /* ANSI and OEM */
148 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
149 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
150 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
151 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
152 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
153 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
154 /* reserved for alternate ANSI and OEM */
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
163 /* reserved for system */
164 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
165 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
168 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
170 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
171 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
172 LF_FACESIZE);
173 fontW->lfFaceName[LF_FACESIZE-1] = 0;
176 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
178 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
179 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
180 LF_FACESIZE, NULL, NULL);
181 fontA->lfFaceName[LF_FACESIZE-1] = 0;
184 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
186 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
188 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
189 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
190 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
191 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
192 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
193 fontA->elfStyle[LF_FACESIZE-1] = '\0';
194 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
195 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
196 fontA->elfScript[LF_FACESIZE-1] = '\0';
199 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
201 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
203 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
204 fontW->elfFullName, LF_FULLFACESIZE );
205 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
206 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
207 fontW->elfStyle, LF_FACESIZE );
208 fontW->elfStyle[LF_FACESIZE-1] = '\0';
209 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
210 fontW->elfScript, LF_FACESIZE );
211 fontW->elfScript[LF_FACESIZE-1] = '\0';
214 /***********************************************************************
215 * TEXTMETRIC conversion functions.
217 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
219 ptmA->tmHeight = ptmW->tmHeight;
220 ptmA->tmAscent = ptmW->tmAscent;
221 ptmA->tmDescent = ptmW->tmDescent;
222 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
223 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
224 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
225 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
226 ptmA->tmWeight = ptmW->tmWeight;
227 ptmA->tmOverhang = ptmW->tmOverhang;
228 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
229 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
230 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
231 if (ptmW->tmCharSet == SYMBOL_CHARSET)
233 ptmA->tmFirstChar = 0x1e;
234 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
236 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
238 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
239 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
241 else
243 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
244 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
246 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
247 ptmA->tmBreakChar = ptmW->tmBreakChar;
248 ptmA->tmItalic = ptmW->tmItalic;
249 ptmA->tmUnderlined = ptmW->tmUnderlined;
250 ptmA->tmStruckOut = ptmW->tmStruckOut;
251 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
252 ptmA->tmCharSet = ptmW->tmCharSet;
256 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
258 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
259 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
260 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
261 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
262 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
263 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
266 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
268 WCHAR buf[12];
269 DWORD count = sizeof(buf), type, err;
271 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
272 if (!err)
274 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
275 else *value = atoiW( buf );
277 return err;
280 static UINT get_subpixel_orientation( HKEY key )
282 static const WCHAR smoothing_orientation[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
283 'O','r','i','e','n','t','a','t','i','o','n',0};
284 DWORD orient;
286 /* FIXME: handle vertical orientations even though Windows doesn't */
287 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
289 switch (orient)
291 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
292 return WINE_GGO_HBGR_BITMAP;
293 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
294 return WINE_GGO_HRGB_BITMAP;
296 return GGO_GRAY4_BITMAP;
299 static UINT get_default_smoothing( HKEY key )
301 static const WCHAR smoothing[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
302 static const WCHAR smoothing_type[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
303 DWORD enabled, type;
305 if (get_key_value( key, smoothing, &enabled )) return 0;
306 if (!enabled) return GGO_BITMAP;
308 if (!get_key_value( key, smoothing_type, &type ) && type == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
309 return get_subpixel_orientation( key );
311 return GGO_GRAY4_BITMAP;
314 /* compute positions for text rendering, in device coords */
315 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
317 TEXTMETRICW tm;
318 PHYSDEV dev;
320 size->cx = size->cy = 0;
321 if (!count) return TRUE;
323 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
324 dev->funcs->pGetTextMetrics( dev, &tm );
326 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
327 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
329 if (dc->breakExtra || dc->breakRem)
331 int i, space = 0, rem = dc->breakRem;
333 for (i = 0; i < count; i++)
335 if (str[i] == tm.tmBreakChar)
337 space += dc->breakExtra;
338 if (rem > 0)
340 space++;
341 rem--;
344 dx[i] += space;
347 size->cx = dx[count - 1];
348 size->cy = tm.tmHeight;
349 return TRUE;
352 /* compute positions for text rendering, in device coords */
353 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
355 TEXTMETRICW tm;
356 PHYSDEV dev;
358 size->cx = size->cy = 0;
359 if (!count) return TRUE;
361 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
362 dev->funcs->pGetTextMetrics( dev, &tm );
364 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
365 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
367 if (dc->breakExtra || dc->breakRem)
369 WORD space_index;
370 int i, space = 0, rem = dc->breakRem;
372 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
373 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
375 for (i = 0; i < count; i++)
377 if (indices[i] == space_index)
379 space += dc->breakExtra;
380 if (rem > 0)
382 space++;
383 rem--;
386 dx[i] += space;
389 size->cx = dx[count - 1];
390 size->cy = tm.tmHeight;
391 return TRUE;
394 /***********************************************************************
395 * GdiGetCodePage (GDI32.@)
397 DWORD WINAPI GdiGetCodePage( HDC hdc )
399 UINT cp = CP_ACP;
400 DC *dc = get_dc_ptr( hdc );
402 if (dc)
404 cp = dc->font_code_page;
405 release_dc_ptr( dc );
407 return cp;
410 /***********************************************************************
411 * get_text_charset_info
413 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
415 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
417 UINT ret = DEFAULT_CHARSET;
418 PHYSDEV dev;
420 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
421 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
423 if (ret == DEFAULT_CHARSET && fs)
424 memset(fs, 0, sizeof(FONTSIGNATURE));
425 return ret;
428 /***********************************************************************
429 * GetTextCharsetInfo (GDI32.@)
431 UINT WINAPI GetTextCharsetInfo(HDC hdc, FONTSIGNATURE *fs, DWORD flags)
433 UINT ret = DEFAULT_CHARSET;
434 DC *dc = get_dc_ptr(hdc);
436 if (dc)
438 ret = get_text_charset_info( dc, fs, flags );
439 release_dc_ptr( dc );
441 return ret;
444 /***********************************************************************
445 * FONT_mbtowc
447 * Returns a Unicode translation of str using the charset of the
448 * currently selected font in hdc. If count is -1 then str is assumed
449 * to be '\0' terminated, otherwise it contains the number of bytes to
450 * convert. If plenW is non-NULL, on return it will point to the
451 * number of WCHARs that have been written. If pCP is non-NULL, on
452 * return it will point to the codepage used in the conversion. The
453 * caller should free the returned LPWSTR from the process heap
454 * itself.
456 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
458 UINT cp;
459 INT lenW;
460 LPWSTR strW;
462 cp = GdiGetCodePage( hdc );
464 if(count == -1) count = strlen(str);
465 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
466 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
467 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
468 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
469 if(plenW) *plenW = lenW;
470 if(pCP) *pCP = cp;
471 return strW;
474 /***********************************************************************
475 * CreateFontIndirectExA (GDI32.@)
477 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
479 ENUMLOGFONTEXDVW enumexW;
481 if (!penumexA) return 0;
483 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
484 enumexW.elfDesignVector = penumexA->elfDesignVector;
485 return CreateFontIndirectExW( &enumexW );
488 /***********************************************************************
489 * CreateFontIndirectExW (GDI32.@)
491 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
493 HFONT hFont;
494 FONTOBJ *fontPtr;
495 const LOGFONTW *plf;
497 if (!penumex) return 0;
499 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
500 penumex->elfEnumLogfontEx.elfStyle[0] ||
501 penumex->elfEnumLogfontEx.elfScript[0])
503 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
504 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
505 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
506 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
509 plf = &penumex->elfEnumLogfontEx.elfLogFont;
510 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
512 fontPtr->logfont = *plf;
514 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
516 HeapFree( GetProcessHeap(), 0, fontPtr );
517 return 0;
520 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
521 plf->lfHeight, plf->lfWidth,
522 plf->lfEscapement, plf->lfOrientation,
523 plf->lfPitchAndFamily,
524 plf->lfOutPrecision, plf->lfClipPrecision,
525 plf->lfQuality, plf->lfCharSet,
526 debugstr_w(plf->lfFaceName),
527 plf->lfWeight > 400 ? "Bold" : "",
528 plf->lfItalic ? "Italic" : "",
529 plf->lfUnderline ? "Underline" : "", hFont);
531 return hFont;
534 /***********************************************************************
535 * CreateFontIndirectA (GDI32.@)
537 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
539 LOGFONTW lfW;
541 if (!plfA) return 0;
543 FONT_LogFontAToW( plfA, &lfW );
544 return CreateFontIndirectW( &lfW );
547 /***********************************************************************
548 * CreateFontIndirectW (GDI32.@)
550 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
552 ENUMLOGFONTEXDVW exdv;
554 if (!plf) return 0;
556 exdv.elfEnumLogfontEx.elfLogFont = *plf;
557 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
558 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
559 exdv.elfEnumLogfontEx.elfScript[0] = 0;
560 return CreateFontIndirectExW( &exdv );
563 /*************************************************************************
564 * CreateFontA (GDI32.@)
566 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
567 INT orient, INT weight, DWORD italic,
568 DWORD underline, DWORD strikeout, DWORD charset,
569 DWORD outpres, DWORD clippres, DWORD quality,
570 DWORD pitch, LPCSTR name )
572 LOGFONTA logfont;
574 logfont.lfHeight = height;
575 logfont.lfWidth = width;
576 logfont.lfEscapement = esc;
577 logfont.lfOrientation = orient;
578 logfont.lfWeight = weight;
579 logfont.lfItalic = italic;
580 logfont.lfUnderline = underline;
581 logfont.lfStrikeOut = strikeout;
582 logfont.lfCharSet = charset;
583 logfont.lfOutPrecision = outpres;
584 logfont.lfClipPrecision = clippres;
585 logfont.lfQuality = quality;
586 logfont.lfPitchAndFamily = pitch;
588 if (name)
589 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
590 else
591 logfont.lfFaceName[0] = '\0';
593 return CreateFontIndirectA( &logfont );
596 /*************************************************************************
597 * CreateFontW (GDI32.@)
599 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
600 INT orient, INT weight, DWORD italic,
601 DWORD underline, DWORD strikeout, DWORD charset,
602 DWORD outpres, DWORD clippres, DWORD quality,
603 DWORD pitch, LPCWSTR name )
605 LOGFONTW logfont;
607 logfont.lfHeight = height;
608 logfont.lfWidth = width;
609 logfont.lfEscapement = esc;
610 logfont.lfOrientation = orient;
611 logfont.lfWeight = weight;
612 logfont.lfItalic = italic;
613 logfont.lfUnderline = underline;
614 logfont.lfStrikeOut = strikeout;
615 logfont.lfCharSet = charset;
616 logfont.lfOutPrecision = outpres;
617 logfont.lfClipPrecision = clippres;
618 logfont.lfQuality = quality;
619 logfont.lfPitchAndFamily = pitch;
621 if (name)
622 lstrcpynW(logfont.lfFaceName, name, ARRAY_SIZE(logfont.lfFaceName));
623 else
624 logfont.lfFaceName[0] = '\0';
626 return CreateFontIndirectW( &logfont );
629 #define ASSOC_CHARSET_OEM 1
630 #define ASSOC_CHARSET_ANSI 2
631 #define ASSOC_CHARSET_SYMBOL 4
633 static DWORD get_associated_charset_info(void)
635 static DWORD associated_charset = -1;
637 if (associated_charset == -1)
639 static const WCHAR assoc_charset_reg_keyW[] = {'S','y','s','t','e','m','\\',
640 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
641 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
642 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
643 static const WCHAR ansiW[] = {'A','N','S','I','(','0','0',')','\0'};
644 static const WCHAR oemW[] = {'O','E','M','(','F','F',')','\0'};
645 static const WCHAR symbolW[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
646 static const WCHAR yesW[] = {'Y','E','S','\0'};
647 HKEY hkey;
648 WCHAR dataW[32];
649 DWORD type, data_len;
651 associated_charset = 0;
653 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
654 assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS)
655 return 0;
657 data_len = sizeof(dataW);
658 if (!RegQueryValueExW(hkey, ansiW, NULL, &type, (LPBYTE)dataW, &data_len) &&
659 type == REG_SZ && !strcmpiW(dataW, yesW))
660 associated_charset |= ASSOC_CHARSET_ANSI;
662 data_len = sizeof(dataW);
663 if (!RegQueryValueExW(hkey, oemW, NULL, &type, (LPBYTE)dataW, &data_len) &&
664 type == REG_SZ && !strcmpiW(dataW, yesW))
665 associated_charset |= ASSOC_CHARSET_OEM;
667 data_len = sizeof(dataW);
668 if (!RegQueryValueExW(hkey, symbolW, NULL, &type, (LPBYTE)dataW, &data_len) &&
669 type == REG_SZ && !strcmpiW(dataW, yesW))
670 associated_charset |= ASSOC_CHARSET_SYMBOL;
672 RegCloseKey(hkey);
674 TRACE("associated_charset = %d\n", associated_charset);
677 return associated_charset;
680 static void update_font_code_page( DC *dc, HANDLE font )
682 CHARSETINFO csi;
683 int charset = get_text_charset_info( dc, NULL, 0 );
685 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
687 LOGFONTW lf;
689 GetObjectW( font, sizeof(lf), &lf );
690 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
691 charset = DEFAULT_CHARSET;
694 /* Hmm, nicely designed api this one! */
695 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
696 dc->font_code_page = csi.ciACP;
697 else {
698 switch(charset) {
699 case OEM_CHARSET:
700 dc->font_code_page = GetOEMCP();
701 break;
702 case DEFAULT_CHARSET:
703 dc->font_code_page = GetACP();
704 break;
706 case VISCII_CHARSET:
707 case TCVN_CHARSET:
708 case KOI8_CHARSET:
709 case ISO3_CHARSET:
710 case ISO4_CHARSET:
711 case ISO10_CHARSET:
712 case CELTIC_CHARSET:
713 /* FIXME: These have no place here, but because x11drv
714 enumerates fonts with these (made up) charsets some apps
715 might use them and then the FIXME below would become
716 annoying. Now we could pick the intended codepage for
717 each of these, but since it's broken anyway we'll just
718 use CP_ACP and hope it'll go away...
720 dc->font_code_page = CP_ACP;
721 break;
723 default:
724 FIXME("Can't find codepage for charset %d\n", charset);
725 dc->font_code_page = CP_ACP;
726 break;
730 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
733 static struct font_gamma_ramp *get_font_gamma_ramp( void )
735 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
736 'D','e','s','k','t','o','p',0 };
737 static const WCHAR smoothing_gamma[] = { 'F','o','n','t','S','m','o','o','t','h','i','n','g',
738 'G','a','m','m','a',0 };
739 const DWORD gamma_default = 1400;
740 struct font_gamma_ramp *ramp;
741 DWORD i, gamma;
742 HKEY key;
744 ramp = HeapAlloc( GetProcessHeap(), 0, sizeof(*ramp) );
745 if ( ramp == NULL) return NULL;
747 gamma = gamma_default;
748 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key ) == ERROR_SUCCESS)
750 if (get_key_value( key, smoothing_gamma, &gamma ) || gamma == 0)
751 gamma = gamma_default;
752 RegCloseKey( key );
754 gamma = min( max( gamma, 1000 ), 2200 );
757 /* Calibrating the difference between the registry value and the Wine gamma value.
758 This looks roughly similar to Windows Native with the same registry value.
759 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
760 gamma = 1000 * gamma / 1400;
762 for (i = 0; i < 256; i++)
764 ramp->encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
765 ramp->decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
768 ramp->gamma = gamma;
769 TRACE("gamma %d\n", ramp->gamma);
771 return ramp;
774 /***********************************************************************
775 * FONT_SelectObject
777 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
779 HGDIOBJ ret = 0;
780 DC *dc = get_dc_ptr( hdc );
781 PHYSDEV physdev;
782 UINT aa_flags = 0;
784 if (!dc) return 0;
786 if (!GDI_inc_ref_count( handle ))
788 release_dc_ptr( dc );
789 return 0;
792 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
793 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
795 ret = dc->hFont;
796 dc->hFont = handle;
797 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
798 update_font_code_page( dc, handle );
799 if (dc->font_gamma_ramp == NULL)
800 dc->font_gamma_ramp = get_font_gamma_ramp();
801 GDI_dec_ref_count( ret );
803 else GDI_dec_ref_count( handle );
805 release_dc_ptr( dc );
806 return ret;
810 /***********************************************************************
811 * FONT_GetObjectA
813 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
815 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
816 LOGFONTA lfA;
818 if (!font) return 0;
819 if (buffer)
821 FONT_LogFontWToA( &font->logfont, &lfA );
822 if (count > sizeof(lfA)) count = sizeof(lfA);
823 memcpy( buffer, &lfA, count );
825 else count = sizeof(lfA);
826 GDI_ReleaseObj( handle );
827 return count;
830 /***********************************************************************
831 * FONT_GetObjectW
833 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
835 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
837 if (!font) return 0;
838 if (buffer)
840 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
841 memcpy( buffer, &font->logfont, count );
843 else count = sizeof(LOGFONTW);
844 GDI_ReleaseObj( handle );
845 return count;
849 /***********************************************************************
850 * FONT_DeleteObject
852 static BOOL FONT_DeleteObject( HGDIOBJ handle )
854 FONTOBJ *obj;
856 if (!(obj = free_gdi_handle( handle ))) return FALSE;
857 HeapFree( GetProcessHeap(), 0, obj );
858 return TRUE;
862 /***********************************************************************
863 * nulldrv_SelectFont
865 HFONT CDECL nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
867 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
868 'D','e','s','k','t','o','p',0 };
869 static int orientation = -1, smoothing = -1;
870 LOGFONTW lf;
871 HKEY key;
873 if (*aa_flags) return 0;
875 GetObjectW( font, sizeof(lf), &lf );
876 switch (lf.lfQuality)
878 case NONANTIALIASED_QUALITY:
879 *aa_flags = GGO_BITMAP;
880 break;
881 case ANTIALIASED_QUALITY:
882 *aa_flags = GGO_GRAY4_BITMAP;
883 break;
884 case CLEARTYPE_QUALITY:
885 case CLEARTYPE_NATURAL_QUALITY:
886 if (orientation == -1)
888 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
889 orientation = get_subpixel_orientation( key );
890 RegCloseKey( key );
892 *aa_flags = orientation;
893 break;
894 default:
895 if (smoothing == -1)
897 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
898 smoothing = get_default_smoothing( key );
899 RegCloseKey( key );
901 *aa_flags = smoothing;
902 break;
904 return 0;
908 /***********************************************************************
909 * FONT_EnumInstance
911 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
912 * We have to use other types because of the FONTENUMPROCW definition.
914 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
915 DWORD fType, LPARAM lp )
917 struct font_enum *pfe = (struct font_enum *)lp;
918 INT ret = 1;
920 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
921 if ((!pfe->lpLogFontParam ||
922 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
923 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
924 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
926 /* convert font metrics */
927 ENUMLOGFONTEXA logfont;
928 NEWTEXTMETRICEXA tmA;
930 if (!pfe->unicode)
932 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
933 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
934 plf = (LOGFONTW *)&logfont.elfLogFont;
935 ptm = (TEXTMETRICW *)&tmA;
937 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
938 pfe->retval = ret;
940 return ret;
943 /***********************************************************************
944 * FONT_EnumFontFamiliesEx
946 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
947 LPARAM lParam, BOOL unicode )
949 INT ret = 0;
950 DC *dc = get_dc_ptr( hDC );
951 struct font_enum fe;
953 if (dc)
955 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
957 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
958 fe.lpLogFontParam = plf;
959 fe.lpEnumFunc = efproc;
960 fe.lpData = lParam;
961 fe.unicode = unicode;
962 fe.hdc = hDC;
963 fe.retval = 1;
964 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
965 release_dc_ptr( dc );
967 return ret ? fe.retval : 0;
970 /***********************************************************************
971 * EnumFontFamiliesExW (GDI32.@)
973 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
974 FONTENUMPROCW efproc,
975 LPARAM lParam, DWORD dwFlags )
977 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
980 /***********************************************************************
981 * EnumFontFamiliesExA (GDI32.@)
983 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
984 FONTENUMPROCA efproc,
985 LPARAM lParam, DWORD dwFlags)
987 LOGFONTW lfW, *plfW;
989 if (plf)
991 FONT_LogFontAToW( plf, &lfW );
992 plfW = &lfW;
994 else plfW = NULL;
996 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
999 /***********************************************************************
1000 * EnumFontFamiliesA (GDI32.@)
1002 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
1003 FONTENUMPROCA efproc, LPARAM lpData )
1005 LOGFONTA lf, *plf;
1007 if (lpFamily)
1009 if (!*lpFamily) return 1;
1010 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
1011 lf.lfCharSet = DEFAULT_CHARSET;
1012 lf.lfPitchAndFamily = 0;
1013 plf = &lf;
1015 else plf = NULL;
1017 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
1020 /***********************************************************************
1021 * EnumFontFamiliesW (GDI32.@)
1023 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
1024 FONTENUMPROCW efproc, LPARAM lpData )
1026 LOGFONTW lf, *plf;
1028 if (lpFamily)
1030 if (!*lpFamily) return 1;
1031 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
1032 lf.lfCharSet = DEFAULT_CHARSET;
1033 lf.lfPitchAndFamily = 0;
1034 plf = &lf;
1036 else plf = NULL;
1038 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
1041 /***********************************************************************
1042 * EnumFontsA (GDI32.@)
1044 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
1045 LPARAM lpData )
1047 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
1050 /***********************************************************************
1051 * EnumFontsW (GDI32.@)
1053 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
1054 LPARAM lpData )
1056 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
1060 /***********************************************************************
1061 * GetTextCharacterExtra (GDI32.@)
1063 INT WINAPI GetTextCharacterExtra( HDC hdc )
1065 INT ret;
1066 DC *dc = get_dc_ptr( hdc );
1067 if (!dc) return 0x80000000;
1068 ret = dc->charExtra;
1069 release_dc_ptr( dc );
1070 return ret;
1074 /***********************************************************************
1075 * SetTextCharacterExtra (GDI32.@)
1077 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
1079 INT ret = 0x80000000;
1080 DC * dc = get_dc_ptr( hdc );
1082 if (dc)
1084 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
1085 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
1086 if (extra != 0x80000000)
1088 ret = dc->charExtra;
1089 dc->charExtra = extra;
1091 release_dc_ptr( dc );
1093 return ret;
1097 /***********************************************************************
1098 * SetTextJustification (GDI32.@)
1100 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
1102 BOOL ret;
1103 PHYSDEV physdev;
1104 DC * dc = get_dc_ptr( hdc );
1106 if (!dc) return FALSE;
1108 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
1109 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
1110 if (ret)
1112 extra = abs((extra * dc->vport_ext.cx + dc->wnd_ext.cx / 2) / dc->wnd_ext.cx);
1113 if (!extra) breaks = 0;
1114 if (breaks)
1116 dc->breakExtra = extra / breaks;
1117 dc->breakRem = extra - (breaks * dc->breakExtra);
1119 else
1121 dc->breakExtra = 0;
1122 dc->breakRem = 0;
1125 release_dc_ptr( dc );
1126 return ret;
1130 /***********************************************************************
1131 * GetTextFaceA (GDI32.@)
1133 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
1135 INT res = GetTextFaceW(hdc, 0, NULL);
1136 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
1137 GetTextFaceW( hdc, res, nameW );
1139 if (name)
1141 if (count)
1143 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
1144 if (res == 0)
1145 res = count;
1146 name[count-1] = 0;
1147 /* GetTextFaceA does NOT include the nul byte in the return count. */
1148 res--;
1150 else
1151 res = 0;
1153 else
1154 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
1155 HeapFree( GetProcessHeap(), 0, nameW );
1156 return res;
1159 /***********************************************************************
1160 * GetTextFaceW (GDI32.@)
1162 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
1164 PHYSDEV dev;
1165 INT ret;
1167 DC * dc = get_dc_ptr( hdc );
1168 if (!dc) return 0;
1170 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
1171 ret = dev->funcs->pGetTextFace( dev, count, name );
1172 release_dc_ptr( dc );
1173 return ret;
1177 /***********************************************************************
1178 * GetTextExtentPoint32A (GDI32.@)
1180 * See GetTextExtentPoint32W.
1182 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1183 LPSIZE size )
1185 BOOL ret = FALSE;
1186 INT wlen;
1187 LPWSTR p;
1189 if (count < 0) return FALSE;
1191 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1193 if (p)
1195 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1196 HeapFree( GetProcessHeap(), 0, p );
1199 TRACE("(%p %s %d %p): returning %d x %d\n",
1200 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1201 return ret;
1205 /***********************************************************************
1206 * GetTextExtentPoint32W [GDI32.@]
1208 * Computes width/height for a string.
1210 * Computes width and height of the specified string.
1212 * RETURNS
1213 * Success: TRUE
1214 * Failure: FALSE
1216 BOOL WINAPI GetTextExtentPoint32W(
1217 HDC hdc, /* [in] Handle of device context */
1218 LPCWSTR str, /* [in] Address of text string */
1219 INT count, /* [in] Number of characters in string */
1220 LPSIZE size) /* [out] Address of structure for string size */
1222 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1225 /***********************************************************************
1226 * GetTextExtentExPointI [GDI32.@]
1228 * Computes width and height of the array of glyph indices.
1230 * PARAMS
1231 * hdc [I] Handle of device context.
1232 * indices [I] Glyph index array.
1233 * count [I] Number of glyphs in array.
1234 * max_ext [I] Maximum width in glyphs.
1235 * nfit [O] Maximum number of characters.
1236 * dxs [O] Partial string widths.
1237 * size [O] Returned string size.
1239 * RETURNS
1240 * Success: TRUE
1241 * Failure: FALSE
1243 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1244 LPINT nfit, LPINT dxs, LPSIZE size )
1246 DC *dc;
1247 int i;
1248 BOOL ret;
1249 INT buffer[256], *pos = dxs;
1251 if (count < 0) return FALSE;
1253 dc = get_dc_ptr( hdc );
1254 if (!dc) return FALSE;
1256 if (!dxs)
1258 pos = buffer;
1259 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1261 release_dc_ptr( dc );
1262 return FALSE;
1266 ret = get_char_positions_indices( dc, indices, count, pos, size );
1267 if (ret)
1269 if (dxs || nfit)
1271 for (i = 0; i < count; i++)
1273 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1274 if (nfit && dx > (unsigned int)max_ext) break;
1275 if (dxs) dxs[i] = dx;
1277 if (nfit) *nfit = i;
1280 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1281 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1284 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1285 release_dc_ptr( dc );
1287 TRACE("(%p %p %d %p): returning %d x %d\n",
1288 hdc, indices, count, size, size->cx, size->cy );
1289 return ret;
1292 /***********************************************************************
1293 * GetTextExtentPointI [GDI32.@]
1295 * Computes width and height of the array of glyph indices.
1297 * PARAMS
1298 * hdc [I] Handle of device context.
1299 * indices [I] Glyph index array.
1300 * count [I] Number of glyphs in array.
1301 * size [O] Returned string size.
1303 * RETURNS
1304 * Success: TRUE
1305 * Failure: FALSE
1307 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1309 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1313 /***********************************************************************
1314 * GetTextExtentPointA (GDI32.@)
1316 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1317 LPSIZE size )
1319 TRACE("not bug compatible.\n");
1320 return GetTextExtentPoint32A( hdc, str, count, size );
1323 /***********************************************************************
1324 * GetTextExtentPointW (GDI32.@)
1326 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1327 LPSIZE size )
1329 TRACE("not bug compatible.\n");
1330 return GetTextExtentPoint32W( hdc, str, count, size );
1334 /***********************************************************************
1335 * GetTextExtentExPointA (GDI32.@)
1337 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1338 INT maxExt, LPINT lpnFit,
1339 LPINT alpDx, LPSIZE size )
1341 BOOL ret;
1342 INT wlen;
1343 INT *walpDx = NULL;
1344 LPWSTR p = NULL;
1346 if (count < 0) return FALSE;
1347 if (maxExt < -1) return FALSE;
1349 if (alpDx)
1351 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1352 if (!walpDx) return FALSE;
1355 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1356 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1357 if (walpDx)
1359 INT n = lpnFit ? *lpnFit : wlen;
1360 INT i, j;
1361 for(i = 0, j = 0; i < n; i++, j++)
1363 alpDx[j] = walpDx[i];
1364 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1367 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1368 HeapFree( GetProcessHeap(), 0, p );
1369 HeapFree( GetProcessHeap(), 0, walpDx );
1370 return ret;
1374 /***********************************************************************
1375 * GetTextExtentExPointW (GDI32.@)
1377 * Return the size of the string as it would be if it was output properly by
1378 * e.g. TextOut.
1380 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
1381 LPINT nfit, LPINT dxs, LPSIZE size )
1383 DC *dc;
1384 int i;
1385 BOOL ret;
1386 INT buffer[256], *pos = dxs;
1388 if (count < 0) return FALSE;
1390 dc = get_dc_ptr(hdc);
1391 if (!dc) return FALSE;
1393 if (!dxs)
1395 pos = buffer;
1396 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
1398 release_dc_ptr( dc );
1399 return FALSE;
1403 ret = get_char_positions( dc, str, count, pos, size );
1404 if (ret)
1406 if (dxs || nfit)
1408 for (i = 0; i < count; i++)
1410 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
1411 if (nfit && dx > (unsigned int)max_ext) break;
1412 if (dxs) dxs[i] = dx;
1414 if (nfit) *nfit = i;
1417 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
1418 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
1421 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
1422 release_dc_ptr( dc );
1424 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
1425 return ret;
1428 /***********************************************************************
1429 * GetTextMetricsA (GDI32.@)
1431 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1433 TEXTMETRICW tm32;
1435 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1436 FONT_TextMetricWToA( &tm32, metrics );
1437 return TRUE;
1440 /***********************************************************************
1441 * GetTextMetricsW (GDI32.@)
1443 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1445 PHYSDEV physdev;
1446 BOOL ret = FALSE;
1447 DC * dc = get_dc_ptr( hdc );
1448 if (!dc) return FALSE;
1450 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1451 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1453 if (ret)
1455 /* device layer returns values in device units
1456 * therefore we have to convert them to logical */
1458 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1459 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1460 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
1461 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
1462 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
1463 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
1464 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
1465 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
1466 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
1467 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
1468 ret = TRUE;
1470 TRACE("text metrics:\n"
1471 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1472 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1473 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1474 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1475 " PitchAndFamily = %02x\n"
1476 " --------------------\n"
1477 " InternalLeading = %i\n"
1478 " Ascent = %i\n"
1479 " Descent = %i\n"
1480 " Height = %i\n",
1481 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1482 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1483 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1484 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1485 metrics->tmPitchAndFamily,
1486 metrics->tmInternalLeading,
1487 metrics->tmAscent,
1488 metrics->tmDescent,
1489 metrics->tmHeight );
1491 release_dc_ptr( dc );
1492 return ret;
1496 /***********************************************************************
1497 * GetOutlineTextMetricsA (GDI32.@)
1498 * Gets metrics for TrueType fonts.
1500 * NOTES
1501 * If the supplied buffer isn't big enough Windows partially fills it up to
1502 * its given length and returns that length.
1504 * RETURNS
1505 * Success: Non-zero or size of required buffer
1506 * Failure: 0
1508 UINT WINAPI GetOutlineTextMetricsA(
1509 HDC hdc, /* [in] Handle of device context */
1510 UINT cbData, /* [in] Size of metric data array */
1511 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1513 char buf[512], *ptr;
1514 UINT ret, needed;
1515 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1516 OUTLINETEXTMETRICA *output = lpOTM;
1517 INT left, len;
1519 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1520 return 0;
1521 if(ret > sizeof(buf))
1522 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1523 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1525 needed = sizeof(OUTLINETEXTMETRICA);
1526 if(lpOTMW->otmpFamilyName)
1527 needed += WideCharToMultiByte(CP_ACP, 0,
1528 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1529 NULL, 0, NULL, NULL);
1530 if(lpOTMW->otmpFaceName)
1531 needed += WideCharToMultiByte(CP_ACP, 0,
1532 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1533 NULL, 0, NULL, NULL);
1534 if(lpOTMW->otmpStyleName)
1535 needed += WideCharToMultiByte(CP_ACP, 0,
1536 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1537 NULL, 0, NULL, NULL);
1538 if(lpOTMW->otmpFullName)
1539 needed += WideCharToMultiByte(CP_ACP, 0,
1540 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1541 NULL, 0, NULL, NULL);
1543 if(!lpOTM) {
1544 ret = needed;
1545 goto end;
1548 TRACE("needed = %d\n", needed);
1549 if(needed > cbData)
1550 /* Since the supplied buffer isn't big enough, we'll alloc one
1551 that is and memcpy the first cbData bytes into the lpOTM at
1552 the end. */
1553 output = HeapAlloc(GetProcessHeap(), 0, needed);
1555 ret = output->otmSize = min(needed, cbData);
1556 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1557 output->otmFiller = 0;
1558 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1559 output->otmfsSelection = lpOTMW->otmfsSelection;
1560 output->otmfsType = lpOTMW->otmfsType;
1561 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1562 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1563 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1564 output->otmEMSquare = lpOTMW->otmEMSquare;
1565 output->otmAscent = lpOTMW->otmAscent;
1566 output->otmDescent = lpOTMW->otmDescent;
1567 output->otmLineGap = lpOTMW->otmLineGap;
1568 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1569 output->otmsXHeight = lpOTMW->otmsXHeight;
1570 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1571 output->otmMacAscent = lpOTMW->otmMacAscent;
1572 output->otmMacDescent = lpOTMW->otmMacDescent;
1573 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1574 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1575 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1576 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1577 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1578 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1579 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1580 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1581 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1582 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1585 ptr = (char*)(output + 1);
1586 left = needed - sizeof(*output);
1588 if(lpOTMW->otmpFamilyName) {
1589 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1590 len = WideCharToMultiByte(CP_ACP, 0,
1591 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1592 ptr, left, NULL, NULL);
1593 left -= len;
1594 ptr += len;
1595 } else
1596 output->otmpFamilyName = 0;
1598 if(lpOTMW->otmpFaceName) {
1599 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1600 len = WideCharToMultiByte(CP_ACP, 0,
1601 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1602 ptr, left, NULL, NULL);
1603 left -= len;
1604 ptr += len;
1605 } else
1606 output->otmpFaceName = 0;
1608 if(lpOTMW->otmpStyleName) {
1609 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1610 len = WideCharToMultiByte(CP_ACP, 0,
1611 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1612 ptr, left, NULL, NULL);
1613 left -= len;
1614 ptr += len;
1615 } else
1616 output->otmpStyleName = 0;
1618 if(lpOTMW->otmpFullName) {
1619 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1620 len = WideCharToMultiByte(CP_ACP, 0,
1621 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1622 ptr, left, NULL, NULL);
1623 left -= len;
1624 } else
1625 output->otmpFullName = 0;
1627 assert(left == 0);
1629 if(output != lpOTM) {
1630 memcpy(lpOTM, output, cbData);
1631 HeapFree(GetProcessHeap(), 0, output);
1633 /* check if the string offsets really fit into the provided size */
1634 /* FIXME: should we check string length as well? */
1635 /* make sure that we don't read/write beyond the provided buffer */
1636 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1638 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1639 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1642 /* make sure that we don't read/write beyond the provided buffer */
1643 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1645 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1646 lpOTM->otmpFaceName = 0; /* doesn't fit */
1649 /* make sure that we don't read/write beyond the provided buffer */
1650 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1652 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1653 lpOTM->otmpStyleName = 0; /* doesn't fit */
1656 /* make sure that we don't read/write beyond the provided buffer */
1657 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1659 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1660 lpOTM->otmpFullName = 0; /* doesn't fit */
1664 end:
1665 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1666 HeapFree(GetProcessHeap(), 0, lpOTMW);
1668 return ret;
1672 /***********************************************************************
1673 * GetOutlineTextMetricsW [GDI32.@]
1675 UINT WINAPI GetOutlineTextMetricsW(
1676 HDC hdc, /* [in] Handle of device context */
1677 UINT cbData, /* [in] Size of metric data array */
1678 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1680 DC *dc = get_dc_ptr( hdc );
1681 OUTLINETEXTMETRICW *output = lpOTM;
1682 PHYSDEV dev;
1683 UINT ret;
1685 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1686 if(!dc) return 0;
1688 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1689 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1691 if (lpOTM && ret > cbData)
1693 output = HeapAlloc(GetProcessHeap(), 0, ret);
1694 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1697 if (lpOTM && ret)
1699 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1700 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1701 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
1702 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
1703 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
1704 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
1705 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
1706 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
1707 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
1708 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
1709 output->otmAscent = height_to_LP( dc, output->otmAscent);
1710 output->otmDescent = height_to_LP( dc, output->otmDescent);
1711 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
1712 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
1713 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
1714 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
1715 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
1716 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
1717 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
1718 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
1719 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
1720 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
1721 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
1722 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
1723 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
1724 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
1725 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
1726 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
1727 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
1728 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
1729 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
1730 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
1731 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
1732 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
1734 if(output != lpOTM)
1736 memcpy(lpOTM, output, cbData);
1737 HeapFree(GetProcessHeap(), 0, output);
1738 ret = cbData;
1741 release_dc_ptr(dc);
1742 return ret;
1745 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1747 INT i, count = lastChar - firstChar + 1;
1748 UINT mbcp;
1749 UINT c;
1750 LPSTR str;
1752 if (count <= 0)
1753 return NULL;
1755 mbcp = GdiGetCodePage(hdc);
1756 switch (mbcp)
1758 case 932:
1759 case 936:
1760 case 949:
1761 case 950:
1762 case 1361:
1763 if (lastChar > 0xffff)
1764 return NULL;
1765 if ((firstChar ^ lastChar) > 0xff)
1766 return NULL;
1767 break;
1768 default:
1769 if (lastChar > 0xff)
1770 return NULL;
1771 mbcp = 0;
1772 break;
1775 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1776 if (str == NULL)
1777 return NULL;
1779 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1781 if (mbcp) {
1782 if (c > 0xff)
1783 str[i++] = (BYTE)(c >> 8);
1784 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1785 str[i] = 0x1f; /* FIXME: use default character */
1786 else
1787 str[i] = (BYTE)c;
1789 else
1790 str[i] = (BYTE)c;
1792 str[i] = '\0';
1794 *pByteLen = i;
1796 return str;
1799 /***********************************************************************
1800 * GetCharWidthW (GDI32.@)
1801 * GetCharWidth32W (GDI32.@)
1803 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1804 LPINT buffer )
1806 UINT i;
1807 BOOL ret;
1808 PHYSDEV dev;
1809 DC * dc = get_dc_ptr( hdc );
1811 if (!dc) return FALSE;
1813 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1814 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1816 if (ret)
1818 /* convert device units to logical */
1819 for( i = firstChar; i <= lastChar; i++, buffer++ )
1820 *buffer = width_to_LP( dc, *buffer );
1822 release_dc_ptr( dc );
1823 return ret;
1827 /***********************************************************************
1828 * GetCharWidthA (GDI32.@)
1829 * GetCharWidth32A (GDI32.@)
1831 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1832 LPINT buffer )
1834 INT i, wlen;
1835 LPSTR str;
1836 LPWSTR wstr;
1837 BOOL ret = TRUE;
1839 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1840 if(str == NULL)
1841 return FALSE;
1843 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1845 for(i = 0; i < wlen; i++)
1847 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1849 ret = FALSE;
1850 break;
1852 buffer++;
1855 HeapFree(GetProcessHeap(), 0, str);
1856 HeapFree(GetProcessHeap(), 0, wstr);
1858 return ret;
1862 /* helper for nulldrv_ExtTextOut */
1863 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
1864 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1866 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1867 UINT indices[3] = {0, 0, 0x20};
1868 unsigned int i;
1869 DWORD ret, size;
1870 int stride;
1872 indices[0] = index;
1873 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
1875 for (i = 0; i < ARRAY_SIZE( indices ); i++)
1877 index = indices[i];
1878 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
1879 if (ret != GDI_ERROR) break;
1882 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1883 if (!image) return ERROR_SUCCESS;
1885 image->ptr = NULL;
1886 image->free = NULL;
1887 if (!ret) /* empty glyph */
1889 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
1890 return ERROR_SUCCESS;
1893 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1894 size = metrics->gmBlackBoxY * stride;
1896 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1897 image->is_copy = TRUE;
1898 image->free = free_heap_bits;
1900 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
1901 if (ret == GDI_ERROR)
1903 HeapFree( GetProcessHeap(), 0, image->ptr );
1904 return ERROR_NOT_FOUND;
1906 return ERROR_SUCCESS;
1909 /* helper for nulldrv_ExtTextOut */
1910 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1911 LPCWSTR str, UINT count, const INT *dx )
1913 UINT i;
1914 RECT rect, bounds;
1916 reset_bounds( &bounds );
1917 for (i = 0; i < count; i++)
1919 GLYPHMETRICS metrics;
1921 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
1923 rect.left = x + metrics.gmptGlyphOrigin.x;
1924 rect.top = y - metrics.gmptGlyphOrigin.y;
1925 rect.right = rect.left + metrics.gmBlackBoxX;
1926 rect.bottom = rect.top + metrics.gmBlackBoxY;
1927 add_bounds_rect( &bounds, &rect );
1929 if (dx)
1931 if (flags & ETO_PDY)
1933 x += dx[ i * 2 ];
1934 y += dx[ i * 2 + 1];
1936 else x += dx[ i ];
1938 else
1940 x += metrics.gmCellIncX;
1941 y += metrics.gmCellIncY;
1944 return bounds;
1947 /* helper for nulldrv_ExtTextOut */
1948 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1949 const struct gdi_image_bits *image, const RECT *clip )
1951 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1952 UINT i, count, max_count;
1953 LONG x, y;
1954 BYTE *ptr = image->ptr;
1955 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1956 POINT *pts;
1957 RECT rect, clipped_rect;
1959 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1960 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1961 rect.right = rect.left + metrics->gmBlackBoxX;
1962 rect.bottom = rect.top + metrics->gmBlackBoxY;
1963 if (!clip) clipped_rect = rect;
1964 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1966 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1967 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1968 if (!pts) return;
1970 count = 0;
1971 ptr += (clipped_rect.top - rect.top) * stride;
1972 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1974 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1976 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1977 pts[count].x = rect.left + x;
1978 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1979 pts[count + 1].x = rect.left + x;
1980 if (pts[count + 1].x > pts[count].x)
1982 pts[count].y = pts[count + 1].y = y;
1983 count += 2;
1987 assert( count <= max_count );
1988 dp_to_lp( dc, pts, count );
1989 for (i = 0; i < count; i += 2) Polyline( dc->hSelf, pts + i, 2 );
1990 HeapFree( GetProcessHeap(), 0, pts );
1993 /***********************************************************************
1994 * nulldrv_ExtTextOut
1996 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1997 LPCWSTR str, UINT count, const INT *dx )
1999 DC *dc = get_nulldrv_dc( dev );
2000 UINT i;
2001 DWORD err;
2002 HGDIOBJ orig;
2003 HPEN pen;
2005 if (flags & ETO_OPAQUE)
2007 RECT rc = *rect;
2008 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, dc->backgroundColor ) );
2010 if (brush)
2012 orig = SelectObject( dev->hdc, brush );
2013 dp_to_lp( dc, (POINT *)&rc, 2 );
2014 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
2015 SelectObject( dev->hdc, orig );
2016 DeleteObject( brush );
2020 if (!count) return TRUE;
2022 if (dc->aa_flags != GGO_BITMAP)
2024 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
2025 BITMAPINFO *info = (BITMAPINFO *)buffer;
2026 struct gdi_image_bits bits;
2027 struct bitblt_coords src, dst;
2028 PHYSDEV dst_dev;
2029 /* FIXME Subpixel modes */
2030 UINT aa_flags = GGO_GRAY4_BITMAP;
2032 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
2033 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
2034 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
2035 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
2037 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
2038 src.x = src.visrect.left;
2039 src.y = src.visrect.top;
2040 src.width = src.visrect.right - src.visrect.left;
2041 src.height = src.visrect.bottom - src.visrect.top;
2042 dst = src;
2043 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
2044 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
2046 /* we can avoid the GetImage, just query the needed format */
2047 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
2048 info->bmiHeader.biSize = sizeof(info->bmiHeader);
2049 info->bmiHeader.biWidth = src.width;
2050 info->bmiHeader.biHeight = -src.height;
2051 info->bmiHeader.biSizeImage = get_dib_image_size( info );
2052 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
2053 if (!err || err == ERROR_BAD_FORMAT)
2055 /* make the source rectangle relative to the source bits */
2056 src.x = src.y = 0;
2057 src.visrect.left = src.visrect.top = 0;
2058 src.visrect.right = src.width;
2059 src.visrect.bottom = src.height;
2061 bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
2062 if (!bits.ptr) return ERROR_OUTOFMEMORY;
2063 bits.is_copy = TRUE;
2064 bits.free = free_heap_bits;
2065 err = ERROR_SUCCESS;
2068 else
2070 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
2071 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
2072 if (!err && !bits.is_copy)
2074 void *ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
2075 if (!ptr)
2077 if (bits.free) bits.free( &bits );
2078 return ERROR_OUTOFMEMORY;
2080 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
2081 if (bits.free) bits.free( &bits );
2082 bits.ptr = ptr;
2083 bits.is_copy = TRUE;
2084 bits.free = free_heap_bits;
2087 if (!err)
2089 /* make x,y relative to the image bits */
2090 x += src.visrect.left - dst.visrect.left;
2091 y += src.visrect.top - dst.visrect.top;
2092 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
2093 aa_flags, str, count, dx );
2094 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
2095 if (bits.free) bits.free( &bits );
2096 return !err;
2100 pen = CreatePen( PS_SOLID, 1, dc->textColor );
2101 orig = SelectObject( dev->hdc, pen );
2103 for (i = 0; i < count; i++)
2105 GLYPHMETRICS metrics;
2106 struct gdi_image_bits image;
2108 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
2109 if (err) continue;
2111 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
2112 if (image.free) image.free( &image );
2114 if (dx)
2116 if (flags & ETO_PDY)
2118 x += dx[ i * 2 ];
2119 y += dx[ i * 2 + 1];
2121 else x += dx[ i ];
2123 else
2125 x += metrics.gmCellIncX;
2126 y += metrics.gmCellIncY;
2130 SelectObject( dev->hdc, orig );
2131 DeleteObject( pen );
2132 return TRUE;
2136 /***********************************************************************
2137 * ExtTextOutA (GDI32.@)
2139 * See ExtTextOutW.
2141 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
2142 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
2144 INT wlen;
2145 UINT codepage;
2146 LPWSTR p;
2147 BOOL ret;
2148 LPINT lpDxW = NULL;
2150 if (flags & ETO_GLYPH_INDEX)
2151 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
2153 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2155 if (lpDx) {
2156 unsigned int i = 0, j = 0;
2158 /* allocate enough for a ETO_PDY */
2159 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2160 while(i < count) {
2161 if(IsDBCSLeadByteEx(codepage, str[i]))
2163 if(flags & ETO_PDY)
2165 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2166 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2168 else
2169 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2170 i = i + 2;
2172 else
2174 if(flags & ETO_PDY)
2176 lpDxW[j++] = lpDx[i * 2];
2177 lpDxW[j++] = lpDx[i * 2 + 1];
2179 else
2180 lpDxW[j++] = lpDx[i];
2181 i = i + 1;
2186 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2188 HeapFree( GetProcessHeap(), 0, p );
2189 HeapFree( GetProcessHeap(), 0, lpDxW );
2190 return ret;
2193 /***********************************************************************
2194 * get_line_width
2196 * Scale the underline / strikeout line width.
2198 static inline int get_line_width( DC *dc, int metric_size )
2200 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
2201 if (width == 0) width = 1;
2202 if (metric_size < 0) width = -width;
2203 return width;
2206 /***********************************************************************
2207 * ExtTextOutW (GDI32.@)
2209 * Draws text using the currently selected font, background color, and text color.
2212 * PARAMS
2213 * x,y [I] coordinates of string
2214 * flags [I]
2215 * ETO_GRAYED - undocumented on MSDN
2216 * ETO_OPAQUE - use background color for fill the rectangle
2217 * ETO_CLIPPED - clipping text to the rectangle
2218 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2219 * than encoded characters. Implies ETO_IGNORELANGUAGE
2220 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2221 * Affects BiDi ordering
2222 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2223 * ETO_PDY - unimplemented
2224 * ETO_NUMERICSLATIN - unimplemented always assumed -
2225 * do not translate numbers into locale representations
2226 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2227 * lprect [I] dimensions for clipping or/and opaquing
2228 * str [I] text string
2229 * count [I] number of symbols in string
2230 * lpDx [I] optional parameter with distance between drawing characters
2232 * RETURNS
2233 * Success: TRUE
2234 * Failure: FALSE
2236 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2237 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2239 BOOL ret = FALSE;
2240 LPWSTR reordered_str = (LPWSTR)str;
2241 WORD *glyphs = NULL;
2242 UINT align;
2243 DWORD layout;
2244 POINT pt;
2245 TEXTMETRICW tm;
2246 LOGFONTW lf;
2247 double cosEsc, sinEsc;
2248 INT char_extra;
2249 SIZE sz;
2250 RECT rc;
2251 POINT *deltas = NULL, width = {0, 0};
2252 DWORD type;
2253 DC * dc = get_dc_ptr( hdc );
2254 PHYSDEV physdev;
2255 INT breakRem;
2256 static int quietfixme = 0;
2258 if (!dc) return FALSE;
2260 align = dc->textAlign;
2261 breakRem = dc->breakRem;
2262 layout = dc->layout;
2264 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2266 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2267 quietfixme = 1;
2270 update_dc( dc );
2271 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2272 type = GetObjectType(hdc);
2273 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2275 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2276 release_dc_ptr( dc );
2277 return ret;
2280 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2281 if (layout & LAYOUT_RTL)
2283 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2284 align ^= TA_RTLREADING;
2287 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2289 INT cGlyphs;
2290 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2292 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2293 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2294 reordered_str, count, NULL, &glyphs, &cGlyphs);
2296 flags |= ETO_IGNORELANGUAGE;
2297 if (glyphs)
2299 flags |= ETO_GLYPH_INDEX;
2300 if (cGlyphs != count)
2301 count = cGlyphs;
2304 else if(flags & ETO_GLYPH_INDEX)
2305 glyphs = reordered_str;
2307 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2308 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2309 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->backgroundMode, dc->MapMode);
2311 if(align & TA_UPDATECP)
2313 pt = dc->cur_pos;
2314 x = pt.x;
2315 y = pt.y;
2318 GetTextMetricsW(hdc, &tm);
2319 GetObjectW(dc->hFont, sizeof(lf), &lf);
2321 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2322 lf.lfEscapement = 0;
2324 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2325 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2327 lf.lfEscapement = -lf.lfEscapement;
2330 if(lf.lfEscapement != 0)
2332 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2333 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2335 else
2337 cosEsc = 1;
2338 sinEsc = 0;
2341 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
2343 rc = *lprect;
2344 lp_to_dp(dc, (POINT*)&rc, 2);
2345 order_rect( &rc );
2346 if (flags & ETO_OPAQUE)
2347 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2349 else flags &= ~ETO_CLIPPED;
2351 if(count == 0)
2353 ret = TRUE;
2354 goto done;
2357 pt.x = x;
2358 pt.y = y;
2359 lp_to_dp(dc, &pt, 1);
2360 x = pt.x;
2361 y = pt.y;
2363 char_extra = GetTextCharacterExtra(hdc);
2364 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
2365 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2367 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2369 UINT i;
2370 POINT total = {0, 0}, desired[2];
2372 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2373 if (lpDx)
2375 if (flags & ETO_PDY)
2377 for (i = 0; i < count; i++)
2379 deltas[i].x = lpDx[i * 2] + char_extra;
2380 deltas[i].y = -lpDx[i * 2 + 1];
2383 else
2385 for (i = 0; i < count; i++)
2387 deltas[i].x = lpDx[i] + char_extra;
2388 deltas[i].y = 0;
2392 else
2394 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
2396 if (flags & ETO_GLYPH_INDEX)
2397 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
2398 else
2399 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
2401 deltas[0].x = dx[0];
2402 deltas[0].y = 0;
2403 for (i = 1; i < count; i++)
2405 deltas[i].x = dx[i] - dx[i - 1];
2406 deltas[i].y = 0;
2408 HeapFree( GetProcessHeap(), 0, dx );
2411 for(i = 0; i < count; i++)
2413 total.x += deltas[i].x;
2414 total.y += deltas[i].y;
2416 desired[0].x = desired[0].y = 0;
2418 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2419 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2421 lp_to_dp(dc, desired, 2);
2422 desired[1].x -= desired[0].x;
2423 desired[1].y -= desired[0].y;
2425 if (dc->GraphicsMode == GM_COMPATIBLE)
2427 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2428 desired[1].x = -desired[1].x;
2429 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2430 desired[1].y = -desired[1].y;
2433 deltas[i].x = desired[1].x - width.x;
2434 deltas[i].y = desired[1].y - width.y;
2436 width = desired[1];
2438 flags |= ETO_PDY;
2440 else
2442 POINT desired[2];
2444 if(flags & ETO_GLYPH_INDEX)
2445 GetTextExtentPointI(hdc, glyphs, count, &sz);
2446 else
2447 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2448 desired[0].x = desired[0].y = 0;
2449 desired[1].x = sz.cx;
2450 desired[1].y = 0;
2451 lp_to_dp(dc, desired, 2);
2452 desired[1].x -= desired[0].x;
2453 desired[1].y -= desired[0].y;
2455 if (dc->GraphicsMode == GM_COMPATIBLE)
2457 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2458 desired[1].x = -desired[1].x;
2459 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2460 desired[1].y = -desired[1].y;
2462 width = desired[1];
2465 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2466 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2467 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2469 case TA_LEFT:
2470 if (align & TA_UPDATECP)
2472 pt.x = x + width.x;
2473 pt.y = y + width.y;
2474 dp_to_lp(dc, &pt, 1);
2475 MoveToEx(hdc, pt.x, pt.y, NULL);
2477 break;
2479 case TA_CENTER:
2480 x -= width.x / 2;
2481 y -= width.y / 2;
2482 break;
2484 case TA_RIGHT:
2485 x -= width.x;
2486 y -= width.y;
2487 if (align & TA_UPDATECP)
2489 pt.x = x;
2490 pt.y = y;
2491 dp_to_lp(dc, &pt, 1);
2492 MoveToEx(hdc, pt.x, pt.y, NULL);
2494 break;
2497 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2499 case TA_TOP:
2500 y += tm.tmAscent * cosEsc;
2501 x += tm.tmAscent * sinEsc;
2502 break;
2504 case TA_BOTTOM:
2505 y -= tm.tmDescent * cosEsc;
2506 x -= tm.tmDescent * sinEsc;
2507 break;
2509 case TA_BASELINE:
2510 break;
2513 if (dc->backgroundMode != TRANSPARENT)
2515 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2517 if(!(flags & ETO_OPAQUE) || !lprect ||
2518 x < rc.left || x + width.x >= rc.right ||
2519 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2521 RECT text_box;
2522 text_box.left = x;
2523 text_box.right = x + width.x;
2524 text_box.top = y - tm.tmAscent;
2525 text_box.bottom = y + tm.tmDescent;
2527 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2528 if (!is_rect_empty( &text_box ))
2529 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2534 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2535 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2537 done:
2538 HeapFree(GetProcessHeap(), 0, deltas);
2539 if(glyphs != reordered_str)
2540 HeapFree(GetProcessHeap(), 0, glyphs);
2541 if(reordered_str != str)
2542 HeapFree(GetProcessHeap(), 0, reordered_str);
2544 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2546 int underlinePos, strikeoutPos;
2547 int underlineWidth, strikeoutWidth;
2548 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2549 OUTLINETEXTMETRICW* otm = NULL;
2550 POINT pts[5];
2551 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2552 HBRUSH hbrush = CreateSolidBrush(dc->textColor);
2554 hbrush = SelectObject(hdc, hbrush);
2556 if(!size)
2558 underlinePos = 0;
2559 underlineWidth = tm.tmAscent / 20 + 1;
2560 strikeoutPos = tm.tmAscent / 2;
2561 strikeoutWidth = underlineWidth;
2563 else
2565 otm = HeapAlloc(GetProcessHeap(), 0, size);
2566 GetOutlineTextMetricsW(hdc, size, otm);
2567 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2568 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2569 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
2570 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2571 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2572 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
2573 HeapFree(GetProcessHeap(), 0, otm);
2577 if (lf.lfUnderline)
2579 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2580 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2581 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2582 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2583 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2584 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2585 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2586 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2587 pts[4].x = pts[0].x;
2588 pts[4].y = pts[0].y;
2589 dp_to_lp(dc, pts, 5);
2590 Polygon(hdc, pts, 5);
2593 if (lf.lfStrikeOut)
2595 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2596 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2597 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2598 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2599 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2600 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2601 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2602 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2603 pts[4].x = pts[0].x;
2604 pts[4].y = pts[0].y;
2605 dp_to_lp(dc, pts, 5);
2606 Polygon(hdc, pts, 5);
2609 SelectObject(hdc, hpen);
2610 hbrush = SelectObject(hdc, hbrush);
2611 DeleteObject(hbrush);
2614 release_dc_ptr( dc );
2616 return ret;
2620 /***********************************************************************
2621 * TextOutA (GDI32.@)
2623 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2625 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2629 /***********************************************************************
2630 * TextOutW (GDI32.@)
2632 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2634 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2638 /***********************************************************************
2639 * PolyTextOutA (GDI32.@)
2641 * See PolyTextOutW.
2643 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2645 for (; cStrings>0; cStrings--, pptxt++)
2646 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2647 return FALSE;
2648 return TRUE;
2653 /***********************************************************************
2654 * PolyTextOutW (GDI32.@)
2656 * Draw several Strings
2658 * RETURNS
2659 * TRUE: Success.
2660 * FALSE: Failure.
2662 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2664 for (; cStrings>0; cStrings--, pptxt++)
2665 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2666 return FALSE;
2667 return TRUE;
2671 /***********************************************************************
2672 * SetMapperFlags (GDI32.@)
2674 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2676 DC *dc = get_dc_ptr( hdc );
2677 DWORD ret = GDI_ERROR;
2679 if (dc)
2681 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2682 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2683 if (flags != GDI_ERROR)
2685 ret = dc->mapperFlags;
2686 dc->mapperFlags = flags;
2688 release_dc_ptr( dc );
2690 return ret;
2693 /***********************************************************************
2694 * GetAspectRatioFilterEx (GDI32.@)
2696 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2698 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2699 return FALSE;
2703 /***********************************************************************
2704 * GetCharABCWidthsA (GDI32.@)
2706 * See GetCharABCWidthsW.
2708 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2709 LPABC abc )
2711 INT i, wlen;
2712 LPSTR str;
2713 LPWSTR wstr;
2714 BOOL ret = TRUE;
2716 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2717 if (str == NULL)
2718 return FALSE;
2720 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2721 if (wstr == NULL)
2723 HeapFree(GetProcessHeap(), 0, str);
2724 return FALSE;
2727 for(i = 0; i < wlen; i++)
2729 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2731 ret = FALSE;
2732 break;
2734 abc++;
2737 HeapFree(GetProcessHeap(), 0, str);
2738 HeapFree(GetProcessHeap(), 0, wstr);
2740 return ret;
2744 /******************************************************************************
2745 * GetCharABCWidthsW [GDI32.@]
2747 * Retrieves widths of characters in range.
2749 * PARAMS
2750 * hdc [I] Handle of device context
2751 * firstChar [I] First character in range to query
2752 * lastChar [I] Last character in range to query
2753 * abc [O] Address of character-width structure
2755 * NOTES
2756 * Only works with TrueType fonts
2758 * RETURNS
2759 * Success: TRUE
2760 * Failure: FALSE
2762 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2763 LPABC abc )
2765 DC *dc = get_dc_ptr(hdc);
2766 PHYSDEV dev;
2767 unsigned int i;
2768 BOOL ret;
2769 TEXTMETRICW tm;
2771 if (!dc) return FALSE;
2773 if (!abc)
2775 release_dc_ptr( dc );
2776 return FALSE;
2779 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2780 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2781 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2783 release_dc_ptr( dc );
2784 return FALSE;
2787 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2788 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2789 if (ret)
2791 /* convert device units to logical */
2792 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2793 abc->abcA = width_to_LP(dc, abc->abcA);
2794 abc->abcB = width_to_LP(dc, abc->abcB);
2795 abc->abcC = width_to_LP(dc, abc->abcC);
2799 release_dc_ptr( dc );
2800 return ret;
2804 /******************************************************************************
2805 * GetCharABCWidthsI [GDI32.@]
2807 * Retrieves widths of characters in range.
2809 * PARAMS
2810 * hdc [I] Handle of device context
2811 * firstChar [I] First glyphs in range to query
2812 * count [I] Last glyphs in range to query
2813 * pgi [i] Array of glyphs to query
2814 * abc [O] Address of character-width structure
2816 * NOTES
2817 * Only works with TrueType fonts
2819 * RETURNS
2820 * Success: TRUE
2821 * Failure: FALSE
2823 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2824 LPWORD pgi, LPABC abc)
2826 DC *dc = get_dc_ptr(hdc);
2827 PHYSDEV dev;
2828 unsigned int i;
2829 BOOL ret;
2831 if (!dc) return FALSE;
2833 if (!abc)
2835 release_dc_ptr( dc );
2836 return FALSE;
2839 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2840 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2841 if (ret)
2843 /* convert device units to logical */
2844 for( i = 0; i < count; i++, abc++ ) {
2845 abc->abcA = width_to_LP(dc, abc->abcA);
2846 abc->abcB = width_to_LP(dc, abc->abcB);
2847 abc->abcC = width_to_LP(dc, abc->abcC);
2851 release_dc_ptr( dc );
2852 return ret;
2856 /***********************************************************************
2857 * GetGlyphOutlineA (GDI32.@)
2859 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2860 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2861 LPVOID lpBuffer, const MAT2 *lpmat2 )
2863 if (!lpmat2) return GDI_ERROR;
2865 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2866 UINT cp;
2867 int len;
2868 char mbchs[2];
2869 WCHAR wChar;
2871 cp = GdiGetCodePage(hdc);
2872 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2873 len = 2;
2874 mbchs[0] = (uChar & 0xff00) >> 8;
2875 mbchs[1] = (uChar & 0xff);
2876 } else {
2877 len = 1;
2878 mbchs[0] = (uChar & 0xff);
2880 wChar = 0;
2881 MultiByteToWideChar(cp, 0, mbchs, len, &wChar, 1);
2882 uChar = wChar;
2885 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2886 lpmat2);
2889 /***********************************************************************
2890 * GetGlyphOutlineW (GDI32.@)
2892 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2893 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2894 LPVOID lpBuffer, const MAT2 *lpmat2 )
2896 DC *dc;
2897 DWORD ret;
2898 PHYSDEV dev;
2900 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2901 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2903 if (!lpmat2) return GDI_ERROR;
2905 dc = get_dc_ptr(hdc);
2906 if(!dc) return GDI_ERROR;
2908 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2909 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2910 release_dc_ptr( dc );
2911 return ret;
2915 /***********************************************************************
2916 * CreateScalableFontResourceA (GDI32.@)
2918 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2919 LPCSTR lpszResourceFile,
2920 LPCSTR lpszFontFile,
2921 LPCSTR lpszCurrentPath )
2923 LPWSTR lpszResourceFileW = NULL;
2924 LPWSTR lpszFontFileW = NULL;
2925 LPWSTR lpszCurrentPathW = NULL;
2926 int len;
2927 BOOL ret;
2929 if (lpszResourceFile)
2931 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2932 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2933 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2936 if (lpszFontFile)
2938 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2939 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2940 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2943 if (lpszCurrentPath)
2945 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2946 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2947 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2950 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2951 lpszFontFileW, lpszCurrentPathW);
2953 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2954 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2955 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2957 return ret;
2960 /***********************************************************************
2961 * CreateScalableFontResourceW (GDI32.@)
2963 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2964 LPCWSTR font_file, LPCWSTR font_path )
2966 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2967 debugstr_w(font_file), debugstr_w(font_path) );
2969 return WineEngCreateScalableFontResource( hidden, resource_file,
2970 font_file, font_path );
2973 /*************************************************************************
2974 * GetKerningPairsA (GDI32.@)
2976 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2977 LPKERNINGPAIR kern_pairA )
2979 UINT cp;
2980 CPINFO cpi;
2981 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2982 KERNINGPAIR *kern_pairW;
2984 if (!cPairs && kern_pairA)
2986 SetLastError(ERROR_INVALID_PARAMETER);
2987 return 0;
2990 cp = GdiGetCodePage(hDC);
2992 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2993 * to fail on an invalid character for CP_SYMBOL.
2995 cpi.DefaultChar[0] = 0;
2996 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2998 FIXME("Can't find codepage %u info\n", cp);
2999 return 0;
3002 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
3003 if (!total_kern_pairs) return 0;
3005 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
3006 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
3008 for (i = 0; i < total_kern_pairs; i++)
3010 char first, second;
3012 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
3013 continue;
3015 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
3016 continue;
3018 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
3019 continue;
3021 if (kern_pairA)
3023 if (kern_pairs_copied >= cPairs) break;
3025 kern_pairA->wFirst = (BYTE)first;
3026 kern_pairA->wSecond = (BYTE)second;
3027 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
3028 kern_pairA++;
3030 kern_pairs_copied++;
3033 HeapFree(GetProcessHeap(), 0, kern_pairW);
3035 return kern_pairs_copied;
3038 /*************************************************************************
3039 * GetKerningPairsW (GDI32.@)
3041 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
3042 LPKERNINGPAIR lpKerningPairs )
3044 DC *dc;
3045 DWORD ret;
3046 PHYSDEV dev;
3048 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
3050 if (!cPairs && lpKerningPairs)
3052 SetLastError(ERROR_INVALID_PARAMETER);
3053 return 0;
3056 dc = get_dc_ptr(hDC);
3057 if (!dc) return 0;
3059 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
3060 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
3061 release_dc_ptr( dc );
3062 return ret;
3065 /*************************************************************************
3066 * TranslateCharsetInfo [GDI32.@]
3068 * Fills a CHARSETINFO structure for a character set, code page, or
3069 * font. This allows making the correspondence between different labels
3070 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
3071 * of the same encoding.
3073 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
3074 * only one codepage should be set in *lpSrc.
3076 * RETURNS
3077 * TRUE on success, FALSE on failure.
3080 BOOL WINAPI TranslateCharsetInfo(
3081 LPDWORD lpSrc, /* [in]
3082 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
3083 if flags == TCI_SRCCHARSET: a character set value
3084 if flags == TCI_SRCCODEPAGE: a code page value
3086 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
3087 DWORD flags /* [in] determines interpretation of lpSrc */)
3089 int index = 0;
3090 switch (flags) {
3091 case TCI_SRCFONTSIG:
3092 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3093 break;
3094 case TCI_SRCCODEPAGE:
3095 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3096 break;
3097 case TCI_SRCCHARSET:
3098 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3099 break;
3100 default:
3101 return FALSE;
3103 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3104 *lpCs = FONT_tci[index];
3105 return TRUE;
3108 /*************************************************************************
3109 * GetFontLanguageInfo (GDI32.@)
3111 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3113 FONTSIGNATURE fontsig;
3114 static const DWORD GCP_DBCS_MASK=FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB,
3115 GCP_DIACRITIC_MASK=0x00000000,
3116 FLI_GLYPHS_MASK=0x00000000,
3117 GCP_GLYPHSHAPE_MASK=FS_ARABIC,
3118 GCP_KASHIDA_MASK=0x00000000,
3119 GCP_LIGATE_MASK=0x00000000,
3120 GCP_REORDER_MASK=FS_HEBREW|FS_ARABIC;
3122 DWORD result=0;
3124 GetTextCharsetInfo( hdc, &fontsig, 0 );
3125 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3127 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3128 result|=GCP_DBCS;
3130 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3131 result|=GCP_DIACRITIC;
3133 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3134 result|=FLI_GLYPHS;
3136 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3137 result|=GCP_GLYPHSHAPE;
3139 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3140 result|=GCP_KASHIDA;
3142 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3143 result|=GCP_LIGATE;
3145 if( GetKerningPairsW( hdc, 0, NULL ) )
3146 result|=GCP_USEKERNING;
3148 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3149 if( GetTextAlign( hdc) & TA_RTLREADING )
3150 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3151 result|=GCP_REORDER;
3153 return result;
3157 /*************************************************************************
3158 * GetFontData [GDI32.@]
3160 * Retrieve data for TrueType font.
3162 * RETURNS
3164 * success: Number of bytes returned
3165 * failure: GDI_ERROR
3167 * NOTES
3169 * Calls SetLastError()
3172 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3173 LPVOID buffer, DWORD length)
3175 DC *dc = get_dc_ptr(hdc);
3176 PHYSDEV dev;
3177 DWORD ret;
3179 if(!dc) return GDI_ERROR;
3181 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3182 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3183 release_dc_ptr( dc );
3184 return ret;
3187 /*************************************************************************
3188 * GetGlyphIndicesA [GDI32.@]
3190 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3191 LPWORD pgi, DWORD flags)
3193 DWORD ret;
3194 WCHAR *lpstrW;
3195 INT countW;
3197 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3198 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3200 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3201 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3202 HeapFree(GetProcessHeap(), 0, lpstrW);
3204 return ret;
3207 /*************************************************************************
3208 * GetGlyphIndicesW [GDI32.@]
3210 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3211 LPWORD pgi, DWORD flags)
3213 DC *dc = get_dc_ptr(hdc);
3214 PHYSDEV dev;
3215 DWORD ret;
3217 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3218 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3220 if(!dc) return GDI_ERROR;
3222 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3223 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3224 release_dc_ptr( dc );
3225 return ret;
3228 /*************************************************************************
3229 * GetCharacterPlacementA [GDI32.@]
3231 * See GetCharacterPlacementW.
3233 * NOTES:
3234 * the web browser control of ie4 calls this with dwFlags=0
3236 DWORD WINAPI
3237 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3238 INT nMaxExtent, GCP_RESULTSA *lpResults,
3239 DWORD dwFlags)
3241 WCHAR *lpStringW;
3242 INT uCountW;
3243 GCP_RESULTSW resultsW;
3244 DWORD ret;
3245 UINT font_cp;
3247 TRACE("%s, %d, %d, 0x%08x\n",
3248 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3250 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3252 if (!lpResults)
3254 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, NULL, dwFlags);
3255 HeapFree(GetProcessHeap(), 0, lpStringW);
3256 return ret;
3259 /* both structs are equal in size */
3260 memcpy(&resultsW, lpResults, sizeof(resultsW));
3262 if(lpResults->lpOutString)
3263 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3265 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3267 lpResults->nGlyphs = resultsW.nGlyphs;
3268 lpResults->nMaxFit = resultsW.nMaxFit;
3270 if(lpResults->lpOutString) {
3271 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3272 lpResults->lpOutString, uCount, NULL, NULL );
3275 HeapFree(GetProcessHeap(), 0, lpStringW);
3276 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3278 return ret;
3281 /*************************************************************************
3282 * GetCharacterPlacementW [GDI32.@]
3284 * Retrieve information about a string. This includes the width, reordering,
3285 * Glyphing and so on.
3287 * RETURNS
3289 * The width and height of the string if successful, 0 if failed.
3291 * BUGS
3293 * All flags except GCP_REORDER are not yet implemented.
3294 * Reordering is not 100% compliant to the Windows BiDi method.
3295 * Caret positioning is not yet implemented for BiDi.
3296 * Classes are not yet implemented.
3299 DWORD WINAPI
3300 GetCharacterPlacementW(
3301 HDC hdc, /* [in] Device context for which the rendering is to be done */
3302 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3303 INT uCount, /* [in] Number of WORDS in string. */
3304 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3305 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
3306 DWORD dwFlags /* [in] Flags specifying how to process the string */
3309 DWORD ret=0;
3310 SIZE size;
3311 UINT i, nSet;
3313 TRACE("%s, %d, %d, 0x%08x\n",
3314 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3316 if (!uCount)
3317 return 0;
3319 if (!lpResults)
3320 return GetTextExtentPoint32W(hdc, lpString, uCount, &size) ? MAKELONG(size.cx, size.cy) : 0;
3322 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3323 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3324 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3325 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3326 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3328 if(dwFlags&(~GCP_REORDER))
3329 FIXME("flags 0x%08x ignored\n", dwFlags);
3330 if(lpResults->lpClass)
3331 FIXME("classes not implemented\n");
3332 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3333 FIXME("Caret positions for complex scripts not implemented\n");
3335 nSet = (UINT)uCount;
3336 if(nSet > lpResults->nGlyphs)
3337 nSet = lpResults->nGlyphs;
3339 /* return number of initialized fields */
3340 lpResults->nGlyphs = nSet;
3342 if((dwFlags&GCP_REORDER)==0 )
3344 /* Treat the case where no special handling was requested in a fastpath way */
3345 /* copy will do if the GCP_REORDER flag is not set */
3346 if(lpResults->lpOutString)
3347 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3349 if(lpResults->lpOrder)
3351 for(i = 0; i < nSet; i++)
3352 lpResults->lpOrder[i] = i;
3355 else
3357 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3358 nSet, lpResults->lpOrder, NULL, NULL );
3361 /* FIXME: Will use the placement chars */
3362 if (lpResults->lpDx)
3364 int c;
3365 for (i = 0; i < nSet; i++)
3367 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3368 lpResults->lpDx[i]= c;
3372 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3374 int pos = 0;
3376 lpResults->lpCaretPos[0] = 0;
3377 for (i = 1; i < nSet; i++)
3378 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3379 lpResults->lpCaretPos[i] = (pos += size.cx);
3382 if(lpResults->lpGlyphs)
3383 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3385 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3386 ret = MAKELONG(size.cx, size.cy);
3388 return ret;
3391 /*************************************************************************
3392 * GetCharABCWidthsFloatA [GDI32.@]
3394 * See GetCharABCWidthsFloatW.
3396 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3398 INT i, wlen;
3399 LPSTR str;
3400 LPWSTR wstr;
3401 BOOL ret = TRUE;
3403 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3404 if (str == NULL)
3405 return FALSE;
3407 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3409 for (i = 0; i < wlen; i++)
3411 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3413 ret = FALSE;
3414 break;
3416 abcf++;
3419 HeapFree( GetProcessHeap(), 0, str );
3420 HeapFree( GetProcessHeap(), 0, wstr );
3422 return ret;
3425 /*************************************************************************
3426 * GetCharABCWidthsFloatW [GDI32.@]
3428 * Retrieves widths of a range of characters.
3430 * PARAMS
3431 * hdc [I] Handle to device context.
3432 * first [I] First character in range to query.
3433 * last [I] Last character in range to query.
3434 * abcf [O] Array of LPABCFLOAT structures.
3436 * RETURNS
3437 * Success: TRUE
3438 * Failure: FALSE
3440 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3442 UINT i;
3443 ABC *abc;
3444 PHYSDEV dev;
3445 BOOL ret = FALSE;
3446 DC *dc = get_dc_ptr( hdc );
3448 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3450 if (!dc) return FALSE;
3452 if (!abcf) goto done;
3453 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3455 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3456 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3457 if (ret)
3459 /* convert device units to logical */
3460 FLOAT scale = fabs( dc->xformVport2World.eM11 );
3461 for (i = first; i <= last; i++, abcf++)
3463 abcf->abcfA = abc[i - first].abcA * scale;
3464 abcf->abcfB = abc[i - first].abcB * scale;
3465 abcf->abcfC = abc[i - first].abcC * scale;
3468 HeapFree( GetProcessHeap(), 0, abc );
3470 done:
3471 release_dc_ptr( dc );
3472 return ret;
3475 /*************************************************************************
3476 * GetCharWidthFloatA [GDI32.@]
3478 BOOL WINAPI GetCharWidthFloatA( HDC hdc, UINT first, UINT last, float *buffer )
3480 WCHAR *wstr;
3481 int i, wlen;
3482 char *str;
3484 if (!(str = FONT_GetCharsByRangeA( hdc, first, last, &i )))
3485 return FALSE;
3486 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3487 heap_free(str);
3489 for (i = 0; i < wlen; ++i)
3491 if (!GetCharWidthFloatW( hdc, wstr[i], wstr[i], &buffer[i] ))
3493 heap_free(wstr);
3494 return FALSE;
3497 heap_free(wstr);
3498 return TRUE;
3501 /*************************************************************************
3502 * GetCharWidthFloatW [GDI32.@]
3504 BOOL WINAPI GetCharWidthFloatW( HDC hdc, UINT first, UINT last, float *buffer )
3506 DC *dc = get_dc_ptr( hdc );
3507 int *ibuffer;
3508 PHYSDEV dev;
3509 BOOL ret;
3510 UINT i;
3512 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc, first, last, buffer);
3514 if (!dc) return FALSE;
3516 if (!(ibuffer = heap_alloc( (last - first + 1) * sizeof(int) )))
3518 release_dc_ptr( dc );
3519 return FALSE;
3522 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
3523 if ((ret = dev->funcs->pGetCharWidth( dev, first, last, ibuffer )))
3525 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
3526 for (i = first; i <= last; ++i)
3527 buffer[i - first] = ibuffer[i - first] * scale;
3530 heap_free(ibuffer);
3531 return ret;
3534 /***********************************************************************
3536 * Font Resource API *
3538 ***********************************************************************/
3540 /***********************************************************************
3541 * AddFontResourceA (GDI32.@)
3543 INT WINAPI AddFontResourceA( LPCSTR str )
3545 return AddFontResourceExA( str, 0, NULL);
3548 /***********************************************************************
3549 * AddFontResourceW (GDI32.@)
3551 INT WINAPI AddFontResourceW( LPCWSTR str )
3553 return AddFontResourceExW(str, 0, NULL);
3557 /***********************************************************************
3558 * AddFontResourceExA (GDI32.@)
3560 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3562 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3563 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3564 INT ret;
3566 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3567 ret = AddFontResourceExW(strW, fl, pdv);
3568 HeapFree(GetProcessHeap(), 0, strW);
3569 return ret;
3572 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3574 HRSRC rsrc = FindResourceW(hModule, name, type);
3575 HGLOBAL hMem = LoadResource(hModule, rsrc);
3576 LPVOID *pMem = LockResource(hMem);
3577 int *num_total = (int *)lParam;
3578 DWORD num_in_res;
3580 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3581 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3583 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3584 return FALSE;
3587 *num_total += num_in_res;
3588 return TRUE;
3591 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3593 HANDLE file, mapping;
3594 void *ptr;
3596 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3597 if (file == INVALID_HANDLE_VALUE) return NULL;
3599 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3601 CloseHandle( file );
3602 return NULL;
3605 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3606 CloseHandle( file );
3607 if (!mapping) return NULL;
3609 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3610 CloseHandle( mapping );
3612 return ptr;
3615 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
3617 WORD align, type_id, count;
3618 DWORD res_off;
3620 if (size < rsrc_off + 10) return NULL;
3621 align = *(WORD *)(ptr + rsrc_off);
3622 rsrc_off += 2;
3623 type_id = *(WORD *)(ptr + rsrc_off);
3624 while (type_id && type_id != type)
3626 count = *(WORD *)(ptr + rsrc_off + 2);
3627 rsrc_off += 8 + count * 12;
3628 if (size < rsrc_off + 8) return NULL;
3629 type_id = *(WORD *)(ptr + rsrc_off);
3631 if (!type_id) return NULL;
3632 count = *(WORD *)(ptr + rsrc_off + 2);
3633 if (size < rsrc_off + 8 + count * 12) return NULL;
3634 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3635 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
3636 if (size < res_off + *len) return NULL;
3637 return ptr + res_off;
3640 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
3642 LARGE_INTEGER size;
3643 BYTE *ptr = map_file( res, &size );
3644 const IMAGE_DOS_HEADER *dos;
3645 const IMAGE_OS2_HEADER *ne;
3646 WORD *fontdir;
3647 char *data;
3648 WCHAR *name = NULL;
3649 DWORD len;
3651 if (!ptr) return NULL;
3653 if (size.u.LowPart < sizeof( *dos )) goto fail;
3654 dos = (const IMAGE_DOS_HEADER *)ptr;
3655 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3656 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3657 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3659 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3660 if (!fontdir) goto fail;
3661 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
3663 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
3664 if (!data) goto fail;
3665 if (!memchr( data, 0, len )) goto fail;
3667 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
3668 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3669 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
3671 fail:
3672 UnmapViewOfFile( ptr );
3673 return name;
3676 /***********************************************************************
3677 * AddFontResourceExW (GDI32.@)
3679 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3681 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3682 WCHAR *filename;
3683 BOOL hidden;
3685 if (ret == 0)
3687 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3688 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3689 if (hModule != NULL)
3691 int num_resources = 0;
3692 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3694 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3695 wine_dbgstr_w(str));
3696 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3697 ret = num_resources;
3698 FreeLibrary(hModule);
3700 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3702 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3703 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3704 HeapFree( GetProcessHeap(), 0, filename );
3707 return ret;
3710 /***********************************************************************
3711 * RemoveFontResourceA (GDI32.@)
3713 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3715 return RemoveFontResourceExA(str, 0, 0);
3718 /***********************************************************************
3719 * RemoveFontResourceW (GDI32.@)
3721 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3723 return RemoveFontResourceExW(str, 0, 0);
3726 /***********************************************************************
3727 * AddFontMemResourceEx (GDI32.@)
3729 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3731 HANDLE ret;
3732 DWORD num_fonts;
3734 if (!pbFont || !cbFont || !pcFonts)
3736 SetLastError(ERROR_INVALID_PARAMETER);
3737 return NULL;
3740 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3741 if (ret)
3743 __TRY
3745 *pcFonts = num_fonts;
3747 __EXCEPT_PAGE_FAULT
3749 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3750 RemoveFontMemResourceEx(ret);
3751 ret = 0;
3753 __ENDTRY
3755 return ret;
3758 /***********************************************************************
3759 * RemoveFontMemResourceEx (GDI32.@)
3761 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3763 FIXME("(%p) stub\n", fh);
3764 return TRUE;
3767 /***********************************************************************
3768 * RemoveFontResourceExA (GDI32.@)
3770 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3772 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3773 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3774 INT ret;
3776 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3777 ret = RemoveFontResourceExW(strW, fl, pdv);
3778 HeapFree(GetProcessHeap(), 0, strW);
3779 return ret;
3782 /***********************************************************************
3783 * RemoveFontResourceExW (GDI32.@)
3785 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3787 int ret = WineEngRemoveFontResourceEx( str, fl, pdv );
3788 WCHAR *filename;
3789 BOOL hidden;
3791 if (ret == 0)
3793 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3794 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3795 if (hModule != NULL)
3797 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
3798 FreeLibrary(hModule);
3800 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
3802 if (hidden) fl |= FR_PRIVATE | FR_NOT_ENUM;
3803 ret = WineEngRemoveFontResourceEx( filename, fl, pdv );
3804 HeapFree( GetProcessHeap(), 0, filename );
3807 return ret;
3810 /***********************************************************************
3811 * GetFontResourceInfoW (GDI32.@)
3813 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
3815 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
3816 return FALSE;
3819 /***********************************************************************
3820 * GetTextCharset (GDI32.@)
3822 UINT WINAPI GetTextCharset(HDC hdc)
3824 /* MSDN docs say this is equivalent */
3825 return GetTextCharsetInfo(hdc, NULL, 0);
3828 /***********************************************************************
3829 * GdiGetCharDimensions (GDI32.@)
3831 * Gets the average width of the characters in the English alphabet.
3833 * PARAMS
3834 * hdc [I] Handle to the device context to measure on.
3835 * lptm [O] Pointer to memory to store the text metrics into.
3836 * height [O] On exit, the maximum height of characters in the English alphabet.
3838 * RETURNS
3839 * The average width of characters in the English alphabet.
3841 * NOTES
3842 * This function is used by the dialog manager to get the size of a dialog
3843 * unit. It should also be used by other pieces of code that need to know
3844 * the size of a dialog unit in logical units without having access to the
3845 * window handle of the dialog.
3846 * Windows caches the font metrics from this function, but we don't and
3847 * there doesn't appear to be an immediate advantage to do so.
3849 * SEE ALSO
3850 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3852 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3854 SIZE sz;
3855 static const WCHAR alphabet[] = {
3856 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3857 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3858 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3860 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3862 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3864 if (height) *height = sz.cy;
3865 return (sz.cx / 26 + 1) / 2;
3868 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3870 FIXME("(%d): stub\n", fEnableEUDC);
3871 return FALSE;
3874 /***********************************************************************
3875 * GetCharWidthI (GDI32.@)
3877 * Retrieve widths of characters.
3879 * PARAMS
3880 * hdc [I] Handle to a device context.
3881 * first [I] First glyph in range to query.
3882 * count [I] Number of glyph indices to query.
3883 * glyphs [I] Array of glyphs to query.
3884 * buffer [O] Buffer to receive character widths.
3886 * NOTES
3887 * Only works with TrueType fonts.
3889 * RETURNS
3890 * Success: TRUE
3891 * Failure: FALSE
3893 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3895 ABC *abc;
3896 unsigned int i;
3898 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3900 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3901 return FALSE;
3903 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3905 HeapFree(GetProcessHeap(), 0, abc);
3906 return FALSE;
3909 for (i = 0; i < count; i++)
3910 buffer[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
3912 HeapFree(GetProcessHeap(), 0, abc);
3913 return TRUE;
3916 /***********************************************************************
3917 * GetFontUnicodeRanges (GDI32.@)
3919 * Retrieve a list of supported Unicode characters in a font.
3921 * PARAMS
3922 * hdc [I] Handle to a device context.
3923 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3925 * RETURNS
3926 * Success: Number of bytes written to the buffer pointed to by lpgs.
3927 * Failure: 0
3930 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3932 DWORD ret;
3933 PHYSDEV dev;
3934 DC *dc = get_dc_ptr(hdc);
3936 TRACE("(%p, %p)\n", hdc, lpgs);
3938 if (!dc) return 0;
3940 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3941 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3942 release_dc_ptr(dc);
3943 return ret;
3947 /*************************************************************
3948 * FontIsLinked (GDI32.@)
3950 BOOL WINAPI FontIsLinked(HDC hdc)
3952 DC *dc = get_dc_ptr(hdc);
3953 PHYSDEV dev;
3954 BOOL ret;
3956 if (!dc) return FALSE;
3957 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3958 ret = dev->funcs->pFontIsLinked( dev );
3959 release_dc_ptr(dc);
3960 TRACE("returning %d\n", ret);
3961 return ret;
3964 /*************************************************************
3965 * GetFontRealizationInfo (GDI32.@)
3967 BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info)
3969 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, unk);
3970 PHYSDEV dev;
3971 BOOL ret;
3972 DC *dc;
3974 if (info->size != sizeof(*info) && !is_v0)
3975 return FALSE;
3977 dc = get_dc_ptr(hdc);
3978 if (!dc) return FALSE;
3979 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
3980 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
3981 release_dc_ptr(dc);
3982 return ret;
3985 struct realization_info
3987 DWORD flags; /* 1 for bitmap fonts, 3 for scalable fonts */
3988 DWORD cache_num; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
3989 DWORD instance_id; /* identifies a realized font instance */
3992 /*************************************************************
3993 * GdiRealizationInfo (GDI32.@)
3995 * Returns a structure that contains some font information.
3997 BOOL WINAPI GdiRealizationInfo(HDC hdc, struct realization_info *info)
3999 struct font_realization_info ri;
4000 BOOL ret;
4002 ri.size = sizeof(ri);
4003 ret = GetFontRealizationInfo( hdc, &ri );
4004 if (ret)
4006 info->flags = ri.flags;
4007 info->cache_num = ri.cache_num;
4008 info->instance_id = ri.instance_id;
4011 return ret;
4014 /*************************************************************
4015 * GetCharWidthInfo (GDI32.@)
4018 BOOL WINAPI GetCharWidthInfo(HDC hdc, struct char_width_info *info)
4020 PHYSDEV dev;
4021 BOOL ret;
4022 DC *dc;
4024 dc = get_dc_ptr(hdc);
4025 if (!dc) return FALSE;
4026 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
4027 ret = dev->funcs->pGetCharWidthInfo( dev, info );
4029 if (ret)
4031 info->lsb = width_to_LP( dc, info->lsb );
4032 info->rsb = width_to_LP( dc, info->rsb );
4034 release_dc_ptr(dc);
4035 return ret;