4 * Copyright 1993 Alexandre Julliard
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
24 #include "wine/port.h"
36 #include "gdi_private.h"
37 #include "wine/exception.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 #ifdef WORDS_BIGENDIAN
42 #define get_be_word(x) (x)
44 #define get_be_word(x) RtlUshortByteSwap(x)
47 WINE_DEFAULT_DEBUG_CHANNEL(font);
49 /* Device -> World size conversion */
51 /* Performs a device to world transformation on the specified width (which
52 * is in integer format).
54 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
58 /* Perform operation with floating point */
59 floatWidth = (double)width * dc->xformVport2World.eM11;
60 /* Round to integers */
61 return GDI_ROUND(floatWidth);
64 /* Performs a device to world transformation on the specified size (which
65 * is in integer format).
67 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
71 /* Perform operation with floating point */
72 floatHeight = (double)height * dc->xformVport2World.eM22;
73 /* Round to integers */
74 return GDI_ROUND(floatHeight);
77 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
80 pt[0].x = pt[0].y = 0;
83 LPtoDP(dc->hSelf, pt, 2);
84 return pt[1].x - pt[0].x;
87 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
90 pt[0].x = pt[0].y = 0;
93 LPtoDP(dc->hSelf, pt, 2);
94 return pt[1].y - pt[0].y;
97 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
98 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
99 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
100 static BOOL FONT_DeleteObject( HGDIOBJ handle );
102 static const struct gdi_obj_funcs font_funcs =
104 FONT_SelectObject, /* pSelectObject */
105 FONT_GetObjectA, /* pGetObjectA */
106 FONT_GetObjectW, /* pGetObjectW */
107 NULL, /* pUnrealizeObject */
108 FONT_DeleteObject /* pDeleteObject */
119 LPLOGFONTW lpLogFontParam;
120 FONTENUMPROCW lpEnumFunc;
127 * For TranslateCharsetInfo
129 #define MAXTCIINDEX 32
130 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
132 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
133 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
134 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
135 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
136 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
137 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
138 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
139 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
140 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
141 /* reserved by ANSI */
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
145 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
146 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
147 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
148 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
150 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
151 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
152 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
153 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
154 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
155 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
156 /* reserved for alternate ANSI and OEM */
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
163 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
164 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
165 /* reserved for system */
166 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
167 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
170 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
172 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
173 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
175 fontW->lfFaceName[LF_FACESIZE-1] = 0;
178 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
180 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
181 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
182 LF_FACESIZE, NULL, NULL);
183 fontA->lfFaceName[LF_FACESIZE-1] = 0;
186 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
188 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
190 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
191 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
192 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
193 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
194 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
195 fontA->elfStyle[LF_FACESIZE-1] = '\0';
196 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
197 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
198 fontA->elfScript[LF_FACESIZE-1] = '\0';
201 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
203 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
205 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
206 fontW->elfFullName, LF_FULLFACESIZE );
207 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
208 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
209 fontW->elfStyle, LF_FACESIZE );
210 fontW->elfStyle[LF_FACESIZE-1] = '\0';
211 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
212 fontW->elfScript, LF_FACESIZE );
213 fontW->elfScript[LF_FACESIZE-1] = '\0';
216 /***********************************************************************
217 * TEXTMETRIC conversion functions.
219 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
221 ptmA->tmHeight = ptmW->tmHeight;
222 ptmA->tmAscent = ptmW->tmAscent;
223 ptmA->tmDescent = ptmW->tmDescent;
224 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
225 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
226 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
227 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
228 ptmA->tmWeight = ptmW->tmWeight;
229 ptmA->tmOverhang = ptmW->tmOverhang;
230 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
231 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
232 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
233 if (ptmW->tmCharSet == SYMBOL_CHARSET)
235 ptmA->tmFirstChar = 0x1e;
236 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
238 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
240 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
241 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
245 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
246 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
248 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
249 ptmA->tmBreakChar = ptmW->tmBreakChar;
250 ptmA->tmItalic = ptmW->tmItalic;
251 ptmA->tmUnderlined = ptmW->tmUnderlined;
252 ptmA->tmStruckOut = ptmW->tmStruckOut;
253 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
254 ptmA->tmCharSet = ptmW->tmCharSet;
258 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
260 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
261 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
262 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
263 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
264 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
265 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
268 static DWORD get_font_ppem( HDC hdc )
272 DC *dc = get_dc_ptr( hdc );
274 if (!dc) return GDI_ERROR;
276 GetTextMetricsW( hdc, &tm );
277 ppem = abs( INTERNAL_YWSTODS( dc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading ) );
278 release_dc_ptr( dc );
282 #define GASP_GRIDFIT 0x01
283 #define GASP_DOGRAY 0x02
285 static BOOL get_gasp_flags( HDC hdc, WORD *flags )
287 DWORD size, gasp_tag = 0x70736167;
288 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
289 WORD *alloced = NULL, *ptr = buf;
290 WORD num_recs, version;
291 DWORD ppem = get_font_ppem( hdc );
295 if (ppem == GDI_ERROR) return FALSE;
297 size = GetFontData( hdc, gasp_tag, 0, NULL, 0 );
298 if (size == GDI_ERROR) return FALSE;
299 if (size < 4 * sizeof(WORD)) return FALSE;
300 if (size > sizeof(buf))
302 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
303 if (!ptr) return FALSE;
306 GetFontData( hdc, gasp_tag, 0, ptr, size );
308 version = get_be_word( *ptr++ );
309 num_recs = get_be_word( *ptr++ );
311 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
313 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
319 *flags = get_be_word( *(ptr + 1) );
320 if (ppem <= get_be_word( *ptr )) break;
323 TRACE( "got flags %04x for ppem %d\n", *flags, ppem );
327 HeapFree( GetProcessHeap(), 0, alloced );
331 UINT get_font_aa_flags( HDC hdc )
336 if (GetObjectType( hdc ) == OBJ_MEMDC)
339 GetObjectW( GetCurrentObject( hdc, OBJ_BITMAP ), sizeof(bm), &bm );
340 if (bm.bmBitsPixel <= 8) return GGO_BITMAP;
342 else if (GetDeviceCaps( hdc, BITSPIXEL ) <= 8) return GGO_BITMAP;
344 GetObjectW( GetCurrentObject( hdc, OBJ_FONT ), sizeof(lf), &lf );
345 if (lf.lfQuality == NONANTIALIASED_QUALITY) return GGO_BITMAP;
347 if (get_gasp_flags( hdc, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
350 /* FIXME, check user prefs */
351 return GGO_GRAY4_BITMAP;
354 /***********************************************************************
355 * GdiGetCodePage (GDI32.@)
357 DWORD WINAPI GdiGetCodePage( HDC hdc )
360 DC *dc = get_dc_ptr( hdc );
364 cp = dc->font_code_page;
365 release_dc_ptr( dc );
370 /***********************************************************************
373 * Returns a Unicode translation of str using the charset of the
374 * currently selected font in hdc. If count is -1 then str is assumed
375 * to be '\0' terminated, otherwise it contains the number of bytes to
376 * convert. If plenW is non-NULL, on return it will point to the
377 * number of WCHARs that have been written. If pCP is non-NULL, on
378 * return it will point to the codepage used in the conversion. The
379 * caller should free the returned LPWSTR from the process heap
382 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
388 cp = GdiGetCodePage( hdc );
390 if(count == -1) count = strlen(str);
391 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
392 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
393 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
394 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
395 if(plenW) *plenW = lenW;
400 /***********************************************************************
401 * CreateFontIndirectExA (GDI32.@)
403 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
405 ENUMLOGFONTEXDVW enumexW;
407 if (!penumexA) return 0;
409 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
410 enumexW.elfDesignVector = penumexA->elfDesignVector;
411 return CreateFontIndirectExW( &enumexW );
414 /***********************************************************************
415 * CreateFontIndirectExW (GDI32.@)
417 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
423 if (!penumex) return 0;
425 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
426 penumex->elfEnumLogfontEx.elfStyle[0] ||
427 penumex->elfEnumLogfontEx.elfScript[0])
429 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
430 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
431 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
432 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
435 plf = &penumex->elfEnumLogfontEx.elfLogFont;
436 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
438 fontPtr->logfont = *plf;
440 if (plf->lfEscapement != plf->lfOrientation)
442 /* this should really depend on whether GM_ADVANCED is set */
443 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
444 WARN("orientation angle %f set to "
445 "escapement angle %f for new font %p\n",
446 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
449 if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs )))
451 HeapFree( GetProcessHeap(), 0, fontPtr );
455 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
456 plf->lfHeight, plf->lfWidth,
457 plf->lfEscapement, plf->lfOrientation,
458 plf->lfPitchAndFamily,
459 plf->lfOutPrecision, plf->lfClipPrecision,
460 plf->lfQuality, plf->lfCharSet,
461 debugstr_w(plf->lfFaceName),
462 plf->lfWeight > 400 ? "Bold" : "",
463 plf->lfItalic ? "Italic" : "",
464 plf->lfUnderline ? "Underline" : "", hFont);
469 /***********************************************************************
470 * CreateFontIndirectA (GDI32.@)
472 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
478 FONT_LogFontAToW( plfA, &lfW );
479 return CreateFontIndirectW( &lfW );
482 /***********************************************************************
483 * CreateFontIndirectW (GDI32.@)
485 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
487 ENUMLOGFONTEXDVW exdv;
491 exdv.elfEnumLogfontEx.elfLogFont = *plf;
492 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
493 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
494 exdv.elfEnumLogfontEx.elfScript[0] = 0;
495 return CreateFontIndirectExW( &exdv );
498 /*************************************************************************
499 * CreateFontA (GDI32.@)
501 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
502 INT orient, INT weight, DWORD italic,
503 DWORD underline, DWORD strikeout, DWORD charset,
504 DWORD outpres, DWORD clippres, DWORD quality,
505 DWORD pitch, LPCSTR name )
509 logfont.lfHeight = height;
510 logfont.lfWidth = width;
511 logfont.lfEscapement = esc;
512 logfont.lfOrientation = orient;
513 logfont.lfWeight = weight;
514 logfont.lfItalic = italic;
515 logfont.lfUnderline = underline;
516 logfont.lfStrikeOut = strikeout;
517 logfont.lfCharSet = charset;
518 logfont.lfOutPrecision = outpres;
519 logfont.lfClipPrecision = clippres;
520 logfont.lfQuality = quality;
521 logfont.lfPitchAndFamily = pitch;
524 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
526 logfont.lfFaceName[0] = '\0';
528 return CreateFontIndirectA( &logfont );
531 /*************************************************************************
532 * CreateFontW (GDI32.@)
534 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
535 INT orient, INT weight, DWORD italic,
536 DWORD underline, DWORD strikeout, DWORD charset,
537 DWORD outpres, DWORD clippres, DWORD quality,
538 DWORD pitch, LPCWSTR name )
542 logfont.lfHeight = height;
543 logfont.lfWidth = width;
544 logfont.lfEscapement = esc;
545 logfont.lfOrientation = orient;
546 logfont.lfWeight = weight;
547 logfont.lfItalic = italic;
548 logfont.lfUnderline = underline;
549 logfont.lfStrikeOut = strikeout;
550 logfont.lfCharSet = charset;
551 logfont.lfOutPrecision = outpres;
552 logfont.lfClipPrecision = clippres;
553 logfont.lfQuality = quality;
554 logfont.lfPitchAndFamily = pitch;
557 lstrcpynW(logfont.lfFaceName, name,
558 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
560 logfont.lfFaceName[0] = '\0';
562 return CreateFontIndirectW( &logfont );
565 static void update_font_code_page( DC *dc )
568 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
570 /* Hmm, nicely designed api this one! */
571 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
572 dc->font_code_page = csi.ciACP;
576 dc->font_code_page = GetOEMCP();
578 case DEFAULT_CHARSET:
579 dc->font_code_page = GetACP();
589 /* FIXME: These have no place here, but because x11drv
590 enumerates fonts with these (made up) charsets some apps
591 might use them and then the FIXME below would become
592 annoying. Now we could pick the intended codepage for
593 each of these, but since it's broken anyway we'll just
594 use CP_ACP and hope it'll go away...
596 dc->font_code_page = CP_ACP;
600 FIXME("Can't find codepage for charset %d\n", charset);
601 dc->font_code_page = CP_ACP;
606 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
609 /***********************************************************************
612 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
615 DC *dc = get_dc_ptr( hdc );
620 if (!GDI_inc_ref_count( handle ))
622 release_dc_ptr( dc );
626 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
627 if (physdev->funcs->pSelectFont( physdev, handle ))
631 update_font_code_page( dc );
632 GDI_dec_ref_count( ret );
634 else GDI_dec_ref_count( handle );
636 release_dc_ptr( dc );
641 /***********************************************************************
644 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
646 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
652 FONT_LogFontWToA( &font->logfont, &lfA );
653 if (count > sizeof(lfA)) count = sizeof(lfA);
654 memcpy( buffer, &lfA, count );
656 else count = sizeof(lfA);
657 GDI_ReleaseObj( handle );
661 /***********************************************************************
664 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
666 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
671 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
672 memcpy( buffer, &font->logfont, count );
674 else count = sizeof(LOGFONTW);
675 GDI_ReleaseObj( handle );
680 /***********************************************************************
683 static BOOL FONT_DeleteObject( HGDIOBJ handle )
687 WineEngDestroyFontInstance( handle );
689 if (!(obj = free_gdi_handle( handle ))) return FALSE;
690 return HeapFree( GetProcessHeap(), 0, obj );
694 /***********************************************************************
697 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
698 * We have to use other types because of the FONTENUMPROCW definition.
700 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
701 DWORD fType, LPARAM lp )
703 struct font_enum *pfe = (struct font_enum *)lp;
706 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
707 if ((!pfe->lpLogFontParam ||
708 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
709 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
710 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
712 /* convert font metrics */
713 ENUMLOGFONTEXA logfont;
714 NEWTEXTMETRICEXA tmA;
718 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
719 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
720 plf = (LOGFONTW *)&logfont.elfLogFont;
721 ptm = (TEXTMETRICW *)&tmA;
723 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
728 /***********************************************************************
729 * FONT_EnumFontFamiliesEx
731 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
732 LPARAM lParam, BOOL unicode )
735 DC *dc = get_dc_ptr( hDC );
740 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
742 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
743 fe.lpLogFontParam = plf;
744 fe.lpEnumFunc = efproc;
746 fe.unicode = unicode;
748 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
749 release_dc_ptr( dc );
754 /***********************************************************************
755 * EnumFontFamiliesExW (GDI32.@)
757 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
758 FONTENUMPROCW efproc,
759 LPARAM lParam, DWORD dwFlags )
761 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
764 /***********************************************************************
765 * EnumFontFamiliesExA (GDI32.@)
767 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
768 FONTENUMPROCA efproc,
769 LPARAM lParam, DWORD dwFlags)
775 FONT_LogFontAToW( plf, &lfW );
780 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
783 /***********************************************************************
784 * EnumFontFamiliesA (GDI32.@)
786 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
787 FONTENUMPROCA efproc, LPARAM lpData )
793 if (!*lpFamily) return 1;
794 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
795 lf.lfCharSet = DEFAULT_CHARSET;
796 lf.lfPitchAndFamily = 0;
801 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
804 /***********************************************************************
805 * EnumFontFamiliesW (GDI32.@)
807 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
808 FONTENUMPROCW efproc, LPARAM lpData )
814 if (!*lpFamily) return 1;
815 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
816 lf.lfCharSet = DEFAULT_CHARSET;
817 lf.lfPitchAndFamily = 0;
822 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
825 /***********************************************************************
826 * EnumFontsA (GDI32.@)
828 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
831 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
834 /***********************************************************************
835 * EnumFontsW (GDI32.@)
837 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
840 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
844 /***********************************************************************
845 * GetTextCharacterExtra (GDI32.@)
847 INT WINAPI GetTextCharacterExtra( HDC hdc )
850 DC *dc = get_dc_ptr( hdc );
851 if (!dc) return 0x80000000;
853 release_dc_ptr( dc );
858 /***********************************************************************
859 * SetTextCharacterExtra (GDI32.@)
861 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
863 INT ret = 0x80000000;
864 DC * dc = get_dc_ptr( hdc );
868 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
869 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
870 if (extra != 0x80000000)
873 dc->charExtra = extra;
875 release_dc_ptr( dc );
881 /***********************************************************************
882 * SetTextJustification (GDI32.@)
884 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
888 DC * dc = get_dc_ptr( hdc );
890 if (!dc) return FALSE;
892 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
893 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
896 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
897 if (!extra) breaks = 0;
900 dc->breakExtra = extra / breaks;
901 dc->breakRem = extra - (breaks * dc->breakExtra);
909 release_dc_ptr( dc );
914 /***********************************************************************
915 * GetTextFaceA (GDI32.@)
917 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
919 INT res = GetTextFaceW(hdc, 0, NULL);
920 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
921 GetTextFaceW( hdc, res, nameW );
927 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
931 /* GetTextFaceA does NOT include the nul byte in the return count. */
938 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
939 HeapFree( GetProcessHeap(), 0, nameW );
943 /***********************************************************************
944 * GetTextFaceW (GDI32.@)
946 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
951 DC * dc = get_dc_ptr( hdc );
954 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
955 ret = dev->funcs->pGetTextFace( dev, count, name );
956 release_dc_ptr( dc );
961 /***********************************************************************
962 * GetTextExtentPoint32A (GDI32.@)
964 * See GetTextExtentPoint32W.
966 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
973 if (count < 0) return FALSE;
975 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
979 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
980 HeapFree( GetProcessHeap(), 0, p );
983 TRACE("(%p %s %d %p): returning %d x %d\n",
984 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
989 /***********************************************************************
990 * GetTextExtentPoint32W [GDI32.@]
992 * Computes width/height for a string.
994 * Computes width and height of the specified string.
1000 BOOL WINAPI GetTextExtentPoint32W(
1001 HDC hdc, /* [in] Handle of device context */
1002 LPCWSTR str, /* [in] Address of text string */
1003 INT count, /* [in] Number of characters in string */
1004 LPSIZE size) /* [out] Address of structure for string size */
1006 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1009 /***********************************************************************
1010 * GetTextExtentExPointI [GDI32.@]
1012 * Computes width and height of the array of glyph indices.
1015 * hdc [I] Handle of device context.
1016 * indices [I] Glyph index array.
1017 * count [I] Number of glyphs in array.
1018 * max_ext [I] Maximum width in glyphs.
1019 * nfit [O] Maximum number of characters.
1020 * dxs [O] Partial string widths.
1021 * size [O] Returned string size.
1027 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1028 LPINT nfit, LPINT dxs, LPSIZE size )
1034 if (count < 0) return FALSE;
1036 dc = get_dc_ptr( hdc );
1037 if (!dc) return FALSE;
1039 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
1040 ret = dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, nfit, dxs, size );
1041 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1042 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1043 size->cx += count * dc->charExtra;
1044 release_dc_ptr( dc );
1046 TRACE("(%p %p %d %p): returning %d x %d\n",
1047 hdc, indices, count, size, size->cx, size->cy );
1051 /***********************************************************************
1052 * GetTextExtentPointI [GDI32.@]
1054 * Computes width and height of the array of glyph indices.
1057 * hdc [I] Handle of device context.
1058 * indices [I] Glyph index array.
1059 * count [I] Number of glyphs in array.
1060 * size [O] Returned string size.
1066 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1068 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1072 /***********************************************************************
1073 * GetTextExtentPointA (GDI32.@)
1075 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1078 TRACE("not bug compatible.\n");
1079 return GetTextExtentPoint32A( hdc, str, count, size );
1082 /***********************************************************************
1083 * GetTextExtentPointW (GDI32.@)
1085 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1088 TRACE("not bug compatible.\n");
1089 return GetTextExtentPoint32W( hdc, str, count, size );
1093 /***********************************************************************
1094 * GetTextExtentExPointA (GDI32.@)
1096 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1097 INT maxExt, LPINT lpnFit,
1098 LPINT alpDx, LPSIZE size )
1105 if (count < 0) return FALSE;
1109 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1110 if (!walpDx) return FALSE;
1113 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1114 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1117 INT n = lpnFit ? *lpnFit : wlen;
1119 for(i = 0, j = 0; i < n; i++, j++)
1121 alpDx[j] = walpDx[i];
1122 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1125 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1126 HeapFree( GetProcessHeap(), 0, p );
1127 HeapFree( GetProcessHeap(), 0, walpDx );
1132 /***********************************************************************
1133 * GetTextExtentExPointW (GDI32.@)
1135 * Return the size of the string as it would be if it was output properly by
1138 * This should include
1139 * - Intercharacter spacing
1140 * - justification spacing (not yet done)
1141 * - kerning? see below
1143 * Kerning. Since kerning would be carried out by the rendering code it should
1144 * be done by the driver. However they don't support it yet. Also I am not
1145 * yet persuaded that (certainly under Win95) any kerning is actually done.
1147 * str: According to MSDN this should be null-terminated. That is not true; a
1148 * null will not terminate it early.
1149 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1150 * than count. I have seen it be either the size of the full string or
1151 * 1 less than the size of the full string. I have not seen it bear any
1152 * resemblance to the portion that would fit.
1153 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1154 * trailing intercharacter spacing and any trailing justification.
1157 * Currently we do this by measuring each character etc. We should do it by
1158 * passing the request to the driver, perhaps by extending the
1159 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1160 * thinking about kerning issues and rounding issues in the justification.
1163 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1164 INT maxExt, LPINT lpnFit,
1165 LPINT alpDx, LPSIZE size )
1174 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1176 if (count < 0) return FALSE;
1178 dc = get_dc_ptr(hdc);
1179 if (!dc) return FALSE;
1181 GetTextMetricsW(hdc, &tm);
1183 /* If we need to calculate nFit, then we need the partial extents even if
1184 the user hasn't provided us with an array. */
1187 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1191 SetLastError(ERROR_OUTOFMEMORY);
1198 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
1199 ret = dev->funcs->pGetTextExtentExPoint(dev, str, count, 0, NULL, dxs, size);
1201 /* Perform device size to world size transformations. */
1204 INT extra = dc->charExtra,
1205 breakExtra = dc->breakExtra,
1206 breakRem = dc->breakRem,
1211 for (i = 0; i < count; ++i)
1213 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1214 dxs[i] += (i+1) * extra;
1215 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1217 dxs[i] += breakExtra;
1224 if (dxs[i] <= maxExt)
1227 breakRem = dc->breakRem;
1229 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1230 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1232 if (!dxs && count > 1 && (breakExtra || breakRem))
1234 for (i = 0; i < count; i++)
1236 if (str[i] == tm.tmBreakChar)
1238 size->cx += breakExtra;
1253 HeapFree(GetProcessHeap(), 0, dxs);
1255 release_dc_ptr( dc );
1257 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1261 /***********************************************************************
1262 * GetTextMetricsA (GDI32.@)
1264 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1268 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1269 FONT_TextMetricWToA( &tm32, metrics );
1273 /***********************************************************************
1274 * GetTextMetricsW (GDI32.@)
1276 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1280 DC * dc = get_dc_ptr( hdc );
1281 if (!dc) return FALSE;
1283 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1284 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1288 /* device layer returns values in device units
1289 * therefore we have to convert them to logical */
1291 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1292 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1294 #define WDPTOLP(x) ((x<0)? \
1295 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1296 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1297 #define HDPTOLP(y) ((y<0)? \
1298 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1299 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1301 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1302 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1303 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1304 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1305 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1306 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1307 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1308 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1312 TRACE("text metrics:\n"
1313 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1314 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1315 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1316 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1317 " PitchAndFamily = %02x\n"
1318 " --------------------\n"
1319 " InternalLeading = %i\n"
1323 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1324 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1325 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1326 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1327 metrics->tmPitchAndFamily,
1328 metrics->tmInternalLeading,
1331 metrics->tmHeight );
1333 release_dc_ptr( dc );
1338 /***********************************************************************
1339 * GetOutlineTextMetricsA (GDI32.@)
1340 * Gets metrics for TrueType fonts.
1343 * If the supplied buffer isn't big enough Windows partially fills it up to
1344 * its given length and returns that length.
1347 * Success: Non-zero or size of required buffer
1350 UINT WINAPI GetOutlineTextMetricsA(
1351 HDC hdc, /* [in] Handle of device context */
1352 UINT cbData, /* [in] Size of metric data array */
1353 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1355 char buf[512], *ptr;
1357 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1358 OUTLINETEXTMETRICA *output = lpOTM;
1361 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1363 if(ret > sizeof(buf))
1364 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1365 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1367 needed = sizeof(OUTLINETEXTMETRICA);
1368 if(lpOTMW->otmpFamilyName)
1369 needed += WideCharToMultiByte(CP_ACP, 0,
1370 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1371 NULL, 0, NULL, NULL);
1372 if(lpOTMW->otmpFaceName)
1373 needed += WideCharToMultiByte(CP_ACP, 0,
1374 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1375 NULL, 0, NULL, NULL);
1376 if(lpOTMW->otmpStyleName)
1377 needed += WideCharToMultiByte(CP_ACP, 0,
1378 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1379 NULL, 0, NULL, NULL);
1380 if(lpOTMW->otmpFullName)
1381 needed += WideCharToMultiByte(CP_ACP, 0,
1382 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1383 NULL, 0, NULL, NULL);
1390 TRACE("needed = %d\n", needed);
1392 /* Since the supplied buffer isn't big enough, we'll alloc one
1393 that is and memcpy the first cbData bytes into the lpOTM at
1395 output = HeapAlloc(GetProcessHeap(), 0, needed);
1397 ret = output->otmSize = min(needed, cbData);
1398 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1399 output->otmFiller = 0;
1400 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1401 output->otmfsSelection = lpOTMW->otmfsSelection;
1402 output->otmfsType = lpOTMW->otmfsType;
1403 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1404 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1405 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1406 output->otmEMSquare = lpOTMW->otmEMSquare;
1407 output->otmAscent = lpOTMW->otmAscent;
1408 output->otmDescent = lpOTMW->otmDescent;
1409 output->otmLineGap = lpOTMW->otmLineGap;
1410 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1411 output->otmsXHeight = lpOTMW->otmsXHeight;
1412 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1413 output->otmMacAscent = lpOTMW->otmMacAscent;
1414 output->otmMacDescent = lpOTMW->otmMacDescent;
1415 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1416 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1417 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1418 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1419 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1420 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1421 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1422 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1423 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1424 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1427 ptr = (char*)(output + 1);
1428 left = needed - sizeof(*output);
1430 if(lpOTMW->otmpFamilyName) {
1431 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1432 len = WideCharToMultiByte(CP_ACP, 0,
1433 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1434 ptr, left, NULL, NULL);
1438 output->otmpFamilyName = 0;
1440 if(lpOTMW->otmpFaceName) {
1441 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1442 len = WideCharToMultiByte(CP_ACP, 0,
1443 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1444 ptr, left, NULL, NULL);
1448 output->otmpFaceName = 0;
1450 if(lpOTMW->otmpStyleName) {
1451 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1452 len = WideCharToMultiByte(CP_ACP, 0,
1453 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1454 ptr, left, NULL, NULL);
1458 output->otmpStyleName = 0;
1460 if(lpOTMW->otmpFullName) {
1461 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1462 len = WideCharToMultiByte(CP_ACP, 0,
1463 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1464 ptr, left, NULL, NULL);
1467 output->otmpFullName = 0;
1471 if(output != lpOTM) {
1472 memcpy(lpOTM, output, cbData);
1473 HeapFree(GetProcessHeap(), 0, output);
1475 /* check if the string offsets really fit into the provided size */
1476 /* FIXME: should we check string length as well? */
1477 /* make sure that we don't read/write beyond the provided buffer */
1478 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1480 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1481 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1484 /* make sure that we don't read/write beyond the provided buffer */
1485 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1487 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1488 lpOTM->otmpFaceName = 0; /* doesn't fit */
1491 /* make sure that we don't read/write beyond the provided buffer */
1492 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1494 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1495 lpOTM->otmpStyleName = 0; /* doesn't fit */
1498 /* make sure that we don't read/write beyond the provided buffer */
1499 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1501 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1502 lpOTM->otmpFullName = 0; /* doesn't fit */
1507 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1508 HeapFree(GetProcessHeap(), 0, lpOTMW);
1514 /***********************************************************************
1515 * GetOutlineTextMetricsW [GDI32.@]
1517 UINT WINAPI GetOutlineTextMetricsW(
1518 HDC hdc, /* [in] Handle of device context */
1519 UINT cbData, /* [in] Size of metric data array */
1520 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1522 DC *dc = get_dc_ptr( hdc );
1523 OUTLINETEXTMETRICW *output = lpOTM;
1527 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1530 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1531 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1533 if (lpOTM && ret > cbData)
1535 output = HeapAlloc(GetProcessHeap(), 0, ret);
1536 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1541 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1542 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1544 #define WDPTOLP(x) ((x<0)? \
1545 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1546 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1547 #define HDPTOLP(y) ((y<0)? \
1548 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1549 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1551 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1552 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1553 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1554 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1555 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1556 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1557 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1558 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1559 output->otmAscent = HDPTOLP(output->otmAscent);
1560 output->otmDescent = HDPTOLP(output->otmDescent);
1561 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1562 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1563 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1564 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1565 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1566 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1567 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1568 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1569 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1570 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1571 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1572 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1573 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1574 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1575 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1576 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1577 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1578 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1579 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1580 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1581 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1582 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1587 memcpy(lpOTM, output, cbData);
1588 HeapFree(GetProcessHeap(), 0, output);
1596 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1598 INT i, count = lastChar - firstChar + 1;
1605 switch (GdiGetCodePage(hdc))
1612 if (lastChar > 0xffff)
1614 if ((firstChar ^ lastChar) > 0xff)
1618 if (lastChar > 0xff)
1623 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1627 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1630 str[i++] = (BYTE)(c >> 8);
1640 /***********************************************************************
1641 * GetCharWidthW (GDI32.@)
1642 * GetCharWidth32W (GDI32.@)
1644 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1650 DC * dc = get_dc_ptr( hdc );
1652 if (!dc) return FALSE;
1654 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1655 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1659 /* convert device units to logical */
1660 for( i = firstChar; i <= lastChar; i++, buffer++ )
1661 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1663 release_dc_ptr( dc );
1668 /***********************************************************************
1669 * GetCharWidthA (GDI32.@)
1670 * GetCharWidth32A (GDI32.@)
1672 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1680 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1684 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1686 for(i = 0; i < wlen; i++)
1688 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1696 HeapFree(GetProcessHeap(), 0, str);
1697 HeapFree(GetProcessHeap(), 0, wstr);
1703 /* helper for nulldrv_ExtTextOut */
1704 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags,
1705 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1707 UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
1708 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1709 UINT indices[3] = {0, 0, 0x20};
1716 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1719 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
1720 if (ret != GDI_ERROR) break;
1723 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1724 if (!image) return ERROR_SUCCESS;
1728 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1730 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1731 size = metrics->gmBlackBoxY * stride;
1733 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1734 image->is_copy = TRUE;
1735 image->free = free_heap_bits;
1737 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, image->ptr, &identity );
1738 if (ret == GDI_ERROR)
1740 HeapFree( GetProcessHeap(), 0, image->ptr );
1741 return ERROR_NOT_FOUND;
1743 return ERROR_SUCCESS;
1746 /* helper for nulldrv_ExtTextOut */
1747 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1748 LPCWSTR str, UINT count, const INT *dx )
1753 rect.left = rect.top = INT_MAX;
1754 rect.right = rect.bottom = INT_MIN;
1755 for (i = 0; i < count; i++)
1757 GLYPHMETRICS metrics;
1759 if (get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, NULL )) continue;
1761 rect.left = min( rect.left, x + metrics.gmptGlyphOrigin.x );
1762 rect.top = min( rect.top, y - metrics.gmptGlyphOrigin.y );
1763 rect.right = max( rect.right, x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX );
1764 rect.bottom = max( rect.bottom, y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY );
1768 if (flags & ETO_PDY)
1771 y += dx[ i * 2 + 1];
1777 x += metrics.gmCellIncX;
1778 y += metrics.gmCellIncY;
1784 /* helper for nulldrv_ExtTextOut */
1785 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1786 const struct gdi_image_bits *image, const RECT *clip )
1788 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1789 UINT x, y, i, count;
1790 BYTE *ptr = image->ptr;
1791 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1793 RECT rect, clipped_rect;
1795 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1796 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1797 rect.right = rect.left + metrics->gmBlackBoxX;
1798 rect.bottom = rect.top + metrics->gmBlackBoxY;
1799 if (!clip) clipped_rect = rect;
1800 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1802 pts = HeapAlloc( GetProcessHeap(), 0,
1803 max(2,metrics->gmBlackBoxX) * metrics->gmBlackBoxY * sizeof(*pts) );
1807 ptr += (clipped_rect.top - rect.top) * stride;
1808 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1810 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1812 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1813 pts[count].x = rect.left + x;
1814 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1815 pts[count + 1].x = rect.left + x;
1816 if (pts[count + 1].x > pts[count].x)
1818 pts[count].y = pts[count + 1].y = y;
1823 DPtoLP( hdc, pts, count );
1824 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1825 HeapFree( GetProcessHeap(), 0, pts );
1828 /***********************************************************************
1829 * nulldrv_ExtTextOut
1831 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1832 LPCWSTR str, UINT count, const INT *dx )
1834 DC *dc = get_nulldrv_dc( dev );
1840 if (flags & ETO_OPAQUE)
1843 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1847 orig = SelectObject( dev->hdc, brush );
1848 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1849 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1850 SelectObject( dev->hdc, orig );
1851 DeleteObject( brush );
1855 if (!count) return TRUE;
1857 aa_flags = get_font_aa_flags( dev->hdc );
1859 if (aa_flags != GGO_BITMAP)
1861 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1862 BITMAPINFO *info = (BITMAPINFO *)buffer;
1863 struct gdi_image_bits bits;
1864 struct bitblt_coords src, dst;
1868 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1869 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1870 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1871 if (get_clip_box( dc, &clip )) intersect_rect( &src.visrect, &src.visrect, &clip );
1872 if (is_rect_empty( &src.visrect )) return TRUE;
1874 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1875 src.x = src.visrect.left;
1876 src.y = src.visrect.top;
1877 src.width = src.visrect.right - src.visrect.left;
1878 src.height = src.visrect.bottom - src.visrect.top;
1880 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1881 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1883 /* we can avoid the GetImage, just query the needed format */
1884 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1885 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1886 info->bmiHeader.biWidth = src.width;
1887 info->bmiHeader.biHeight = -src.height;
1888 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, NULL, NULL, NULL, 0 );
1889 if (!err || err == ERROR_BAD_FORMAT)
1891 /* make the source rectangle relative to the source bits */
1893 src.visrect.left = src.visrect.top = 0;
1894 src.visrect.right = src.width;
1895 src.visrect.bottom = src.height;
1897 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1898 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1899 bits.is_copy = TRUE;
1900 bits.free = free_heap_bits;
1901 err = ERROR_SUCCESS;
1906 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1907 err = src_dev->funcs->pGetImage( src_dev, 0, info, &bits, &src );
1908 if (!err && !bits.is_copy)
1910 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1913 if (bits.free) bits.free( &bits );
1914 return ERROR_OUTOFMEMORY;
1916 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1917 if (bits.free) bits.free( &bits );
1919 bits.is_copy = TRUE;
1920 bits.free = free_heap_bits;
1925 /* make x,y relative to the image bits */
1926 x += src.visrect.left - dst.visrect.left;
1927 y += src.visrect.top - dst.visrect.top;
1928 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1929 aa_flags, str, count, dx );
1930 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, &bits, &src, &dst, SRCCOPY );
1931 if (bits.free) bits.free( &bits );
1936 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1937 orig = SelectObject( dev->hdc, pen );
1939 for (i = 0; i < count; i++)
1941 GLYPHMETRICS metrics;
1942 struct gdi_image_bits image;
1944 err = get_glyph_bitmap( dev->hdc, (UINT)str[i], GGO_BITMAP, &metrics, &image );
1947 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1948 if (image.free) image.free( &image );
1952 if (flags & ETO_PDY)
1955 y += dx[ i * 2 + 1];
1961 x += metrics.gmCellIncX;
1962 y += metrics.gmCellIncY;
1966 SelectObject( dev->hdc, orig );
1967 DeleteObject( pen );
1972 /***********************************************************************
1973 * ExtTextOutA (GDI32.@)
1977 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1978 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1986 if (flags & ETO_GLYPH_INDEX)
1987 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1989 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1992 unsigned int i = 0, j = 0;
1994 /* allocate enough for a ETO_PDY */
1995 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
1997 if(IsDBCSLeadByteEx(codepage, str[i]))
2001 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2002 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2005 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2012 lpDxW[j++] = lpDx[i * 2];
2013 lpDxW[j++] = lpDx[i * 2 + 1];
2016 lpDxW[j++] = lpDx[i];
2022 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2024 HeapFree( GetProcessHeap(), 0, p );
2025 HeapFree( GetProcessHeap(), 0, lpDxW );
2030 /***********************************************************************
2031 * ExtTextOutW (GDI32.@)
2033 * Draws text using the currently selected font, background color, and text color.
2037 * x,y [I] coordinates of string
2039 * ETO_GRAYED - undocumented on MSDN
2040 * ETO_OPAQUE - use background color for fill the rectangle
2041 * ETO_CLIPPED - clipping text to the rectangle
2042 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2043 * than encoded characters. Implies ETO_IGNORELANGUAGE
2044 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2045 * Affects BiDi ordering
2046 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2047 * ETO_PDY - unimplemented
2048 * ETO_NUMERICSLATIN - unimplemented always assumed -
2049 * do not translate numbers into locale representations
2050 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2051 * lprect [I] dimensions for clipping or/and opaquing
2052 * str [I] text string
2053 * count [I] number of symbols in string
2054 * lpDx [I] optional parameter with distance between drawing characters
2060 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2061 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2064 LPWSTR reordered_str = (LPWSTR)str;
2065 WORD *glyphs = NULL;
2066 UINT align = GetTextAlign( hdc );
2067 DWORD layout = GetLayout( hdc );
2071 double cosEsc, sinEsc;
2075 BOOL done_extents = FALSE;
2076 POINT *deltas = NULL, width = {0, 0};
2078 DC * dc = get_dc_ptr( hdc );
2081 static int quietfixme = 0;
2083 if (!dc) return FALSE;
2085 breakRem = dc->breakRem;
2087 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2089 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2094 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2095 type = GetObjectType(hdc);
2096 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2098 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2099 release_dc_ptr( dc );
2104 flags &= ~ETO_CLIPPED;
2106 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2107 if (layout & LAYOUT_RTL)
2109 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2110 align ^= TA_RTLREADING;
2113 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2116 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2118 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2119 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2120 reordered_str, count, NULL, &glyphs, &cGlyphs);
2122 flags |= ETO_IGNORELANGUAGE;
2125 flags |= ETO_GLYPH_INDEX;
2126 if (cGlyphs != count)
2130 else if(flags & ETO_GLYPH_INDEX)
2131 glyphs = reordered_str;
2133 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2134 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2135 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2137 if(align & TA_UPDATECP)
2139 GetCurrentPositionEx( hdc, &pt );
2144 GetTextMetricsW(hdc, &tm);
2145 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2147 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2148 lf.lfEscapement = 0;
2150 if(lf.lfEscapement != 0)
2152 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2153 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2161 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
2165 if(flags & ETO_GLYPH_INDEX)
2166 GetTextExtentPointI(hdc, glyphs, count, &sz);
2168 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2170 done_extents = TRUE;
2173 rc.right = x + sz.cx;
2174 rc.bottom = y + sz.cy;
2181 LPtoDP(hdc, (POINT*)&rc, 2);
2183 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
2184 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
2187 if (flags & ETO_OPAQUE)
2188 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2198 LPtoDP(hdc, &pt, 1);
2202 char_extra = GetTextCharacterExtra(hdc);
2203 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2207 POINT total = {0, 0}, desired[2];
2209 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2210 for(i = 0; i < count; i++)
2216 deltas[i].x = lpDx[i * 2] + char_extra;
2217 deltas[i].y = -lpDx[i * 2 + 1];
2221 deltas[i].x = lpDx[i] + char_extra;
2228 if(flags & ETO_GLYPH_INDEX)
2229 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2231 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2233 deltas[i].x = tmpsz.cx;
2237 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2239 deltas[i].x = deltas[i].x + dc->breakExtra;
2246 total.x += deltas[i].x;
2247 total.y += deltas[i].y;
2249 desired[0].x = desired[0].y = 0;
2251 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2252 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2254 LPtoDP(hdc, desired, 2);
2255 desired[1].x -= desired[0].x;
2256 desired[1].y -= desired[0].y;
2257 if (layout & LAYOUT_RTL) desired[1].x = -desired[1].x;
2259 deltas[i].x = desired[1].x - width.x;
2260 deltas[i].y = desired[1].y - width.y;
2270 if(flags & ETO_GLYPH_INDEX)
2271 GetTextExtentPointI(hdc, glyphs, count, &sz);
2273 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2274 done_extents = TRUE;
2276 width.x = abs(INTERNAL_XWSTODS(dc, sz.cx));
2280 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2281 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2282 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2285 if (align & TA_UPDATECP)
2289 DPtoLP(hdc, &pt, 1);
2290 MoveToEx(hdc, pt.x, pt.y, NULL);
2302 if (align & TA_UPDATECP)
2306 DPtoLP(hdc, &pt, 1);
2307 MoveToEx(hdc, pt.x, pt.y, NULL);
2312 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2315 y += tm.tmAscent * cosEsc;
2316 x += tm.tmAscent * sinEsc;
2320 y -= tm.tmDescent * cosEsc;
2321 x -= tm.tmDescent * sinEsc;
2328 if (GetBkMode(hdc) != TRANSPARENT)
2330 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2332 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width.x >= rc.right ||
2333 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2337 rc.right = x + width.x;
2338 rc.top = y - tm.tmAscent;
2339 rc.bottom = y + tm.tmDescent;
2341 if(flags & ETO_CLIPPED)
2343 rc.left = max(lprect->left, rc.left);
2344 rc.right = min(lprect->right, rc.right);
2345 rc.top = max(lprect->top, rc.top);
2346 rc.bottom = min(lprect->bottom, rc.bottom);
2348 if(rc.left < rc.right && rc.top < rc.bottom)
2349 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2354 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
2356 HFONT orig_font = dc->hFont, cur_font;
2359 POINT *offsets = NULL;
2362 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2363 for(i = 0; i < count; i++)
2365 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
2366 if(cur_font != dc->hFont)
2371 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2372 offsets[0].x = offsets[0].y = 0;
2377 for(j = 1; j < count; j++)
2379 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
2380 offsets[j].x = offsets[j - 1].x + abs(INTERNAL_XWSTODS(dc, tmpsz.cx));
2386 for(j = 1; j < count; j++)
2388 offsets[j].x = offsets[j - 1].x + deltas[j].x;
2389 offsets[j].y = offsets[j - 1].y + deltas[j].y;
2395 physdev->funcs->pExtTextOut( physdev, x + offsets[i - span].x,
2396 y + offsets[i - span].y,
2397 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
2398 span, deltas ? (INT*)(deltas + (i - span)) : NULL);
2401 SelectObject(hdc, cur_font);
2403 glyphs[span++] = glyph;
2407 ret = physdev->funcs->pExtTextOut(physdev, x + (offsets ? offsets[count - span].x : 0),
2408 y + (offsets ? offsets[count - span].y : 0),
2409 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
2410 span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2411 SelectObject(hdc, orig_font);
2412 HeapFree(GetProcessHeap(), 0, offsets);
2418 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2420 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2421 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2422 flags |= ETO_GLYPH_INDEX;
2424 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2425 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2429 HeapFree(GetProcessHeap(), 0, deltas);
2430 if(glyphs != reordered_str)
2431 HeapFree(GetProcessHeap(), 0, glyphs);
2432 if(reordered_str != str)
2433 HeapFree(GetProcessHeap(), 0, reordered_str);
2435 release_dc_ptr( dc );
2437 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2439 int underlinePos, strikeoutPos;
2440 int underlineWidth, strikeoutWidth;
2441 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2442 OUTLINETEXTMETRICW* otm = NULL;
2444 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2445 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2447 hbrush = SelectObject(hdc, hbrush);
2452 underlineWidth = tm.tmAscent / 20 + 1;
2453 strikeoutPos = tm.tmAscent / 2;
2454 strikeoutWidth = underlineWidth;
2458 otm = HeapAlloc(GetProcessHeap(), 0, size);
2459 GetOutlineTextMetricsW(hdc, size, otm);
2460 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2461 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2462 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2463 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2464 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2465 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2466 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2467 HeapFree(GetProcessHeap(), 0, otm);
2473 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2474 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2475 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2476 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2477 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2478 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2479 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2480 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2481 pts[4].x = pts[0].x;
2482 pts[4].y = pts[0].y;
2483 DPtoLP(hdc, pts, 5);
2484 Polygon(hdc, pts, 5);
2489 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2490 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2491 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2492 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2493 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2494 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2495 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2496 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2497 pts[4].x = pts[0].x;
2498 pts[4].y = pts[0].y;
2499 DPtoLP(hdc, pts, 5);
2500 Polygon(hdc, pts, 5);
2503 SelectObject(hdc, hpen);
2504 hbrush = SelectObject(hdc, hbrush);
2505 DeleteObject(hbrush);
2512 /***********************************************************************
2513 * TextOutA (GDI32.@)
2515 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2517 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2521 /***********************************************************************
2522 * TextOutW (GDI32.@)
2524 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2526 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2530 /***********************************************************************
2531 * PolyTextOutA (GDI32.@)
2535 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2537 for (; cStrings>0; cStrings--, pptxt++)
2538 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2545 /***********************************************************************
2546 * PolyTextOutW (GDI32.@)
2548 * Draw several Strings
2554 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2556 for (; cStrings>0; cStrings--, pptxt++)
2557 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2563 /***********************************************************************
2564 * SetMapperFlags (GDI32.@)
2566 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2568 DC *dc = get_dc_ptr( hdc );
2569 DWORD ret = GDI_ERROR;
2573 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2574 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2575 if (flags != GDI_ERROR)
2577 ret = dc->mapperFlags;
2578 dc->mapperFlags = flags;
2580 release_dc_ptr( dc );
2585 /***********************************************************************
2586 * GetAspectRatioFilterEx (GDI32.@)
2588 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2590 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2595 /***********************************************************************
2596 * GetCharABCWidthsA (GDI32.@)
2598 * See GetCharABCWidthsW.
2600 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2608 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2612 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2615 HeapFree(GetProcessHeap(), 0, str);
2619 for(i = 0; i < wlen; i++)
2621 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2629 HeapFree(GetProcessHeap(), 0, str);
2630 HeapFree(GetProcessHeap(), 0, wstr);
2636 /******************************************************************************
2637 * GetCharABCWidthsW [GDI32.@]
2639 * Retrieves widths of characters in range.
2642 * hdc [I] Handle of device context
2643 * firstChar [I] First character in range to query
2644 * lastChar [I] Last character in range to query
2645 * abc [O] Address of character-width structure
2648 * Only works with TrueType fonts
2654 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2657 DC *dc = get_dc_ptr(hdc);
2662 if (!dc) return FALSE;
2666 release_dc_ptr( dc );
2670 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2671 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2674 /* convert device units to logical */
2675 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2676 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2677 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2678 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2682 release_dc_ptr( dc );
2687 /******************************************************************************
2688 * GetCharABCWidthsI [GDI32.@]
2690 * Retrieves widths of characters in range.
2693 * hdc [I] Handle of device context
2694 * firstChar [I] First glyphs in range to query
2695 * count [I] Last glyphs in range to query
2696 * pgi [i] Array of glyphs to query
2697 * abc [O] Address of character-width structure
2700 * Only works with TrueType fonts
2706 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2707 LPWORD pgi, LPABC abc)
2709 DC *dc = get_dc_ptr(hdc);
2714 if (!dc) return FALSE;
2718 release_dc_ptr( dc );
2722 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2723 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2726 /* convert device units to logical */
2727 for( i = 0; i < count; i++, abc++ ) {
2728 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2729 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2730 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2734 release_dc_ptr( dc );
2739 /***********************************************************************
2740 * GetGlyphOutlineA (GDI32.@)
2742 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2743 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2744 LPVOID lpBuffer, const MAT2 *lpmat2 )
2746 if (!lpmat2) return GDI_ERROR;
2748 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2753 cp = GdiGetCodePage(hdc);
2754 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2756 mbchs[0] = (uChar & 0xff00) >> 8;
2757 mbchs[1] = (uChar & 0xff);
2760 mbchs[0] = (uChar & 0xff);
2763 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2766 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2770 /***********************************************************************
2771 * GetGlyphOutlineW (GDI32.@)
2773 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2774 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2775 LPVOID lpBuffer, const MAT2 *lpmat2 )
2781 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2782 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2784 if (!lpmat2) return GDI_ERROR;
2786 dc = get_dc_ptr(hdc);
2787 if(!dc) return GDI_ERROR;
2789 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2790 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2791 release_dc_ptr( dc );
2796 /***********************************************************************
2797 * CreateScalableFontResourceA (GDI32.@)
2799 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2800 LPCSTR lpszResourceFile,
2801 LPCSTR lpszFontFile,
2802 LPCSTR lpszCurrentPath )
2804 LPWSTR lpszResourceFileW = NULL;
2805 LPWSTR lpszFontFileW = NULL;
2806 LPWSTR lpszCurrentPathW = NULL;
2810 if (lpszResourceFile)
2812 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2813 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2814 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2819 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2820 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2821 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2824 if (lpszCurrentPath)
2826 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2827 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2828 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2831 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2832 lpszFontFileW, lpszCurrentPathW);
2834 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2835 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2836 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2841 /***********************************************************************
2842 * CreateScalableFontResourceW (GDI32.@)
2844 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2845 LPCWSTR lpszResourceFile,
2846 LPCWSTR lpszFontFile,
2847 LPCWSTR lpszCurrentPath )
2850 FIXME("(%d,%s,%s,%s): stub\n",
2851 fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
2852 debugstr_w(lpszCurrentPath) );
2854 /* fHidden=1 - only visible for the calling app, read-only, not
2855 * enumerated with EnumFonts/EnumFontFamilies
2856 * lpszCurrentPath can be NULL
2859 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2860 if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2862 SetLastError(ERROR_FILE_EXISTS);
2865 return FALSE; /* create failed */
2868 /*************************************************************************
2869 * GetKerningPairsA (GDI32.@)
2871 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2872 LPKERNINGPAIR kern_pairA )
2876 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2877 KERNINGPAIR *kern_pairW;
2879 if (!cPairs && kern_pairA)
2881 SetLastError(ERROR_INVALID_PARAMETER);
2885 cp = GdiGetCodePage(hDC);
2887 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2888 * to fail on an invalid character for CP_SYMBOL.
2890 cpi.DefaultChar[0] = 0;
2891 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2893 FIXME("Can't find codepage %u info\n", cp);
2897 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2898 if (!total_kern_pairs) return 0;
2900 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2901 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2903 for (i = 0; i < total_kern_pairs; i++)
2907 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2910 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2913 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2918 if (kern_pairs_copied >= cPairs) break;
2920 kern_pairA->wFirst = (BYTE)first;
2921 kern_pairA->wSecond = (BYTE)second;
2922 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2925 kern_pairs_copied++;
2928 HeapFree(GetProcessHeap(), 0, kern_pairW);
2930 return kern_pairs_copied;
2933 /*************************************************************************
2934 * GetKerningPairsW (GDI32.@)
2936 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2937 LPKERNINGPAIR lpKerningPairs )
2943 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2945 if (!cPairs && lpKerningPairs)
2947 SetLastError(ERROR_INVALID_PARAMETER);
2951 dc = get_dc_ptr(hDC);
2954 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2955 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2956 release_dc_ptr( dc );
2960 /*************************************************************************
2961 * TranslateCharsetInfo [GDI32.@]
2963 * Fills a CHARSETINFO structure for a character set, code page, or
2964 * font. This allows making the correspondence between different labels
2965 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2966 * of the same encoding.
2968 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2969 * only one codepage should be set in *lpSrc.
2972 * TRUE on success, FALSE on failure.
2975 BOOL WINAPI TranslateCharsetInfo(
2976 LPDWORD lpSrc, /* [in]
2977 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2978 if flags == TCI_SRCCHARSET: a character set value
2979 if flags == TCI_SRCCODEPAGE: a code page value
2981 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2982 DWORD flags /* [in] determines interpretation of lpSrc */)
2986 case TCI_SRCFONTSIG:
2987 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2989 case TCI_SRCCODEPAGE:
2990 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2992 case TCI_SRCCHARSET:
2993 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2998 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2999 *lpCs = FONT_tci[index];
3003 /*************************************************************************
3004 * GetFontLanguageInfo (GDI32.@)
3006 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3008 FONTSIGNATURE fontsig;
3009 static const DWORD GCP_DBCS_MASK=0x003F0000,
3010 GCP_DIACRITIC_MASK=0x00000000,
3011 FLI_GLYPHS_MASK=0x00000000,
3012 GCP_GLYPHSHAPE_MASK=0x00000040,
3013 GCP_KASHIDA_MASK=0x00000000,
3014 GCP_LIGATE_MASK=0x00000000,
3015 GCP_USEKERNING_MASK=0x00000000,
3016 GCP_REORDER_MASK=0x00000060;
3020 GetTextCharsetInfo( hdc, &fontsig, 0 );
3021 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3023 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3026 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3027 result|=GCP_DIACRITIC;
3029 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3032 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3033 result|=GCP_GLYPHSHAPE;
3035 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3036 result|=GCP_KASHIDA;
3038 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3041 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3042 result|=GCP_USEKERNING;
3044 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3045 if( GetTextAlign( hdc) & TA_RTLREADING )
3046 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3047 result|=GCP_REORDER;
3053 /*************************************************************************
3054 * GetFontData [GDI32.@]
3056 * Retrieve data for TrueType font.
3060 * success: Number of bytes returned
3061 * failure: GDI_ERROR
3065 * Calls SetLastError()
3068 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3069 LPVOID buffer, DWORD length)
3071 DC *dc = get_dc_ptr(hdc);
3075 if(!dc) return GDI_ERROR;
3077 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3078 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3079 release_dc_ptr( dc );
3083 /*************************************************************************
3084 * GetGlyphIndicesA [GDI32.@]
3086 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3087 LPWORD pgi, DWORD flags)
3093 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3094 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3096 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3097 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3098 HeapFree(GetProcessHeap(), 0, lpstrW);
3103 /*************************************************************************
3104 * GetGlyphIndicesW [GDI32.@]
3106 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3107 LPWORD pgi, DWORD flags)
3109 DC *dc = get_dc_ptr(hdc);
3113 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3114 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3116 if(!dc) return GDI_ERROR;
3118 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3119 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3120 release_dc_ptr( dc );
3124 /*************************************************************************
3125 * GetCharacterPlacementA [GDI32.@]
3127 * See GetCharacterPlacementW.
3130 * the web browser control of ie4 calls this with dwFlags=0
3133 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3134 INT nMaxExtent, GCP_RESULTSA *lpResults,
3139 GCP_RESULTSW resultsW;
3143 TRACE("%s, %d, %d, 0x%08x\n",
3144 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3146 /* both structs are equal in size */
3147 memcpy(&resultsW, lpResults, sizeof(resultsW));
3149 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3150 if(lpResults->lpOutString)
3151 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3153 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3155 lpResults->nGlyphs = resultsW.nGlyphs;
3156 lpResults->nMaxFit = resultsW.nMaxFit;
3158 if(lpResults->lpOutString) {
3159 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3160 lpResults->lpOutString, uCount, NULL, NULL );
3163 HeapFree(GetProcessHeap(), 0, lpStringW);
3164 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3169 /*************************************************************************
3170 * GetCharacterPlacementW [GDI32.@]
3172 * Retrieve information about a string. This includes the width, reordering,
3173 * Glyphing and so on.
3177 * The width and height of the string if successful, 0 if failed.
3181 * All flags except GCP_REORDER are not yet implemented.
3182 * Reordering is not 100% compliant to the Windows BiDi method.
3183 * Caret positioning is not yet implemented for BiDi.
3184 * Classes are not yet implemented.
3188 GetCharacterPlacementW(
3189 HDC hdc, /* [in] Device context for which the rendering is to be done */
3190 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3191 INT uCount, /* [in] Number of WORDS in string. */
3192 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3193 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
3194 DWORD dwFlags /* [in] Flags specifying how to process the string */
3201 TRACE("%s, %d, %d, 0x%08x\n",
3202 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3204 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3205 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3206 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3207 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3208 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3210 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
3211 if(lpResults->lpClass) FIXME("classes not implemented\n");
3212 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3213 FIXME("Caret positions for complex scripts not implemented\n");
3215 nSet = (UINT)uCount;
3216 if(nSet > lpResults->nGlyphs)
3217 nSet = lpResults->nGlyphs;
3219 /* return number of initialized fields */
3220 lpResults->nGlyphs = nSet;
3222 if((dwFlags&GCP_REORDER)==0 )
3224 /* Treat the case where no special handling was requested in a fastpath way */
3225 /* copy will do if the GCP_REORDER flag is not set */
3226 if(lpResults->lpOutString)
3227 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3229 if(lpResults->lpOrder)
3231 for(i = 0; i < nSet; i++)
3232 lpResults->lpOrder[i] = i;
3236 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3237 nSet, lpResults->lpOrder, NULL, NULL );
3240 /* FIXME: Will use the placement chars */
3241 if (lpResults->lpDx)
3244 for (i = 0; i < nSet; i++)
3246 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3247 lpResults->lpDx[i]= c;
3251 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3255 lpResults->lpCaretPos[0] = 0;
3256 for (i = 1; i < nSet; i++)
3257 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3258 lpResults->lpCaretPos[i] = (pos += size.cx);
3261 if(lpResults->lpGlyphs)
3262 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3264 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3265 ret = MAKELONG(size.cx, size.cy);
3270 /*************************************************************************
3271 * GetCharABCWidthsFloatA [GDI32.@]
3273 * See GetCharABCWidthsFloatW.
3275 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3282 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3286 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3288 for (i = 0; i < wlen; i++)
3290 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3298 HeapFree( GetProcessHeap(), 0, str );
3299 HeapFree( GetProcessHeap(), 0, wstr );
3304 /*************************************************************************
3305 * GetCharABCWidthsFloatW [GDI32.@]
3307 * Retrieves widths of a range of characters.
3310 * hdc [I] Handle to device context.
3311 * first [I] First character in range to query.
3312 * last [I] Last character in range to query.
3313 * abcf [O] Array of LPABCFLOAT structures.
3319 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3325 DC *dc = get_dc_ptr( hdc );
3327 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3329 if (!dc) return FALSE;
3331 if (!abcf) goto done;
3332 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3334 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3335 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3338 /* convert device units to logical */
3339 for (i = first; i <= last; i++, abcf++)
3341 abcf->abcfA = abc->abcA * dc->xformVport2World.eM11;
3342 abcf->abcfB = abc->abcB * dc->xformVport2World.eM11;
3343 abcf->abcfC = abc->abcC * dc->xformVport2World.eM11;
3346 HeapFree( GetProcessHeap(), 0, abc );
3349 release_dc_ptr( dc );
3353 /*************************************************************************
3354 * GetCharWidthFloatA [GDI32.@]
3356 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3357 UINT iLastChar, PFLOAT pxBuffer)
3359 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3363 /*************************************************************************
3364 * GetCharWidthFloatW [GDI32.@]
3366 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3367 UINT iLastChar, PFLOAT pxBuffer)
3369 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3374 /***********************************************************************
3376 * Font Resource API *
3378 ***********************************************************************/
3380 /***********************************************************************
3381 * AddFontResourceA (GDI32.@)
3383 INT WINAPI AddFontResourceA( LPCSTR str )
3385 return AddFontResourceExA( str, 0, NULL);
3388 /***********************************************************************
3389 * AddFontResourceW (GDI32.@)
3391 INT WINAPI AddFontResourceW( LPCWSTR str )
3393 return AddFontResourceExW(str, 0, NULL);
3397 /***********************************************************************
3398 * AddFontResourceExA (GDI32.@)
3400 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3402 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3403 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3406 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3407 ret = AddFontResourceExW(strW, fl, pdv);
3408 HeapFree(GetProcessHeap(), 0, strW);
3412 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3414 HRSRC rsrc = FindResourceW(hModule, name, type);
3415 HGLOBAL hMem = LoadResource(hModule, rsrc);
3416 LPVOID *pMem = LockResource(hMem);
3417 int *num_total = (int *)lParam;
3420 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3421 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3423 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3427 *num_total += num_in_res;
3431 /***********************************************************************
3432 * AddFontResourceExW (GDI32.@)
3434 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3436 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3439 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3440 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3441 if (hModule != NULL)
3443 int num_resources = 0;
3444 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3446 TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3447 wine_dbgstr_w(str));
3448 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3449 ret = num_resources;
3450 FreeLibrary(hModule);
3456 /***********************************************************************
3457 * RemoveFontResourceA (GDI32.@)
3459 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3461 return RemoveFontResourceExA(str, 0, 0);
3464 /***********************************************************************
3465 * RemoveFontResourceW (GDI32.@)
3467 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3469 return RemoveFontResourceExW(str, 0, 0);
3472 /***********************************************************************
3473 * AddFontMemResourceEx (GDI32.@)
3475 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3480 if (!pbFont || !cbFont || !pcFonts)
3482 SetLastError(ERROR_INVALID_PARAMETER);
3486 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3491 *pcFonts = num_fonts;
3495 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3496 RemoveFontMemResourceEx(ret);
3504 /***********************************************************************
3505 * RemoveFontMemResourceEx (GDI32.@)
3507 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3509 FIXME("(%p) stub\n", fh);
3513 /***********************************************************************
3514 * RemoveFontResourceExA (GDI32.@)
3516 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3518 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3519 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3522 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3523 ret = RemoveFontResourceExW(strW, fl, pdv);
3524 HeapFree(GetProcessHeap(), 0, strW);
3528 /***********************************************************************
3529 * RemoveFontResourceExW (GDI32.@)
3531 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3533 return WineEngRemoveFontResourceEx(str, fl, pdv);
3536 /***********************************************************************
3537 * GetTextCharset (GDI32.@)
3539 UINT WINAPI GetTextCharset(HDC hdc)
3541 /* MSDN docs say this is equivalent */
3542 return GetTextCharsetInfo(hdc, NULL, 0);
3545 /***********************************************************************
3546 * GetTextCharsetInfo (GDI32.@)
3548 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3550 UINT ret = DEFAULT_CHARSET;
3551 DC *dc = get_dc_ptr(hdc);
3556 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3557 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3558 release_dc_ptr( dc );
3561 if (ret == DEFAULT_CHARSET && fs)
3562 memset(fs, 0, sizeof(FONTSIGNATURE));
3566 /***********************************************************************
3567 * GdiGetCharDimensions (GDI32.@)
3569 * Gets the average width of the characters in the English alphabet.
3572 * hdc [I] Handle to the device context to measure on.
3573 * lptm [O] Pointer to memory to store the text metrics into.
3574 * height [O] On exit, the maximum height of characters in the English alphabet.
3577 * The average width of characters in the English alphabet.
3580 * This function is used by the dialog manager to get the size of a dialog
3581 * unit. It should also be used by other pieces of code that need to know
3582 * the size of a dialog unit in logical units without having access to the
3583 * window handle of the dialog.
3584 * Windows caches the font metrics from this function, but we don't and
3585 * there doesn't appear to be an immediate advantage to do so.
3588 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3590 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3593 static const WCHAR alphabet[] = {
3594 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3595 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3596 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3598 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3600 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3602 if (height) *height = sz.cy;
3603 return (sz.cx / 26 + 1) / 2;
3606 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3608 FIXME("(%d): stub\n", fEnableEUDC);
3612 /***********************************************************************
3613 * GetCharWidthI (GDI32.@)
3615 * Retrieve widths of characters.
3618 * hdc [I] Handle to a device context.
3619 * first [I] First glyph in range to query.
3620 * count [I] Number of glyph indices to query.
3621 * glyphs [I] Array of glyphs to query.
3622 * buffer [O] Buffer to receive character widths.
3625 * Only works with TrueType fonts.
3631 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3636 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3638 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3641 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3643 HeapFree(GetProcessHeap(), 0, abc);
3647 for (i = 0; i < count; i++)
3648 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3650 HeapFree(GetProcessHeap(), 0, abc);
3654 /***********************************************************************
3655 * GetFontUnicodeRanges (GDI32.@)
3657 * Retrieve a list of supported Unicode characters in a font.
3660 * hdc [I] Handle to a device context.
3661 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3664 * Success: Number of bytes written to the buffer pointed to by lpgs.
3668 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3672 DC *dc = get_dc_ptr(hdc);
3674 TRACE("(%p, %p)\n", hdc, lpgs);
3678 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3679 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3685 /*************************************************************
3686 * FontIsLinked (GDI32.@)
3688 BOOL WINAPI FontIsLinked(HDC hdc)
3690 DC *dc = get_dc_ptr(hdc);
3694 if (!dc) return FALSE;
3695 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3696 ret = dev->funcs->pFontIsLinked( dev );
3698 TRACE("returning %d\n", ret);
3702 /*************************************************************
3703 * GdiRealizationInfo (GDI32.@)
3705 * Returns a structure that contains some font information.
3707 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3709 DC *dc = get_dc_ptr(hdc);
3713 if (!dc) return FALSE;
3714 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3715 ret = dev->funcs->pGdiRealizationInfo( dev, info );