msvcp60: Fixed basic_istream::getline(basic_string) implementation.
[wine/multimedia.git] / dlls / gdi32 / font.c
blob027c39278cd48c50f95cbadbc68707d236f1f51e
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <limits.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include "winerror.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "winreg.h"
37 #include "gdi_private.h"
38 #include "wine/exception.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(font);
44 /* Device -> World size conversion */
46 /* Performs a device to world transformation on the specified width (which
47 * is in integer format).
49 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
51 double floatWidth;
53 /* Perform operation with floating point */
54 floatWidth = (double)width * dc->xformVport2World.eM11;
55 /* Round to integers */
56 return GDI_ROUND(floatWidth);
59 /* Performs a device to world transformation on the specified size (which
60 * is in integer format).
62 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
64 double floatHeight;
66 /* Perform operation with floating point */
67 floatHeight = (double)height * dc->xformVport2World.eM22;
68 /* Round to integers */
69 return GDI_ROUND(floatHeight);
72 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
74 POINT pt[2];
75 pt[0].x = pt[0].y = 0;
76 pt[1].x = width;
77 pt[1].y = 0;
78 LPtoDP(dc->hSelf, pt, 2);
79 return pt[1].x - pt[0].x;
82 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
84 POINT pt[2];
85 pt[0].x = pt[0].y = 0;
86 pt[1].x = 0;
87 pt[1].y = height;
88 LPtoDP(dc->hSelf, pt, 2);
89 return pt[1].y - pt[0].y;
92 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
93 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
94 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
95 static BOOL FONT_DeleteObject( HGDIOBJ handle );
97 static const struct gdi_obj_funcs font_funcs =
99 FONT_SelectObject, /* pSelectObject */
100 FONT_GetObjectA, /* pGetObjectA */
101 FONT_GetObjectW, /* pGetObjectW */
102 NULL, /* pUnrealizeObject */
103 FONT_DeleteObject /* pDeleteObject */
106 typedef struct
108 LOGFONTW logfont;
109 } FONTOBJ;
111 struct font_enum
113 LPLOGFONTW lpLogFontParam;
114 FONTENUMPROCW lpEnumFunc;
115 LPARAM lpData;
116 BOOL unicode;
117 HDC hdc;
118 INT retval;
122 * For TranslateCharsetInfo
124 #define MAXTCIINDEX 32
125 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
126 /* ANSI */
127 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
128 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
129 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
130 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
131 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
132 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
133 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
134 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
135 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
136 /* reserved by ANSI */
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144 /* ANSI and OEM */
145 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
146 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
147 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
148 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
149 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
150 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
151 /* reserved for alternate ANSI and OEM */
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { 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 /* reserved for system */
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
165 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
167 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
168 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
169 LF_FACESIZE);
170 fontW->lfFaceName[LF_FACESIZE-1] = 0;
173 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
175 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
176 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
177 LF_FACESIZE, NULL, NULL);
178 fontA->lfFaceName[LF_FACESIZE-1] = 0;
181 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
183 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
185 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
186 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
187 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
188 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
189 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
190 fontA->elfStyle[LF_FACESIZE-1] = '\0';
191 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
192 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
193 fontA->elfScript[LF_FACESIZE-1] = '\0';
196 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
198 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
200 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
201 fontW->elfFullName, LF_FULLFACESIZE );
202 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
203 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
204 fontW->elfStyle, LF_FACESIZE );
205 fontW->elfStyle[LF_FACESIZE-1] = '\0';
206 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
207 fontW->elfScript, LF_FACESIZE );
208 fontW->elfScript[LF_FACESIZE-1] = '\0';
211 /***********************************************************************
212 * TEXTMETRIC conversion functions.
214 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
216 ptmA->tmHeight = ptmW->tmHeight;
217 ptmA->tmAscent = ptmW->tmAscent;
218 ptmA->tmDescent = ptmW->tmDescent;
219 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
220 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
221 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
222 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
223 ptmA->tmWeight = ptmW->tmWeight;
224 ptmA->tmOverhang = ptmW->tmOverhang;
225 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
226 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
227 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
228 if (ptmW->tmCharSet == SYMBOL_CHARSET)
230 ptmA->tmFirstChar = 0x1e;
231 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
233 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
235 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
236 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
238 else
240 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
241 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
243 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
244 ptmA->tmBreakChar = ptmW->tmBreakChar;
245 ptmA->tmItalic = ptmW->tmItalic;
246 ptmA->tmUnderlined = ptmW->tmUnderlined;
247 ptmA->tmStruckOut = ptmW->tmStruckOut;
248 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
249 ptmA->tmCharSet = ptmW->tmCharSet;
253 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
255 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
256 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
257 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
258 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
259 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
260 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
263 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
265 WCHAR buf[12];
266 DWORD count = sizeof(buf), type, err;
268 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
269 if (!err)
271 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
272 else *value = atoiW( buf );
274 return err;
277 static UINT get_subpixel_orientation( HKEY key )
279 static const WCHAR smoothing_orientation[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
280 'O','r','i','e','n','t','a','t','i','o','n',0};
281 DWORD orient;
283 /* FIXME: handle vertical orientations even though Windows doesn't */
284 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
286 switch (orient)
288 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
289 return WINE_GGO_HBGR_BITMAP;
290 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
291 return WINE_GGO_HRGB_BITMAP;
293 return GGO_GRAY4_BITMAP;
296 static UINT get_default_smoothing( HKEY key )
298 static const WCHAR smoothing[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
299 static const WCHAR smoothing_type[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
300 DWORD enabled, type;
302 if (get_key_value( key, smoothing, &enabled )) return 0;
303 if (!enabled) return GGO_BITMAP;
305 if (!get_key_value( key, smoothing_type, &type ) && type == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
306 return get_subpixel_orientation( key );
308 return GGO_GRAY4_BITMAP;
312 /***********************************************************************
313 * GdiGetCodePage (GDI32.@)
315 DWORD WINAPI GdiGetCodePage( HDC hdc )
317 UINT cp = CP_ACP;
318 DC *dc = get_dc_ptr( hdc );
320 if (dc)
322 cp = dc->font_code_page;
323 release_dc_ptr( dc );
325 return cp;
328 /***********************************************************************
329 * FONT_mbtowc
331 * Returns a Unicode translation of str using the charset of the
332 * currently selected font in hdc. If count is -1 then str is assumed
333 * to be '\0' terminated, otherwise it contains the number of bytes to
334 * convert. If plenW is non-NULL, on return it will point to the
335 * number of WCHARs that have been written. If pCP is non-NULL, on
336 * return it will point to the codepage used in the conversion. The
337 * caller should free the returned LPWSTR from the process heap
338 * itself.
340 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
342 UINT cp;
343 INT lenW;
344 LPWSTR strW;
346 cp = GdiGetCodePage( hdc );
348 if(count == -1) count = strlen(str);
349 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
350 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
351 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
352 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
353 if(plenW) *plenW = lenW;
354 if(pCP) *pCP = cp;
355 return strW;
358 /***********************************************************************
359 * CreateFontIndirectExA (GDI32.@)
361 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
363 ENUMLOGFONTEXDVW enumexW;
365 if (!penumexA) return 0;
367 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
368 enumexW.elfDesignVector = penumexA->elfDesignVector;
369 return CreateFontIndirectExW( &enumexW );
372 /***********************************************************************
373 * CreateFontIndirectExW (GDI32.@)
375 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
377 HFONT hFont;
378 FONTOBJ *fontPtr;
379 const LOGFONTW *plf;
381 if (!penumex) return 0;
383 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
384 penumex->elfEnumLogfontEx.elfStyle[0] ||
385 penumex->elfEnumLogfontEx.elfScript[0])
387 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
388 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
389 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
390 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
393 plf = &penumex->elfEnumLogfontEx.elfLogFont;
394 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
396 fontPtr->logfont = *plf;
398 if (plf->lfEscapement != plf->lfOrientation)
400 /* this should really depend on whether GM_ADVANCED is set */
401 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
402 WARN("orientation angle %f set to "
403 "escapement angle %f for new font %p\n",
404 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
407 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &font_funcs )))
409 HeapFree( GetProcessHeap(), 0, fontPtr );
410 return 0;
413 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
414 plf->lfHeight, plf->lfWidth,
415 plf->lfEscapement, plf->lfOrientation,
416 plf->lfPitchAndFamily,
417 plf->lfOutPrecision, plf->lfClipPrecision,
418 plf->lfQuality, plf->lfCharSet,
419 debugstr_w(plf->lfFaceName),
420 plf->lfWeight > 400 ? "Bold" : "",
421 plf->lfItalic ? "Italic" : "",
422 plf->lfUnderline ? "Underline" : "", hFont);
424 return hFont;
427 /***********************************************************************
428 * CreateFontIndirectA (GDI32.@)
430 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
432 LOGFONTW lfW;
434 if (!plfA) return 0;
436 FONT_LogFontAToW( plfA, &lfW );
437 return CreateFontIndirectW( &lfW );
440 /***********************************************************************
441 * CreateFontIndirectW (GDI32.@)
443 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
445 ENUMLOGFONTEXDVW exdv;
447 if (!plf) return 0;
449 exdv.elfEnumLogfontEx.elfLogFont = *plf;
450 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
451 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
452 exdv.elfEnumLogfontEx.elfScript[0] = 0;
453 return CreateFontIndirectExW( &exdv );
456 /*************************************************************************
457 * CreateFontA (GDI32.@)
459 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
460 INT orient, INT weight, DWORD italic,
461 DWORD underline, DWORD strikeout, DWORD charset,
462 DWORD outpres, DWORD clippres, DWORD quality,
463 DWORD pitch, LPCSTR name )
465 LOGFONTA logfont;
467 logfont.lfHeight = height;
468 logfont.lfWidth = width;
469 logfont.lfEscapement = esc;
470 logfont.lfOrientation = orient;
471 logfont.lfWeight = weight;
472 logfont.lfItalic = italic;
473 logfont.lfUnderline = underline;
474 logfont.lfStrikeOut = strikeout;
475 logfont.lfCharSet = charset;
476 logfont.lfOutPrecision = outpres;
477 logfont.lfClipPrecision = clippres;
478 logfont.lfQuality = quality;
479 logfont.lfPitchAndFamily = pitch;
481 if (name)
482 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
483 else
484 logfont.lfFaceName[0] = '\0';
486 return CreateFontIndirectA( &logfont );
489 /*************************************************************************
490 * CreateFontW (GDI32.@)
492 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
493 INT orient, INT weight, DWORD italic,
494 DWORD underline, DWORD strikeout, DWORD charset,
495 DWORD outpres, DWORD clippres, DWORD quality,
496 DWORD pitch, LPCWSTR name )
498 LOGFONTW logfont;
500 logfont.lfHeight = height;
501 logfont.lfWidth = width;
502 logfont.lfEscapement = esc;
503 logfont.lfOrientation = orient;
504 logfont.lfWeight = weight;
505 logfont.lfItalic = italic;
506 logfont.lfUnderline = underline;
507 logfont.lfStrikeOut = strikeout;
508 logfont.lfCharSet = charset;
509 logfont.lfOutPrecision = outpres;
510 logfont.lfClipPrecision = clippres;
511 logfont.lfQuality = quality;
512 logfont.lfPitchAndFamily = pitch;
514 if (name)
515 lstrcpynW(logfont.lfFaceName, name,
516 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
517 else
518 logfont.lfFaceName[0] = '\0';
520 return CreateFontIndirectW( &logfont );
523 static void update_font_code_page( DC *dc )
525 CHARSETINFO csi;
526 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
528 /* Hmm, nicely designed api this one! */
529 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
530 dc->font_code_page = csi.ciACP;
531 else {
532 switch(charset) {
533 case OEM_CHARSET:
534 dc->font_code_page = GetOEMCP();
535 break;
536 case DEFAULT_CHARSET:
537 dc->font_code_page = GetACP();
538 break;
540 case VISCII_CHARSET:
541 case TCVN_CHARSET:
542 case KOI8_CHARSET:
543 case ISO3_CHARSET:
544 case ISO4_CHARSET:
545 case ISO10_CHARSET:
546 case CELTIC_CHARSET:
547 /* FIXME: These have no place here, but because x11drv
548 enumerates fonts with these (made up) charsets some apps
549 might use them and then the FIXME below would become
550 annoying. Now we could pick the intended codepage for
551 each of these, but since it's broken anyway we'll just
552 use CP_ACP and hope it'll go away...
554 dc->font_code_page = CP_ACP;
555 break;
557 default:
558 FIXME("Can't find codepage for charset %d\n", charset);
559 dc->font_code_page = CP_ACP;
560 break;
564 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
567 /***********************************************************************
568 * FONT_SelectObject
570 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
572 HGDIOBJ ret = 0;
573 DC *dc = get_dc_ptr( hdc );
574 PHYSDEV physdev;
575 UINT aa_flags = 0;
577 if (!dc) return 0;
579 if (!GDI_inc_ref_count( handle ))
581 release_dc_ptr( dc );
582 return 0;
585 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
586 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
588 ret = dc->hFont;
589 dc->hFont = handle;
590 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
591 update_font_code_page( dc );
592 GDI_dec_ref_count( ret );
594 else GDI_dec_ref_count( handle );
596 release_dc_ptr( dc );
597 return ret;
601 /***********************************************************************
602 * FONT_GetObjectA
604 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
606 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
607 LOGFONTA lfA;
609 if (!font) return 0;
610 if (buffer)
612 FONT_LogFontWToA( &font->logfont, &lfA );
613 if (count > sizeof(lfA)) count = sizeof(lfA);
614 memcpy( buffer, &lfA, count );
616 else count = sizeof(lfA);
617 GDI_ReleaseObj( handle );
618 return count;
621 /***********************************************************************
622 * FONT_GetObjectW
624 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
626 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
628 if (!font) return 0;
629 if (buffer)
631 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
632 memcpy( buffer, &font->logfont, count );
634 else count = sizeof(LOGFONTW);
635 GDI_ReleaseObj( handle );
636 return count;
640 /***********************************************************************
641 * FONT_DeleteObject
643 static BOOL FONT_DeleteObject( HGDIOBJ handle )
645 FONTOBJ *obj;
647 WineEngDestroyFontInstance( handle );
649 if (!(obj = free_gdi_handle( handle ))) return FALSE;
650 return HeapFree( GetProcessHeap(), 0, obj );
654 /***********************************************************************
655 * nulldrv_SelectFont
657 HFONT nulldrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
659 static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
660 'D','e','s','k','t','o','p',0 };
661 LOGFONTW lf;
662 HKEY key;
664 if (*aa_flags) return 0;
666 GetObjectW( font, sizeof(lf), &lf );
667 switch (lf.lfQuality)
669 case NONANTIALIASED_QUALITY:
670 *aa_flags = GGO_BITMAP;
671 break;
672 case ANTIALIASED_QUALITY:
673 *aa_flags = GGO_GRAY4_BITMAP;
674 break;
675 case CLEARTYPE_QUALITY:
676 case CLEARTYPE_NATURAL_QUALITY:
677 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
678 *aa_flags = get_subpixel_orientation( key );
679 RegCloseKey( key );
680 break;
681 default:
682 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
683 *aa_flags = get_default_smoothing( key );
684 RegCloseKey( key );
685 break;
687 return 0;
691 /***********************************************************************
692 * FONT_EnumInstance
694 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
695 * We have to use other types because of the FONTENUMPROCW definition.
697 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
698 DWORD fType, LPARAM lp )
700 struct font_enum *pfe = (struct font_enum *)lp;
701 INT ret = 1;
703 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
704 if ((!pfe->lpLogFontParam ||
705 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
706 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
707 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
709 /* convert font metrics */
710 ENUMLOGFONTEXA logfont;
711 NEWTEXTMETRICEXA tmA;
713 if (!pfe->unicode)
715 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
716 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
717 plf = (LOGFONTW *)&logfont.elfLogFont;
718 ptm = (TEXTMETRICW *)&tmA;
720 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
721 pfe->retval = ret;
723 return ret;
726 /***********************************************************************
727 * FONT_EnumFontFamiliesEx
729 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
730 LPARAM lParam, BOOL unicode )
732 INT ret = 0;
733 DC *dc = get_dc_ptr( hDC );
734 struct font_enum fe;
736 if (dc)
738 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
740 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
741 fe.lpLogFontParam = plf;
742 fe.lpEnumFunc = efproc;
743 fe.lpData = lParam;
744 fe.unicode = unicode;
745 fe.hdc = hDC;
746 fe.retval = 1;
747 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
748 release_dc_ptr( dc );
750 return ret ? fe.retval : 0;
753 /***********************************************************************
754 * EnumFontFamiliesExW (GDI32.@)
756 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
757 FONTENUMPROCW efproc,
758 LPARAM lParam, DWORD dwFlags )
760 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
763 /***********************************************************************
764 * EnumFontFamiliesExA (GDI32.@)
766 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
767 FONTENUMPROCA efproc,
768 LPARAM lParam, DWORD dwFlags)
770 LOGFONTW lfW, *plfW;
772 if (plf)
774 FONT_LogFontAToW( plf, &lfW );
775 plfW = &lfW;
777 else plfW = NULL;
779 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
782 /***********************************************************************
783 * EnumFontFamiliesA (GDI32.@)
785 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
786 FONTENUMPROCA efproc, LPARAM lpData )
788 LOGFONTA lf, *plf;
790 if (lpFamily)
792 if (!*lpFamily) return 1;
793 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
794 lf.lfCharSet = DEFAULT_CHARSET;
795 lf.lfPitchAndFamily = 0;
796 plf = &lf;
798 else plf = NULL;
800 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
803 /***********************************************************************
804 * EnumFontFamiliesW (GDI32.@)
806 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
807 FONTENUMPROCW efproc, LPARAM lpData )
809 LOGFONTW lf, *plf;
811 if (lpFamily)
813 if (!*lpFamily) return 1;
814 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
815 lf.lfCharSet = DEFAULT_CHARSET;
816 lf.lfPitchAndFamily = 0;
817 plf = &lf;
819 else plf = NULL;
821 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
824 /***********************************************************************
825 * EnumFontsA (GDI32.@)
827 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
828 LPARAM lpData )
830 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
833 /***********************************************************************
834 * EnumFontsW (GDI32.@)
836 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
837 LPARAM lpData )
839 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
843 /***********************************************************************
844 * GetTextCharacterExtra (GDI32.@)
846 INT WINAPI GetTextCharacterExtra( HDC hdc )
848 INT ret;
849 DC *dc = get_dc_ptr( hdc );
850 if (!dc) return 0x80000000;
851 ret = dc->charExtra;
852 release_dc_ptr( dc );
853 return ret;
857 /***********************************************************************
858 * SetTextCharacterExtra (GDI32.@)
860 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
862 INT ret = 0x80000000;
863 DC * dc = get_dc_ptr( hdc );
865 if (dc)
867 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
868 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
869 if (extra != 0x80000000)
871 ret = dc->charExtra;
872 dc->charExtra = extra;
874 release_dc_ptr( dc );
876 return ret;
880 /***********************************************************************
881 * SetTextJustification (GDI32.@)
883 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
885 BOOL ret;
886 PHYSDEV physdev;
887 DC * dc = get_dc_ptr( hdc );
889 if (!dc) return FALSE;
891 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
892 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
893 if (ret)
895 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
896 if (!extra) breaks = 0;
897 if (breaks)
899 dc->breakExtra = extra / breaks;
900 dc->breakRem = extra - (breaks * dc->breakExtra);
902 else
904 dc->breakExtra = 0;
905 dc->breakRem = 0;
908 release_dc_ptr( dc );
909 return ret;
913 /***********************************************************************
914 * GetTextFaceA (GDI32.@)
916 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
918 INT res = GetTextFaceW(hdc, 0, NULL);
919 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
920 GetTextFaceW( hdc, res, nameW );
922 if (name)
924 if (count)
926 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
927 if (res == 0)
928 res = count;
929 name[count-1] = 0;
930 /* GetTextFaceA does NOT include the nul byte in the return count. */
931 res--;
933 else
934 res = 0;
936 else
937 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
938 HeapFree( GetProcessHeap(), 0, nameW );
939 return res;
942 /***********************************************************************
943 * GetTextFaceW (GDI32.@)
945 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
947 PHYSDEV dev;
948 INT ret;
950 DC * dc = get_dc_ptr( hdc );
951 if (!dc) return 0;
953 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
954 ret = dev->funcs->pGetTextFace( dev, count, name );
955 release_dc_ptr( dc );
956 return ret;
960 /***********************************************************************
961 * GetTextExtentPoint32A (GDI32.@)
963 * See GetTextExtentPoint32W.
965 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
966 LPSIZE size )
968 BOOL ret = FALSE;
969 INT wlen;
970 LPWSTR p;
972 if (count < 0) return FALSE;
974 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
976 if (p)
978 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
979 HeapFree( GetProcessHeap(), 0, p );
982 TRACE("(%p %s %d %p): returning %d x %d\n",
983 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
984 return ret;
988 /***********************************************************************
989 * GetTextExtentPoint32W [GDI32.@]
991 * Computes width/height for a string.
993 * Computes width and height of the specified string.
995 * RETURNS
996 * Success: TRUE
997 * Failure: FALSE
999 BOOL WINAPI GetTextExtentPoint32W(
1000 HDC hdc, /* [in] Handle of device context */
1001 LPCWSTR str, /* [in] Address of text string */
1002 INT count, /* [in] Number of characters in string */
1003 LPSIZE size) /* [out] Address of structure for string size */
1005 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1008 /***********************************************************************
1009 * GetTextExtentExPointI [GDI32.@]
1011 * Computes width and height of the array of glyph indices.
1013 * PARAMS
1014 * hdc [I] Handle of device context.
1015 * indices [I] Glyph index array.
1016 * count [I] Number of glyphs in array.
1017 * max_ext [I] Maximum width in glyphs.
1018 * nfit [O] Maximum number of characters.
1019 * dxs [O] Partial string widths.
1020 * size [O] Returned string size.
1022 * RETURNS
1023 * Success: TRUE
1024 * Failure: FALSE
1026 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1027 LPINT nfit, LPINT dxs, LPSIZE size )
1029 PHYSDEV dev;
1030 BOOL ret;
1031 DC *dc;
1033 if (count < 0) return FALSE;
1035 dc = get_dc_ptr( hdc );
1036 if (!dc) return FALSE;
1038 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
1039 ret = dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, nfit, dxs, size );
1040 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1041 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1042 size->cx += count * dc->charExtra;
1043 release_dc_ptr( dc );
1045 TRACE("(%p %p %d %p): returning %d x %d\n",
1046 hdc, indices, count, size, size->cx, size->cy );
1047 return ret;
1050 /***********************************************************************
1051 * GetTextExtentPointI [GDI32.@]
1053 * Computes width and height of the array of glyph indices.
1055 * PARAMS
1056 * hdc [I] Handle of device context.
1057 * indices [I] Glyph index array.
1058 * count [I] Number of glyphs in array.
1059 * size [O] Returned string size.
1061 * RETURNS
1062 * Success: TRUE
1063 * Failure: FALSE
1065 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1067 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1071 /***********************************************************************
1072 * GetTextExtentPointA (GDI32.@)
1074 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1075 LPSIZE size )
1077 TRACE("not bug compatible.\n");
1078 return GetTextExtentPoint32A( hdc, str, count, size );
1081 /***********************************************************************
1082 * GetTextExtentPointW (GDI32.@)
1084 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1085 LPSIZE size )
1087 TRACE("not bug compatible.\n");
1088 return GetTextExtentPoint32W( hdc, str, count, size );
1092 /***********************************************************************
1093 * GetTextExtentExPointA (GDI32.@)
1095 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1096 INT maxExt, LPINT lpnFit,
1097 LPINT alpDx, LPSIZE size )
1099 BOOL ret;
1100 INT wlen;
1101 INT *walpDx = NULL;
1102 LPWSTR p = NULL;
1104 if (count < 0) return FALSE;
1106 if (alpDx)
1108 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1109 if (!walpDx) return FALSE;
1112 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1113 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1114 if (walpDx)
1116 INT n = lpnFit ? *lpnFit : wlen;
1117 INT i, j;
1118 for(i = 0, j = 0; i < n; i++, j++)
1120 alpDx[j] = walpDx[i];
1121 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1124 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1125 HeapFree( GetProcessHeap(), 0, p );
1126 HeapFree( GetProcessHeap(), 0, walpDx );
1127 return ret;
1131 /***********************************************************************
1132 * GetTextExtentExPointW (GDI32.@)
1134 * Return the size of the string as it would be if it was output properly by
1135 * e.g. TextOut.
1137 * This should include
1138 * - Intercharacter spacing
1139 * - justification spacing (not yet done)
1140 * - kerning? see below
1142 * Kerning. Since kerning would be carried out by the rendering code it should
1143 * be done by the driver. However they don't support it yet. Also I am not
1144 * yet persuaded that (certainly under Win95) any kerning is actually done.
1146 * str: According to MSDN this should be null-terminated. That is not true; a
1147 * null will not terminate it early.
1148 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1149 * than count. I have seen it be either the size of the full string or
1150 * 1 less than the size of the full string. I have not seen it bear any
1151 * resemblance to the portion that would fit.
1152 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1153 * trailing intercharacter spacing and any trailing justification.
1155 * FIXME
1156 * Currently we do this by measuring each character etc. We should do it by
1157 * passing the request to the driver, perhaps by extending the
1158 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1159 * thinking about kerning issues and rounding issues in the justification.
1162 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1163 INT maxExt, LPINT lpnFit,
1164 LPINT alpDx, LPSIZE size )
1166 INT nFit = 0;
1167 LPINT dxs = NULL;
1168 DC *dc;
1169 BOOL ret = FALSE;
1170 TEXTMETRICW tm;
1171 PHYSDEV dev;
1173 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1175 if (count < 0) return FALSE;
1177 dc = get_dc_ptr(hdc);
1178 if (!dc) return FALSE;
1180 GetTextMetricsW(hdc, &tm);
1182 /* If we need to calculate nFit, then we need the partial extents even if
1183 the user hasn't provided us with an array. */
1184 if (lpnFit)
1186 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1187 if (! dxs)
1189 release_dc_ptr(dc);
1190 SetLastError(ERROR_OUTOFMEMORY);
1191 return FALSE;
1194 else
1195 dxs = alpDx;
1197 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
1198 ret = dev->funcs->pGetTextExtentExPoint(dev, str, count, 0, NULL, dxs, size);
1200 /* Perform device size to world size transformations. */
1201 if (ret)
1203 INT extra = dc->charExtra,
1204 breakExtra = dc->breakExtra,
1205 breakRem = dc->breakRem,
1208 if (dxs)
1210 for (i = 0; i < count; ++i)
1212 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1213 dxs[i] += (i+1) * extra;
1214 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1216 dxs[i] += breakExtra;
1217 if (breakRem > 0)
1219 breakRem--;
1220 dxs[i]++;
1223 if (dxs[i] <= maxExt)
1224 ++nFit;
1226 breakRem = dc->breakRem;
1228 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1229 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1231 if (!dxs && count > 1 && (breakExtra || breakRem))
1233 for (i = 0; i < count; i++)
1235 if (str[i] == tm.tmBreakChar)
1237 size->cx += breakExtra;
1238 if (breakRem > 0)
1240 breakRem--;
1241 (size->cx)++;
1248 if (lpnFit)
1249 *lpnFit = nFit;
1251 if (! alpDx)
1252 HeapFree(GetProcessHeap(), 0, dxs);
1254 release_dc_ptr( dc );
1256 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1257 return ret;
1260 /***********************************************************************
1261 * GetTextMetricsA (GDI32.@)
1263 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1265 TEXTMETRICW tm32;
1267 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1268 FONT_TextMetricWToA( &tm32, metrics );
1269 return TRUE;
1272 /***********************************************************************
1273 * GetTextMetricsW (GDI32.@)
1275 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1277 PHYSDEV physdev;
1278 BOOL ret = FALSE;
1279 DC * dc = get_dc_ptr( hdc );
1280 if (!dc) return FALSE;
1282 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1283 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1285 if (ret)
1287 /* device layer returns values in device units
1288 * therefore we have to convert them to logical */
1290 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1291 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1293 #define WDPTOLP(x) ((x<0)? \
1294 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1295 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1296 #define HDPTOLP(y) ((y<0)? \
1297 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1298 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1300 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1301 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1302 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1303 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1304 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1305 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1306 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1307 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1308 ret = TRUE;
1309 #undef WDPTOLP
1310 #undef HDPTOLP
1311 TRACE("text metrics:\n"
1312 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1313 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1314 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1315 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1316 " PitchAndFamily = %02x\n"
1317 " --------------------\n"
1318 " InternalLeading = %i\n"
1319 " Ascent = %i\n"
1320 " Descent = %i\n"
1321 " Height = %i\n",
1322 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1323 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1324 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1325 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1326 metrics->tmPitchAndFamily,
1327 metrics->tmInternalLeading,
1328 metrics->tmAscent,
1329 metrics->tmDescent,
1330 metrics->tmHeight );
1332 release_dc_ptr( dc );
1333 return ret;
1337 /***********************************************************************
1338 * GetOutlineTextMetricsA (GDI32.@)
1339 * Gets metrics for TrueType fonts.
1341 * NOTES
1342 * If the supplied buffer isn't big enough Windows partially fills it up to
1343 * its given length and returns that length.
1345 * RETURNS
1346 * Success: Non-zero or size of required buffer
1347 * Failure: 0
1349 UINT WINAPI GetOutlineTextMetricsA(
1350 HDC hdc, /* [in] Handle of device context */
1351 UINT cbData, /* [in] Size of metric data array */
1352 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1354 char buf[512], *ptr;
1355 UINT ret, needed;
1356 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1357 OUTLINETEXTMETRICA *output = lpOTM;
1358 INT left, len;
1360 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1361 return 0;
1362 if(ret > sizeof(buf))
1363 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1364 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1366 needed = sizeof(OUTLINETEXTMETRICA);
1367 if(lpOTMW->otmpFamilyName)
1368 needed += WideCharToMultiByte(CP_ACP, 0,
1369 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1370 NULL, 0, NULL, NULL);
1371 if(lpOTMW->otmpFaceName)
1372 needed += WideCharToMultiByte(CP_ACP, 0,
1373 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1374 NULL, 0, NULL, NULL);
1375 if(lpOTMW->otmpStyleName)
1376 needed += WideCharToMultiByte(CP_ACP, 0,
1377 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1378 NULL, 0, NULL, NULL);
1379 if(lpOTMW->otmpFullName)
1380 needed += WideCharToMultiByte(CP_ACP, 0,
1381 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1382 NULL, 0, NULL, NULL);
1384 if(!lpOTM) {
1385 ret = needed;
1386 goto end;
1389 TRACE("needed = %d\n", needed);
1390 if(needed > cbData)
1391 /* Since the supplied buffer isn't big enough, we'll alloc one
1392 that is and memcpy the first cbData bytes into the lpOTM at
1393 the end. */
1394 output = HeapAlloc(GetProcessHeap(), 0, needed);
1396 ret = output->otmSize = min(needed, cbData);
1397 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1398 output->otmFiller = 0;
1399 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1400 output->otmfsSelection = lpOTMW->otmfsSelection;
1401 output->otmfsType = lpOTMW->otmfsType;
1402 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1403 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1404 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1405 output->otmEMSquare = lpOTMW->otmEMSquare;
1406 output->otmAscent = lpOTMW->otmAscent;
1407 output->otmDescent = lpOTMW->otmDescent;
1408 output->otmLineGap = lpOTMW->otmLineGap;
1409 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1410 output->otmsXHeight = lpOTMW->otmsXHeight;
1411 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1412 output->otmMacAscent = lpOTMW->otmMacAscent;
1413 output->otmMacDescent = lpOTMW->otmMacDescent;
1414 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1415 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1416 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1417 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1418 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1419 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1420 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1421 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1422 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1423 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1426 ptr = (char*)(output + 1);
1427 left = needed - sizeof(*output);
1429 if(lpOTMW->otmpFamilyName) {
1430 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1431 len = WideCharToMultiByte(CP_ACP, 0,
1432 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1433 ptr, left, NULL, NULL);
1434 left -= len;
1435 ptr += len;
1436 } else
1437 output->otmpFamilyName = 0;
1439 if(lpOTMW->otmpFaceName) {
1440 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1441 len = WideCharToMultiByte(CP_ACP, 0,
1442 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1443 ptr, left, NULL, NULL);
1444 left -= len;
1445 ptr += len;
1446 } else
1447 output->otmpFaceName = 0;
1449 if(lpOTMW->otmpStyleName) {
1450 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1451 len = WideCharToMultiByte(CP_ACP, 0,
1452 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1453 ptr, left, NULL, NULL);
1454 left -= len;
1455 ptr += len;
1456 } else
1457 output->otmpStyleName = 0;
1459 if(lpOTMW->otmpFullName) {
1460 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1461 len = WideCharToMultiByte(CP_ACP, 0,
1462 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1463 ptr, left, NULL, NULL);
1464 left -= len;
1465 } else
1466 output->otmpFullName = 0;
1468 assert(left == 0);
1470 if(output != lpOTM) {
1471 memcpy(lpOTM, output, cbData);
1472 HeapFree(GetProcessHeap(), 0, output);
1474 /* check if the string offsets really fit into the provided size */
1475 /* FIXME: should we check string length as well? */
1476 /* make sure that we don't read/write beyond the provided buffer */
1477 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1479 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1480 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1483 /* make sure that we don't read/write beyond the provided buffer */
1484 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1486 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1487 lpOTM->otmpFaceName = 0; /* doesn't fit */
1490 /* make sure that we don't read/write beyond the provided buffer */
1491 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1493 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1494 lpOTM->otmpStyleName = 0; /* doesn't fit */
1497 /* make sure that we don't read/write beyond the provided buffer */
1498 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1500 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1501 lpOTM->otmpFullName = 0; /* doesn't fit */
1505 end:
1506 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1507 HeapFree(GetProcessHeap(), 0, lpOTMW);
1509 return ret;
1513 /***********************************************************************
1514 * GetOutlineTextMetricsW [GDI32.@]
1516 UINT WINAPI GetOutlineTextMetricsW(
1517 HDC hdc, /* [in] Handle of device context */
1518 UINT cbData, /* [in] Size of metric data array */
1519 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1521 DC *dc = get_dc_ptr( hdc );
1522 OUTLINETEXTMETRICW *output = lpOTM;
1523 PHYSDEV dev;
1524 UINT ret;
1526 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1527 if(!dc) return 0;
1529 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1530 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1532 if (lpOTM && ret > cbData)
1534 output = HeapAlloc(GetProcessHeap(), 0, ret);
1535 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1538 if (lpOTM && ret)
1540 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1541 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1543 #define WDPTOLP(x) ((x<0)? \
1544 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1545 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1546 #define HDPTOLP(y) ((y<0)? \
1547 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1548 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1550 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1551 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1552 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1553 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1554 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1555 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1556 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1557 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1558 output->otmAscent = HDPTOLP(output->otmAscent);
1559 output->otmDescent = HDPTOLP(output->otmDescent);
1560 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1561 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1562 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1563 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1564 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1565 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1566 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1567 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1568 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1569 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1570 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1571 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1572 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1573 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1574 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1575 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1576 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1577 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1578 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1579 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1580 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1581 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1582 #undef WDPTOLP
1583 #undef HDPTOLP
1584 if(output != lpOTM)
1586 memcpy(lpOTM, output, cbData);
1587 HeapFree(GetProcessHeap(), 0, output);
1588 ret = cbData;
1591 release_dc_ptr(dc);
1592 return ret;
1595 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1597 INT i, count = lastChar - firstChar + 1;
1598 UINT mbcp;
1599 UINT c;
1600 LPSTR str;
1602 if (count <= 0)
1603 return NULL;
1605 mbcp = GdiGetCodePage(hdc);
1606 switch (mbcp)
1608 case 932:
1609 case 936:
1610 case 949:
1611 case 950:
1612 case 1361:
1613 if (lastChar > 0xffff)
1614 return NULL;
1615 if ((firstChar ^ lastChar) > 0xff)
1616 return NULL;
1617 break;
1618 default:
1619 if (lastChar > 0xff)
1620 return NULL;
1621 mbcp = 0;
1622 break;
1625 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1626 if (str == NULL)
1627 return NULL;
1629 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1631 if (mbcp) {
1632 if (c > 0xff)
1633 str[i++] = (BYTE)(c >> 8);
1634 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
1635 str[i] = 0x1f; /* FIXME: use default character */
1636 else
1637 str[i] = (BYTE)c;
1639 else
1640 str[i] = (BYTE)c;
1642 str[i] = '\0';
1644 *pByteLen = i;
1646 return str;
1649 /***********************************************************************
1650 * GetCharWidthW (GDI32.@)
1651 * GetCharWidth32W (GDI32.@)
1653 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1654 LPINT buffer )
1656 UINT i;
1657 BOOL ret;
1658 PHYSDEV dev;
1659 DC * dc = get_dc_ptr( hdc );
1661 if (!dc) return FALSE;
1663 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1664 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1666 if (ret)
1668 /* convert device units to logical */
1669 for( i = firstChar; i <= lastChar; i++, buffer++ )
1670 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1672 release_dc_ptr( dc );
1673 return ret;
1677 /***********************************************************************
1678 * GetCharWidthA (GDI32.@)
1679 * GetCharWidth32A (GDI32.@)
1681 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1682 LPINT buffer )
1684 INT i, wlen;
1685 LPSTR str;
1686 LPWSTR wstr;
1687 BOOL ret = TRUE;
1689 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1690 if(str == NULL)
1691 return FALSE;
1693 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1695 for(i = 0; i < wlen; i++)
1697 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1699 ret = FALSE;
1700 break;
1702 buffer++;
1705 HeapFree(GetProcessHeap(), 0, str);
1706 HeapFree(GetProcessHeap(), 0, wstr);
1708 return ret;
1712 /* helper for nulldrv_ExtTextOut */
1713 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags,
1714 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1716 UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
1717 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1718 UINT indices[3] = {0, 0, 0x20};
1719 int i;
1720 DWORD ret, size;
1721 int stride;
1723 indices[0] = index;
1725 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1727 index = indices[i];
1728 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
1729 if (ret != GDI_ERROR) break;
1732 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1733 if (!image) return ERROR_SUCCESS;
1735 image->ptr = NULL;
1736 image->free = NULL;
1737 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1739 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1740 size = metrics->gmBlackBoxY * stride;
1742 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1743 image->is_copy = TRUE;
1744 image->free = free_heap_bits;
1746 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, image->ptr, &identity );
1747 if (ret == GDI_ERROR)
1749 HeapFree( GetProcessHeap(), 0, image->ptr );
1750 return ERROR_NOT_FOUND;
1752 return ERROR_SUCCESS;
1755 /* helper for nulldrv_ExtTextOut */
1756 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1757 LPCWSTR str, UINT count, const INT *dx )
1759 int i;
1760 RECT rect, bounds;
1762 reset_bounds( &bounds );
1763 for (i = 0; i < count; i++)
1765 GLYPHMETRICS metrics;
1767 if (get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, NULL )) continue;
1769 rect.left = x + metrics.gmptGlyphOrigin.x;
1770 rect.top = y - metrics.gmptGlyphOrigin.y;
1771 rect.right = rect.left + metrics.gmBlackBoxX;
1772 rect.bottom = rect.top + metrics.gmBlackBoxY;
1773 add_bounds_rect( &bounds, &rect );
1775 if (dx)
1777 if (flags & ETO_PDY)
1779 x += dx[ i * 2 ];
1780 y += dx[ i * 2 + 1];
1782 else x += dx[ i ];
1784 else
1786 x += metrics.gmCellIncX;
1787 y += metrics.gmCellIncY;
1790 return bounds;
1793 /* helper for nulldrv_ExtTextOut */
1794 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1795 const struct gdi_image_bits *image, const RECT *clip )
1797 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1798 UINT x, y, i, count, max_count;
1799 BYTE *ptr = image->ptr;
1800 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1801 POINT *pts;
1802 RECT rect, clipped_rect;
1804 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1805 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1806 rect.right = rect.left + metrics->gmBlackBoxX;
1807 rect.bottom = rect.top + metrics->gmBlackBoxY;
1808 if (!clip) clipped_rect = rect;
1809 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1811 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
1812 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
1813 if (!pts) return;
1815 count = 0;
1816 ptr += (clipped_rect.top - rect.top) * stride;
1817 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1819 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1821 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1822 pts[count].x = rect.left + x;
1823 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1824 pts[count + 1].x = rect.left + x;
1825 if (pts[count + 1].x > pts[count].x)
1827 pts[count].y = pts[count + 1].y = y;
1828 count += 2;
1832 assert( count <= max_count );
1833 DPtoLP( hdc, pts, count );
1834 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1835 HeapFree( GetProcessHeap(), 0, pts );
1838 /***********************************************************************
1839 * nulldrv_ExtTextOut
1841 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1842 LPCWSTR str, UINT count, const INT *dx )
1844 DC *dc = get_nulldrv_dc( dev );
1845 UINT i;
1846 DWORD err;
1847 HGDIOBJ orig;
1848 HPEN pen;
1850 if (flags & ETO_OPAQUE)
1852 RECT rc = *rect;
1853 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1855 if (brush)
1857 orig = SelectObject( dev->hdc, brush );
1858 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1859 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1860 SelectObject( dev->hdc, orig );
1861 DeleteObject( brush );
1865 if (!count) return TRUE;
1867 if (dc->aa_flags != GGO_BITMAP)
1869 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1870 BITMAPINFO *info = (BITMAPINFO *)buffer;
1871 struct gdi_image_bits bits;
1872 struct bitblt_coords src, dst;
1873 PHYSDEV dst_dev;
1874 /* FIXME Subpixel modes */
1875 UINT aa_flags = GGO_GRAY4_BITMAP;
1877 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1878 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1879 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1880 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1882 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1883 src.x = src.visrect.left;
1884 src.y = src.visrect.top;
1885 src.width = src.visrect.right - src.visrect.left;
1886 src.height = src.visrect.bottom - src.visrect.top;
1887 dst = src;
1888 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1889 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1891 /* we can avoid the GetImage, just query the needed format */
1892 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1893 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1894 info->bmiHeader.biWidth = src.width;
1895 info->bmiHeader.biHeight = -src.height;
1896 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
1897 if (!err || err == ERROR_BAD_FORMAT)
1899 /* make the source rectangle relative to the source bits */
1900 src.x = src.y = 0;
1901 src.visrect.left = src.visrect.top = 0;
1902 src.visrect.right = src.width;
1903 src.visrect.bottom = src.height;
1905 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1906 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1907 bits.is_copy = TRUE;
1908 bits.free = free_heap_bits;
1909 err = ERROR_SUCCESS;
1912 else
1914 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1915 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
1916 if (!err && !bits.is_copy)
1918 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1919 if (!ptr)
1921 if (bits.free) bits.free( &bits );
1922 return ERROR_OUTOFMEMORY;
1924 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1925 if (bits.free) bits.free( &bits );
1926 bits.ptr = ptr;
1927 bits.is_copy = TRUE;
1928 bits.free = free_heap_bits;
1931 if (!err)
1933 /* make x,y relative to the image bits */
1934 x += src.visrect.left - dst.visrect.left;
1935 y += src.visrect.top - dst.visrect.top;
1936 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1937 aa_flags, str, count, dx );
1938 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
1939 if (bits.free) bits.free( &bits );
1940 return !err;
1944 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1945 orig = SelectObject( dev->hdc, pen );
1947 for (i = 0; i < count; i++)
1949 GLYPHMETRICS metrics;
1950 struct gdi_image_bits image;
1952 err = get_glyph_bitmap( dev->hdc, (UINT)str[i], GGO_BITMAP, &metrics, &image );
1953 if (err) continue;
1955 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1956 if (image.free) image.free( &image );
1958 if (dx)
1960 if (flags & ETO_PDY)
1962 x += dx[ i * 2 ];
1963 y += dx[ i * 2 + 1];
1965 else x += dx[ i ];
1967 else
1969 x += metrics.gmCellIncX;
1970 y += metrics.gmCellIncY;
1974 SelectObject( dev->hdc, orig );
1975 DeleteObject( pen );
1976 return TRUE;
1980 /***********************************************************************
1981 * ExtTextOutA (GDI32.@)
1983 * See ExtTextOutW.
1985 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1986 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1988 INT wlen;
1989 UINT codepage;
1990 LPWSTR p;
1991 BOOL ret;
1992 LPINT lpDxW = NULL;
1994 if (flags & ETO_GLYPH_INDEX)
1995 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1997 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1999 if (lpDx) {
2000 unsigned int i = 0, j = 0;
2002 /* allocate enough for a ETO_PDY */
2003 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2004 while(i < count) {
2005 if(IsDBCSLeadByteEx(codepage, str[i]))
2007 if(flags & ETO_PDY)
2009 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2010 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2012 else
2013 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2014 i = i + 2;
2016 else
2018 if(flags & ETO_PDY)
2020 lpDxW[j++] = lpDx[i * 2];
2021 lpDxW[j++] = lpDx[i * 2 + 1];
2023 else
2024 lpDxW[j++] = lpDx[i];
2025 i = i + 1;
2030 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2032 HeapFree( GetProcessHeap(), 0, p );
2033 HeapFree( GetProcessHeap(), 0, lpDxW );
2034 return ret;
2038 /***********************************************************************
2039 * ExtTextOutW (GDI32.@)
2041 * Draws text using the currently selected font, background color, and text color.
2044 * PARAMS
2045 * x,y [I] coordinates of string
2046 * flags [I]
2047 * ETO_GRAYED - undocumented on MSDN
2048 * ETO_OPAQUE - use background color for fill the rectangle
2049 * ETO_CLIPPED - clipping text to the rectangle
2050 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2051 * than encoded characters. Implies ETO_IGNORELANGUAGE
2052 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2053 * Affects BiDi ordering
2054 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2055 * ETO_PDY - unimplemented
2056 * ETO_NUMERICSLATIN - unimplemented always assumed -
2057 * do not translate numbers into locale representations
2058 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2059 * lprect [I] dimensions for clipping or/and opaquing
2060 * str [I] text string
2061 * count [I] number of symbols in string
2062 * lpDx [I] optional parameter with distance between drawing characters
2064 * RETURNS
2065 * Success: TRUE
2066 * Failure: FALSE
2068 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2069 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2071 BOOL ret = FALSE;
2072 LPWSTR reordered_str = (LPWSTR)str;
2073 WORD *glyphs = NULL;
2074 UINT align = GetTextAlign( hdc );
2075 DWORD layout = GetLayout( hdc );
2076 POINT pt;
2077 TEXTMETRICW tm;
2078 LOGFONTW lf;
2079 double cosEsc, sinEsc;
2080 INT char_extra;
2081 SIZE sz;
2082 RECT rc;
2083 BOOL done_extents = FALSE;
2084 POINT *deltas = NULL, width = {0, 0};
2085 DWORD type;
2086 DC * dc = get_dc_ptr( hdc );
2087 PHYSDEV physdev;
2088 INT breakRem;
2089 static int quietfixme = 0;
2091 if (!dc) return FALSE;
2093 breakRem = dc->breakRem;
2095 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2097 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2098 quietfixme = 1;
2101 update_dc( dc );
2102 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2103 type = GetObjectType(hdc);
2104 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2106 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2107 release_dc_ptr( dc );
2108 return ret;
2111 if (!lprect)
2112 flags &= ~ETO_CLIPPED;
2114 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2115 if (layout & LAYOUT_RTL)
2117 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2118 align ^= TA_RTLREADING;
2121 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2123 INT cGlyphs;
2124 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2126 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2127 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2128 reordered_str, count, NULL, &glyphs, &cGlyphs);
2130 flags |= ETO_IGNORELANGUAGE;
2131 if (glyphs)
2133 flags |= ETO_GLYPH_INDEX;
2134 if (cGlyphs != count)
2135 count = cGlyphs;
2138 else if(flags & ETO_GLYPH_INDEX)
2139 glyphs = reordered_str;
2141 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2142 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2143 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2145 if(align & TA_UPDATECP)
2147 GetCurrentPositionEx( hdc, &pt );
2148 x = pt.x;
2149 y = pt.y;
2152 GetTextMetricsW(hdc, &tm);
2153 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2155 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2156 lf.lfEscapement = 0;
2158 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
2159 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
2161 lf.lfEscapement = -lf.lfEscapement;
2164 if(lf.lfEscapement != 0)
2166 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2167 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2169 else
2171 cosEsc = 1;
2172 sinEsc = 0;
2175 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
2177 if(!lprect)
2179 if(flags & ETO_GLYPH_INDEX)
2180 GetTextExtentPointI(hdc, glyphs, count, &sz);
2181 else
2182 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2184 done_extents = TRUE;
2185 rc.left = x;
2186 rc.top = y;
2187 rc.right = x + sz.cx;
2188 rc.bottom = y + sz.cy;
2190 else
2192 rc = *lprect;
2195 LPtoDP(hdc, (POINT*)&rc, 2);
2197 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
2198 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
2201 if (lprect && (flags & ETO_OPAQUE))
2202 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2204 if(count == 0)
2206 ret = TRUE;
2207 goto done;
2210 pt.x = x;
2211 pt.y = y;
2212 LPtoDP(hdc, &pt, 1);
2213 x = pt.x;
2214 y = pt.y;
2216 char_extra = GetTextCharacterExtra(hdc);
2217 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2219 UINT i;
2220 SIZE tmpsz;
2221 POINT total = {0, 0}, desired[2];
2223 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2224 for(i = 0; i < count; i++)
2226 if(lpDx)
2228 if(flags & ETO_PDY)
2230 deltas[i].x = lpDx[i * 2] + char_extra;
2231 deltas[i].y = -lpDx[i * 2 + 1];
2233 else
2235 deltas[i].x = lpDx[i] + char_extra;
2236 deltas[i].y = 0;
2240 else
2242 if(flags & ETO_GLYPH_INDEX)
2243 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2244 else
2245 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2247 deltas[i].x = tmpsz.cx;
2248 deltas[i].y = 0;
2251 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2253 deltas[i].x = deltas[i].x + dc->breakExtra;
2254 if (breakRem > 0)
2256 breakRem--;
2257 deltas[i].x++;
2260 total.x += deltas[i].x;
2261 total.y += deltas[i].y;
2263 desired[0].x = desired[0].y = 0;
2265 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2266 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2268 LPtoDP(hdc, desired, 2);
2269 desired[1].x -= desired[0].x;
2270 desired[1].y -= desired[0].y;
2272 if (dc->GraphicsMode == GM_COMPATIBLE)
2274 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
2275 desired[1].x = -desired[1].x;
2276 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
2277 desired[1].y = -desired[1].y;
2279 else
2281 if (layout & LAYOUT_RTL) desired[1].x = -desired[1].x;
2284 deltas[i].x = desired[1].x - width.x;
2285 deltas[i].y = desired[1].y - width.y;
2287 width = desired[1];
2289 flags |= ETO_PDY;
2291 else
2293 if(!done_extents)
2295 if(flags & ETO_GLYPH_INDEX)
2296 GetTextExtentPointI(hdc, glyphs, count, &sz);
2297 else
2298 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2299 done_extents = TRUE;
2301 width.x = abs(INTERNAL_XWSTODS(dc, sz.cx));
2302 width.y = 0;
2305 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2306 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2307 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2309 case TA_LEFT:
2310 if (align & TA_UPDATECP)
2312 pt.x = x + width.x;
2313 pt.y = y + width.y;
2314 DPtoLP(hdc, &pt, 1);
2315 MoveToEx(hdc, pt.x, pt.y, NULL);
2317 break;
2319 case TA_CENTER:
2320 x -= width.x / 2;
2321 y -= width.y / 2;
2322 break;
2324 case TA_RIGHT:
2325 x -= width.x;
2326 y -= width.y;
2327 if (align & TA_UPDATECP)
2329 pt.x = x;
2330 pt.y = y;
2331 DPtoLP(hdc, &pt, 1);
2332 MoveToEx(hdc, pt.x, pt.y, NULL);
2334 break;
2337 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2339 case TA_TOP:
2340 y += tm.tmAscent * cosEsc;
2341 x += tm.tmAscent * sinEsc;
2342 break;
2344 case TA_BOTTOM:
2345 y -= tm.tmDescent * cosEsc;
2346 x -= tm.tmDescent * sinEsc;
2347 break;
2349 case TA_BASELINE:
2350 break;
2353 if (GetBkMode(hdc) != TRANSPARENT)
2355 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2357 if(!(flags & ETO_OPAQUE) || !lprect ||
2358 x < rc.left || x + width.x >= rc.right ||
2359 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2361 RECT text_box;
2362 text_box.left = x;
2363 text_box.right = x + width.x;
2364 text_box.top = y - tm.tmAscent;
2365 text_box.bottom = y + tm.tmDescent;
2367 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
2368 if (!is_rect_empty( &text_box ))
2369 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2374 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
2376 HFONT orig_font = dc->hFont, cur_font;
2377 UINT glyph;
2378 INT span = 0;
2379 POINT *offsets = NULL;
2380 unsigned int i;
2382 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2383 for(i = 0; i < count; i++)
2385 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
2386 if(cur_font != dc->hFont)
2388 if(!offsets)
2390 unsigned int j;
2391 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2392 offsets[0].x = offsets[0].y = 0;
2394 if(!deltas)
2396 SIZE tmpsz;
2397 for(j = 1; j < count; j++)
2399 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
2400 offsets[j].x = offsets[j - 1].x + abs(INTERNAL_XWSTODS(dc, tmpsz.cx));
2401 offsets[j].y = 0;
2404 else
2406 for(j = 1; j < count; j++)
2408 offsets[j].x = offsets[j - 1].x + deltas[j].x;
2409 offsets[j].y = offsets[j - 1].y + deltas[j].y;
2413 if(span)
2415 physdev->funcs->pExtTextOut( physdev, x + offsets[i - span].x,
2416 y + offsets[i - span].y,
2417 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
2418 span, deltas ? (INT*)(deltas + (i - span)) : NULL);
2419 span = 0;
2421 SelectObject(hdc, cur_font);
2423 glyphs[span++] = glyph;
2425 if(i == count - 1)
2427 ret = physdev->funcs->pExtTextOut(physdev, x + (offsets ? offsets[count - span].x : 0),
2428 y + (offsets ? offsets[count - span].y : 0),
2429 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
2430 span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2431 SelectObject(hdc, orig_font);
2432 HeapFree(GetProcessHeap(), 0, offsets);
2436 else
2438 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2440 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2441 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2442 flags |= ETO_GLYPH_INDEX;
2444 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2445 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2448 done:
2449 HeapFree(GetProcessHeap(), 0, deltas);
2450 if(glyphs != reordered_str)
2451 HeapFree(GetProcessHeap(), 0, glyphs);
2452 if(reordered_str != str)
2453 HeapFree(GetProcessHeap(), 0, reordered_str);
2455 release_dc_ptr( dc );
2457 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2459 int underlinePos, strikeoutPos;
2460 int underlineWidth, strikeoutWidth;
2461 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2462 OUTLINETEXTMETRICW* otm = NULL;
2463 POINT pts[5];
2464 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2465 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2467 hbrush = SelectObject(hdc, hbrush);
2469 if(!size)
2471 underlinePos = 0;
2472 underlineWidth = tm.tmAscent / 20 + 1;
2473 strikeoutPos = tm.tmAscent / 2;
2474 strikeoutWidth = underlineWidth;
2476 else
2478 otm = HeapAlloc(GetProcessHeap(), 0, size);
2479 GetOutlineTextMetricsW(hdc, size, otm);
2480 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2481 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2482 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2483 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2484 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2485 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2486 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2487 HeapFree(GetProcessHeap(), 0, otm);
2491 if (lf.lfUnderline)
2493 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2494 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2495 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2496 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2497 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2498 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2499 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2500 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2501 pts[4].x = pts[0].x;
2502 pts[4].y = pts[0].y;
2503 DPtoLP(hdc, pts, 5);
2504 Polygon(hdc, pts, 5);
2507 if (lf.lfStrikeOut)
2509 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2510 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2511 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2512 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2513 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2514 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2515 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2516 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2517 pts[4].x = pts[0].x;
2518 pts[4].y = pts[0].y;
2519 DPtoLP(hdc, pts, 5);
2520 Polygon(hdc, pts, 5);
2523 SelectObject(hdc, hpen);
2524 hbrush = SelectObject(hdc, hbrush);
2525 DeleteObject(hbrush);
2528 return ret;
2532 /***********************************************************************
2533 * TextOutA (GDI32.@)
2535 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2537 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2541 /***********************************************************************
2542 * TextOutW (GDI32.@)
2544 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2546 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2550 /***********************************************************************
2551 * PolyTextOutA (GDI32.@)
2553 * See PolyTextOutW.
2555 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2557 for (; cStrings>0; cStrings--, pptxt++)
2558 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2559 return FALSE;
2560 return TRUE;
2565 /***********************************************************************
2566 * PolyTextOutW (GDI32.@)
2568 * Draw several Strings
2570 * RETURNS
2571 * TRUE: Success.
2572 * FALSE: Failure.
2574 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2576 for (; cStrings>0; cStrings--, pptxt++)
2577 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2578 return FALSE;
2579 return TRUE;
2583 /***********************************************************************
2584 * SetMapperFlags (GDI32.@)
2586 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2588 DC *dc = get_dc_ptr( hdc );
2589 DWORD ret = GDI_ERROR;
2591 if (dc)
2593 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2594 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2595 if (flags != GDI_ERROR)
2597 ret = dc->mapperFlags;
2598 dc->mapperFlags = flags;
2600 release_dc_ptr( dc );
2602 return ret;
2605 /***********************************************************************
2606 * GetAspectRatioFilterEx (GDI32.@)
2608 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2610 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2611 return FALSE;
2615 /***********************************************************************
2616 * GetCharABCWidthsA (GDI32.@)
2618 * See GetCharABCWidthsW.
2620 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2621 LPABC abc )
2623 INT i, wlen;
2624 LPSTR str;
2625 LPWSTR wstr;
2626 BOOL ret = TRUE;
2628 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2629 if (str == NULL)
2630 return FALSE;
2632 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2633 if (wstr == NULL)
2635 HeapFree(GetProcessHeap(), 0, str);
2636 return FALSE;
2639 for(i = 0; i < wlen; i++)
2641 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2643 ret = FALSE;
2644 break;
2646 abc++;
2649 HeapFree(GetProcessHeap(), 0, str);
2650 HeapFree(GetProcessHeap(), 0, wstr);
2652 return ret;
2656 /******************************************************************************
2657 * GetCharABCWidthsW [GDI32.@]
2659 * Retrieves widths of characters in range.
2661 * PARAMS
2662 * hdc [I] Handle of device context
2663 * firstChar [I] First character in range to query
2664 * lastChar [I] Last character in range to query
2665 * abc [O] Address of character-width structure
2667 * NOTES
2668 * Only works with TrueType fonts
2670 * RETURNS
2671 * Success: TRUE
2672 * Failure: FALSE
2674 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2675 LPABC abc )
2677 DC *dc = get_dc_ptr(hdc);
2678 PHYSDEV dev;
2679 unsigned int i;
2680 BOOL ret;
2681 TEXTMETRICW tm;
2683 if (!dc) return FALSE;
2685 if (!abc)
2687 release_dc_ptr( dc );
2688 return FALSE;
2691 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2692 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2693 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
2695 release_dc_ptr( dc );
2696 return FALSE;
2699 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2700 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2701 if (ret)
2703 /* convert device units to logical */
2704 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2705 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2706 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2707 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2711 release_dc_ptr( dc );
2712 return ret;
2716 /******************************************************************************
2717 * GetCharABCWidthsI [GDI32.@]
2719 * Retrieves widths of characters in range.
2721 * PARAMS
2722 * hdc [I] Handle of device context
2723 * firstChar [I] First glyphs in range to query
2724 * count [I] Last glyphs in range to query
2725 * pgi [i] Array of glyphs to query
2726 * abc [O] Address of character-width structure
2728 * NOTES
2729 * Only works with TrueType fonts
2731 * RETURNS
2732 * Success: TRUE
2733 * Failure: FALSE
2735 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2736 LPWORD pgi, LPABC abc)
2738 DC *dc = get_dc_ptr(hdc);
2739 PHYSDEV dev;
2740 unsigned int i;
2741 BOOL ret;
2743 if (!dc) return FALSE;
2745 if (!abc)
2747 release_dc_ptr( dc );
2748 return FALSE;
2751 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2752 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2753 if (ret)
2755 /* convert device units to logical */
2756 for( i = 0; i < count; i++, abc++ ) {
2757 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2758 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2759 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2763 release_dc_ptr( dc );
2764 return ret;
2768 /***********************************************************************
2769 * GetGlyphOutlineA (GDI32.@)
2771 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2772 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2773 LPVOID lpBuffer, const MAT2 *lpmat2 )
2775 if (!lpmat2) return GDI_ERROR;
2777 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2778 UINT cp;
2779 int len;
2780 char mbchs[2];
2782 cp = GdiGetCodePage(hdc);
2783 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2784 len = 2;
2785 mbchs[0] = (uChar & 0xff00) >> 8;
2786 mbchs[1] = (uChar & 0xff);
2787 } else {
2788 len = 1;
2789 mbchs[0] = (uChar & 0xff);
2791 uChar = 0;
2792 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2795 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2796 lpmat2);
2799 /***********************************************************************
2800 * GetGlyphOutlineW (GDI32.@)
2802 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2803 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2804 LPVOID lpBuffer, const MAT2 *lpmat2 )
2806 DC *dc;
2807 DWORD ret;
2808 PHYSDEV dev;
2810 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2811 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2813 if (!lpmat2) return GDI_ERROR;
2815 dc = get_dc_ptr(hdc);
2816 if(!dc) return GDI_ERROR;
2818 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2819 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2820 release_dc_ptr( dc );
2821 return ret;
2825 /***********************************************************************
2826 * CreateScalableFontResourceA (GDI32.@)
2828 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2829 LPCSTR lpszResourceFile,
2830 LPCSTR lpszFontFile,
2831 LPCSTR lpszCurrentPath )
2833 LPWSTR lpszResourceFileW = NULL;
2834 LPWSTR lpszFontFileW = NULL;
2835 LPWSTR lpszCurrentPathW = NULL;
2836 int len;
2837 BOOL ret;
2839 if (lpszResourceFile)
2841 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2842 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2843 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2846 if (lpszFontFile)
2848 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2849 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2850 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2853 if (lpszCurrentPath)
2855 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2856 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2857 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2860 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2861 lpszFontFileW, lpszCurrentPathW);
2863 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2864 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2865 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2867 return ret;
2870 /***********************************************************************
2871 * CreateScalableFontResourceW (GDI32.@)
2873 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
2874 LPCWSTR font_file, LPCWSTR font_path )
2876 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
2877 debugstr_w(font_file), debugstr_w(font_path) );
2879 return WineEngCreateScalableFontResource( hidden, resource_file,
2880 font_file, font_path );
2883 /*************************************************************************
2884 * GetKerningPairsA (GDI32.@)
2886 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2887 LPKERNINGPAIR kern_pairA )
2889 UINT cp;
2890 CPINFO cpi;
2891 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2892 KERNINGPAIR *kern_pairW;
2894 if (!cPairs && kern_pairA)
2896 SetLastError(ERROR_INVALID_PARAMETER);
2897 return 0;
2900 cp = GdiGetCodePage(hDC);
2902 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2903 * to fail on an invalid character for CP_SYMBOL.
2905 cpi.DefaultChar[0] = 0;
2906 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2908 FIXME("Can't find codepage %u info\n", cp);
2909 return 0;
2912 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2913 if (!total_kern_pairs) return 0;
2915 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2916 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2918 for (i = 0; i < total_kern_pairs; i++)
2920 char first, second;
2922 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2923 continue;
2925 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2926 continue;
2928 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2929 continue;
2931 if (kern_pairA)
2933 if (kern_pairs_copied >= cPairs) break;
2935 kern_pairA->wFirst = (BYTE)first;
2936 kern_pairA->wSecond = (BYTE)second;
2937 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2938 kern_pairA++;
2940 kern_pairs_copied++;
2943 HeapFree(GetProcessHeap(), 0, kern_pairW);
2945 return kern_pairs_copied;
2948 /*************************************************************************
2949 * GetKerningPairsW (GDI32.@)
2951 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2952 LPKERNINGPAIR lpKerningPairs )
2954 DC *dc;
2955 DWORD ret;
2956 PHYSDEV dev;
2958 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2960 if (!cPairs && lpKerningPairs)
2962 SetLastError(ERROR_INVALID_PARAMETER);
2963 return 0;
2966 dc = get_dc_ptr(hDC);
2967 if (!dc) return 0;
2969 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2970 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2971 release_dc_ptr( dc );
2972 return ret;
2975 /*************************************************************************
2976 * TranslateCharsetInfo [GDI32.@]
2978 * Fills a CHARSETINFO structure for a character set, code page, or
2979 * font. This allows making the correspondence between different labels
2980 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2981 * of the same encoding.
2983 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2984 * only one codepage should be set in *lpSrc.
2986 * RETURNS
2987 * TRUE on success, FALSE on failure.
2990 BOOL WINAPI TranslateCharsetInfo(
2991 LPDWORD lpSrc, /* [in]
2992 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2993 if flags == TCI_SRCCHARSET: a character set value
2994 if flags == TCI_SRCCODEPAGE: a code page value
2996 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2997 DWORD flags /* [in] determines interpretation of lpSrc */)
2999 int index = 0;
3000 switch (flags) {
3001 case TCI_SRCFONTSIG:
3002 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3003 break;
3004 case TCI_SRCCODEPAGE:
3005 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3006 break;
3007 case TCI_SRCCHARSET:
3008 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3009 break;
3010 default:
3011 return FALSE;
3013 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3014 *lpCs = FONT_tci[index];
3015 return TRUE;
3018 /*************************************************************************
3019 * GetFontLanguageInfo (GDI32.@)
3021 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3023 FONTSIGNATURE fontsig;
3024 static const DWORD GCP_DBCS_MASK=0x003F0000,
3025 GCP_DIACRITIC_MASK=0x00000000,
3026 FLI_GLYPHS_MASK=0x00000000,
3027 GCP_GLYPHSHAPE_MASK=0x00000040,
3028 GCP_KASHIDA_MASK=0x00000000,
3029 GCP_LIGATE_MASK=0x00000000,
3030 GCP_USEKERNING_MASK=0x00000000,
3031 GCP_REORDER_MASK=0x00000060;
3033 DWORD result=0;
3035 GetTextCharsetInfo( hdc, &fontsig, 0 );
3036 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3038 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3039 result|=GCP_DBCS;
3041 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3042 result|=GCP_DIACRITIC;
3044 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3045 result|=FLI_GLYPHS;
3047 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3048 result|=GCP_GLYPHSHAPE;
3050 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3051 result|=GCP_KASHIDA;
3053 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3054 result|=GCP_LIGATE;
3056 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3057 result|=GCP_USEKERNING;
3059 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3060 if( GetTextAlign( hdc) & TA_RTLREADING )
3061 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3062 result|=GCP_REORDER;
3064 return result;
3068 /*************************************************************************
3069 * GetFontData [GDI32.@]
3071 * Retrieve data for TrueType font.
3073 * RETURNS
3075 * success: Number of bytes returned
3076 * failure: GDI_ERROR
3078 * NOTES
3080 * Calls SetLastError()
3083 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3084 LPVOID buffer, DWORD length)
3086 DC *dc = get_dc_ptr(hdc);
3087 PHYSDEV dev;
3088 DWORD ret;
3090 if(!dc) return GDI_ERROR;
3092 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3093 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3094 release_dc_ptr( dc );
3095 return ret;
3098 /*************************************************************************
3099 * GetGlyphIndicesA [GDI32.@]
3101 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3102 LPWORD pgi, DWORD flags)
3104 DWORD ret;
3105 WCHAR *lpstrW;
3106 INT countW;
3108 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3109 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3111 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3112 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3113 HeapFree(GetProcessHeap(), 0, lpstrW);
3115 return ret;
3118 /*************************************************************************
3119 * GetGlyphIndicesW [GDI32.@]
3121 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3122 LPWORD pgi, DWORD flags)
3124 DC *dc = get_dc_ptr(hdc);
3125 PHYSDEV dev;
3126 DWORD ret;
3128 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3129 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3131 if(!dc) return GDI_ERROR;
3133 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3134 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3135 release_dc_ptr( dc );
3136 return ret;
3139 /*************************************************************************
3140 * GetCharacterPlacementA [GDI32.@]
3142 * See GetCharacterPlacementW.
3144 * NOTES:
3145 * the web browser control of ie4 calls this with dwFlags=0
3147 DWORD WINAPI
3148 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3149 INT nMaxExtent, GCP_RESULTSA *lpResults,
3150 DWORD dwFlags)
3152 WCHAR *lpStringW;
3153 INT uCountW;
3154 GCP_RESULTSW resultsW;
3155 DWORD ret;
3156 UINT font_cp;
3158 TRACE("%s, %d, %d, 0x%08x\n",
3159 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3161 /* both structs are equal in size */
3162 memcpy(&resultsW, lpResults, sizeof(resultsW));
3164 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3165 if(lpResults->lpOutString)
3166 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3168 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3170 lpResults->nGlyphs = resultsW.nGlyphs;
3171 lpResults->nMaxFit = resultsW.nMaxFit;
3173 if(lpResults->lpOutString) {
3174 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3175 lpResults->lpOutString, uCount, NULL, NULL );
3178 HeapFree(GetProcessHeap(), 0, lpStringW);
3179 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3181 return ret;
3184 /*************************************************************************
3185 * GetCharacterPlacementW [GDI32.@]
3187 * Retrieve information about a string. This includes the width, reordering,
3188 * Glyphing and so on.
3190 * RETURNS
3192 * The width and height of the string if successful, 0 if failed.
3194 * BUGS
3196 * All flags except GCP_REORDER are not yet implemented.
3197 * Reordering is not 100% compliant to the Windows BiDi method.
3198 * Caret positioning is not yet implemented for BiDi.
3199 * Classes are not yet implemented.
3202 DWORD WINAPI
3203 GetCharacterPlacementW(
3204 HDC hdc, /* [in] Device context for which the rendering is to be done */
3205 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3206 INT uCount, /* [in] Number of WORDS in string. */
3207 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3208 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
3209 DWORD dwFlags /* [in] Flags specifying how to process the string */
3212 DWORD ret=0;
3213 SIZE size;
3214 UINT i, nSet;
3216 TRACE("%s, %d, %d, 0x%08x\n",
3217 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3219 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3220 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3221 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3222 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3223 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3225 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
3226 if(lpResults->lpClass) FIXME("classes not implemented\n");
3227 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3228 FIXME("Caret positions for complex scripts not implemented\n");
3230 nSet = (UINT)uCount;
3231 if(nSet > lpResults->nGlyphs)
3232 nSet = lpResults->nGlyphs;
3234 /* return number of initialized fields */
3235 lpResults->nGlyphs = nSet;
3237 if((dwFlags&GCP_REORDER)==0 )
3239 /* Treat the case where no special handling was requested in a fastpath way */
3240 /* copy will do if the GCP_REORDER flag is not set */
3241 if(lpResults->lpOutString)
3242 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3244 if(lpResults->lpOrder)
3246 for(i = 0; i < nSet; i++)
3247 lpResults->lpOrder[i] = i;
3249 } else
3251 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3252 nSet, lpResults->lpOrder, NULL, NULL );
3255 /* FIXME: Will use the placement chars */
3256 if (lpResults->lpDx)
3258 int c;
3259 for (i = 0; i < nSet; i++)
3261 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3262 lpResults->lpDx[i]= c;
3266 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3268 int pos = 0;
3270 lpResults->lpCaretPos[0] = 0;
3271 for (i = 1; i < nSet; i++)
3272 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3273 lpResults->lpCaretPos[i] = (pos += size.cx);
3276 if(lpResults->lpGlyphs)
3277 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3279 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3280 ret = MAKELONG(size.cx, size.cy);
3282 return ret;
3285 /*************************************************************************
3286 * GetCharABCWidthsFloatA [GDI32.@]
3288 * See GetCharABCWidthsFloatW.
3290 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3292 INT i, wlen;
3293 LPSTR str;
3294 LPWSTR wstr;
3295 BOOL ret = TRUE;
3297 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3298 if (str == NULL)
3299 return FALSE;
3301 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3303 for (i = 0; i < wlen; i++)
3305 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3307 ret = FALSE;
3308 break;
3310 abcf++;
3313 HeapFree( GetProcessHeap(), 0, str );
3314 HeapFree( GetProcessHeap(), 0, wstr );
3316 return ret;
3319 /*************************************************************************
3320 * GetCharABCWidthsFloatW [GDI32.@]
3322 * Retrieves widths of a range of characters.
3324 * PARAMS
3325 * hdc [I] Handle to device context.
3326 * first [I] First character in range to query.
3327 * last [I] Last character in range to query.
3328 * abcf [O] Array of LPABCFLOAT structures.
3330 * RETURNS
3331 * Success: TRUE
3332 * Failure: FALSE
3334 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3336 UINT i;
3337 ABC *abc;
3338 PHYSDEV dev;
3339 BOOL ret = FALSE;
3340 DC *dc = get_dc_ptr( hdc );
3342 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3344 if (!dc) return FALSE;
3346 if (!abcf) goto done;
3347 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3349 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3350 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3351 if (ret)
3353 /* convert device units to logical */
3354 for (i = first; i <= last; i++, abcf++)
3356 abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
3357 abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
3358 abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3361 HeapFree( GetProcessHeap(), 0, abc );
3363 done:
3364 release_dc_ptr( dc );
3365 return ret;
3368 /*************************************************************************
3369 * GetCharWidthFloatA [GDI32.@]
3371 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3372 UINT iLastChar, PFLOAT pxBuffer)
3374 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3375 return 0;
3378 /*************************************************************************
3379 * GetCharWidthFloatW [GDI32.@]
3381 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3382 UINT iLastChar, PFLOAT pxBuffer)
3384 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3385 return 0;
3389 /***********************************************************************
3391 * Font Resource API *
3393 ***********************************************************************/
3395 /***********************************************************************
3396 * AddFontResourceA (GDI32.@)
3398 INT WINAPI AddFontResourceA( LPCSTR str )
3400 return AddFontResourceExA( str, 0, NULL);
3403 /***********************************************************************
3404 * AddFontResourceW (GDI32.@)
3406 INT WINAPI AddFontResourceW( LPCWSTR str )
3408 return AddFontResourceExW(str, 0, NULL);
3412 /***********************************************************************
3413 * AddFontResourceExA (GDI32.@)
3415 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3417 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3418 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3419 INT ret;
3421 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3422 ret = AddFontResourceExW(strW, fl, pdv);
3423 HeapFree(GetProcessHeap(), 0, strW);
3424 return ret;
3427 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3429 HRSRC rsrc = FindResourceW(hModule, name, type);
3430 HGLOBAL hMem = LoadResource(hModule, rsrc);
3431 LPVOID *pMem = LockResource(hMem);
3432 int *num_total = (int *)lParam;
3433 DWORD num_in_res;
3435 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3436 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3438 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3439 return FALSE;
3442 *num_total += num_in_res;
3443 return TRUE;
3446 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
3448 HANDLE file, mapping;
3449 void *ptr;
3451 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
3452 if (file == INVALID_HANDLE_VALUE) return NULL;
3454 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
3456 CloseHandle( file );
3457 return NULL;
3460 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
3461 CloseHandle( file );
3462 if (!mapping) return NULL;
3464 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3465 CloseHandle( mapping );
3467 return ptr;
3470 static WCHAR *get_scalable_filename( const WCHAR *res )
3472 LARGE_INTEGER size;
3473 BYTE *ptr = map_file( res, &size );
3474 const IMAGE_DOS_HEADER *dos;
3475 const IMAGE_OS2_HEADER *ne;
3476 WCHAR *name = NULL;
3477 WORD rsrc_off, align, type_id, count;
3478 DWORD res_off, res_len, i;
3479 int len;
3481 if (!ptr) return NULL;
3483 if (size.u.LowPart < sizeof( *dos )) goto fail;
3484 dos = (const IMAGE_DOS_HEADER *)ptr;
3485 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
3486 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
3487 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
3488 rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
3489 if (size.u.LowPart < rsrc_off + 10) goto fail;
3490 align = *(WORD *)(ptr + rsrc_off);
3491 rsrc_off += 2;
3492 type_id = *(WORD *)(ptr + rsrc_off);
3493 while (type_id && type_id != 0x80cc)
3495 count = *(WORD *)(ptr + rsrc_off + 2);
3496 rsrc_off += 8 + count * 12;
3497 if (size.u.LowPart < rsrc_off + 8) goto fail;
3498 type_id = *(WORD *)(ptr + rsrc_off);
3500 if (!type_id) goto fail;
3501 count = *(WORD *)(ptr + rsrc_off + 2);
3502 if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;
3504 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
3505 res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
3506 if (size.u.LowPart < res_off + res_len) goto fail;
3508 for (i = 0; i < res_len; i++)
3509 if (ptr[ res_off + i ] == 0) break;
3510 if (i == res_len) goto fail;
3512 len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
3513 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3514 if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );
3516 fail:
3517 UnmapViewOfFile( ptr );
3518 return name;
3521 /***********************************************************************
3522 * AddFontResourceExW (GDI32.@)
3524 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3526 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3527 WCHAR *filename;
3529 if (ret == 0)
3531 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3532 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3533 if (hModule != NULL)
3535 int num_resources = 0;
3536 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3538 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3539 wine_dbgstr_w(str));
3540 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3541 ret = num_resources;
3542 FreeLibrary(hModule);
3544 else if ((filename = get_scalable_filename( str )) != NULL)
3546 ret = WineEngAddFontResourceEx( filename, fl, pdv );
3547 HeapFree( GetProcessHeap(), 0, filename );
3550 return ret;
3553 /***********************************************************************
3554 * RemoveFontResourceA (GDI32.@)
3556 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3558 return RemoveFontResourceExA(str, 0, 0);
3561 /***********************************************************************
3562 * RemoveFontResourceW (GDI32.@)
3564 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3566 return RemoveFontResourceExW(str, 0, 0);
3569 /***********************************************************************
3570 * AddFontMemResourceEx (GDI32.@)
3572 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3574 HANDLE ret;
3575 DWORD num_fonts;
3577 if (!pbFont || !cbFont || !pcFonts)
3579 SetLastError(ERROR_INVALID_PARAMETER);
3580 return NULL;
3583 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3584 if (ret)
3586 __TRY
3588 *pcFonts = num_fonts;
3590 __EXCEPT_PAGE_FAULT
3592 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3593 RemoveFontMemResourceEx(ret);
3594 ret = 0;
3596 __ENDTRY
3598 return ret;
3601 /***********************************************************************
3602 * RemoveFontMemResourceEx (GDI32.@)
3604 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3606 FIXME("(%p) stub\n", fh);
3607 return TRUE;
3610 /***********************************************************************
3611 * RemoveFontResourceExA (GDI32.@)
3613 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3615 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3616 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3617 INT ret;
3619 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3620 ret = RemoveFontResourceExW(strW, fl, pdv);
3621 HeapFree(GetProcessHeap(), 0, strW);
3622 return ret;
3625 /***********************************************************************
3626 * RemoveFontResourceExW (GDI32.@)
3628 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3630 return WineEngRemoveFontResourceEx(str, fl, pdv);
3633 /***********************************************************************
3634 * GetTextCharset (GDI32.@)
3636 UINT WINAPI GetTextCharset(HDC hdc)
3638 /* MSDN docs say this is equivalent */
3639 return GetTextCharsetInfo(hdc, NULL, 0);
3642 /***********************************************************************
3643 * GetTextCharsetInfo (GDI32.@)
3645 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3647 UINT ret = DEFAULT_CHARSET;
3648 DC *dc = get_dc_ptr(hdc);
3649 PHYSDEV dev;
3651 if (dc)
3653 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3654 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3655 release_dc_ptr( dc );
3658 if (ret == DEFAULT_CHARSET && fs)
3659 memset(fs, 0, sizeof(FONTSIGNATURE));
3660 return ret;
3663 /***********************************************************************
3664 * GdiGetCharDimensions (GDI32.@)
3666 * Gets the average width of the characters in the English alphabet.
3668 * PARAMS
3669 * hdc [I] Handle to the device context to measure on.
3670 * lptm [O] Pointer to memory to store the text metrics into.
3671 * height [O] On exit, the maximum height of characters in the English alphabet.
3673 * RETURNS
3674 * The average width of characters in the English alphabet.
3676 * NOTES
3677 * This function is used by the dialog manager to get the size of a dialog
3678 * unit. It should also be used by other pieces of code that need to know
3679 * the size of a dialog unit in logical units without having access to the
3680 * window handle of the dialog.
3681 * Windows caches the font metrics from this function, but we don't and
3682 * there doesn't appear to be an immediate advantage to do so.
3684 * SEE ALSO
3685 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3687 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3689 SIZE sz;
3690 static const WCHAR alphabet[] = {
3691 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3692 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3693 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3695 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3697 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3699 if (height) *height = sz.cy;
3700 return (sz.cx / 26 + 1) / 2;
3703 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3705 FIXME("(%d): stub\n", fEnableEUDC);
3706 return FALSE;
3709 /***********************************************************************
3710 * GetCharWidthI (GDI32.@)
3712 * Retrieve widths of characters.
3714 * PARAMS
3715 * hdc [I] Handle to a device context.
3716 * first [I] First glyph in range to query.
3717 * count [I] Number of glyph indices to query.
3718 * glyphs [I] Array of glyphs to query.
3719 * buffer [O] Buffer to receive character widths.
3721 * NOTES
3722 * Only works with TrueType fonts.
3724 * RETURNS
3725 * Success: TRUE
3726 * Failure: FALSE
3728 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3730 ABC *abc;
3731 unsigned int i;
3733 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3735 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3736 return FALSE;
3738 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3740 HeapFree(GetProcessHeap(), 0, abc);
3741 return FALSE;
3744 for (i = 0; i < count; i++)
3745 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3747 HeapFree(GetProcessHeap(), 0, abc);
3748 return TRUE;
3751 /***********************************************************************
3752 * GetFontUnicodeRanges (GDI32.@)
3754 * Retrieve a list of supported Unicode characters in a font.
3756 * PARAMS
3757 * hdc [I] Handle to a device context.
3758 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3760 * RETURNS
3761 * Success: Number of bytes written to the buffer pointed to by lpgs.
3762 * Failure: 0
3765 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3767 DWORD ret;
3768 PHYSDEV dev;
3769 DC *dc = get_dc_ptr(hdc);
3771 TRACE("(%p, %p)\n", hdc, lpgs);
3773 if (!dc) return 0;
3775 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3776 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3777 release_dc_ptr(dc);
3778 return ret;
3782 /*************************************************************
3783 * FontIsLinked (GDI32.@)
3785 BOOL WINAPI FontIsLinked(HDC hdc)
3787 DC *dc = get_dc_ptr(hdc);
3788 PHYSDEV dev;
3789 BOOL ret;
3791 if (!dc) return FALSE;
3792 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3793 ret = dev->funcs->pFontIsLinked( dev );
3794 release_dc_ptr(dc);
3795 TRACE("returning %d\n", ret);
3796 return ret;
3799 /*************************************************************
3800 * GdiRealizationInfo (GDI32.@)
3802 * Returns a structure that contains some font information.
3804 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3806 DC *dc = get_dc_ptr(hdc);
3807 PHYSDEV dev;
3808 BOOL ret;
3810 if (!dc) return FALSE;
3811 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3812 ret = dev->funcs->pGdiRealizationInfo( dev, info );
3813 release_dc_ptr(dc);
3814 return ret;