push 43f03fe87c2254c6df67b2de3c08b5b20fd64327
[wine/hacks.git] / dlls / gdi32 / font.c
blob107536ea5bc925c9edc15d2c6c3fc6cb204eca34
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 CHARSETINFO csi;
251 int charset = GetTextCharset(hdc);
253 /* Hmm, nicely designed api this one! */
254 if(TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
255 cp = csi.ciACP;
256 else {
257 switch(charset) {
258 case OEM_CHARSET:
259 cp = GetOEMCP();
260 break;
261 case DEFAULT_CHARSET:
262 cp = GetACP();
263 break;
265 case VISCII_CHARSET:
266 case TCVN_CHARSET:
267 case KOI8_CHARSET:
268 case ISO3_CHARSET:
269 case ISO4_CHARSET:
270 case ISO10_CHARSET:
271 case CELTIC_CHARSET:
272 /* FIXME: These have no place here, but because x11drv
273 enumerates fonts with these (made up) charsets some apps
274 might use them and then the FIXME below would become
275 annoying. Now we could pick the intended codepage for
276 each of these, but since it's broken anyway we'll just
277 use CP_ACP and hope it'll go away...
279 cp = CP_ACP;
280 break;
282 default:
283 FIXME("Can't find codepage for charset %d\n", charset);
284 break;
288 TRACE("charset %d => cp %d\n", charset, cp);
289 return cp;
292 /***********************************************************************
293 * FONT_mbtowc
295 * Returns a Unicode translation of str using the charset of the
296 * currently selected font in hdc. If count is -1 then str is assumed
297 * to be '\0' terminated, otherwise it contains the number of bytes to
298 * convert. If plenW is non-NULL, on return it will point to the
299 * number of WCHARs that have been written. If pCP is non-NULL, on
300 * return it will point to the codepage used in the conversion. The
301 * caller should free the returned LPWSTR from the process heap
302 * itself.
304 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
306 UINT cp;
307 INT lenW;
308 LPWSTR strW;
310 cp = GdiGetCodePage( hdc );
312 if(count == -1) count = strlen(str);
313 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
314 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
315 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
316 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
317 if(plenW) *plenW = lenW;
318 if(pCP) *pCP = cp;
319 return strW;
323 /***********************************************************************
324 * CreateFontIndirectA (GDI32.@)
326 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
328 LOGFONTW lfW;
330 if (!plfA) return 0;
332 FONT_LogFontAToW( plfA, &lfW );
333 return CreateFontIndirectW( &lfW );
336 /***********************************************************************
337 * CreateFontIndirectW (GDI32.@)
339 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
341 static const WCHAR ItalicW[] = {' ','I','t','a','l','i','c','\0'};
342 static const WCHAR BoldW[] = {' ','B','o','l','d','\0'};
343 WCHAR *pFaceNameItalicSuffix, *pFaceNameBoldSuffix;
344 WCHAR *pFaceNameSuffix = NULL;
345 HFONT hFont;
346 FONTOBJ *fontPtr;
348 if (!plf) return 0;
350 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
352 fontPtr->logfont = *plf;
354 if (plf->lfEscapement != plf->lfOrientation)
356 /* this should really depend on whether GM_ADVANCED is set */
357 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
358 WARN("orientation angle %f set to "
359 "escapement angle %f for new font %p\n",
360 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
363 pFaceNameItalicSuffix = strstrW(fontPtr->logfont.lfFaceName, ItalicW);
364 if (pFaceNameItalicSuffix)
366 fontPtr->logfont.lfItalic = TRUE;
367 pFaceNameSuffix = pFaceNameItalicSuffix;
370 pFaceNameBoldSuffix = strstrW(fontPtr->logfont.lfFaceName, BoldW);
371 if (pFaceNameBoldSuffix)
373 if (fontPtr->logfont.lfWeight < FW_BOLD)
374 fontPtr->logfont.lfWeight = FW_BOLD;
375 if (!pFaceNameSuffix || (pFaceNameBoldSuffix < pFaceNameSuffix))
376 pFaceNameSuffix = pFaceNameBoldSuffix;
379 if (pFaceNameSuffix) *pFaceNameSuffix = 0;
381 if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs )))
383 HeapFree( GetProcessHeap(), 0, fontPtr );
384 return 0;
387 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
388 plf->lfHeight, plf->lfWidth,
389 plf->lfEscapement, plf->lfOrientation,
390 plf->lfPitchAndFamily,
391 plf->lfOutPrecision, plf->lfClipPrecision,
392 plf->lfQuality, plf->lfCharSet,
393 debugstr_w(plf->lfFaceName),
394 plf->lfWeight > 400 ? "Bold" : "",
395 plf->lfItalic ? "Italic" : "",
396 plf->lfUnderline ? "Underline" : "", hFont);
398 return hFont;
401 /*************************************************************************
402 * CreateFontA (GDI32.@)
404 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
405 INT orient, INT weight, DWORD italic,
406 DWORD underline, DWORD strikeout, DWORD charset,
407 DWORD outpres, DWORD clippres, DWORD quality,
408 DWORD pitch, LPCSTR name )
410 LOGFONTA logfont;
412 logfont.lfHeight = height;
413 logfont.lfWidth = width;
414 logfont.lfEscapement = esc;
415 logfont.lfOrientation = orient;
416 logfont.lfWeight = weight;
417 logfont.lfItalic = italic;
418 logfont.lfUnderline = underline;
419 logfont.lfStrikeOut = strikeout;
420 logfont.lfCharSet = charset;
421 logfont.lfOutPrecision = outpres;
422 logfont.lfClipPrecision = clippres;
423 logfont.lfQuality = quality;
424 logfont.lfPitchAndFamily = pitch;
426 if (name)
427 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
428 else
429 logfont.lfFaceName[0] = '\0';
431 return CreateFontIndirectA( &logfont );
434 /*************************************************************************
435 * CreateFontW (GDI32.@)
437 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
438 INT orient, INT weight, DWORD italic,
439 DWORD underline, DWORD strikeout, DWORD charset,
440 DWORD outpres, DWORD clippres, DWORD quality,
441 DWORD pitch, LPCWSTR name )
443 LOGFONTW logfont;
445 logfont.lfHeight = height;
446 logfont.lfWidth = width;
447 logfont.lfEscapement = esc;
448 logfont.lfOrientation = orient;
449 logfont.lfWeight = weight;
450 logfont.lfItalic = italic;
451 logfont.lfUnderline = underline;
452 logfont.lfStrikeOut = strikeout;
453 logfont.lfCharSet = charset;
454 logfont.lfOutPrecision = outpres;
455 logfont.lfClipPrecision = clippres;
456 logfont.lfQuality = quality;
457 logfont.lfPitchAndFamily = pitch;
459 if (name)
460 lstrcpynW(logfont.lfFaceName, name,
461 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
462 else
463 logfont.lfFaceName[0] = '\0';
465 return CreateFontIndirectW( &logfont );
469 /***********************************************************************
470 * FONT_SelectObject
472 * If the driver supports vector fonts we create a gdi font first and
473 * then call the driver to give it a chance to supply its own device
474 * font. If the driver wants to do this it returns TRUE and we can
475 * delete the gdi font, if the driver wants to use the gdi font it
476 * should return FALSE, to signal an error return GDI_ERROR. For
477 * drivers that don't support vector fonts they must supply their own
478 * font.
480 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
482 HGDIOBJ ret = 0;
483 DC *dc = get_dc_ptr( hdc );
485 if (!dc) return 0;
487 if (!GDI_inc_ref_count( handle ))
489 release_dc_ptr( dc );
490 return 0;
493 if (GetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_VA_ABLE)
494 dc->gdiFont = WineEngCreateFontInstance( dc, handle );
496 if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont );
498 if (ret && dc->gdiFont) dc->gdiFont = 0;
500 if (ret == HGDI_ERROR)
502 GDI_dec_ref_count( handle );
503 ret = 0; /* SelectObject returns 0 on error */
505 else
507 ret = dc->hFont;
508 dc->hFont = handle;
509 GDI_dec_ref_count( ret );
511 release_dc_ptr( dc );
512 return ret;
516 /***********************************************************************
517 * FONT_GetObjectA
519 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
521 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
522 LOGFONTA lfA;
524 if (!font) return 0;
525 if (buffer)
527 FONT_LogFontWToA( &font->logfont, &lfA );
528 if (count > sizeof(lfA)) count = sizeof(lfA);
529 memcpy( buffer, &lfA, count );
531 else count = sizeof(lfA);
532 GDI_ReleaseObj( handle );
533 return count;
536 /***********************************************************************
537 * FONT_GetObjectW
539 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
541 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
543 if (!font) return 0;
544 if (buffer)
546 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
547 memcpy( buffer, &font->logfont, count );
549 else count = sizeof(LOGFONTW);
550 GDI_ReleaseObj( handle );
551 return count;
555 /***********************************************************************
556 * FONT_DeleteObject
558 static BOOL FONT_DeleteObject( HGDIOBJ handle )
560 FONTOBJ *obj;
562 WineEngDestroyFontInstance( handle );
564 if (!(obj = free_gdi_handle( handle ))) return FALSE;
565 return HeapFree( GetProcessHeap(), 0, obj );
569 /***********************************************************************
570 * FONT_EnumInstance
572 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
573 * We have to use other types because of the FONTENUMPROCW definition.
575 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
576 DWORD fType, LPARAM lp )
578 fontEnum32 *pfe = (fontEnum32*)lp;
579 INT ret = 1;
581 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
582 if ((!pfe->lpLogFontParam ||
583 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
584 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
585 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
587 /* convert font metrics */
588 ENUMLOGFONTEXA logfont;
589 NEWTEXTMETRICEXA tmA;
591 pfe->dwFlags |= ENUM_CALLED;
592 if (!(pfe->dwFlags & ENUM_UNICODE))
594 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
595 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
596 plf = (LOGFONTW *)&logfont.elfLogFont;
597 ptm = (TEXTMETRICW *)&tmA;
600 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
602 return ret;
605 /***********************************************************************
606 * FONT_EnumFontFamiliesEx
608 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf,
609 FONTENUMPROCW efproc,
610 LPARAM lParam, DWORD dwUnicode)
612 INT ret = 1, ret2;
613 DC *dc = get_dc_ptr( hDC );
614 fontEnum32 fe32;
615 BOOL enum_gdi_fonts;
617 if (!dc) return 0;
619 if (plf)
620 TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName),
621 plf->lfCharSet);
622 fe32.lpLogFontParam = plf;
623 fe32.lpEnumFunc = efproc;
624 fe32.lpData = lParam;
625 fe32.dwFlags = dwUnicode;
626 fe32.hdc = hDC;
628 enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE;
630 if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
632 ret = 0;
633 goto done;
636 if (enum_gdi_fonts)
637 ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 );
638 fe32.dwFlags &= ~ENUM_CALLED;
639 if (ret && dc->funcs->pEnumDeviceFonts) {
640 ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 );
641 if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
642 ret = ret2;
644 done:
645 release_dc_ptr( dc );
646 return ret;
649 /***********************************************************************
650 * EnumFontFamiliesExW (GDI32.@)
652 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
653 FONTENUMPROCW efproc,
654 LPARAM lParam, DWORD dwFlags )
656 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE );
659 /***********************************************************************
660 * EnumFontFamiliesExA (GDI32.@)
662 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
663 FONTENUMPROCA efproc,
664 LPARAM lParam, DWORD dwFlags)
666 LOGFONTW lfW, *plfW;
668 if (plf)
670 FONT_LogFontAToW( plf, &lfW );
671 plfW = &lfW;
673 else plfW = NULL;
675 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, 0);
678 /***********************************************************************
679 * EnumFontFamiliesA (GDI32.@)
681 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
682 FONTENUMPROCA efproc, LPARAM lpData )
684 LOGFONTA lf, *plf;
686 if (lpFamily)
688 if (!*lpFamily) return 1;
689 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
690 lf.lfCharSet = DEFAULT_CHARSET;
691 lf.lfPitchAndFamily = 0;
692 plf = &lf;
694 else plf = NULL;
696 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
699 /***********************************************************************
700 * EnumFontFamiliesW (GDI32.@)
702 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
703 FONTENUMPROCW efproc, LPARAM lpData )
705 LOGFONTW lf, *plf;
707 if (lpFamily)
709 if (!*lpFamily) return 1;
710 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
711 lf.lfCharSet = DEFAULT_CHARSET;
712 lf.lfPitchAndFamily = 0;
713 plf = &lf;
715 else plf = NULL;
717 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
720 /***********************************************************************
721 * EnumFontsA (GDI32.@)
723 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
724 LPARAM lpData )
726 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
729 /***********************************************************************
730 * EnumFontsW (GDI32.@)
732 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
733 LPARAM lpData )
735 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
739 /***********************************************************************
740 * GetTextCharacterExtra (GDI32.@)
742 INT WINAPI GetTextCharacterExtra( HDC hdc )
744 INT ret;
745 DC *dc = get_dc_ptr( hdc );
746 if (!dc) return 0x80000000;
747 ret = dc->charExtra;
748 release_dc_ptr( dc );
749 return ret;
753 /***********************************************************************
754 * SetTextCharacterExtra (GDI32.@)
756 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
758 INT prev;
759 DC * dc = get_dc_ptr( hdc );
760 if (!dc) return 0x80000000;
761 if (dc->funcs->pSetTextCharacterExtra)
762 prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra );
763 else
765 prev = dc->charExtra;
766 dc->charExtra = extra;
768 release_dc_ptr( dc );
769 return prev;
773 /***********************************************************************
774 * SetTextJustification (GDI32.@)
776 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
778 BOOL ret = TRUE;
779 DC * dc = get_dc_ptr( hdc );
780 if (!dc) return FALSE;
781 if (dc->funcs->pSetTextJustification)
782 ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks );
783 else
785 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
786 if (!extra) breaks = 0;
787 if (breaks)
789 dc->breakExtra = extra / breaks;
790 dc->breakRem = extra - (breaks * dc->breakExtra);
792 else
794 dc->breakExtra = 0;
795 dc->breakRem = 0;
798 release_dc_ptr( dc );
799 return ret;
803 /***********************************************************************
804 * GetTextFaceA (GDI32.@)
806 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
808 INT res = GetTextFaceW(hdc, 0, NULL);
809 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
810 GetTextFaceW( hdc, res, nameW );
812 if (name)
814 if (count)
816 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
817 if (res == 0)
818 res = count;
819 name[count-1] = 0;
820 /* GetTextFaceA does NOT include the nul byte in the return count. */
821 res--;
823 else
824 res = 0;
826 else
827 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
828 HeapFree( GetProcessHeap(), 0, nameW );
829 return res;
832 /***********************************************************************
833 * GetTextFaceW (GDI32.@)
835 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
837 FONTOBJ *font;
838 INT ret = 0;
840 DC * dc = get_dc_ptr( hdc );
841 if (!dc) return 0;
843 if(dc->gdiFont)
844 ret = WineEngGetTextFace(dc->gdiFont, count, name);
845 else if ((font = GDI_GetObjPtr( dc->hFont, OBJ_FONT )))
847 INT n = strlenW(font->logfont.lfFaceName) + 1;
848 if (name)
850 lstrcpynW( name, font->logfont.lfFaceName, count );
851 ret = min(count, n);
853 else ret = n;
854 GDI_ReleaseObj( dc->hFont );
856 release_dc_ptr( dc );
857 return ret;
861 /***********************************************************************
862 * GetTextExtentPoint32A (GDI32.@)
864 * See GetTextExtentPoint32W.
866 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
867 LPSIZE size )
869 BOOL ret = FALSE;
870 INT wlen;
871 LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
873 if (p) {
874 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
875 HeapFree( GetProcessHeap(), 0, p );
878 TRACE("(%p %s %d %p): returning %d x %d\n",
879 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
880 return ret;
884 /***********************************************************************
885 * GetTextExtentPoint32W [GDI32.@]
887 * Computes width/height for a string.
889 * Computes width and height of the specified string.
891 * RETURNS
892 * Success: TRUE
893 * Failure: FALSE
895 BOOL WINAPI GetTextExtentPoint32W(
896 HDC hdc, /* [in] Handle of device context */
897 LPCWSTR str, /* [in] Address of text string */
898 INT count, /* [in] Number of characters in string */
899 LPSIZE size) /* [out] Address of structure for string size */
901 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
904 /***********************************************************************
905 * GetTextExtentExPointI [GDI32.@]
907 * Computes width and height of the array of glyph indices.
909 * PARAMS
910 * hdc [I] Handle of device context.
911 * indices [I] Glyph index array.
912 * count [I] Number of glyphs in array.
913 * max_ext [I] Maximum width in glyphs.
914 * nfit [O] Maximum number of characters.
915 * dxs [O] Partial string widths.
916 * size [O] Returned string size.
918 * RETURNS
919 * Success: TRUE
920 * Failure: FALSE
922 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
923 LPINT nfit, LPINT dxs, LPSIZE size )
925 BOOL ret = FALSE;
926 DC * dc = get_dc_ptr( hdc );
927 if (!dc) return FALSE;
929 if(dc->gdiFont) {
930 ret = WineEngGetTextExtentExPointI(dc->gdiFont, indices, count, max_ext, nfit, dxs, size);
931 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
932 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
933 size->cx += count * dc->charExtra;
935 else if(dc->funcs->pGetTextExtentExPoint) {
936 FIXME("calling GetTextExtentExPoint\n");
937 ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, indices, count,
938 max_ext, nfit, dxs, size );
941 release_dc_ptr( dc );
943 TRACE("(%p %p %d %p): returning %d x %d\n",
944 hdc, indices, count, size, size->cx, size->cy );
945 return ret;
948 /***********************************************************************
949 * GetTextExtentPointI [GDI32.@]
951 * Computes width and height of the array of glyph indices.
953 * PARAMS
954 * hdc [I] Handle of device context.
955 * indices [I] Glyph index array.
956 * count [I] Number of glyphs in array.
957 * size [O] Returned string size.
959 * RETURNS
960 * Success: TRUE
961 * Failure: FALSE
963 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
965 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
969 /***********************************************************************
970 * GetTextExtentPointA (GDI32.@)
972 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
973 LPSIZE size )
975 TRACE("not bug compatible.\n");
976 return GetTextExtentPoint32A( hdc, str, count, size );
979 /***********************************************************************
980 * GetTextExtentPointW (GDI32.@)
982 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
983 LPSIZE size )
985 TRACE("not bug compatible.\n");
986 return GetTextExtentPoint32W( hdc, str, count, size );
990 /***********************************************************************
991 * GetTextExtentExPointA (GDI32.@)
993 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
994 INT maxExt, LPINT lpnFit,
995 LPINT alpDx, LPSIZE size )
997 BOOL ret;
998 INT wlen;
999 INT *walpDx = NULL;
1000 LPWSTR p = NULL;
1002 if (alpDx &&
1003 NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
1004 return FALSE;
1006 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1007 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1008 if (walpDx)
1010 INT n = lpnFit ? *lpnFit : wlen;
1011 INT i, j;
1012 for(i = 0, j = 0; i < n; i++, j++)
1014 alpDx[j] = walpDx[i];
1015 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1018 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1019 HeapFree( GetProcessHeap(), 0, p );
1020 HeapFree( GetProcessHeap(), 0, walpDx );
1021 return ret;
1025 /***********************************************************************
1026 * GetTextExtentExPointW (GDI32.@)
1028 * Return the size of the string as it would be if it was output properly by
1029 * e.g. TextOut.
1031 * This should include
1032 * - Intercharacter spacing
1033 * - justification spacing (not yet done)
1034 * - kerning? see below
1036 * Kerning. Since kerning would be carried out by the rendering code it should
1037 * be done by the driver. However they don't support it yet. Also I am not
1038 * yet persuaded that (certainly under Win95) any kerning is actually done.
1040 * str: According to MSDN this should be null-terminated. That is not true; a
1041 * null will not terminate it early.
1042 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1043 * than count. I have seen it be either the size of the full string or
1044 * 1 less than the size of the full string. I have not seen it bear any
1045 * resemblance to the portion that would fit.
1046 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1047 * trailing intercharacter spacing and any trailing justification.
1049 * FIXME
1050 * Currently we do this by measuring each character etc. We should do it by
1051 * passing the request to the driver, perhaps by extending the
1052 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1053 * thinking about kerning issues and rounding issues in the justification.
1056 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1057 INT maxExt, LPINT lpnFit,
1058 LPINT alpDx, LPSIZE size )
1060 INT nFit = 0;
1061 LPINT dxs = NULL;
1062 DC *dc;
1063 BOOL ret = FALSE;
1064 TEXTMETRICW tm;
1066 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1068 dc = get_dc_ptr(hdc);
1069 if (! dc)
1070 return FALSE;
1072 GetTextMetricsW(hdc, &tm);
1074 /* If we need to calculate nFit, then we need the partial extents even if
1075 the user hasn't provided us with an array. */
1076 if (lpnFit)
1078 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1079 if (! dxs)
1081 release_dc_ptr(dc);
1082 SetLastError(ERROR_OUTOFMEMORY);
1083 return FALSE;
1086 else
1087 dxs = alpDx;
1089 if (dc->gdiFont)
1090 ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
1091 0, NULL, dxs, size);
1092 else if (dc->funcs->pGetTextExtentExPoint)
1093 ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
1094 0, NULL, dxs, size);
1096 /* Perform device size to world size transformations. */
1097 if (ret)
1099 INT extra = dc->charExtra,
1100 breakExtra = dc->breakExtra,
1101 breakRem = dc->breakRem,
1104 if (dxs)
1106 for (i = 0; i < count; ++i)
1108 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1109 dxs[i] += (i+1) * extra;
1110 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1112 dxs[i] += breakExtra;
1113 if (breakRem > 0)
1115 breakRem--;
1116 dxs[i]++;
1119 if (dxs[i] <= maxExt)
1120 ++nFit;
1122 breakRem = dc->breakRem;
1124 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1125 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1127 if (!dxs && count > 1 && (breakExtra || breakRem))
1129 for (i = 0; i < count; i++)
1131 if (str[i] == tm.tmBreakChar)
1133 size->cx += breakExtra;
1134 if (breakRem > 0)
1136 breakRem--;
1137 (size->cx)++;
1144 if (lpnFit)
1145 *lpnFit = nFit;
1147 if (! alpDx)
1148 HeapFree(GetProcessHeap(), 0, dxs);
1150 release_dc_ptr( dc );
1152 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1153 return ret;
1156 /***********************************************************************
1157 * GetTextMetricsA (GDI32.@)
1159 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1161 TEXTMETRICW tm32;
1163 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1164 FONT_TextMetricWToA( &tm32, metrics );
1165 return TRUE;
1168 /***********************************************************************
1169 * GetTextMetricsW (GDI32.@)
1171 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1173 BOOL ret = FALSE;
1174 DC * dc = get_dc_ptr( hdc );
1175 if (!dc) return FALSE;
1177 if (dc->gdiFont)
1178 ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1179 else if (dc->funcs->pGetTextMetrics)
1180 ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1182 if (ret)
1184 /* device layer returns values in device units
1185 * therefore we have to convert them to logical */
1187 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1188 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1190 #define WDPTOLP(x) ((x<0)? \
1191 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1192 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1193 #define HDPTOLP(y) ((y<0)? \
1194 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1195 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1197 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1198 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1199 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1200 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1201 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1202 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1203 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1204 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1205 ret = TRUE;
1206 #undef WDPTOLP
1207 #undef HDPTOLP
1208 TRACE("text metrics:\n"
1209 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1210 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1211 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1212 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1213 " PitchAndFamily = %02x\n"
1214 " --------------------\n"
1215 " InternalLeading = %i\n"
1216 " Ascent = %i\n"
1217 " Descent = %i\n"
1218 " Height = %i\n",
1219 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1220 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1221 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1222 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1223 metrics->tmPitchAndFamily,
1224 metrics->tmInternalLeading,
1225 metrics->tmAscent,
1226 metrics->tmDescent,
1227 metrics->tmHeight );
1229 release_dc_ptr( dc );
1230 return ret;
1234 /***********************************************************************
1235 * GetOutlineTextMetricsA (GDI32.@)
1236 * Gets metrics for TrueType fonts.
1238 * NOTES
1239 * If the supplied buffer isn't big enough Windows partially fills it up to
1240 * its given length and returns that length.
1242 * RETURNS
1243 * Success: Non-zero or size of required buffer
1244 * Failure: 0
1246 UINT WINAPI GetOutlineTextMetricsA(
1247 HDC hdc, /* [in] Handle of device context */
1248 UINT cbData, /* [in] Size of metric data array */
1249 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1251 char buf[512], *ptr;
1252 UINT ret, needed;
1253 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1254 OUTLINETEXTMETRICA *output = lpOTM;
1255 INT left, len;
1257 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1258 return 0;
1259 if(ret > sizeof(buf))
1260 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1261 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1263 needed = sizeof(OUTLINETEXTMETRICA);
1264 if(lpOTMW->otmpFamilyName)
1265 needed += WideCharToMultiByte(CP_ACP, 0,
1266 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1267 NULL, 0, NULL, NULL);
1268 if(lpOTMW->otmpFaceName)
1269 needed += WideCharToMultiByte(CP_ACP, 0,
1270 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1271 NULL, 0, NULL, NULL);
1272 if(lpOTMW->otmpStyleName)
1273 needed += WideCharToMultiByte(CP_ACP, 0,
1274 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1275 NULL, 0, NULL, NULL);
1276 if(lpOTMW->otmpFullName)
1277 needed += WideCharToMultiByte(CP_ACP, 0,
1278 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1279 NULL, 0, NULL, NULL);
1281 if(!lpOTM) {
1282 ret = needed;
1283 goto end;
1286 TRACE("needed = %d\n", needed);
1287 if(needed > cbData)
1288 /* Since the supplied buffer isn't big enough, we'll alloc one
1289 that is and memcpy the first cbData bytes into the lpOTM at
1290 the end. */
1291 output = HeapAlloc(GetProcessHeap(), 0, needed);
1293 ret = output->otmSize = min(needed, cbData);
1294 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1295 output->otmFiller = 0;
1296 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1297 output->otmfsSelection = lpOTMW->otmfsSelection;
1298 output->otmfsType = lpOTMW->otmfsType;
1299 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1300 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1301 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1302 output->otmEMSquare = lpOTMW->otmEMSquare;
1303 output->otmAscent = lpOTMW->otmAscent;
1304 output->otmDescent = lpOTMW->otmDescent;
1305 output->otmLineGap = lpOTMW->otmLineGap;
1306 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1307 output->otmsXHeight = lpOTMW->otmsXHeight;
1308 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1309 output->otmMacAscent = lpOTMW->otmMacAscent;
1310 output->otmMacDescent = lpOTMW->otmMacDescent;
1311 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1312 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1313 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1314 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1315 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1316 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1317 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1318 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1319 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1320 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1323 ptr = (char*)(output + 1);
1324 left = needed - sizeof(*output);
1326 if(lpOTMW->otmpFamilyName) {
1327 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1328 len = WideCharToMultiByte(CP_ACP, 0,
1329 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1330 ptr, left, NULL, NULL);
1331 left -= len;
1332 ptr += len;
1333 } else
1334 output->otmpFamilyName = 0;
1336 if(lpOTMW->otmpFaceName) {
1337 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1338 len = WideCharToMultiByte(CP_ACP, 0,
1339 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1340 ptr, left, NULL, NULL);
1341 left -= len;
1342 ptr += len;
1343 } else
1344 output->otmpFaceName = 0;
1346 if(lpOTMW->otmpStyleName) {
1347 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1348 len = WideCharToMultiByte(CP_ACP, 0,
1349 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1350 ptr, left, NULL, NULL);
1351 left -= len;
1352 ptr += len;
1353 } else
1354 output->otmpStyleName = 0;
1356 if(lpOTMW->otmpFullName) {
1357 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1358 len = WideCharToMultiByte(CP_ACP, 0,
1359 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1360 ptr, left, NULL, NULL);
1361 left -= len;
1362 } else
1363 output->otmpFullName = 0;
1365 assert(left == 0);
1367 if(output != lpOTM) {
1368 memcpy(lpOTM, output, cbData);
1369 HeapFree(GetProcessHeap(), 0, output);
1371 /* check if the string offsets really fit into the provided size */
1372 /* FIXME: should we check string length as well? */
1373 /* make sure that we don't read/write beyond the provided buffer */
1374 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1376 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1377 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1380 /* make sure that we don't read/write beyond the provided buffer */
1381 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1383 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1384 lpOTM->otmpFaceName = 0; /* doesn't fit */
1387 /* make sure that we don't read/write beyond the provided buffer */
1388 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1390 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1391 lpOTM->otmpStyleName = 0; /* doesn't fit */
1394 /* make sure that we don't read/write beyond the provided buffer */
1395 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1397 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1398 lpOTM->otmpFullName = 0; /* doesn't fit */
1402 end:
1403 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1404 HeapFree(GetProcessHeap(), 0, lpOTMW);
1406 return ret;
1410 /***********************************************************************
1411 * GetOutlineTextMetricsW [GDI32.@]
1413 UINT WINAPI GetOutlineTextMetricsW(
1414 HDC hdc, /* [in] Handle of device context */
1415 UINT cbData, /* [in] Size of metric data array */
1416 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1418 DC *dc = get_dc_ptr( hdc );
1419 OUTLINETEXTMETRICW *output = lpOTM;
1420 UINT ret;
1422 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1423 if(!dc) return 0;
1425 if(dc->gdiFont) {
1426 ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1427 if(lpOTM && ret) {
1428 if(ret > cbData) {
1429 output = HeapAlloc(GetProcessHeap(), 0, ret);
1430 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1433 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1434 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1436 #define WDPTOLP(x) ((x<0)? \
1437 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1438 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1439 #define HDPTOLP(y) ((y<0)? \
1440 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1441 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1443 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1444 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1445 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1446 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1447 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1448 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1449 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1450 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1451 output->otmAscent = HDPTOLP(output->otmAscent);
1452 output->otmDescent = HDPTOLP(output->otmDescent);
1453 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1454 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1455 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1456 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1457 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1458 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1459 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1460 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1461 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1462 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1463 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1464 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1465 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1466 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1467 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1468 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1469 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1470 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1471 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1472 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1473 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1474 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1475 #undef WDPTOLP
1476 #undef HDPTOLP
1477 if(output != lpOTM) {
1478 memcpy(lpOTM, output, cbData);
1479 HeapFree(GetProcessHeap(), 0, output);
1480 ret = cbData;
1485 else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1486 but really this should just be a return 0. */
1488 ret = sizeof(*lpOTM);
1489 if (lpOTM) {
1490 if(cbData < ret)
1491 ret = 0;
1492 else {
1493 memset(lpOTM, 0, ret);
1494 lpOTM->otmSize = sizeof(*lpOTM);
1495 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1497 Further fill of the structure not implemented,
1498 Needs real values for the structure members
1503 release_dc_ptr(dc);
1504 return ret;
1508 /***********************************************************************
1509 * GetCharWidthW (GDI32.@)
1510 * GetCharWidth32W (GDI32.@)
1512 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1513 LPINT buffer )
1515 UINT i;
1516 BOOL ret = FALSE;
1517 DC * dc = get_dc_ptr( hdc );
1518 if (!dc) return FALSE;
1520 if (dc->gdiFont)
1521 ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1522 else if (dc->funcs->pGetCharWidth)
1523 ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1525 if (ret)
1527 /* convert device units to logical */
1528 for( i = firstChar; i <= lastChar; i++, buffer++ )
1529 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1530 ret = TRUE;
1532 release_dc_ptr( dc );
1533 return ret;
1537 /***********************************************************************
1538 * GetCharWidthA (GDI32.@)
1539 * GetCharWidth32A (GDI32.@)
1541 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1542 LPINT buffer )
1544 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
1545 LPSTR str;
1546 LPWSTR wstr;
1547 BOOL ret = TRUE;
1549 if(count <= 0) return FALSE;
1551 str = HeapAlloc(GetProcessHeap(), 0, count);
1552 for(i = 0; i < count; i++)
1553 str[i] = (BYTE)(firstChar + i);
1555 wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1557 for(i = 0; i < wlen; i++)
1559 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1561 ret = FALSE;
1562 break;
1564 buffer++;
1567 HeapFree(GetProcessHeap(), 0, str);
1568 HeapFree(GetProcessHeap(), 0, wstr);
1570 return ret;
1574 /***********************************************************************
1575 * ExtTextOutA (GDI32.@)
1577 * See ExtTextOutW.
1579 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1580 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1582 INT wlen;
1583 UINT codepage;
1584 LPWSTR p;
1585 BOOL ret;
1586 LPINT lpDxW = NULL;
1588 if (flags & ETO_GLYPH_INDEX)
1589 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1591 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1593 if (lpDx) {
1594 unsigned int i = 0, j = 0;
1596 lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT));
1597 while(i < count) {
1598 if(IsDBCSLeadByteEx(codepage, str[i])) {
1599 lpDxW[j++] = lpDx[i] + lpDx[i+1];
1600 i = i + 2;
1601 } else {
1602 lpDxW[j++] = lpDx[i];
1603 i = i + 1;
1608 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1610 HeapFree( GetProcessHeap(), 0, p );
1611 HeapFree( GetProcessHeap(), 0, lpDxW );
1612 return ret;
1616 /***********************************************************************
1617 * ExtTextOutW (GDI32.@)
1619 * Draws text using the currently selected font, background color, and text color.
1622 * PARAMS
1623 * x,y [I] coordinates of string
1624 * flags [I]
1625 * ETO_GRAYED - undocumented on MSDN
1626 * ETO_OPAQUE - use background color for fill the rectangle
1627 * ETO_CLIPPED - clipping text to the rectangle
1628 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1629 * than encoded characters. Implies ETO_IGNORELANGUAGE
1630 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1631 * Affects BiDi ordering
1632 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1633 * ETO_PDY - unimplemented
1634 * ETO_NUMERICSLATIN - unimplemented always assumed -
1635 * do not translate numbers into locale representations
1636 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1637 * lprect [I] dimensions for clipping or/and opaquing
1638 * str [I] text string
1639 * count [I] number of symbols in string
1640 * lpDx [I] optional parameter with distance between drawing characters
1642 * RETURNS
1643 * Success: TRUE
1644 * Failure: FALSE
1646 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1647 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1649 BOOL ret = FALSE;
1650 LPWSTR reordered_str = (LPWSTR)str;
1651 WORD *glyphs = NULL;
1652 UINT align = GetTextAlign( hdc );
1653 POINT pt;
1654 TEXTMETRICW tm;
1655 LOGFONTW lf;
1656 double cosEsc, sinEsc;
1657 INT *deltas = NULL, char_extra;
1658 SIZE sz;
1659 RECT rc;
1660 BOOL done_extents = FALSE;
1661 INT width = 0, xwidth = 0, ywidth = 0;
1662 DWORD type;
1663 DC * dc = get_dc_ptr( hdc );
1664 INT breakRem;
1665 static int quietfixme = 0;
1667 if (!dc) return FALSE;
1669 breakRem = dc->breakRem;
1671 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
1673 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
1674 quietfixme = 1;
1676 if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1678 release_dc_ptr( dc );
1679 return ret;
1682 update_dc( dc );
1683 type = GetObjectType(hdc);
1684 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1686 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1687 release_dc_ptr( dc );
1688 return ret;
1691 if (!lprect)
1692 flags &= ~ETO_CLIPPED;
1694 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
1696 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1698 BIDI_Reorder( str, count, GCP_REORDER,
1699 ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
1700 WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
1701 reordered_str, count, NULL );
1703 flags |= ETO_IGNORELANGUAGE;
1706 TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
1707 lprect, debugstr_wn(str, count), count, lpDx);
1709 if(flags & ETO_GLYPH_INDEX)
1710 glyphs = reordered_str;
1712 if(lprect)
1713 TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
1714 lprect->bottom);
1715 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1717 if(align & TA_UPDATECP)
1719 GetCurrentPositionEx( hdc, &pt );
1720 x = pt.x;
1721 y = pt.y;
1724 GetTextMetricsW(hdc, &tm);
1725 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1727 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1728 lf.lfEscapement = 0;
1730 if(lf.lfEscapement != 0)
1732 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1733 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1735 else
1737 cosEsc = 1;
1738 sinEsc = 0;
1741 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1743 if(!lprect)
1745 if(flags & ETO_GLYPH_INDEX)
1746 GetTextExtentPointI(hdc, glyphs, count, &sz);
1747 else
1748 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1750 done_extents = TRUE;
1751 rc.left = x;
1752 rc.top = y;
1753 rc.right = x + sz.cx;
1754 rc.bottom = y + sz.cy;
1756 else
1758 rc = *lprect;
1761 LPtoDP(hdc, (POINT*)&rc, 2);
1763 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1764 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1767 if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1768 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1770 if(count == 0)
1772 ret = TRUE;
1773 goto done;
1776 pt.x = x;
1777 pt.y = y;
1778 LPtoDP(hdc, &pt, 1);
1779 x = pt.x;
1780 y = pt.y;
1782 char_extra = GetTextCharacterExtra(hdc);
1783 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
1785 UINT i;
1786 SIZE tmpsz;
1787 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
1788 for(i = 0; i < count; i++)
1790 if(lpDx && (flags & ETO_PDY))
1791 deltas[i] = lpDx[i*2] + char_extra;
1792 else if(lpDx)
1793 deltas[i] = lpDx[i] + char_extra;
1794 else
1796 if(flags & ETO_GLYPH_INDEX)
1797 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1798 else
1799 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
1801 deltas[i] = tmpsz.cx;
1804 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
1806 deltas[i] = deltas[i] + dc->breakExtra;
1807 if (breakRem > 0)
1809 breakRem--;
1810 deltas[i]++;
1813 deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
1814 width += deltas[i];
1817 else
1819 if(!done_extents)
1821 if(flags & ETO_GLYPH_INDEX)
1822 GetTextExtentPointI(hdc, glyphs, count, &sz);
1823 else
1824 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1825 done_extents = TRUE;
1827 width = INTERNAL_XWSTODS(dc, sz.cx);
1829 xwidth = width * cosEsc;
1830 ywidth = width * sinEsc;
1832 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
1833 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
1834 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
1836 case TA_LEFT:
1837 if (align & TA_UPDATECP)
1839 pt.x = x + xwidth;
1840 pt.y = y - ywidth;
1841 DPtoLP(hdc, &pt, 1);
1842 MoveToEx(hdc, pt.x, pt.y, NULL);
1844 break;
1846 case TA_CENTER:
1847 x -= xwidth / 2;
1848 y += ywidth / 2;
1849 break;
1851 case TA_RIGHT:
1852 x -= xwidth;
1853 y += ywidth;
1854 if (align & TA_UPDATECP)
1856 pt.x = x;
1857 pt.y = y;
1858 DPtoLP(hdc, &pt, 1);
1859 MoveToEx(hdc, pt.x, pt.y, NULL);
1861 break;
1864 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
1866 case TA_TOP:
1867 y += tm.tmAscent * cosEsc;
1868 x += tm.tmAscent * sinEsc;
1869 break;
1871 case TA_BOTTOM:
1872 y -= tm.tmDescent * cosEsc;
1873 x -= tm.tmDescent * sinEsc;
1874 break;
1876 case TA_BASELINE:
1877 break;
1880 if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
1882 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
1884 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
1885 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
1887 RECT rc;
1888 rc.left = x;
1889 rc.right = x + width;
1890 rc.top = y - tm.tmAscent;
1891 rc.bottom = y + tm.tmDescent;
1892 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1897 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
1899 HFONT orig_font = dc->hFont, cur_font;
1900 UINT glyph;
1901 INT span = 0, *offsets = NULL;
1902 unsigned int i;
1904 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1905 for(i = 0; i < count; i++)
1907 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
1908 if(cur_font != dc->hFont)
1910 if(!offsets)
1912 unsigned int j;
1913 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
1914 offsets[0] = 0;
1915 if(!deltas)
1917 SIZE tmpsz;
1918 for(j = 1; j < count; j++)
1920 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
1921 offsets[j] = offsets[j-1] + INTERNAL_XWSTODS(dc, tmpsz.cx);
1924 else
1926 for(j = 1; j < count; j++)
1927 offsets[j] = offsets[j-1] + deltas[j];
1930 if(span)
1932 if (PATH_IsPathOpen(dc->path))
1933 ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
1934 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1935 glyphs, span, deltas ? deltas + i - span : NULL);
1936 else
1937 dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
1938 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1939 glyphs, span, deltas ? deltas + i - span : NULL);
1940 span = 0;
1942 SelectObject(hdc, cur_font);
1944 glyphs[span++] = glyph;
1946 if(i == count - 1)
1948 if (PATH_IsPathOpen(dc->path))
1949 ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
1950 y - (offsets ? offsets[count - span] * sinEsc : 0),
1951 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1952 glyphs, span, deltas ? deltas + count - span : NULL);
1953 else
1954 ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
1955 y - (offsets ? offsets[count - span] * sinEsc : 0),
1956 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1957 glyphs, span, deltas ? deltas + count - span : NULL);
1958 SelectObject(hdc, orig_font);
1959 HeapFree(GetProcessHeap(), 0, offsets);
1963 else
1965 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
1967 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1968 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
1969 flags |= ETO_GLYPH_INDEX;
1972 if (PATH_IsPathOpen(dc->path))
1973 ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
1974 glyphs ? glyphs : reordered_str, count, deltas);
1975 else
1976 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
1977 glyphs ? glyphs : reordered_str, count, deltas);
1980 done:
1981 HeapFree(GetProcessHeap(), 0, deltas);
1982 if(glyphs != reordered_str)
1983 HeapFree(GetProcessHeap(), 0, glyphs);
1984 if(reordered_str != str)
1985 HeapFree(GetProcessHeap(), 0, reordered_str);
1987 release_dc_ptr( dc );
1989 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
1991 int underlinePos, strikeoutPos;
1992 int underlineWidth, strikeoutWidth;
1993 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
1994 OUTLINETEXTMETRICW* otm = NULL;
1996 if(!size)
1998 underlinePos = 0;
1999 underlineWidth = tm.tmAscent / 20 + 1;
2000 strikeoutPos = tm.tmAscent / 2;
2001 strikeoutWidth = underlineWidth;
2003 else
2005 otm = HeapAlloc(GetProcessHeap(), 0, size);
2006 GetOutlineTextMetricsW(hdc, size, otm);
2007 underlinePos = otm->otmsUnderscorePosition;
2008 underlineWidth = otm->otmsUnderscoreSize;
2009 strikeoutPos = otm->otmsStrikeoutPosition;
2010 strikeoutWidth = otm->otmsStrikeoutSize;
2011 HeapFree(GetProcessHeap(), 0, otm);
2014 if (PATH_IsPathOpen(dc->path))
2016 POINT pts[5];
2017 HPEN hpen;
2018 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2020 hbrush = SelectObject(hdc, hbrush);
2021 hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2023 if (lf.lfUnderline)
2025 pts[0].x = x - underlinePos * sinEsc;
2026 pts[0].y = y - underlinePos * cosEsc;
2027 pts[1].x = x + xwidth - underlinePos * sinEsc;
2028 pts[1].y = y - ywidth - underlinePos * cosEsc;
2029 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2030 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2031 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2032 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2033 pts[4].x = pts[0].x;
2034 pts[4].y = pts[0].y;
2035 DPtoLP(hdc, pts, 5);
2036 Polygon(hdc, pts, 5);
2039 if (lf.lfStrikeOut)
2041 pts[0].x = x - strikeoutPos * sinEsc;
2042 pts[0].y = y - strikeoutPos * cosEsc;
2043 pts[1].x = x + xwidth - strikeoutPos * sinEsc;
2044 pts[1].y = y - ywidth - strikeoutPos * cosEsc;
2045 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2046 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2047 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2048 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2049 pts[4].x = pts[0].x;
2050 pts[4].y = pts[0].y;
2051 DPtoLP(hdc, pts, 5);
2052 Polygon(hdc, pts, 5);
2055 SelectObject(hdc, hpen);
2056 hbrush = SelectObject(hdc, hbrush);
2057 DeleteObject(hbrush);
2059 else
2061 POINT pts[2], oldpt;
2062 HPEN hpen;
2064 if (lf.lfUnderline)
2066 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2067 hpen = SelectObject(hdc, hpen);
2068 pts[0].x = x;
2069 pts[0].y = y;
2070 pts[1].x = x + xwidth;
2071 pts[1].y = y - ywidth;
2072 DPtoLP(hdc, pts, 2);
2073 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2074 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2075 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2076 DeleteObject(SelectObject(hdc, hpen));
2079 if (lf.lfStrikeOut)
2081 hpen = CreatePen(PS_SOLID, strikeoutWidth, 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 - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2089 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2090 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2091 DeleteObject(SelectObject(hdc, hpen));
2096 return ret;
2100 /***********************************************************************
2101 * TextOutA (GDI32.@)
2103 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2105 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2109 /***********************************************************************
2110 * TextOutW (GDI32.@)
2112 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2114 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2118 /***********************************************************************
2119 * PolyTextOutA (GDI32.@)
2121 * See PolyTextOutW.
2123 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2125 for (; cStrings>0; cStrings--, pptxt++)
2126 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2127 return FALSE;
2128 return TRUE;
2133 /***********************************************************************
2134 * PolyTextOutW (GDI32.@)
2136 * Draw several Strings
2138 * RETURNS
2139 * TRUE: Success.
2140 * FALSE: Failure.
2142 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2144 for (; cStrings>0; cStrings--, pptxt++)
2145 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2146 return FALSE;
2147 return TRUE;
2151 /* FIXME: all following APIs ******************************************/
2154 /***********************************************************************
2155 * SetMapperFlags (GDI32.@)
2157 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2159 DC *dc = get_dc_ptr( hDC );
2160 DWORD ret = 0;
2161 if(!dc) return 0;
2162 if(dc->funcs->pSetMapperFlags)
2164 ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2165 /* FIXME: ret is just a success flag, we should return a proper value */
2167 else
2168 FIXME("(%p, 0x%08x): stub - harmless\n", hDC, dwFlag);
2169 release_dc_ptr( dc );
2170 return ret;
2173 /***********************************************************************
2174 * GetAspectRatioFilterEx (GDI32.@)
2176 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2178 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2179 return FALSE;
2183 /***********************************************************************
2184 * GetCharABCWidthsA (GDI32.@)
2186 * See GetCharABCWidthsW.
2188 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2189 LPABC abc )
2191 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
2192 LPSTR str;
2193 LPWSTR wstr;
2194 BOOL ret = TRUE;
2196 if(count <= 0) return FALSE;
2198 str = HeapAlloc(GetProcessHeap(), 0, count);
2199 for(i = 0; i < count; i++)
2200 str[i] = (BYTE)(firstChar + i);
2202 wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
2204 for(i = 0; i < wlen; i++)
2206 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2208 ret = FALSE;
2209 break;
2211 abc++;
2214 HeapFree(GetProcessHeap(), 0, str);
2215 HeapFree(GetProcessHeap(), 0, wstr);
2217 return ret;
2221 /******************************************************************************
2222 * GetCharABCWidthsW [GDI32.@]
2224 * Retrieves widths of characters in range.
2226 * PARAMS
2227 * hdc [I] Handle of device context
2228 * firstChar [I] First character in range to query
2229 * lastChar [I] Last character in range to query
2230 * abc [O] Address of character-width structure
2232 * NOTES
2233 * Only works with TrueType fonts
2235 * RETURNS
2236 * Success: TRUE
2237 * Failure: FALSE
2239 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2240 LPABC abc )
2242 DC *dc = get_dc_ptr(hdc);
2243 unsigned int i;
2244 BOOL ret = FALSE;
2246 if (!dc) return FALSE;
2248 if (!abc)
2250 release_dc_ptr( dc );
2251 return FALSE;
2254 if(dc->gdiFont)
2255 ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2256 else
2257 FIXME(": stub\n");
2259 if (ret)
2261 /* convert device units to logical */
2262 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2263 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2264 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2265 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2267 ret = TRUE;
2270 release_dc_ptr( dc );
2271 return ret;
2275 /******************************************************************************
2276 * GetCharABCWidthsI [GDI32.@]
2278 * Retrieves widths of characters in range.
2280 * PARAMS
2281 * hdc [I] Handle of device context
2282 * firstChar [I] First glyphs in range to query
2283 * count [I] Last glyphs in range to query
2284 * pgi [i] Array of glyphs to query
2285 * abc [O] Address of character-width structure
2287 * NOTES
2288 * Only works with TrueType fonts
2290 * RETURNS
2291 * Success: TRUE
2292 * Failure: FALSE
2294 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2295 LPWORD pgi, LPABC abc)
2297 DC *dc = get_dc_ptr(hdc);
2298 unsigned int i;
2299 BOOL ret = FALSE;
2301 if (!dc) return FALSE;
2303 if (!abc)
2305 release_dc_ptr( dc );
2306 return FALSE;
2309 if(dc->gdiFont)
2310 ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2311 else
2312 FIXME(": stub\n");
2314 if (ret)
2316 /* convert device units to logical */
2317 for( i = 0; i < count; i++, abc++ ) {
2318 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2319 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2320 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2322 ret = TRUE;
2325 release_dc_ptr( dc );
2326 return ret;
2330 /***********************************************************************
2331 * GetGlyphOutlineA (GDI32.@)
2333 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2334 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2335 LPVOID lpBuffer, const MAT2 *lpmat2 )
2337 LPWSTR p = NULL;
2338 DWORD ret;
2339 UINT c;
2341 if (!lpmat2) return GDI_ERROR;
2343 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2344 int len;
2345 char mbchs[2];
2346 if(uChar > 0xff) { /* but, 2 bytes character only */
2347 len = 2;
2348 mbchs[0] = (uChar & 0xff00) >> 8;
2349 mbchs[1] = (uChar & 0xff);
2350 } else {
2351 len = 1;
2352 mbchs[0] = (uChar & 0xff);
2354 p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
2355 c = p[0];
2356 } else
2357 c = uChar;
2358 ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
2359 lpmat2);
2360 HeapFree(GetProcessHeap(), 0, p);
2361 return ret;
2364 /***********************************************************************
2365 * GetGlyphOutlineW (GDI32.@)
2367 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2368 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2369 LPVOID lpBuffer, const MAT2 *lpmat2 )
2371 DC *dc;
2372 DWORD ret;
2374 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2375 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2377 if (!lpmat2) return GDI_ERROR;
2379 dc = get_dc_ptr(hdc);
2380 if(!dc) return GDI_ERROR;
2382 if(dc->gdiFont)
2383 ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2384 cbBuffer, lpBuffer, lpmat2);
2385 else
2386 ret = GDI_ERROR;
2388 release_dc_ptr( dc );
2389 return ret;
2393 /***********************************************************************
2394 * CreateScalableFontResourceA (GDI32.@)
2396 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2397 LPCSTR lpszResourceFile,
2398 LPCSTR lpszFontFile,
2399 LPCSTR lpszCurrentPath )
2401 LPWSTR lpszResourceFileW = NULL;
2402 LPWSTR lpszFontFileW = NULL;
2403 LPWSTR lpszCurrentPathW = NULL;
2404 int len;
2405 BOOL ret;
2407 if (lpszResourceFile)
2409 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2410 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2411 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2414 if (lpszFontFile)
2416 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2417 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2418 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2421 if (lpszCurrentPath)
2423 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2424 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2425 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2428 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2429 lpszFontFileW, lpszCurrentPathW);
2431 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2432 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2433 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2435 return ret;
2438 /***********************************************************************
2439 * CreateScalableFontResourceW (GDI32.@)
2441 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2442 LPCWSTR lpszResourceFile,
2443 LPCWSTR lpszFontFile,
2444 LPCWSTR lpszCurrentPath )
2446 HANDLE f;
2447 FIXME("(%d,%s,%s,%s): stub\n",
2448 fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
2449 debugstr_w(lpszCurrentPath) );
2451 /* fHidden=1 - only visible for the calling app, read-only, not
2452 * enumerated with EnumFonts/EnumFontFamilies
2453 * lpszCurrentPath can be NULL
2456 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2457 if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2458 CloseHandle(f);
2459 SetLastError(ERROR_FILE_EXISTS);
2460 return FALSE;
2462 return FALSE; /* create failed */
2465 /*************************************************************************
2466 * GetKerningPairsA (GDI32.@)
2468 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2469 LPKERNINGPAIR kern_pairA )
2471 INT charset;
2472 CHARSETINFO csi;
2473 CPINFO cpi;
2474 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2475 KERNINGPAIR *kern_pairW;
2477 if (!cPairs && kern_pairA)
2479 SetLastError(ERROR_INVALID_PARAMETER);
2480 return 0;
2483 charset = GetTextCharset(hDC);
2484 if (!TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
2486 FIXME("Can't find codepage for charset %d\n", charset);
2487 return 0;
2489 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2490 * to fail on an invalid character for CP_SYMBOL.
2492 cpi.DefaultChar[0] = 0;
2493 if (csi.ciACP != CP_SYMBOL && !GetCPInfo(csi.ciACP, &cpi))
2495 FIXME("Can't find codepage %u info\n", csi.ciACP);
2496 return 0;
2498 TRACE("charset %d => codepage %u\n", charset, csi.ciACP);
2500 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2501 if (!total_kern_pairs) return 0;
2503 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2504 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2506 for (i = 0; i < total_kern_pairs; i++)
2508 char first, second;
2510 if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2511 continue;
2513 if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2514 continue;
2516 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2517 continue;
2519 if (kern_pairA)
2521 if (kern_pairs_copied >= cPairs) break;
2523 kern_pairA->wFirst = (BYTE)first;
2524 kern_pairA->wSecond = (BYTE)second;
2525 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2526 kern_pairA++;
2528 kern_pairs_copied++;
2531 HeapFree(GetProcessHeap(), 0, kern_pairW);
2533 return kern_pairs_copied;
2536 /*************************************************************************
2537 * GetKerningPairsW (GDI32.@)
2539 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2540 LPKERNINGPAIR lpKerningPairs )
2542 DC *dc;
2543 DWORD ret = 0;
2545 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2547 if (!cPairs && lpKerningPairs)
2549 SetLastError(ERROR_INVALID_PARAMETER);
2550 return 0;
2553 dc = get_dc_ptr(hDC);
2554 if (!dc) return 0;
2556 if (dc->gdiFont)
2557 ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
2559 release_dc_ptr( dc );
2560 return ret;
2563 /*************************************************************************
2564 * TranslateCharsetInfo [GDI32.@]
2566 * Fills a CHARSETINFO structure for a character set, code page, or
2567 * font. This allows making the correspondence between different labels
2568 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2569 * of the same encoding.
2571 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2572 * only one codepage should be set in *lpSrc.
2574 * RETURNS
2575 * TRUE on success, FALSE on failure.
2578 BOOL WINAPI TranslateCharsetInfo(
2579 LPDWORD lpSrc, /* [in]
2580 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2581 if flags == TCI_SRCCHARSET: a character set value
2582 if flags == TCI_SRCCODEPAGE: a code page value
2584 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2585 DWORD flags /* [in] determines interpretation of lpSrc */)
2587 int index = 0;
2588 switch (flags) {
2589 case TCI_SRCFONTSIG:
2590 while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
2591 break;
2592 case TCI_SRCCODEPAGE:
2593 while (PtrToUlong(lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
2594 break;
2595 case TCI_SRCCHARSET:
2596 while (PtrToUlong(lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
2597 break;
2598 default:
2599 return FALSE;
2601 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2602 *lpCs = FONT_tci[index];
2603 return TRUE;
2606 /*************************************************************************
2607 * GetFontLanguageInfo (GDI32.@)
2609 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2611 FONTSIGNATURE fontsig;
2612 static const DWORD GCP_DBCS_MASK=0x003F0000,
2613 GCP_DIACRITIC_MASK=0x00000000,
2614 FLI_GLYPHS_MASK=0x00000000,
2615 GCP_GLYPHSHAPE_MASK=0x00000040,
2616 GCP_KASHIDA_MASK=0x00000000,
2617 GCP_LIGATE_MASK=0x00000000,
2618 GCP_USEKERNING_MASK=0x00000000,
2619 GCP_REORDER_MASK=0x00000060;
2621 DWORD result=0;
2623 GetTextCharsetInfo( hdc, &fontsig, 0 );
2624 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2626 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2627 result|=GCP_DBCS;
2629 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2630 result|=GCP_DIACRITIC;
2632 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2633 result|=FLI_GLYPHS;
2635 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2636 result|=GCP_GLYPHSHAPE;
2638 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2639 result|=GCP_KASHIDA;
2641 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2642 result|=GCP_LIGATE;
2644 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2645 result|=GCP_USEKERNING;
2647 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2648 if( GetTextAlign( hdc) & TA_RTLREADING )
2649 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2650 result|=GCP_REORDER;
2652 return result;
2656 /*************************************************************************
2657 * GetFontData [GDI32.@]
2659 * Retrieve data for TrueType font.
2661 * RETURNS
2663 * success: Number of bytes returned
2664 * failure: GDI_ERROR
2666 * NOTES
2668 * Calls SetLastError()
2671 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2672 LPVOID buffer, DWORD length)
2674 DC *dc = get_dc_ptr(hdc);
2675 DWORD ret = GDI_ERROR;
2677 if(!dc) return GDI_ERROR;
2679 if(dc->gdiFont)
2680 ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2682 release_dc_ptr( dc );
2683 return ret;
2686 /*************************************************************************
2687 * GetGlyphIndicesA [GDI32.@]
2689 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2690 LPWORD pgi, DWORD flags)
2692 DWORD ret;
2693 WCHAR *lpstrW;
2694 INT countW;
2696 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2697 hdc, debugstr_an(lpstr, count), count, pgi, flags);
2699 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
2700 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2701 HeapFree(GetProcessHeap(), 0, lpstrW);
2703 return ret;
2706 /*************************************************************************
2707 * GetGlyphIndicesW [GDI32.@]
2709 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2710 LPWORD pgi, DWORD flags)
2712 DC *dc = get_dc_ptr(hdc);
2713 DWORD ret = GDI_ERROR;
2715 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2716 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2718 if(!dc) return GDI_ERROR;
2720 if(dc->gdiFont)
2721 ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2723 release_dc_ptr( dc );
2724 return ret;
2727 /*************************************************************************
2728 * GetCharacterPlacementA [GDI32.@]
2730 * See GetCharacterPlacementW.
2732 * NOTES:
2733 * the web browser control of ie4 calls this with dwFlags=0
2735 DWORD WINAPI
2736 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2737 INT nMaxExtent, GCP_RESULTSA *lpResults,
2738 DWORD dwFlags)
2740 WCHAR *lpStringW;
2741 INT uCountW;
2742 GCP_RESULTSW resultsW;
2743 DWORD ret;
2744 UINT font_cp;
2746 TRACE("%s, %d, %d, 0x%08x\n",
2747 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2749 /* both structs are equal in size */
2750 memcpy(&resultsW, lpResults, sizeof(resultsW));
2752 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
2753 if(lpResults->lpOutString)
2754 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2756 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2758 lpResults->nGlyphs = resultsW.nGlyphs;
2759 lpResults->nMaxFit = resultsW.nMaxFit;
2761 if(lpResults->lpOutString) {
2762 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
2763 lpResults->lpOutString, uCount, NULL, NULL );
2766 HeapFree(GetProcessHeap(), 0, lpStringW);
2767 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2769 return ret;
2772 /*************************************************************************
2773 * GetCharacterPlacementW [GDI32.@]
2775 * Retrieve information about a string. This includes the width, reordering,
2776 * Glyphing and so on.
2778 * RETURNS
2780 * The width and height of the string if successful, 0 if failed.
2782 * BUGS
2784 * All flags except GCP_REORDER are not yet implemented.
2785 * Reordering is not 100% compliant to the Windows BiDi method.
2786 * Caret positioning is not yet implemented for BiDi.
2787 * Classes are not yet implemented.
2790 DWORD WINAPI
2791 GetCharacterPlacementW(
2792 HDC hdc, /* [in] Device context for which the rendering is to be done */
2793 LPCWSTR lpString, /* [in] The string for which information is to be returned */
2794 INT uCount, /* [in] Number of WORDS in string. */
2795 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
2796 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
2797 DWORD dwFlags /* [in] Flags specifying how to process the string */
2800 DWORD ret=0;
2801 SIZE size;
2802 UINT i, nSet;
2804 TRACE("%s, %d, %d, 0x%08x\n",
2805 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2807 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
2808 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2809 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
2810 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
2811 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
2813 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
2814 if(lpResults->lpClass) FIXME("classes not implemented\n");
2815 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
2816 FIXME("Caret positions for complex scripts not implemented\n");
2818 nSet = (UINT)uCount;
2819 if(nSet > lpResults->nGlyphs)
2820 nSet = lpResults->nGlyphs;
2822 /* return number of initialized fields */
2823 lpResults->nGlyphs = nSet;
2825 if((dwFlags&GCP_REORDER)==0 )
2827 /* Treat the case where no special handling was requested in a fastpath way */
2828 /* copy will do if the GCP_REORDER flag is not set */
2829 if(lpResults->lpOutString)
2830 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
2832 if(lpResults->lpOrder)
2834 for(i = 0; i < nSet; i++)
2835 lpResults->lpOrder[i] = i;
2837 } else
2839 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
2840 nSet, lpResults->lpOrder );
2843 /* FIXME: Will use the placement chars */
2844 if (lpResults->lpDx)
2846 int c;
2847 for (i = 0; i < nSet; i++)
2849 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
2850 lpResults->lpDx[i]= c;
2854 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
2856 int pos = 0;
2858 lpResults->lpCaretPos[0] = 0;
2859 for (i = 1; i < nSet; i++)
2860 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
2861 lpResults->lpCaretPos[i] = (pos += size.cx);
2864 if(lpResults->lpGlyphs)
2865 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
2867 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
2868 ret = MAKELONG(size.cx, size.cy);
2870 return ret;
2873 /*************************************************************************
2874 * GetCharABCWidthsFloatA [GDI32.@]
2876 * See GetCharABCWidthsFloatW.
2878 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2880 INT i, wlen, count = (INT)(last - first + 1);
2881 LPSTR str;
2882 LPWSTR wstr;
2883 BOOL ret = TRUE;
2885 if (count <= 0) return FALSE;
2887 str = HeapAlloc(GetProcessHeap(), 0, count);
2889 for(i = 0; i < count; i++)
2890 str[i] = (BYTE)(first + i);
2892 wstr = FONT_mbtowc( hdc, str, count, &wlen, NULL );
2894 for (i = 0; i < wlen; i++)
2896 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
2898 ret = FALSE;
2899 break;
2901 abcf++;
2904 HeapFree( GetProcessHeap(), 0, str );
2905 HeapFree( GetProcessHeap(), 0, wstr );
2907 return ret;
2910 /*************************************************************************
2911 * GetCharABCWidthsFloatW [GDI32.@]
2913 * Retrieves widths of a range of characters.
2915 * PARAMS
2916 * hdc [I] Handle to device context.
2917 * first [I] First character in range to query.
2918 * last [I] Last character in range to query.
2919 * abcf [O] Array of LPABCFLOAT structures.
2921 * RETURNS
2922 * Success: TRUE
2923 * Failure: FALSE
2925 * BUGS
2926 * Only works with TrueType fonts. It also doesn't return real
2927 * floats but converted integers because it's implemented on
2928 * top of GetCharABCWidthsW.
2930 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2932 ABC *abc, *abc_base;
2933 unsigned int i, size = sizeof(ABC) * (last - first + 1);
2934 BOOL ret;
2936 TRACE("%p, %d, %d, %p - partial stub\n", hdc, first, last, abcf);
2938 abc = abc_base = HeapAlloc( GetProcessHeap(), 0, size );
2939 if (!abc) return FALSE;
2941 ret = GetCharABCWidthsW( hdc, first, last, abc );
2942 if (ret)
2944 for (i = first; i <= last; i++, abc++, abcf++)
2946 abcf->abcfA = abc->abcA;
2947 abcf->abcfB = abc->abcB;
2948 abcf->abcfC = abc->abcC;
2951 HeapFree( GetProcessHeap(), 0, abc_base );
2952 return ret;
2955 /*************************************************************************
2956 * GetCharWidthFloatA [GDI32.@]
2958 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
2959 UINT iLastChar, PFLOAT pxBuffer)
2961 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
2962 return 0;
2965 /*************************************************************************
2966 * GetCharWidthFloatW [GDI32.@]
2968 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
2969 UINT iLastChar, PFLOAT pxBuffer)
2971 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
2972 return 0;
2976 /***********************************************************************
2978 * Font Resource API *
2980 ***********************************************************************/
2982 /***********************************************************************
2983 * AddFontResourceA (GDI32.@)
2985 INT WINAPI AddFontResourceA( LPCSTR str )
2987 return AddFontResourceExA( str, 0, NULL);
2990 /***********************************************************************
2991 * AddFontResourceW (GDI32.@)
2993 INT WINAPI AddFontResourceW( LPCWSTR str )
2995 return AddFontResourceExW(str, 0, NULL);
2999 /***********************************************************************
3000 * AddFontResourceExA (GDI32.@)
3002 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3004 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3005 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3006 INT ret;
3008 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3009 ret = AddFontResourceExW(strW, fl, pdv);
3010 HeapFree(GetProcessHeap(), 0, strW);
3011 return ret;
3014 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3016 HRSRC rsrc = FindResourceW(hModule, name, type);
3017 HGLOBAL hMem = LoadResource(hModule, rsrc);
3018 LPVOID *pMem = LockResource(hMem);
3019 int *num_total = (int *)lParam;
3020 DWORD num_in_res;
3022 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3023 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3025 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3026 return FALSE;
3029 *num_total += num_in_res;
3030 return TRUE;
3033 /***********************************************************************
3034 * AddFontResourceExW (GDI32.@)
3036 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3038 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3039 if (ret == 0)
3041 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3042 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3043 if (hModule != NULL)
3045 int num_resources = 0;
3046 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3048 TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3049 wine_dbgstr_w(str));
3050 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3051 ret = num_resources;
3052 FreeLibrary(hModule);
3055 return ret;
3058 /***********************************************************************
3059 * RemoveFontResourceA (GDI32.@)
3061 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3063 return RemoveFontResourceExA(str, 0, 0);
3066 /***********************************************************************
3067 * RemoveFontResourceW (GDI32.@)
3069 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3071 return RemoveFontResourceExW(str, 0, 0);
3074 /***********************************************************************
3075 * AddFontMemResourceEx (GDI32.@)
3077 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3079 return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts);
3082 /***********************************************************************
3083 * RemoveFontMemResourceEx (GDI32.@)
3085 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3087 FIXME("(%p) stub\n", fh);
3088 return TRUE;
3091 /***********************************************************************
3092 * RemoveFontResourceExA (GDI32.@)
3094 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3096 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3097 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3098 INT ret;
3100 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3101 ret = RemoveFontResourceExW(strW, fl, pdv);
3102 HeapFree(GetProcessHeap(), 0, strW);
3103 return ret;
3106 /***********************************************************************
3107 * RemoveFontResourceExW (GDI32.@)
3109 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3111 return WineEngRemoveFontResourceEx(str, fl, pdv);
3114 /***********************************************************************
3115 * GetTextCharset (GDI32.@)
3117 UINT WINAPI GetTextCharset(HDC hdc)
3119 /* MSDN docs say this is equivalent */
3120 return GetTextCharsetInfo(hdc, NULL, 0);
3123 /***********************************************************************
3124 * GetTextCharsetInfo (GDI32.@)
3126 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3128 UINT ret = DEFAULT_CHARSET;
3129 DC *dc = get_dc_ptr(hdc);
3131 if (dc)
3133 if (dc->gdiFont)
3134 ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3136 release_dc_ptr( dc );
3139 if (ret == DEFAULT_CHARSET && fs)
3140 memset(fs, 0, sizeof(FONTSIGNATURE));
3141 return ret;
3144 /***********************************************************************
3145 * GdiGetCharDimensions (GDI32.@)
3147 * Gets the average width of the characters in the English alphabet.
3149 * PARAMS
3150 * hdc [I] Handle to the device context to measure on.
3151 * lptm [O] Pointer to memory to store the text metrics into.
3152 * height [O] On exit, the maximum height of characters in the English alphabet.
3154 * RETURNS
3155 * The average width of characters in the English alphabet.
3157 * NOTES
3158 * This function is used by the dialog manager to get the size of a dialog
3159 * unit. It should also be used by other pieces of code that need to know
3160 * the size of a dialog unit in logical units without having access to the
3161 * window handle of the dialog.
3162 * Windows caches the font metrics from this function, but we don't and
3163 * there doesn't appear to be an immediate advantage to do so.
3165 * SEE ALSO
3166 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3168 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3170 SIZE sz;
3171 static const WCHAR alphabet[] = {
3172 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3173 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3174 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3176 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3178 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3180 if (height) *height = sz.cy;
3181 return (sz.cx / 26 + 1) / 2;
3184 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3186 FIXME("(%d): stub\n", fEnableEUDC);
3187 return FALSE;
3190 /***********************************************************************
3191 * GetCharWidthI (GDI32.@)
3193 * Retrieve widths of characters.
3195 * PARAMS
3196 * hdc [I] Handle to a device context.
3197 * first [I] First glyph in range to query.
3198 * count [I] Number of glyph indices to query.
3199 * glyphs [I] Array of glyphs to query.
3200 * buffer [O] Buffer to receive character widths.
3202 * NOTES
3203 * Only works with TrueType fonts.
3205 * RETURNS
3206 * Success: TRUE
3207 * Failure: FALSE
3209 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3211 ABC *abc;
3212 unsigned int i;
3214 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3216 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3217 return FALSE;
3219 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3221 HeapFree(GetProcessHeap(), 0, abc);
3222 return FALSE;
3225 for (i = 0; i < count; i++)
3226 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3228 HeapFree(GetProcessHeap(), 0, abc);
3229 return TRUE;
3232 /***********************************************************************
3233 * GetFontUnicodeRanges (GDI32.@)
3235 * Retrieve a list of supported Unicode characters in a font.
3237 * PARAMS
3238 * hdc [I] Handle to a device context.
3239 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3241 * RETURNS
3242 * Success: Number of bytes written to the buffer pointed to by lpgs.
3243 * Failure: 0
3246 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3248 DWORD ret = 0;
3249 DC *dc = get_dc_ptr(hdc);
3251 TRACE("(%p, %p)\n", hdc, lpgs);
3253 if (!dc) return 0;
3255 if (dc->gdiFont) ret = WineEngGetFontUnicodeRanges(dc->gdiFont, lpgs);
3256 release_dc_ptr(dc);
3257 return ret;
3261 /*************************************************************
3262 * FontIsLinked (GDI32.@)
3264 BOOL WINAPI FontIsLinked(HDC hdc)
3266 DC *dc = get_dc_ptr(hdc);
3267 BOOL ret = FALSE;
3269 if (!dc) return FALSE;
3270 if (dc->gdiFont) ret = WineEngFontIsLinked(dc->gdiFont);
3271 release_dc_ptr(dc);
3272 TRACE("returning %d\n", ret);
3273 return ret;
3276 /*************************************************************
3277 * GdiRealizationInfo (GDI32.@)
3279 * Returns a structure that contains some font information.
3281 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3283 DC *dc = get_dc_ptr(hdc);
3284 BOOL ret = FALSE;
3286 if (!dc) return FALSE;
3287 if (dc->gdiFont) ret = WineEngRealizationInfo(dc->gdiFont, info);
3288 release_dc_ptr(dc);
3290 return ret;