gdiplus: Add stub for GdipImageRotateFlip.
[wine.git] / dlls / gdi32 / font.c
blobc81a9c82222659a918ec45aed2dc4b4433c9edb6
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include "winerror.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "wownt32.h"
35 #include "gdi_private.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(font);
41 /* Device -> World size conversion */
43 /* Performs a device to world transformation on the specified width (which
44 * is in integer format).
46 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
48 double floatWidth;
50 /* Perform operation with floating point */
51 floatWidth = (double)width * dc->xformVport2World.eM11;
52 /* Round to integers */
53 return GDI_ROUND(floatWidth);
56 /* Performs a device to world transformation on the specified size (which
57 * is in integer format).
59 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
61 double floatHeight;
63 /* Perform operation with floating point */
64 floatHeight = (double)height * dc->xformVport2World.eM22;
65 /* Round to integers */
66 return GDI_ROUND(floatHeight);
69 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
71 POINT pt[2];
72 pt[0].x = pt[0].y = 0;
73 pt[1].x = width;
74 pt[1].y = 0;
75 LPtoDP(dc->hSelf, pt, 2);
76 return pt[1].x - pt[0].x;
79 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
81 POINT pt[2];
82 pt[0].x = pt[0].y = 0;
83 pt[1].x = 0;
84 pt[1].y = height;
85 LPtoDP(dc->hSelf, pt, 2);
86 return pt[1].y - pt[0].y;
89 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
90 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
91 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
92 static BOOL FONT_DeleteObject( HGDIOBJ handle );
94 static const struct gdi_obj_funcs font_funcs =
96 FONT_SelectObject, /* pSelectObject */
97 FONT_GetObjectA, /* pGetObjectA */
98 FONT_GetObjectW, /* pGetObjectW */
99 NULL, /* pUnrealizeObject */
100 FONT_DeleteObject /* pDeleteObject */
103 #define ENUM_UNICODE 0x00000001
104 #define ENUM_CALLED 0x00000002
106 typedef struct
108 GDIOBJHDR header;
109 LOGFONTW logfont;
110 } FONTOBJ;
112 typedef struct
114 LPLOGFONTW lpLogFontParam;
115 FONTENUMPROCW lpEnumFunc;
116 LPARAM lpData;
117 DWORD dwFlags;
118 HDC hdc;
119 } fontEnum32;
122 * For TranslateCharsetInfo
124 #define MAXTCIINDEX 32
125 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
126 /* ANSI */
127 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
128 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
129 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
130 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
131 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
132 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
133 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
134 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
135 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
136 /* reserved by ANSI */
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144 /* ANSI and OEM */
145 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
146 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
147 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
148 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
149 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
150 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
151 /* reserved for alternate ANSI and OEM */
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 /* reserved for system */
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
165 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
167 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
168 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
169 LF_FACESIZE);
170 fontW->lfFaceName[LF_FACESIZE-1] = 0;
173 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
175 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
176 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
177 LF_FACESIZE, NULL, NULL);
178 fontA->lfFaceName[LF_FACESIZE-1] = 0;
181 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
183 FONT_LogFontWToA( (const LOGFONTW *)fontW, (LPLOGFONTA)fontA);
185 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
186 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
187 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
188 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
189 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
190 fontA->elfStyle[LF_FACESIZE-1] = '\0';
191 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
192 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
193 fontA->elfScript[LF_FACESIZE-1] = '\0';
196 /***********************************************************************
197 * TEXTMETRIC conversion functions.
199 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
201 ptmA->tmHeight = ptmW->tmHeight;
202 ptmA->tmAscent = ptmW->tmAscent;
203 ptmA->tmDescent = ptmW->tmDescent;
204 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
205 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
206 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
207 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
208 ptmA->tmWeight = ptmW->tmWeight;
209 ptmA->tmOverhang = ptmW->tmOverhang;
210 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
211 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
212 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
213 if (ptmW->tmCharSet == SYMBOL_CHARSET)
215 ptmA->tmFirstChar = 0x1e;
216 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
218 else
220 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
221 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
223 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
224 ptmA->tmBreakChar = ptmW->tmBreakChar;
225 ptmA->tmItalic = ptmW->tmItalic;
226 ptmA->tmUnderlined = ptmW->tmUnderlined;
227 ptmA->tmStruckOut = ptmW->tmStruckOut;
228 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
229 ptmA->tmCharSet = ptmW->tmCharSet;
233 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
235 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
236 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
237 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
238 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
239 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
240 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
244 /***********************************************************************
245 * GdiGetCodePage (GDI32.@)
247 DWORD WINAPI GdiGetCodePage( HDC hdc )
249 UINT cp = CP_ACP;
250 DC *dc = get_dc_ptr( hdc );
252 if (dc)
254 cp = dc->font_code_page;
255 release_dc_ptr( dc );
257 return cp;
260 /***********************************************************************
261 * FONT_mbtowc
263 * Returns a Unicode translation of str using the charset of the
264 * currently selected font in hdc. If count is -1 then str is assumed
265 * to be '\0' terminated, otherwise it contains the number of bytes to
266 * convert. If plenW is non-NULL, on return it will point to the
267 * number of WCHARs that have been written. If pCP is non-NULL, on
268 * return it will point to the codepage used in the conversion. The
269 * caller should free the returned LPWSTR from the process heap
270 * itself.
272 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
274 UINT cp;
275 INT lenW;
276 LPWSTR strW;
278 cp = GdiGetCodePage( hdc );
280 if(count == -1) count = strlen(str);
281 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
282 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
283 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
284 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
285 if(plenW) *plenW = lenW;
286 if(pCP) *pCP = cp;
287 return strW;
291 /***********************************************************************
292 * CreateFontIndirectA (GDI32.@)
294 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
296 LOGFONTW lfW;
298 if (!plfA) return 0;
300 FONT_LogFontAToW( plfA, &lfW );
301 return CreateFontIndirectW( &lfW );
304 /***********************************************************************
305 * CreateFontIndirectW (GDI32.@)
307 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
309 static const WCHAR ItalicW[] = {' ','I','t','a','l','i','c','\0'};
310 static const WCHAR BoldW[] = {' ','B','o','l','d','\0'};
311 WCHAR *pFaceNameItalicSuffix, *pFaceNameBoldSuffix;
312 WCHAR *pFaceNameSuffix = NULL;
313 HFONT hFont;
314 FONTOBJ *fontPtr;
316 if (!plf) return 0;
318 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
320 fontPtr->logfont = *plf;
322 if (plf->lfEscapement != plf->lfOrientation)
324 /* this should really depend on whether GM_ADVANCED is set */
325 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
326 WARN("orientation angle %f set to "
327 "escapement angle %f for new font %p\n",
328 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
331 pFaceNameItalicSuffix = strstrW(fontPtr->logfont.lfFaceName, ItalicW);
332 if (pFaceNameItalicSuffix)
334 fontPtr->logfont.lfItalic = TRUE;
335 pFaceNameSuffix = pFaceNameItalicSuffix;
338 pFaceNameBoldSuffix = strstrW(fontPtr->logfont.lfFaceName, BoldW);
339 if (pFaceNameBoldSuffix)
341 if (fontPtr->logfont.lfWeight < FW_BOLD)
342 fontPtr->logfont.lfWeight = FW_BOLD;
343 if (!pFaceNameSuffix || (pFaceNameBoldSuffix < pFaceNameSuffix))
344 pFaceNameSuffix = pFaceNameBoldSuffix;
347 if (pFaceNameSuffix) *pFaceNameSuffix = 0;
349 if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs )))
351 HeapFree( GetProcessHeap(), 0, fontPtr );
352 return 0;
355 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
356 plf->lfHeight, plf->lfWidth,
357 plf->lfEscapement, plf->lfOrientation,
358 plf->lfPitchAndFamily,
359 plf->lfOutPrecision, plf->lfClipPrecision,
360 plf->lfQuality, plf->lfCharSet,
361 debugstr_w(plf->lfFaceName),
362 plf->lfWeight > 400 ? "Bold" : "",
363 plf->lfItalic ? "Italic" : "",
364 plf->lfUnderline ? "Underline" : "", hFont);
366 return hFont;
369 /*************************************************************************
370 * CreateFontA (GDI32.@)
372 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
373 INT orient, INT weight, DWORD italic,
374 DWORD underline, DWORD strikeout, DWORD charset,
375 DWORD outpres, DWORD clippres, DWORD quality,
376 DWORD pitch, LPCSTR name )
378 LOGFONTA logfont;
380 logfont.lfHeight = height;
381 logfont.lfWidth = width;
382 logfont.lfEscapement = esc;
383 logfont.lfOrientation = orient;
384 logfont.lfWeight = weight;
385 logfont.lfItalic = italic;
386 logfont.lfUnderline = underline;
387 logfont.lfStrikeOut = strikeout;
388 logfont.lfCharSet = charset;
389 logfont.lfOutPrecision = outpres;
390 logfont.lfClipPrecision = clippres;
391 logfont.lfQuality = quality;
392 logfont.lfPitchAndFamily = pitch;
394 if (name)
395 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
396 else
397 logfont.lfFaceName[0] = '\0';
399 return CreateFontIndirectA( &logfont );
402 /*************************************************************************
403 * CreateFontW (GDI32.@)
405 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
406 INT orient, INT weight, DWORD italic,
407 DWORD underline, DWORD strikeout, DWORD charset,
408 DWORD outpres, DWORD clippres, DWORD quality,
409 DWORD pitch, LPCWSTR name )
411 LOGFONTW logfont;
413 logfont.lfHeight = height;
414 logfont.lfWidth = width;
415 logfont.lfEscapement = esc;
416 logfont.lfOrientation = orient;
417 logfont.lfWeight = weight;
418 logfont.lfItalic = italic;
419 logfont.lfUnderline = underline;
420 logfont.lfStrikeOut = strikeout;
421 logfont.lfCharSet = charset;
422 logfont.lfOutPrecision = outpres;
423 logfont.lfClipPrecision = clippres;
424 logfont.lfQuality = quality;
425 logfont.lfPitchAndFamily = pitch;
427 if (name)
428 lstrcpynW(logfont.lfFaceName, name,
429 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
430 else
431 logfont.lfFaceName[0] = '\0';
433 return CreateFontIndirectW( &logfont );
436 static void update_font_code_page( DC *dc )
438 CHARSETINFO csi;
439 int charset = DEFAULT_CHARSET;
441 if (dc->gdiFont)
442 charset = WineEngGetTextCharsetInfo( dc->gdiFont, NULL, 0 );
444 /* Hmm, nicely designed api this one! */
445 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
446 dc->font_code_page = csi.ciACP;
447 else {
448 switch(charset) {
449 case OEM_CHARSET:
450 dc->font_code_page = GetOEMCP();
451 break;
452 case DEFAULT_CHARSET:
453 dc->font_code_page = GetACP();
454 break;
456 case VISCII_CHARSET:
457 case TCVN_CHARSET:
458 case KOI8_CHARSET:
459 case ISO3_CHARSET:
460 case ISO4_CHARSET:
461 case ISO10_CHARSET:
462 case CELTIC_CHARSET:
463 /* FIXME: These have no place here, but because x11drv
464 enumerates fonts with these (made up) charsets some apps
465 might use them and then the FIXME below would become
466 annoying. Now we could pick the intended codepage for
467 each of these, but since it's broken anyway we'll just
468 use CP_ACP and hope it'll go away...
470 dc->font_code_page = CP_ACP;
471 break;
473 default:
474 FIXME("Can't find codepage for charset %d\n", charset);
475 dc->font_code_page = CP_ACP;
476 break;
480 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
483 /***********************************************************************
484 * FONT_SelectObject
486 * If the driver supports vector fonts we create a gdi font first and
487 * then call the driver to give it a chance to supply its own device
488 * font. If the driver wants to do this it returns TRUE and we can
489 * delete the gdi font, if the driver wants to use the gdi font it
490 * should return FALSE, to signal an error return GDI_ERROR. For
491 * drivers that don't support vector fonts they must supply their own
492 * font.
494 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
496 HGDIOBJ ret = 0;
497 DC *dc = get_dc_ptr( hdc );
499 if (!dc) return 0;
501 if (!GDI_inc_ref_count( handle ))
503 release_dc_ptr( dc );
504 return 0;
507 if (GetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_VA_ABLE)
508 dc->gdiFont = WineEngCreateFontInstance( dc, handle );
510 if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont );
512 if (ret && dc->gdiFont) dc->gdiFont = 0;
514 if (ret == HGDI_ERROR)
516 GDI_dec_ref_count( handle );
517 ret = 0; /* SelectObject returns 0 on error */
519 else
521 ret = dc->hFont;
522 dc->hFont = handle;
523 update_font_code_page( dc );
524 GDI_dec_ref_count( ret );
526 release_dc_ptr( dc );
527 return ret;
531 /***********************************************************************
532 * FONT_GetObjectA
534 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
536 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
537 LOGFONTA lfA;
539 if (!font) return 0;
540 if (buffer)
542 FONT_LogFontWToA( &font->logfont, &lfA );
543 if (count > sizeof(lfA)) count = sizeof(lfA);
544 memcpy( buffer, &lfA, count );
546 else count = sizeof(lfA);
547 GDI_ReleaseObj( handle );
548 return count;
551 /***********************************************************************
552 * FONT_GetObjectW
554 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
556 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
558 if (!font) return 0;
559 if (buffer)
561 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
562 memcpy( buffer, &font->logfont, count );
564 else count = sizeof(LOGFONTW);
565 GDI_ReleaseObj( handle );
566 return count;
570 /***********************************************************************
571 * FONT_DeleteObject
573 static BOOL FONT_DeleteObject( HGDIOBJ handle )
575 FONTOBJ *obj;
577 WineEngDestroyFontInstance( handle );
579 if (!(obj = free_gdi_handle( handle ))) return FALSE;
580 return HeapFree( GetProcessHeap(), 0, obj );
584 /***********************************************************************
585 * FONT_EnumInstance
587 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
588 * We have to use other types because of the FONTENUMPROCW definition.
590 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
591 DWORD fType, LPARAM lp )
593 fontEnum32 *pfe = (fontEnum32*)lp;
594 INT ret = 1;
596 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
597 if ((!pfe->lpLogFontParam ||
598 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
599 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
600 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
602 /* convert font metrics */
603 ENUMLOGFONTEXA logfont;
604 NEWTEXTMETRICEXA tmA;
606 pfe->dwFlags |= ENUM_CALLED;
607 if (!(pfe->dwFlags & ENUM_UNICODE))
609 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
610 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
611 plf = (LOGFONTW *)&logfont.elfLogFont;
612 ptm = (TEXTMETRICW *)&tmA;
615 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
617 return ret;
620 /***********************************************************************
621 * FONT_EnumFontFamiliesEx
623 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf,
624 FONTENUMPROCW efproc,
625 LPARAM lParam, DWORD dwUnicode)
627 INT ret = 1, ret2;
628 DC *dc = get_dc_ptr( hDC );
629 fontEnum32 fe32;
630 BOOL enum_gdi_fonts;
632 if (!dc) return 0;
634 if (plf)
635 TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName),
636 plf->lfCharSet);
637 fe32.lpLogFontParam = plf;
638 fe32.lpEnumFunc = efproc;
639 fe32.lpData = lParam;
640 fe32.dwFlags = dwUnicode;
641 fe32.hdc = hDC;
643 enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE;
645 if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
647 ret = 0;
648 goto done;
651 if (enum_gdi_fonts)
652 ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 );
653 fe32.dwFlags &= ~ENUM_CALLED;
654 if (ret && dc->funcs->pEnumDeviceFonts) {
655 ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 );
656 if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
657 ret = ret2;
659 done:
660 release_dc_ptr( dc );
661 return ret;
664 /***********************************************************************
665 * EnumFontFamiliesExW (GDI32.@)
667 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
668 FONTENUMPROCW efproc,
669 LPARAM lParam, DWORD dwFlags )
671 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE );
674 /***********************************************************************
675 * EnumFontFamiliesExA (GDI32.@)
677 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
678 FONTENUMPROCA efproc,
679 LPARAM lParam, DWORD dwFlags)
681 LOGFONTW lfW, *plfW;
683 if (plf)
685 FONT_LogFontAToW( plf, &lfW );
686 plfW = &lfW;
688 else plfW = NULL;
690 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, 0);
693 /***********************************************************************
694 * EnumFontFamiliesA (GDI32.@)
696 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
697 FONTENUMPROCA efproc, LPARAM lpData )
699 LOGFONTA lf, *plf;
701 if (lpFamily)
703 if (!*lpFamily) return 1;
704 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
705 lf.lfCharSet = DEFAULT_CHARSET;
706 lf.lfPitchAndFamily = 0;
707 plf = &lf;
709 else plf = NULL;
711 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
714 /***********************************************************************
715 * EnumFontFamiliesW (GDI32.@)
717 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
718 FONTENUMPROCW efproc, LPARAM lpData )
720 LOGFONTW lf, *plf;
722 if (lpFamily)
724 if (!*lpFamily) return 1;
725 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
726 lf.lfCharSet = DEFAULT_CHARSET;
727 lf.lfPitchAndFamily = 0;
728 plf = &lf;
730 else plf = NULL;
732 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
735 /***********************************************************************
736 * EnumFontsA (GDI32.@)
738 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
739 LPARAM lpData )
741 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
744 /***********************************************************************
745 * EnumFontsW (GDI32.@)
747 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
748 LPARAM lpData )
750 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
754 /***********************************************************************
755 * GetTextCharacterExtra (GDI32.@)
757 INT WINAPI GetTextCharacterExtra( HDC hdc )
759 INT ret;
760 DC *dc = get_dc_ptr( hdc );
761 if (!dc) return 0x80000000;
762 ret = dc->charExtra;
763 release_dc_ptr( dc );
764 return ret;
768 /***********************************************************************
769 * SetTextCharacterExtra (GDI32.@)
771 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
773 INT prev;
774 DC * dc = get_dc_ptr( hdc );
775 if (!dc) return 0x80000000;
776 if (dc->funcs->pSetTextCharacterExtra)
777 prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra );
778 else
780 prev = dc->charExtra;
781 dc->charExtra = extra;
783 release_dc_ptr( dc );
784 return prev;
788 /***********************************************************************
789 * SetTextJustification (GDI32.@)
791 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
793 BOOL ret = TRUE;
794 DC * dc = get_dc_ptr( hdc );
795 if (!dc) return FALSE;
796 if (dc->funcs->pSetTextJustification)
797 ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks );
798 else
800 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
801 if (!extra) breaks = 0;
802 if (breaks)
804 dc->breakExtra = extra / breaks;
805 dc->breakRem = extra - (breaks * dc->breakExtra);
807 else
809 dc->breakExtra = 0;
810 dc->breakRem = 0;
813 release_dc_ptr( dc );
814 return ret;
818 /***********************************************************************
819 * GetTextFaceA (GDI32.@)
821 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
823 INT res = GetTextFaceW(hdc, 0, NULL);
824 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
825 GetTextFaceW( hdc, res, nameW );
827 if (name)
829 if (count)
831 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
832 if (res == 0)
833 res = count;
834 name[count-1] = 0;
835 /* GetTextFaceA does NOT include the nul byte in the return count. */
836 res--;
838 else
839 res = 0;
841 else
842 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
843 HeapFree( GetProcessHeap(), 0, nameW );
844 return res;
847 /***********************************************************************
848 * GetTextFaceW (GDI32.@)
850 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
852 FONTOBJ *font;
853 INT ret = 0;
855 DC * dc = get_dc_ptr( hdc );
856 if (!dc) return 0;
858 if(dc->gdiFont)
859 ret = WineEngGetTextFace(dc->gdiFont, count, name);
860 else if ((font = GDI_GetObjPtr( dc->hFont, OBJ_FONT )))
862 INT n = strlenW(font->logfont.lfFaceName) + 1;
863 if (name)
865 lstrcpynW( name, font->logfont.lfFaceName, count );
866 ret = min(count, n);
868 else ret = n;
869 GDI_ReleaseObj( dc->hFont );
871 release_dc_ptr( dc );
872 return ret;
876 /***********************************************************************
877 * GetTextExtentPoint32A (GDI32.@)
879 * See GetTextExtentPoint32W.
881 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
882 LPSIZE size )
884 BOOL ret = FALSE;
885 INT wlen;
886 LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
888 if (p) {
889 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
890 HeapFree( GetProcessHeap(), 0, p );
893 TRACE("(%p %s %d %p): returning %d x %d\n",
894 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
895 return ret;
899 /***********************************************************************
900 * GetTextExtentPoint32W [GDI32.@]
902 * Computes width/height for a string.
904 * Computes width and height of the specified string.
906 * RETURNS
907 * Success: TRUE
908 * Failure: FALSE
910 BOOL WINAPI GetTextExtentPoint32W(
911 HDC hdc, /* [in] Handle of device context */
912 LPCWSTR str, /* [in] Address of text string */
913 INT count, /* [in] Number of characters in string */
914 LPSIZE size) /* [out] Address of structure for string size */
916 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
919 /***********************************************************************
920 * GetTextExtentExPointI [GDI32.@]
922 * Computes width and height of the array of glyph indices.
924 * PARAMS
925 * hdc [I] Handle of device context.
926 * indices [I] Glyph index array.
927 * count [I] Number of glyphs in array.
928 * max_ext [I] Maximum width in glyphs.
929 * nfit [O] Maximum number of characters.
930 * dxs [O] Partial string widths.
931 * size [O] Returned string size.
933 * RETURNS
934 * Success: TRUE
935 * Failure: FALSE
937 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
938 LPINT nfit, LPINT dxs, LPSIZE size )
940 BOOL ret = FALSE;
941 DC * dc = get_dc_ptr( hdc );
942 if (!dc) return FALSE;
944 if(dc->gdiFont) {
945 ret = WineEngGetTextExtentExPointI(dc->gdiFont, indices, count, max_ext, nfit, dxs, size);
946 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
947 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
948 size->cx += count * dc->charExtra;
950 else if(dc->funcs->pGetTextExtentExPoint) {
951 FIXME("calling GetTextExtentExPoint\n");
952 ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, indices, count,
953 max_ext, nfit, dxs, size );
956 release_dc_ptr( dc );
958 TRACE("(%p %p %d %p): returning %d x %d\n",
959 hdc, indices, count, size, size->cx, size->cy );
960 return ret;
963 /***********************************************************************
964 * GetTextExtentPointI [GDI32.@]
966 * Computes width and height of the array of glyph indices.
968 * PARAMS
969 * hdc [I] Handle of device context.
970 * indices [I] Glyph index array.
971 * count [I] Number of glyphs in array.
972 * size [O] Returned string size.
974 * RETURNS
975 * Success: TRUE
976 * Failure: FALSE
978 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
980 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
984 /***********************************************************************
985 * GetTextExtentPointA (GDI32.@)
987 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
988 LPSIZE size )
990 TRACE("not bug compatible.\n");
991 return GetTextExtentPoint32A( hdc, str, count, size );
994 /***********************************************************************
995 * GetTextExtentPointW (GDI32.@)
997 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
998 LPSIZE size )
1000 TRACE("not bug compatible.\n");
1001 return GetTextExtentPoint32W( hdc, str, count, size );
1005 /***********************************************************************
1006 * GetTextExtentExPointA (GDI32.@)
1008 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1009 INT maxExt, LPINT lpnFit,
1010 LPINT alpDx, LPSIZE size )
1012 BOOL ret;
1013 INT wlen;
1014 INT *walpDx = NULL;
1015 LPWSTR p = NULL;
1017 if (alpDx &&
1018 NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
1019 return FALSE;
1021 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1022 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1023 if (walpDx)
1025 INT n = lpnFit ? *lpnFit : wlen;
1026 INT i, j;
1027 for(i = 0, j = 0; i < n; i++, j++)
1029 alpDx[j] = walpDx[i];
1030 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1033 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1034 HeapFree( GetProcessHeap(), 0, p );
1035 HeapFree( GetProcessHeap(), 0, walpDx );
1036 return ret;
1040 /***********************************************************************
1041 * GetTextExtentExPointW (GDI32.@)
1043 * Return the size of the string as it would be if it was output properly by
1044 * e.g. TextOut.
1046 * This should include
1047 * - Intercharacter spacing
1048 * - justification spacing (not yet done)
1049 * - kerning? see below
1051 * Kerning. Since kerning would be carried out by the rendering code it should
1052 * be done by the driver. However they don't support it yet. Also I am not
1053 * yet persuaded that (certainly under Win95) any kerning is actually done.
1055 * str: According to MSDN this should be null-terminated. That is not true; a
1056 * null will not terminate it early.
1057 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1058 * than count. I have seen it be either the size of the full string or
1059 * 1 less than the size of the full string. I have not seen it bear any
1060 * resemblance to the portion that would fit.
1061 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1062 * trailing intercharacter spacing and any trailing justification.
1064 * FIXME
1065 * Currently we do this by measuring each character etc. We should do it by
1066 * passing the request to the driver, perhaps by extending the
1067 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1068 * thinking about kerning issues and rounding issues in the justification.
1071 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1072 INT maxExt, LPINT lpnFit,
1073 LPINT alpDx, LPSIZE size )
1075 INT nFit = 0;
1076 LPINT dxs = NULL;
1077 DC *dc;
1078 BOOL ret = FALSE;
1079 TEXTMETRICW tm;
1081 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1083 dc = get_dc_ptr(hdc);
1084 if (! dc)
1085 return FALSE;
1087 GetTextMetricsW(hdc, &tm);
1089 /* If we need to calculate nFit, then we need the partial extents even if
1090 the user hasn't provided us with an array. */
1091 if (lpnFit)
1093 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1094 if (! dxs)
1096 release_dc_ptr(dc);
1097 SetLastError(ERROR_OUTOFMEMORY);
1098 return FALSE;
1101 else
1102 dxs = alpDx;
1104 if (dc->gdiFont)
1105 ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
1106 0, NULL, dxs, size);
1107 else if (dc->funcs->pGetTextExtentExPoint)
1108 ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
1109 0, NULL, dxs, size);
1111 /* Perform device size to world size transformations. */
1112 if (ret)
1114 INT extra = dc->charExtra,
1115 breakExtra = dc->breakExtra,
1116 breakRem = dc->breakRem,
1119 if (dxs)
1121 for (i = 0; i < count; ++i)
1123 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1124 dxs[i] += (i+1) * extra;
1125 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1127 dxs[i] += breakExtra;
1128 if (breakRem > 0)
1130 breakRem--;
1131 dxs[i]++;
1134 if (dxs[i] <= maxExt)
1135 ++nFit;
1137 breakRem = dc->breakRem;
1139 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1140 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1142 if (!dxs && count > 1 && (breakExtra || breakRem))
1144 for (i = 0; i < count; i++)
1146 if (str[i] == tm.tmBreakChar)
1148 size->cx += breakExtra;
1149 if (breakRem > 0)
1151 breakRem--;
1152 (size->cx)++;
1159 if (lpnFit)
1160 *lpnFit = nFit;
1162 if (! alpDx)
1163 HeapFree(GetProcessHeap(), 0, dxs);
1165 release_dc_ptr( dc );
1167 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1168 return ret;
1171 /***********************************************************************
1172 * GetTextMetricsA (GDI32.@)
1174 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1176 TEXTMETRICW tm32;
1178 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1179 FONT_TextMetricWToA( &tm32, metrics );
1180 return TRUE;
1183 /***********************************************************************
1184 * GetTextMetricsW (GDI32.@)
1186 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1188 BOOL ret = FALSE;
1189 DC * dc = get_dc_ptr( hdc );
1190 if (!dc) return FALSE;
1192 if (dc->gdiFont)
1193 ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1194 else if (dc->funcs->pGetTextMetrics)
1195 ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1197 if (ret)
1199 /* device layer returns values in device units
1200 * therefore we have to convert them to logical */
1202 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1203 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1205 #define WDPTOLP(x) ((x<0)? \
1206 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1207 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1208 #define HDPTOLP(y) ((y<0)? \
1209 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1210 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1212 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1213 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1214 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1215 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1216 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1217 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1218 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1219 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1220 ret = TRUE;
1221 #undef WDPTOLP
1222 #undef HDPTOLP
1223 TRACE("text metrics:\n"
1224 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1225 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1226 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1227 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1228 " PitchAndFamily = %02x\n"
1229 " --------------------\n"
1230 " InternalLeading = %i\n"
1231 " Ascent = %i\n"
1232 " Descent = %i\n"
1233 " Height = %i\n",
1234 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1235 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1236 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1237 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1238 metrics->tmPitchAndFamily,
1239 metrics->tmInternalLeading,
1240 metrics->tmAscent,
1241 metrics->tmDescent,
1242 metrics->tmHeight );
1244 release_dc_ptr( dc );
1245 return ret;
1249 /***********************************************************************
1250 * GetOutlineTextMetricsA (GDI32.@)
1251 * Gets metrics for TrueType fonts.
1253 * NOTES
1254 * If the supplied buffer isn't big enough Windows partially fills it up to
1255 * its given length and returns that length.
1257 * RETURNS
1258 * Success: Non-zero or size of required buffer
1259 * Failure: 0
1261 UINT WINAPI GetOutlineTextMetricsA(
1262 HDC hdc, /* [in] Handle of device context */
1263 UINT cbData, /* [in] Size of metric data array */
1264 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1266 char buf[512], *ptr;
1267 UINT ret, needed;
1268 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1269 OUTLINETEXTMETRICA *output = lpOTM;
1270 INT left, len;
1272 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1273 return 0;
1274 if(ret > sizeof(buf))
1275 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1276 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1278 needed = sizeof(OUTLINETEXTMETRICA);
1279 if(lpOTMW->otmpFamilyName)
1280 needed += WideCharToMultiByte(CP_ACP, 0,
1281 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1282 NULL, 0, NULL, NULL);
1283 if(lpOTMW->otmpFaceName)
1284 needed += WideCharToMultiByte(CP_ACP, 0,
1285 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1286 NULL, 0, NULL, NULL);
1287 if(lpOTMW->otmpStyleName)
1288 needed += WideCharToMultiByte(CP_ACP, 0,
1289 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1290 NULL, 0, NULL, NULL);
1291 if(lpOTMW->otmpFullName)
1292 needed += WideCharToMultiByte(CP_ACP, 0,
1293 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1294 NULL, 0, NULL, NULL);
1296 if(!lpOTM) {
1297 ret = needed;
1298 goto end;
1301 TRACE("needed = %d\n", needed);
1302 if(needed > cbData)
1303 /* Since the supplied buffer isn't big enough, we'll alloc one
1304 that is and memcpy the first cbData bytes into the lpOTM at
1305 the end. */
1306 output = HeapAlloc(GetProcessHeap(), 0, needed);
1308 ret = output->otmSize = min(needed, cbData);
1309 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1310 output->otmFiller = 0;
1311 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1312 output->otmfsSelection = lpOTMW->otmfsSelection;
1313 output->otmfsType = lpOTMW->otmfsType;
1314 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1315 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1316 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1317 output->otmEMSquare = lpOTMW->otmEMSquare;
1318 output->otmAscent = lpOTMW->otmAscent;
1319 output->otmDescent = lpOTMW->otmDescent;
1320 output->otmLineGap = lpOTMW->otmLineGap;
1321 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1322 output->otmsXHeight = lpOTMW->otmsXHeight;
1323 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1324 output->otmMacAscent = lpOTMW->otmMacAscent;
1325 output->otmMacDescent = lpOTMW->otmMacDescent;
1326 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1327 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1328 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1329 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1330 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1331 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1332 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1333 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1334 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1335 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1338 ptr = (char*)(output + 1);
1339 left = needed - sizeof(*output);
1341 if(lpOTMW->otmpFamilyName) {
1342 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1343 len = WideCharToMultiByte(CP_ACP, 0,
1344 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1345 ptr, left, NULL, NULL);
1346 left -= len;
1347 ptr += len;
1348 } else
1349 output->otmpFamilyName = 0;
1351 if(lpOTMW->otmpFaceName) {
1352 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1353 len = WideCharToMultiByte(CP_ACP, 0,
1354 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1355 ptr, left, NULL, NULL);
1356 left -= len;
1357 ptr += len;
1358 } else
1359 output->otmpFaceName = 0;
1361 if(lpOTMW->otmpStyleName) {
1362 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1363 len = WideCharToMultiByte(CP_ACP, 0,
1364 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1365 ptr, left, NULL, NULL);
1366 left -= len;
1367 ptr += len;
1368 } else
1369 output->otmpStyleName = 0;
1371 if(lpOTMW->otmpFullName) {
1372 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1373 len = WideCharToMultiByte(CP_ACP, 0,
1374 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1375 ptr, left, NULL, NULL);
1376 left -= len;
1377 } else
1378 output->otmpFullName = 0;
1380 assert(left == 0);
1382 if(output != lpOTM) {
1383 memcpy(lpOTM, output, cbData);
1384 HeapFree(GetProcessHeap(), 0, output);
1386 /* check if the string offsets really fit into the provided size */
1387 /* FIXME: should we check string length as well? */
1388 /* make sure that we don't read/write beyond the provided buffer */
1389 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1391 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1392 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1395 /* make sure that we don't read/write beyond the provided buffer */
1396 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1398 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1399 lpOTM->otmpFaceName = 0; /* doesn't fit */
1402 /* make sure that we don't read/write beyond the provided buffer */
1403 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1405 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1406 lpOTM->otmpStyleName = 0; /* doesn't fit */
1409 /* make sure that we don't read/write beyond the provided buffer */
1410 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1412 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1413 lpOTM->otmpFullName = 0; /* doesn't fit */
1417 end:
1418 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1419 HeapFree(GetProcessHeap(), 0, lpOTMW);
1421 return ret;
1425 /***********************************************************************
1426 * GetOutlineTextMetricsW [GDI32.@]
1428 UINT WINAPI GetOutlineTextMetricsW(
1429 HDC hdc, /* [in] Handle of device context */
1430 UINT cbData, /* [in] Size of metric data array */
1431 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1433 DC *dc = get_dc_ptr( hdc );
1434 OUTLINETEXTMETRICW *output = lpOTM;
1435 UINT ret;
1437 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1438 if(!dc) return 0;
1440 if(dc->gdiFont) {
1441 ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1442 if(lpOTM && ret) {
1443 if(ret > cbData) {
1444 output = HeapAlloc(GetProcessHeap(), 0, ret);
1445 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1448 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1449 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1451 #define WDPTOLP(x) ((x<0)? \
1452 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1453 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1454 #define HDPTOLP(y) ((y<0)? \
1455 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1456 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1458 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1459 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1460 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1461 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1462 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1463 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1464 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1465 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1466 output->otmAscent = HDPTOLP(output->otmAscent);
1467 output->otmDescent = HDPTOLP(output->otmDescent);
1468 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1469 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1470 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1471 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1472 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1473 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1474 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1475 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1476 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1477 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1478 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1479 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1480 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1481 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1482 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1483 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1484 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1485 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1486 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1487 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1488 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1489 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1490 #undef WDPTOLP
1491 #undef HDPTOLP
1492 if(output != lpOTM) {
1493 memcpy(lpOTM, output, cbData);
1494 HeapFree(GetProcessHeap(), 0, output);
1495 ret = cbData;
1500 else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1501 but really this should just be a return 0. */
1503 ret = sizeof(*lpOTM);
1504 if (lpOTM) {
1505 if(cbData < ret)
1506 ret = 0;
1507 else {
1508 memset(lpOTM, 0, ret);
1509 lpOTM->otmSize = sizeof(*lpOTM);
1510 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1512 Further fill of the structure not implemented,
1513 Needs real values for the structure members
1518 release_dc_ptr(dc);
1519 return ret;
1523 /***********************************************************************
1524 * GetCharWidthW (GDI32.@)
1525 * GetCharWidth32W (GDI32.@)
1527 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1528 LPINT buffer )
1530 UINT i;
1531 BOOL ret = FALSE;
1532 DC * dc = get_dc_ptr( hdc );
1533 if (!dc) return FALSE;
1535 if (dc->gdiFont)
1536 ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1537 else if (dc->funcs->pGetCharWidth)
1538 ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1540 if (ret)
1542 /* convert device units to logical */
1543 for( i = firstChar; i <= lastChar; i++, buffer++ )
1544 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1545 ret = TRUE;
1547 release_dc_ptr( dc );
1548 return ret;
1552 /***********************************************************************
1553 * GetCharWidthA (GDI32.@)
1554 * GetCharWidth32A (GDI32.@)
1556 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1557 LPINT buffer )
1559 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
1560 LPSTR str;
1561 LPWSTR wstr;
1562 BOOL ret = TRUE;
1564 if(count <= 0) return FALSE;
1566 str = HeapAlloc(GetProcessHeap(), 0, count);
1567 for(i = 0; i < count; i++)
1568 str[i] = (BYTE)(firstChar + i);
1570 wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1572 for(i = 0; i < wlen; i++)
1574 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1576 ret = FALSE;
1577 break;
1579 buffer++;
1582 HeapFree(GetProcessHeap(), 0, str);
1583 HeapFree(GetProcessHeap(), 0, wstr);
1585 return ret;
1589 /***********************************************************************
1590 * ExtTextOutA (GDI32.@)
1592 * See ExtTextOutW.
1594 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1595 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1597 INT wlen;
1598 UINT codepage;
1599 LPWSTR p;
1600 BOOL ret;
1601 LPINT lpDxW = NULL;
1603 if (flags & ETO_GLYPH_INDEX)
1604 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1606 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1608 if (lpDx) {
1609 unsigned int i = 0, j = 0;
1611 lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT));
1612 while(i < count) {
1613 if(IsDBCSLeadByteEx(codepage, str[i])) {
1614 lpDxW[j++] = lpDx[i] + lpDx[i+1];
1615 i = i + 2;
1616 } else {
1617 lpDxW[j++] = lpDx[i];
1618 i = i + 1;
1623 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1625 HeapFree( GetProcessHeap(), 0, p );
1626 HeapFree( GetProcessHeap(), 0, lpDxW );
1627 return ret;
1631 /***********************************************************************
1632 * ExtTextOutW (GDI32.@)
1634 * Draws text using the currently selected font, background color, and text color.
1637 * PARAMS
1638 * x,y [I] coordinates of string
1639 * flags [I]
1640 * ETO_GRAYED - undocumented on MSDN
1641 * ETO_OPAQUE - use background color for fill the rectangle
1642 * ETO_CLIPPED - clipping text to the rectangle
1643 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1644 * than encoded characters. Implies ETO_IGNORELANGUAGE
1645 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1646 * Affects BiDi ordering
1647 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1648 * ETO_PDY - unimplemented
1649 * ETO_NUMERICSLATIN - unimplemented always assumed -
1650 * do not translate numbers into locale representations
1651 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1652 * lprect [I] dimensions for clipping or/and opaquing
1653 * str [I] text string
1654 * count [I] number of symbols in string
1655 * lpDx [I] optional parameter with distance between drawing characters
1657 * RETURNS
1658 * Success: TRUE
1659 * Failure: FALSE
1661 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1662 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1664 BOOL ret = FALSE;
1665 LPWSTR reordered_str = (LPWSTR)str;
1666 WORD *glyphs = NULL;
1667 UINT align = GetTextAlign( hdc );
1668 POINT pt;
1669 TEXTMETRICW tm;
1670 LOGFONTW lf;
1671 double cosEsc, sinEsc;
1672 INT *deltas = NULL, char_extra;
1673 SIZE sz;
1674 RECT rc;
1675 BOOL done_extents = FALSE;
1676 INT width = 0, xwidth = 0, ywidth = 0;
1677 DWORD type;
1678 DC * dc = get_dc_ptr( hdc );
1679 INT breakRem;
1680 static int quietfixme = 0;
1682 if (!dc) return FALSE;
1684 breakRem = dc->breakRem;
1686 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
1688 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
1689 quietfixme = 1;
1691 if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1693 release_dc_ptr( dc );
1694 return ret;
1697 update_dc( dc );
1698 type = GetObjectType(hdc);
1699 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1701 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1702 release_dc_ptr( dc );
1703 return ret;
1706 if (!lprect)
1707 flags &= ~ETO_CLIPPED;
1709 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
1711 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1713 BIDI_Reorder( str, count, GCP_REORDER,
1714 ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
1715 WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
1716 reordered_str, count, NULL );
1718 flags |= ETO_IGNORELANGUAGE;
1721 TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
1722 lprect, debugstr_wn(str, count), count, lpDx);
1724 if(flags & ETO_GLYPH_INDEX)
1725 glyphs = reordered_str;
1727 if(lprect)
1728 TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
1729 lprect->bottom);
1730 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1732 if(align & TA_UPDATECP)
1734 GetCurrentPositionEx( hdc, &pt );
1735 x = pt.x;
1736 y = pt.y;
1739 GetTextMetricsW(hdc, &tm);
1740 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1742 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1743 lf.lfEscapement = 0;
1745 if(lf.lfEscapement != 0)
1747 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1748 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1750 else
1752 cosEsc = 1;
1753 sinEsc = 0;
1756 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1758 if(!lprect)
1760 if(flags & ETO_GLYPH_INDEX)
1761 GetTextExtentPointI(hdc, glyphs, count, &sz);
1762 else
1763 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1765 done_extents = TRUE;
1766 rc.left = x;
1767 rc.top = y;
1768 rc.right = x + sz.cx;
1769 rc.bottom = y + sz.cy;
1771 else
1773 rc = *lprect;
1776 LPtoDP(hdc, (POINT*)&rc, 2);
1778 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1779 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1782 if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1783 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1785 if(count == 0)
1787 ret = TRUE;
1788 goto done;
1791 pt.x = x;
1792 pt.y = y;
1793 LPtoDP(hdc, &pt, 1);
1794 x = pt.x;
1795 y = pt.y;
1797 char_extra = GetTextCharacterExtra(hdc);
1798 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
1800 UINT i;
1801 SIZE tmpsz;
1802 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
1803 for(i = 0; i < count; i++)
1805 if(lpDx && (flags & ETO_PDY))
1806 deltas[i] = lpDx[i*2] + char_extra;
1807 else if(lpDx)
1808 deltas[i] = lpDx[i] + char_extra;
1809 else
1811 if(flags & ETO_GLYPH_INDEX)
1812 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1813 else
1814 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
1816 deltas[i] = tmpsz.cx;
1819 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
1821 deltas[i] = deltas[i] + dc->breakExtra;
1822 if (breakRem > 0)
1824 breakRem--;
1825 deltas[i]++;
1828 deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
1829 width += deltas[i];
1832 else
1834 if(!done_extents)
1836 if(flags & ETO_GLYPH_INDEX)
1837 GetTextExtentPointI(hdc, glyphs, count, &sz);
1838 else
1839 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1840 done_extents = TRUE;
1842 width = INTERNAL_XWSTODS(dc, sz.cx);
1844 xwidth = width * cosEsc;
1845 ywidth = width * sinEsc;
1847 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
1848 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
1849 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
1851 case TA_LEFT:
1852 if (align & TA_UPDATECP)
1854 pt.x = x + xwidth;
1855 pt.y = y - ywidth;
1856 DPtoLP(hdc, &pt, 1);
1857 MoveToEx(hdc, pt.x, pt.y, NULL);
1859 break;
1861 case TA_CENTER:
1862 x -= xwidth / 2;
1863 y += ywidth / 2;
1864 break;
1866 case TA_RIGHT:
1867 x -= xwidth;
1868 y += ywidth;
1869 if (align & TA_UPDATECP)
1871 pt.x = x;
1872 pt.y = y;
1873 DPtoLP(hdc, &pt, 1);
1874 MoveToEx(hdc, pt.x, pt.y, NULL);
1876 break;
1879 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
1881 case TA_TOP:
1882 y += tm.tmAscent * cosEsc;
1883 x += tm.tmAscent * sinEsc;
1884 break;
1886 case TA_BOTTOM:
1887 y -= tm.tmDescent * cosEsc;
1888 x -= tm.tmDescent * sinEsc;
1889 break;
1891 case TA_BASELINE:
1892 break;
1895 if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
1897 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
1899 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
1900 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
1902 RECT rc;
1903 rc.left = x;
1904 rc.right = x + width;
1905 rc.top = y - tm.tmAscent;
1906 rc.bottom = y + tm.tmDescent;
1907 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1912 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
1914 HFONT orig_font = dc->hFont, cur_font;
1915 UINT glyph;
1916 INT span = 0, *offsets = NULL;
1917 unsigned int i;
1919 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1920 for(i = 0; i < count; i++)
1922 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
1923 if(cur_font != dc->hFont)
1925 if(!offsets)
1927 unsigned int j;
1928 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
1929 offsets[0] = 0;
1930 if(!deltas)
1932 SIZE tmpsz;
1933 for(j = 1; j < count; j++)
1935 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
1936 offsets[j] = offsets[j-1] + INTERNAL_XWSTODS(dc, tmpsz.cx);
1939 else
1941 for(j = 1; j < count; j++)
1942 offsets[j] = offsets[j-1] + deltas[j];
1945 if(span)
1947 if (PATH_IsPathOpen(dc->path))
1948 ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
1949 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1950 glyphs, span, deltas ? deltas + i - span : NULL);
1951 else
1952 dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
1953 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1954 glyphs, span, deltas ? deltas + i - span : NULL);
1955 span = 0;
1957 SelectObject(hdc, cur_font);
1959 glyphs[span++] = glyph;
1961 if(i == count - 1)
1963 if (PATH_IsPathOpen(dc->path))
1964 ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
1965 y - (offsets ? offsets[count - span] * sinEsc : 0),
1966 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1967 glyphs, span, deltas ? deltas + count - span : NULL);
1968 else
1969 ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
1970 y - (offsets ? offsets[count - span] * sinEsc : 0),
1971 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1972 glyphs, span, deltas ? deltas + count - span : NULL);
1973 SelectObject(hdc, orig_font);
1974 HeapFree(GetProcessHeap(), 0, offsets);
1978 else
1980 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
1982 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1983 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
1984 flags |= ETO_GLYPH_INDEX;
1987 if (PATH_IsPathOpen(dc->path))
1988 ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
1989 glyphs ? glyphs : reordered_str, count, deltas);
1990 else
1991 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
1992 glyphs ? glyphs : reordered_str, count, deltas);
1995 done:
1996 HeapFree(GetProcessHeap(), 0, deltas);
1997 if(glyphs != reordered_str)
1998 HeapFree(GetProcessHeap(), 0, glyphs);
1999 if(reordered_str != str)
2000 HeapFree(GetProcessHeap(), 0, reordered_str);
2002 release_dc_ptr( dc );
2004 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2006 int underlinePos, strikeoutPos;
2007 int underlineWidth, strikeoutWidth;
2008 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2009 OUTLINETEXTMETRICW* otm = NULL;
2011 if(!size)
2013 underlinePos = 0;
2014 underlineWidth = tm.tmAscent / 20 + 1;
2015 strikeoutPos = tm.tmAscent / 2;
2016 strikeoutWidth = underlineWidth;
2018 else
2020 otm = HeapAlloc(GetProcessHeap(), 0, size);
2021 GetOutlineTextMetricsW(hdc, size, otm);
2022 underlinePos = otm->otmsUnderscorePosition;
2023 underlineWidth = otm->otmsUnderscoreSize;
2024 strikeoutPos = otm->otmsStrikeoutPosition;
2025 strikeoutWidth = otm->otmsStrikeoutSize;
2026 HeapFree(GetProcessHeap(), 0, otm);
2029 if (PATH_IsPathOpen(dc->path))
2031 POINT pts[5];
2032 HPEN hpen;
2033 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2035 hbrush = SelectObject(hdc, hbrush);
2036 hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2038 if (lf.lfUnderline)
2040 pts[0].x = x - underlinePos * sinEsc;
2041 pts[0].y = y - underlinePos * cosEsc;
2042 pts[1].x = x + xwidth - underlinePos * sinEsc;
2043 pts[1].y = y - ywidth - underlinePos * cosEsc;
2044 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2045 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2046 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2047 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2048 pts[4].x = pts[0].x;
2049 pts[4].y = pts[0].y;
2050 DPtoLP(hdc, pts, 5);
2051 Polygon(hdc, pts, 5);
2054 if (lf.lfStrikeOut)
2056 pts[0].x = x - strikeoutPos * sinEsc;
2057 pts[0].y = y - strikeoutPos * cosEsc;
2058 pts[1].x = x + xwidth - strikeoutPos * sinEsc;
2059 pts[1].y = y - ywidth - strikeoutPos * cosEsc;
2060 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2061 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2062 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2063 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2064 pts[4].x = pts[0].x;
2065 pts[4].y = pts[0].y;
2066 DPtoLP(hdc, pts, 5);
2067 Polygon(hdc, pts, 5);
2070 SelectObject(hdc, hpen);
2071 hbrush = SelectObject(hdc, hbrush);
2072 DeleteObject(hbrush);
2074 else
2076 POINT pts[2], oldpt;
2077 HPEN hpen;
2079 if (lf.lfUnderline)
2081 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2082 hpen = SelectObject(hdc, hpen);
2083 pts[0].x = x;
2084 pts[0].y = y;
2085 pts[1].x = x + xwidth;
2086 pts[1].y = y - ywidth;
2087 DPtoLP(hdc, pts, 2);
2088 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2089 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2090 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2091 DeleteObject(SelectObject(hdc, hpen));
2094 if (lf.lfStrikeOut)
2096 hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
2097 hpen = SelectObject(hdc, hpen);
2098 pts[0].x = x;
2099 pts[0].y = y;
2100 pts[1].x = x + xwidth;
2101 pts[1].y = y - ywidth;
2102 DPtoLP(hdc, pts, 2);
2103 MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2104 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2105 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2106 DeleteObject(SelectObject(hdc, hpen));
2111 return ret;
2115 /***********************************************************************
2116 * TextOutA (GDI32.@)
2118 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2120 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2124 /***********************************************************************
2125 * TextOutW (GDI32.@)
2127 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2129 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2133 /***********************************************************************
2134 * PolyTextOutA (GDI32.@)
2136 * See PolyTextOutW.
2138 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2140 for (; cStrings>0; cStrings--, pptxt++)
2141 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2142 return FALSE;
2143 return TRUE;
2148 /***********************************************************************
2149 * PolyTextOutW (GDI32.@)
2151 * Draw several Strings
2153 * RETURNS
2154 * TRUE: Success.
2155 * FALSE: Failure.
2157 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2159 for (; cStrings>0; cStrings--, pptxt++)
2160 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2161 return FALSE;
2162 return TRUE;
2166 /* FIXME: all following APIs ******************************************/
2169 /***********************************************************************
2170 * SetMapperFlags (GDI32.@)
2172 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2174 DC *dc = get_dc_ptr( hDC );
2175 DWORD ret = 0;
2176 if(!dc) return 0;
2177 if(dc->funcs->pSetMapperFlags)
2179 ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2180 /* FIXME: ret is just a success flag, we should return a proper value */
2182 else
2183 FIXME("(%p, 0x%08x): stub - harmless\n", hDC, dwFlag);
2184 release_dc_ptr( dc );
2185 return ret;
2188 /***********************************************************************
2189 * GetAspectRatioFilterEx (GDI32.@)
2191 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2193 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2194 return FALSE;
2198 /***********************************************************************
2199 * GetCharABCWidthsA (GDI32.@)
2201 * See GetCharABCWidthsW.
2203 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2204 LPABC abc )
2206 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
2207 LPSTR str;
2208 LPWSTR wstr;
2209 BOOL ret = TRUE;
2211 if(count <= 0) return FALSE;
2213 str = HeapAlloc(GetProcessHeap(), 0, count);
2214 for(i = 0; i < count; i++)
2215 str[i] = (BYTE)(firstChar + i);
2217 wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
2219 for(i = 0; i < wlen; i++)
2221 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2223 ret = FALSE;
2224 break;
2226 abc++;
2229 HeapFree(GetProcessHeap(), 0, str);
2230 HeapFree(GetProcessHeap(), 0, wstr);
2232 return ret;
2236 /******************************************************************************
2237 * GetCharABCWidthsW [GDI32.@]
2239 * Retrieves widths of characters in range.
2241 * PARAMS
2242 * hdc [I] Handle of device context
2243 * firstChar [I] First character in range to query
2244 * lastChar [I] Last character in range to query
2245 * abc [O] Address of character-width structure
2247 * NOTES
2248 * Only works with TrueType fonts
2250 * RETURNS
2251 * Success: TRUE
2252 * Failure: FALSE
2254 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2255 LPABC abc )
2257 DC *dc = get_dc_ptr(hdc);
2258 unsigned int i;
2259 BOOL ret = FALSE;
2261 if (!dc) return FALSE;
2263 if (!abc)
2265 release_dc_ptr( dc );
2266 return FALSE;
2269 if(dc->gdiFont)
2270 ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2271 else
2272 FIXME(": stub\n");
2274 if (ret)
2276 /* convert device units to logical */
2277 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2278 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2279 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2280 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2282 ret = TRUE;
2285 release_dc_ptr( dc );
2286 return ret;
2290 /******************************************************************************
2291 * GetCharABCWidthsI [GDI32.@]
2293 * Retrieves widths of characters in range.
2295 * PARAMS
2296 * hdc [I] Handle of device context
2297 * firstChar [I] First glyphs in range to query
2298 * count [I] Last glyphs in range to query
2299 * pgi [i] Array of glyphs to query
2300 * abc [O] Address of character-width structure
2302 * NOTES
2303 * Only works with TrueType fonts
2305 * RETURNS
2306 * Success: TRUE
2307 * Failure: FALSE
2309 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2310 LPWORD pgi, LPABC abc)
2312 DC *dc = get_dc_ptr(hdc);
2313 unsigned int i;
2314 BOOL ret = FALSE;
2316 if (!dc) return FALSE;
2318 if (!abc)
2320 release_dc_ptr( dc );
2321 return FALSE;
2324 if(dc->gdiFont)
2325 ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2326 else
2327 FIXME(": stub\n");
2329 if (ret)
2331 /* convert device units to logical */
2332 for( i = 0; i < count; i++, abc++ ) {
2333 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2334 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2335 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2337 ret = TRUE;
2340 release_dc_ptr( dc );
2341 return ret;
2345 /***********************************************************************
2346 * GetGlyphOutlineA (GDI32.@)
2348 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2349 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2350 LPVOID lpBuffer, const MAT2 *lpmat2 )
2352 LPWSTR p = NULL;
2353 DWORD ret;
2354 UINT c;
2356 if (!lpmat2) return GDI_ERROR;
2358 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2359 int len;
2360 char mbchs[2];
2361 if(uChar > 0xff) { /* but, 2 bytes character only */
2362 len = 2;
2363 mbchs[0] = (uChar & 0xff00) >> 8;
2364 mbchs[1] = (uChar & 0xff);
2365 } else {
2366 len = 1;
2367 mbchs[0] = (uChar & 0xff);
2369 p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
2370 c = p[0];
2371 } else
2372 c = uChar;
2373 ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
2374 lpmat2);
2375 HeapFree(GetProcessHeap(), 0, p);
2376 return ret;
2379 /***********************************************************************
2380 * GetGlyphOutlineW (GDI32.@)
2382 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2383 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2384 LPVOID lpBuffer, const MAT2 *lpmat2 )
2386 DC *dc;
2387 DWORD ret;
2389 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2390 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2392 if (!lpmat2) return GDI_ERROR;
2394 dc = get_dc_ptr(hdc);
2395 if(!dc) return GDI_ERROR;
2397 if(dc->gdiFont)
2398 ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2399 cbBuffer, lpBuffer, lpmat2);
2400 else
2401 ret = GDI_ERROR;
2403 release_dc_ptr( dc );
2404 return ret;
2408 /***********************************************************************
2409 * CreateScalableFontResourceA (GDI32.@)
2411 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2412 LPCSTR lpszResourceFile,
2413 LPCSTR lpszFontFile,
2414 LPCSTR lpszCurrentPath )
2416 LPWSTR lpszResourceFileW = NULL;
2417 LPWSTR lpszFontFileW = NULL;
2418 LPWSTR lpszCurrentPathW = NULL;
2419 int len;
2420 BOOL ret;
2422 if (lpszResourceFile)
2424 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2425 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2426 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2429 if (lpszFontFile)
2431 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2432 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2433 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2436 if (lpszCurrentPath)
2438 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2439 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2440 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2443 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2444 lpszFontFileW, lpszCurrentPathW);
2446 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2447 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2448 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2450 return ret;
2453 /***********************************************************************
2454 * CreateScalableFontResourceW (GDI32.@)
2456 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2457 LPCWSTR lpszResourceFile,
2458 LPCWSTR lpszFontFile,
2459 LPCWSTR lpszCurrentPath )
2461 HANDLE f;
2462 FIXME("(%d,%s,%s,%s): stub\n",
2463 fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
2464 debugstr_w(lpszCurrentPath) );
2466 /* fHidden=1 - only visible for the calling app, read-only, not
2467 * enumerated with EnumFonts/EnumFontFamilies
2468 * lpszCurrentPath can be NULL
2471 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2472 if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2473 CloseHandle(f);
2474 SetLastError(ERROR_FILE_EXISTS);
2475 return FALSE;
2477 return FALSE; /* create failed */
2480 /*************************************************************************
2481 * GetKerningPairsA (GDI32.@)
2483 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2484 LPKERNINGPAIR kern_pairA )
2486 UINT cp;
2487 CPINFO cpi;
2488 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2489 KERNINGPAIR *kern_pairW;
2491 if (!cPairs && kern_pairA)
2493 SetLastError(ERROR_INVALID_PARAMETER);
2494 return 0;
2497 cp = GdiGetCodePage(hDC);
2499 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2500 * to fail on an invalid character for CP_SYMBOL.
2502 cpi.DefaultChar[0] = 0;
2503 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2505 FIXME("Can't find codepage %u info\n", cp);
2506 return 0;
2509 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2510 if (!total_kern_pairs) return 0;
2512 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2513 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2515 for (i = 0; i < total_kern_pairs; i++)
2517 char first, second;
2519 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2520 continue;
2522 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2523 continue;
2525 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2526 continue;
2528 if (kern_pairA)
2530 if (kern_pairs_copied >= cPairs) break;
2532 kern_pairA->wFirst = (BYTE)first;
2533 kern_pairA->wSecond = (BYTE)second;
2534 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2535 kern_pairA++;
2537 kern_pairs_copied++;
2540 HeapFree(GetProcessHeap(), 0, kern_pairW);
2542 return kern_pairs_copied;
2545 /*************************************************************************
2546 * GetKerningPairsW (GDI32.@)
2548 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2549 LPKERNINGPAIR lpKerningPairs )
2551 DC *dc;
2552 DWORD ret = 0;
2554 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2556 if (!cPairs && lpKerningPairs)
2558 SetLastError(ERROR_INVALID_PARAMETER);
2559 return 0;
2562 dc = get_dc_ptr(hDC);
2563 if (!dc) return 0;
2565 if (dc->gdiFont)
2566 ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
2568 release_dc_ptr( dc );
2569 return ret;
2572 /*************************************************************************
2573 * TranslateCharsetInfo [GDI32.@]
2575 * Fills a CHARSETINFO structure for a character set, code page, or
2576 * font. This allows making the correspondence between different labels
2577 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2578 * of the same encoding.
2580 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2581 * only one codepage should be set in *lpSrc.
2583 * RETURNS
2584 * TRUE on success, FALSE on failure.
2587 BOOL WINAPI TranslateCharsetInfo(
2588 LPDWORD lpSrc, /* [in]
2589 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2590 if flags == TCI_SRCCHARSET: a character set value
2591 if flags == TCI_SRCCODEPAGE: a code page value
2593 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2594 DWORD flags /* [in] determines interpretation of lpSrc */)
2596 int index = 0;
2597 switch (flags) {
2598 case TCI_SRCFONTSIG:
2599 while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
2600 break;
2601 case TCI_SRCCODEPAGE:
2602 while (PtrToUlong(lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
2603 break;
2604 case TCI_SRCCHARSET:
2605 while (PtrToUlong(lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
2606 break;
2607 default:
2608 return FALSE;
2610 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2611 *lpCs = FONT_tci[index];
2612 return TRUE;
2615 /*************************************************************************
2616 * GetFontLanguageInfo (GDI32.@)
2618 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2620 FONTSIGNATURE fontsig;
2621 static const DWORD GCP_DBCS_MASK=0x003F0000,
2622 GCP_DIACRITIC_MASK=0x00000000,
2623 FLI_GLYPHS_MASK=0x00000000,
2624 GCP_GLYPHSHAPE_MASK=0x00000040,
2625 GCP_KASHIDA_MASK=0x00000000,
2626 GCP_LIGATE_MASK=0x00000000,
2627 GCP_USEKERNING_MASK=0x00000000,
2628 GCP_REORDER_MASK=0x00000060;
2630 DWORD result=0;
2632 GetTextCharsetInfo( hdc, &fontsig, 0 );
2633 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2635 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2636 result|=GCP_DBCS;
2638 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2639 result|=GCP_DIACRITIC;
2641 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2642 result|=FLI_GLYPHS;
2644 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2645 result|=GCP_GLYPHSHAPE;
2647 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2648 result|=GCP_KASHIDA;
2650 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2651 result|=GCP_LIGATE;
2653 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2654 result|=GCP_USEKERNING;
2656 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2657 if( GetTextAlign( hdc) & TA_RTLREADING )
2658 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2659 result|=GCP_REORDER;
2661 return result;
2665 /*************************************************************************
2666 * GetFontData [GDI32.@]
2668 * Retrieve data for TrueType font.
2670 * RETURNS
2672 * success: Number of bytes returned
2673 * failure: GDI_ERROR
2675 * NOTES
2677 * Calls SetLastError()
2680 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2681 LPVOID buffer, DWORD length)
2683 DC *dc = get_dc_ptr(hdc);
2684 DWORD ret = GDI_ERROR;
2686 if(!dc) return GDI_ERROR;
2688 if(dc->gdiFont)
2689 ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2691 release_dc_ptr( dc );
2692 return ret;
2695 /*************************************************************************
2696 * GetGlyphIndicesA [GDI32.@]
2698 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2699 LPWORD pgi, DWORD flags)
2701 DWORD ret;
2702 WCHAR *lpstrW;
2703 INT countW;
2705 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2706 hdc, debugstr_an(lpstr, count), count, pgi, flags);
2708 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
2709 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2710 HeapFree(GetProcessHeap(), 0, lpstrW);
2712 return ret;
2715 /*************************************************************************
2716 * GetGlyphIndicesW [GDI32.@]
2718 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2719 LPWORD pgi, DWORD flags)
2721 DC *dc = get_dc_ptr(hdc);
2722 DWORD ret = GDI_ERROR;
2724 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2725 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2727 if(!dc) return GDI_ERROR;
2729 if(dc->gdiFont)
2730 ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2732 release_dc_ptr( dc );
2733 return ret;
2736 /*************************************************************************
2737 * GetCharacterPlacementA [GDI32.@]
2739 * See GetCharacterPlacementW.
2741 * NOTES:
2742 * the web browser control of ie4 calls this with dwFlags=0
2744 DWORD WINAPI
2745 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2746 INT nMaxExtent, GCP_RESULTSA *lpResults,
2747 DWORD dwFlags)
2749 WCHAR *lpStringW;
2750 INT uCountW;
2751 GCP_RESULTSW resultsW;
2752 DWORD ret;
2753 UINT font_cp;
2755 TRACE("%s, %d, %d, 0x%08x\n",
2756 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2758 /* both structs are equal in size */
2759 memcpy(&resultsW, lpResults, sizeof(resultsW));
2761 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
2762 if(lpResults->lpOutString)
2763 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2765 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2767 lpResults->nGlyphs = resultsW.nGlyphs;
2768 lpResults->nMaxFit = resultsW.nMaxFit;
2770 if(lpResults->lpOutString) {
2771 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
2772 lpResults->lpOutString, uCount, NULL, NULL );
2775 HeapFree(GetProcessHeap(), 0, lpStringW);
2776 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2778 return ret;
2781 /*************************************************************************
2782 * GetCharacterPlacementW [GDI32.@]
2784 * Retrieve information about a string. This includes the width, reordering,
2785 * Glyphing and so on.
2787 * RETURNS
2789 * The width and height of the string if successful, 0 if failed.
2791 * BUGS
2793 * All flags except GCP_REORDER are not yet implemented.
2794 * Reordering is not 100% compliant to the Windows BiDi method.
2795 * Caret positioning is not yet implemented for BiDi.
2796 * Classes are not yet implemented.
2799 DWORD WINAPI
2800 GetCharacterPlacementW(
2801 HDC hdc, /* [in] Device context for which the rendering is to be done */
2802 LPCWSTR lpString, /* [in] The string for which information is to be returned */
2803 INT uCount, /* [in] Number of WORDS in string. */
2804 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
2805 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
2806 DWORD dwFlags /* [in] Flags specifying how to process the string */
2809 DWORD ret=0;
2810 SIZE size;
2811 UINT i, nSet;
2813 TRACE("%s, %d, %d, 0x%08x\n",
2814 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2816 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
2817 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2818 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
2819 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
2820 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
2822 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
2823 if(lpResults->lpClass) FIXME("classes not implemented\n");
2824 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
2825 FIXME("Caret positions for complex scripts not implemented\n");
2827 nSet = (UINT)uCount;
2828 if(nSet > lpResults->nGlyphs)
2829 nSet = lpResults->nGlyphs;
2831 /* return number of initialized fields */
2832 lpResults->nGlyphs = nSet;
2834 if((dwFlags&GCP_REORDER)==0 )
2836 /* Treat the case where no special handling was requested in a fastpath way */
2837 /* copy will do if the GCP_REORDER flag is not set */
2838 if(lpResults->lpOutString)
2839 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
2841 if(lpResults->lpOrder)
2843 for(i = 0; i < nSet; i++)
2844 lpResults->lpOrder[i] = i;
2846 } else
2848 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
2849 nSet, lpResults->lpOrder );
2852 /* FIXME: Will use the placement chars */
2853 if (lpResults->lpDx)
2855 int c;
2856 for (i = 0; i < nSet; i++)
2858 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
2859 lpResults->lpDx[i]= c;
2863 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
2865 int pos = 0;
2867 lpResults->lpCaretPos[0] = 0;
2868 for (i = 1; i < nSet; i++)
2869 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
2870 lpResults->lpCaretPos[i] = (pos += size.cx);
2873 if(lpResults->lpGlyphs)
2874 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
2876 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
2877 ret = MAKELONG(size.cx, size.cy);
2879 return ret;
2882 /*************************************************************************
2883 * GetCharABCWidthsFloatA [GDI32.@]
2885 * See GetCharABCWidthsFloatW.
2887 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2889 INT i, wlen, count = (INT)(last - first + 1);
2890 LPSTR str;
2891 LPWSTR wstr;
2892 BOOL ret = TRUE;
2894 if (count <= 0) return FALSE;
2896 str = HeapAlloc(GetProcessHeap(), 0, count);
2898 for(i = 0; i < count; i++)
2899 str[i] = (BYTE)(first + i);
2901 wstr = FONT_mbtowc( hdc, str, count, &wlen, NULL );
2903 for (i = 0; i < wlen; i++)
2905 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
2907 ret = FALSE;
2908 break;
2910 abcf++;
2913 HeapFree( GetProcessHeap(), 0, str );
2914 HeapFree( GetProcessHeap(), 0, wstr );
2916 return ret;
2919 /*************************************************************************
2920 * GetCharABCWidthsFloatW [GDI32.@]
2922 * Retrieves widths of a range of characters.
2924 * PARAMS
2925 * hdc [I] Handle to device context.
2926 * first [I] First character in range to query.
2927 * last [I] Last character in range to query.
2928 * abcf [O] Array of LPABCFLOAT structures.
2930 * RETURNS
2931 * Success: TRUE
2932 * Failure: FALSE
2934 * BUGS
2935 * Only works with TrueType fonts. It also doesn't return real
2936 * floats but converted integers because it's implemented on
2937 * top of GetCharABCWidthsW.
2939 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2941 ABC *abc, *abc_base;
2942 unsigned int i, size = sizeof(ABC) * (last - first + 1);
2943 BOOL ret;
2945 TRACE("%p, %d, %d, %p - partial stub\n", hdc, first, last, abcf);
2947 abc = abc_base = HeapAlloc( GetProcessHeap(), 0, size );
2948 if (!abc) return FALSE;
2950 ret = GetCharABCWidthsW( hdc, first, last, abc );
2951 if (ret)
2953 for (i = first; i <= last; i++, abc++, abcf++)
2955 abcf->abcfA = abc->abcA;
2956 abcf->abcfB = abc->abcB;
2957 abcf->abcfC = abc->abcC;
2960 HeapFree( GetProcessHeap(), 0, abc_base );
2961 return ret;
2964 /*************************************************************************
2965 * GetCharWidthFloatA [GDI32.@]
2967 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
2968 UINT iLastChar, PFLOAT pxBuffer)
2970 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
2971 return 0;
2974 /*************************************************************************
2975 * GetCharWidthFloatW [GDI32.@]
2977 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
2978 UINT iLastChar, PFLOAT pxBuffer)
2980 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
2981 return 0;
2985 /***********************************************************************
2987 * Font Resource API *
2989 ***********************************************************************/
2991 /***********************************************************************
2992 * AddFontResourceA (GDI32.@)
2994 INT WINAPI AddFontResourceA( LPCSTR str )
2996 return AddFontResourceExA( str, 0, NULL);
2999 /***********************************************************************
3000 * AddFontResourceW (GDI32.@)
3002 INT WINAPI AddFontResourceW( LPCWSTR str )
3004 return AddFontResourceExW(str, 0, NULL);
3008 /***********************************************************************
3009 * AddFontResourceExA (GDI32.@)
3011 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3013 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3014 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3015 INT ret;
3017 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3018 ret = AddFontResourceExW(strW, fl, pdv);
3019 HeapFree(GetProcessHeap(), 0, strW);
3020 return ret;
3023 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3025 HRSRC rsrc = FindResourceW(hModule, name, type);
3026 HGLOBAL hMem = LoadResource(hModule, rsrc);
3027 LPVOID *pMem = LockResource(hMem);
3028 int *num_total = (int *)lParam;
3029 DWORD num_in_res;
3031 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3032 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3034 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3035 return FALSE;
3038 *num_total += num_in_res;
3039 return TRUE;
3042 /***********************************************************************
3043 * AddFontResourceExW (GDI32.@)
3045 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3047 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3048 if (ret == 0)
3050 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3051 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3052 if (hModule != NULL)
3054 int num_resources = 0;
3055 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3057 TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3058 wine_dbgstr_w(str));
3059 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3060 ret = num_resources;
3061 FreeLibrary(hModule);
3064 return ret;
3067 /***********************************************************************
3068 * RemoveFontResourceA (GDI32.@)
3070 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3072 return RemoveFontResourceExA(str, 0, 0);
3075 /***********************************************************************
3076 * RemoveFontResourceW (GDI32.@)
3078 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3080 return RemoveFontResourceExW(str, 0, 0);
3083 /***********************************************************************
3084 * AddFontMemResourceEx (GDI32.@)
3086 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3088 return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts);
3091 /***********************************************************************
3092 * RemoveFontMemResourceEx (GDI32.@)
3094 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3096 FIXME("(%p) stub\n", fh);
3097 return TRUE;
3100 /***********************************************************************
3101 * RemoveFontResourceExA (GDI32.@)
3103 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3105 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3106 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3107 INT ret;
3109 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3110 ret = RemoveFontResourceExW(strW, fl, pdv);
3111 HeapFree(GetProcessHeap(), 0, strW);
3112 return ret;
3115 /***********************************************************************
3116 * RemoveFontResourceExW (GDI32.@)
3118 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3120 return WineEngRemoveFontResourceEx(str, fl, pdv);
3123 /***********************************************************************
3124 * GetTextCharset (GDI32.@)
3126 UINT WINAPI GetTextCharset(HDC hdc)
3128 /* MSDN docs say this is equivalent */
3129 return GetTextCharsetInfo(hdc, NULL, 0);
3132 /***********************************************************************
3133 * GetTextCharsetInfo (GDI32.@)
3135 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3137 UINT ret = DEFAULT_CHARSET;
3138 DC *dc = get_dc_ptr(hdc);
3140 if (dc)
3142 if (dc->gdiFont)
3143 ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3145 release_dc_ptr( dc );
3148 if (ret == DEFAULT_CHARSET && fs)
3149 memset(fs, 0, sizeof(FONTSIGNATURE));
3150 return ret;
3153 /***********************************************************************
3154 * GdiGetCharDimensions (GDI32.@)
3156 * Gets the average width of the characters in the English alphabet.
3158 * PARAMS
3159 * hdc [I] Handle to the device context to measure on.
3160 * lptm [O] Pointer to memory to store the text metrics into.
3161 * height [O] On exit, the maximum height of characters in the English alphabet.
3163 * RETURNS
3164 * The average width of characters in the English alphabet.
3166 * NOTES
3167 * This function is used by the dialog manager to get the size of a dialog
3168 * unit. It should also be used by other pieces of code that need to know
3169 * the size of a dialog unit in logical units without having access to the
3170 * window handle of the dialog.
3171 * Windows caches the font metrics from this function, but we don't and
3172 * there doesn't appear to be an immediate advantage to do so.
3174 * SEE ALSO
3175 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3177 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3179 SIZE sz;
3180 static const WCHAR alphabet[] = {
3181 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3182 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3183 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3185 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3187 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3189 if (height) *height = sz.cy;
3190 return (sz.cx / 26 + 1) / 2;
3193 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3195 FIXME("(%d): stub\n", fEnableEUDC);
3196 return FALSE;
3199 /***********************************************************************
3200 * GetCharWidthI (GDI32.@)
3202 * Retrieve widths of characters.
3204 * PARAMS
3205 * hdc [I] Handle to a device context.
3206 * first [I] First glyph in range to query.
3207 * count [I] Number of glyph indices to query.
3208 * glyphs [I] Array of glyphs to query.
3209 * buffer [O] Buffer to receive character widths.
3211 * NOTES
3212 * Only works with TrueType fonts.
3214 * RETURNS
3215 * Success: TRUE
3216 * Failure: FALSE
3218 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3220 ABC *abc;
3221 unsigned int i;
3223 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3225 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3226 return FALSE;
3228 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3230 HeapFree(GetProcessHeap(), 0, abc);
3231 return FALSE;
3234 for (i = 0; i < count; i++)
3235 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3237 HeapFree(GetProcessHeap(), 0, abc);
3238 return TRUE;
3241 /***********************************************************************
3242 * GetFontUnicodeRanges (GDI32.@)
3244 * Retrieve a list of supported Unicode characters in a font.
3246 * PARAMS
3247 * hdc [I] Handle to a device context.
3248 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3250 * RETURNS
3251 * Success: Number of bytes written to the buffer pointed to by lpgs.
3252 * Failure: 0
3255 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3257 DWORD ret = 0;
3258 DC *dc = get_dc_ptr(hdc);
3260 TRACE("(%p, %p)\n", hdc, lpgs);
3262 if (!dc) return 0;
3264 if (dc->gdiFont) ret = WineEngGetFontUnicodeRanges(dc->gdiFont, lpgs);
3265 release_dc_ptr(dc);
3266 return ret;
3270 /*************************************************************
3271 * FontIsLinked (GDI32.@)
3273 BOOL WINAPI FontIsLinked(HDC hdc)
3275 DC *dc = get_dc_ptr(hdc);
3276 BOOL ret = FALSE;
3278 if (!dc) return FALSE;
3279 if (dc->gdiFont) ret = WineEngFontIsLinked(dc->gdiFont);
3280 release_dc_ptr(dc);
3281 TRACE("returning %d\n", ret);
3282 return ret;
3285 /*************************************************************
3286 * GdiRealizationInfo (GDI32.@)
3288 * Returns a structure that contains some font information.
3290 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3292 DC *dc = get_dc_ptr(hdc);
3293 BOOL ret = FALSE;
3295 if (!dc) return FALSE;
3296 if (dc->gdiFont) ret = WineEngRealizationInfo(dc->gdiFont, info);
3297 release_dc_ptr(dc);
3299 return ret;