gdi32: Handle a BiDi string being shaped into more or less glyphs than characters...
[wine/multimedia.git] / dlls / gdi32 / font.c
blob17fb381a612d8725ca387709372dfa1e26bfab4e
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include "winerror.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "wownt32.h"
35 #include "gdi_private.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(font);
41 /* Device -> World size conversion */
43 /* Performs a device to world transformation on the specified width (which
44 * is in integer format).
46 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
48 double floatWidth;
50 /* Perform operation with floating point */
51 floatWidth = (double)width * dc->xformVport2World.eM11;
52 /* Round to integers */
53 return GDI_ROUND(floatWidth);
56 /* Performs a device to world transformation on the specified size (which
57 * is in integer format).
59 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
61 double floatHeight;
63 /* Perform operation with floating point */
64 floatHeight = (double)height * dc->xformVport2World.eM22;
65 /* Round to integers */
66 return GDI_ROUND(floatHeight);
69 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
71 POINT pt[2];
72 pt[0].x = pt[0].y = 0;
73 pt[1].x = width;
74 pt[1].y = 0;
75 LPtoDP(dc->hSelf, pt, 2);
76 return pt[1].x - pt[0].x;
79 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
81 POINT pt[2];
82 pt[0].x = pt[0].y = 0;
83 pt[1].x = 0;
84 pt[1].y = height;
85 LPtoDP(dc->hSelf, pt, 2);
86 return pt[1].y - pt[0].y;
89 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
90 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
91 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
92 static BOOL FONT_DeleteObject( HGDIOBJ handle );
94 static const struct gdi_obj_funcs font_funcs =
96 FONT_SelectObject, /* pSelectObject */
97 FONT_GetObjectA, /* pGetObjectA */
98 FONT_GetObjectW, /* pGetObjectW */
99 NULL, /* pUnrealizeObject */
100 FONT_DeleteObject /* pDeleteObject */
103 #define ENUM_UNICODE 0x00000001
104 #define ENUM_CALLED 0x00000002
106 typedef struct
108 GDIOBJHDR header;
109 LOGFONTW logfont;
110 } FONTOBJ;
112 typedef struct
114 LPLOGFONTW lpLogFontParam;
115 FONTENUMPROCW lpEnumFunc;
116 LPARAM lpData;
117 DWORD dwFlags;
118 HDC hdc;
119 } fontEnum32;
122 * For TranslateCharsetInfo
124 #define MAXTCIINDEX 32
125 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
126 /* ANSI */
127 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
128 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
129 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
130 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
131 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
132 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
133 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
134 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
135 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
136 /* reserved by ANSI */
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144 /* ANSI and OEM */
145 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
146 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
147 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
148 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
149 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
150 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
151 /* reserved for alternate ANSI and OEM */
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 /* reserved for system */
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
165 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
167 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
168 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
169 LF_FACESIZE);
170 fontW->lfFaceName[LF_FACESIZE-1] = 0;
173 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
175 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
176 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
177 LF_FACESIZE, NULL, NULL);
178 fontA->lfFaceName[LF_FACESIZE-1] = 0;
181 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
183 FONT_LogFontWToA( (const LOGFONTW *)fontW, (LPLOGFONTA)fontA);
185 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
186 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
187 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
188 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
189 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
190 fontA->elfStyle[LF_FACESIZE-1] = '\0';
191 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
192 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
193 fontA->elfScript[LF_FACESIZE-1] = '\0';
196 /***********************************************************************
197 * TEXTMETRIC conversion functions.
199 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
201 ptmA->tmHeight = ptmW->tmHeight;
202 ptmA->tmAscent = ptmW->tmAscent;
203 ptmA->tmDescent = ptmW->tmDescent;
204 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
205 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
206 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
207 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
208 ptmA->tmWeight = ptmW->tmWeight;
209 ptmA->tmOverhang = ptmW->tmOverhang;
210 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
211 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
212 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
213 if (ptmW->tmCharSet == SYMBOL_CHARSET)
215 ptmA->tmFirstChar = 0x1e;
216 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
218 else
220 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
221 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
223 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
224 ptmA->tmBreakChar = ptmW->tmBreakChar;
225 ptmA->tmItalic = ptmW->tmItalic;
226 ptmA->tmUnderlined = ptmW->tmUnderlined;
227 ptmA->tmStruckOut = ptmW->tmStruckOut;
228 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
229 ptmA->tmCharSet = ptmW->tmCharSet;
233 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
235 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
236 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
237 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
238 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
239 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
240 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
244 /***********************************************************************
245 * GdiGetCodePage (GDI32.@)
247 DWORD WINAPI GdiGetCodePage( HDC hdc )
249 UINT cp = CP_ACP;
250 DC *dc = get_dc_ptr( hdc );
252 if (dc)
254 cp = dc->font_code_page;
255 release_dc_ptr( dc );
257 return cp;
260 /***********************************************************************
261 * FONT_mbtowc
263 * Returns a Unicode translation of str using the charset of the
264 * currently selected font in hdc. If count is -1 then str is assumed
265 * to be '\0' terminated, otherwise it contains the number of bytes to
266 * convert. If plenW is non-NULL, on return it will point to the
267 * number of WCHARs that have been written. If pCP is non-NULL, on
268 * return it will point to the codepage used in the conversion. The
269 * caller should free the returned LPWSTR from the process heap
270 * itself.
272 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
274 UINT cp;
275 INT lenW;
276 LPWSTR strW;
278 cp = GdiGetCodePage( hdc );
280 if(count == -1) count = strlen(str);
281 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
282 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
283 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
284 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
285 if(plenW) *plenW = lenW;
286 if(pCP) *pCP = cp;
287 return strW;
291 /***********************************************************************
292 * CreateFontIndirectA (GDI32.@)
294 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
296 LOGFONTW lfW;
298 if (!plfA) return 0;
300 FONT_LogFontAToW( plfA, &lfW );
301 return CreateFontIndirectW( &lfW );
304 /***********************************************************************
305 * CreateFontIndirectW (GDI32.@)
307 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
309 HFONT hFont;
310 FONTOBJ *fontPtr;
312 if (!plf) return 0;
314 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
316 fontPtr->logfont = *plf;
318 if (plf->lfEscapement != plf->lfOrientation)
320 /* this should really depend on whether GM_ADVANCED is set */
321 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
322 WARN("orientation angle %f set to "
323 "escapement angle %f for new font %p\n",
324 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
327 if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs )))
329 HeapFree( GetProcessHeap(), 0, fontPtr );
330 return 0;
333 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
334 plf->lfHeight, plf->lfWidth,
335 plf->lfEscapement, plf->lfOrientation,
336 plf->lfPitchAndFamily,
337 plf->lfOutPrecision, plf->lfClipPrecision,
338 plf->lfQuality, plf->lfCharSet,
339 debugstr_w(plf->lfFaceName),
340 plf->lfWeight > 400 ? "Bold" : "",
341 plf->lfItalic ? "Italic" : "",
342 plf->lfUnderline ? "Underline" : "", hFont);
344 return hFont;
347 /*************************************************************************
348 * CreateFontA (GDI32.@)
350 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
351 INT orient, INT weight, DWORD italic,
352 DWORD underline, DWORD strikeout, DWORD charset,
353 DWORD outpres, DWORD clippres, DWORD quality,
354 DWORD pitch, LPCSTR name )
356 LOGFONTA logfont;
358 logfont.lfHeight = height;
359 logfont.lfWidth = width;
360 logfont.lfEscapement = esc;
361 logfont.lfOrientation = orient;
362 logfont.lfWeight = weight;
363 logfont.lfItalic = italic;
364 logfont.lfUnderline = underline;
365 logfont.lfStrikeOut = strikeout;
366 logfont.lfCharSet = charset;
367 logfont.lfOutPrecision = outpres;
368 logfont.lfClipPrecision = clippres;
369 logfont.lfQuality = quality;
370 logfont.lfPitchAndFamily = pitch;
372 if (name)
373 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
374 else
375 logfont.lfFaceName[0] = '\0';
377 return CreateFontIndirectA( &logfont );
380 /*************************************************************************
381 * CreateFontW (GDI32.@)
383 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
384 INT orient, INT weight, DWORD italic,
385 DWORD underline, DWORD strikeout, DWORD charset,
386 DWORD outpres, DWORD clippres, DWORD quality,
387 DWORD pitch, LPCWSTR name )
389 LOGFONTW logfont;
391 logfont.lfHeight = height;
392 logfont.lfWidth = width;
393 logfont.lfEscapement = esc;
394 logfont.lfOrientation = orient;
395 logfont.lfWeight = weight;
396 logfont.lfItalic = italic;
397 logfont.lfUnderline = underline;
398 logfont.lfStrikeOut = strikeout;
399 logfont.lfCharSet = charset;
400 logfont.lfOutPrecision = outpres;
401 logfont.lfClipPrecision = clippres;
402 logfont.lfQuality = quality;
403 logfont.lfPitchAndFamily = pitch;
405 if (name)
406 lstrcpynW(logfont.lfFaceName, name,
407 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
408 else
409 logfont.lfFaceName[0] = '\0';
411 return CreateFontIndirectW( &logfont );
414 static void update_font_code_page( DC *dc )
416 CHARSETINFO csi;
417 int charset = DEFAULT_CHARSET;
419 if (dc->gdiFont)
420 charset = WineEngGetTextCharsetInfo( dc->gdiFont, NULL, 0 );
422 /* Hmm, nicely designed api this one! */
423 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
424 dc->font_code_page = csi.ciACP;
425 else {
426 switch(charset) {
427 case OEM_CHARSET:
428 dc->font_code_page = GetOEMCP();
429 break;
430 case DEFAULT_CHARSET:
431 dc->font_code_page = GetACP();
432 break;
434 case VISCII_CHARSET:
435 case TCVN_CHARSET:
436 case KOI8_CHARSET:
437 case ISO3_CHARSET:
438 case ISO4_CHARSET:
439 case ISO10_CHARSET:
440 case CELTIC_CHARSET:
441 /* FIXME: These have no place here, but because x11drv
442 enumerates fonts with these (made up) charsets some apps
443 might use them and then the FIXME below would become
444 annoying. Now we could pick the intended codepage for
445 each of these, but since it's broken anyway we'll just
446 use CP_ACP and hope it'll go away...
448 dc->font_code_page = CP_ACP;
449 break;
451 default:
452 FIXME("Can't find codepage for charset %d\n", charset);
453 dc->font_code_page = CP_ACP;
454 break;
458 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
461 /***********************************************************************
462 * FONT_SelectObject
464 * If the driver supports vector fonts we create a gdi font first and
465 * then call the driver to give it a chance to supply its own device
466 * font. If the driver wants to do this it returns TRUE and we can
467 * delete the gdi font, if the driver wants to use the gdi font it
468 * should return FALSE, to signal an error return GDI_ERROR. For
469 * drivers that don't support vector fonts they must supply their own
470 * font.
472 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
474 HGDIOBJ ret = 0;
475 DC *dc = get_dc_ptr( hdc );
477 if (!dc) return 0;
479 if (!GDI_inc_ref_count( handle ))
481 release_dc_ptr( dc );
482 return 0;
485 if (GetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_VA_ABLE)
486 dc->gdiFont = WineEngCreateFontInstance( dc, handle );
488 if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont );
490 if (ret && dc->gdiFont) dc->gdiFont = 0;
492 if (ret == HGDI_ERROR)
494 GDI_dec_ref_count( handle );
495 ret = 0; /* SelectObject returns 0 on error */
497 else
499 ret = dc->hFont;
500 dc->hFont = handle;
501 update_font_code_page( dc );
502 GDI_dec_ref_count( ret );
504 release_dc_ptr( dc );
505 return ret;
509 /***********************************************************************
510 * FONT_GetObjectA
512 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
514 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
515 LOGFONTA lfA;
517 if (!font) return 0;
518 if (buffer)
520 FONT_LogFontWToA( &font->logfont, &lfA );
521 if (count > sizeof(lfA)) count = sizeof(lfA);
522 memcpy( buffer, &lfA, count );
524 else count = sizeof(lfA);
525 GDI_ReleaseObj( handle );
526 return count;
529 /***********************************************************************
530 * FONT_GetObjectW
532 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
534 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
536 if (!font) return 0;
537 if (buffer)
539 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
540 memcpy( buffer, &font->logfont, count );
542 else count = sizeof(LOGFONTW);
543 GDI_ReleaseObj( handle );
544 return count;
548 /***********************************************************************
549 * FONT_DeleteObject
551 static BOOL FONT_DeleteObject( HGDIOBJ handle )
553 FONTOBJ *obj;
555 WineEngDestroyFontInstance( handle );
557 if (!(obj = free_gdi_handle( handle ))) return FALSE;
558 return HeapFree( GetProcessHeap(), 0, obj );
562 /***********************************************************************
563 * FONT_EnumInstance
565 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
566 * We have to use other types because of the FONTENUMPROCW definition.
568 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
569 DWORD fType, LPARAM lp )
571 fontEnum32 *pfe = (fontEnum32*)lp;
572 INT ret = 1;
574 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
575 if ((!pfe->lpLogFontParam ||
576 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
577 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
578 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
580 /* convert font metrics */
581 ENUMLOGFONTEXA logfont;
582 NEWTEXTMETRICEXA tmA;
584 pfe->dwFlags |= ENUM_CALLED;
585 if (!(pfe->dwFlags & ENUM_UNICODE))
587 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
588 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
589 plf = (LOGFONTW *)&logfont.elfLogFont;
590 ptm = (TEXTMETRICW *)&tmA;
593 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
595 return ret;
598 /***********************************************************************
599 * FONT_EnumFontFamiliesEx
601 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf,
602 FONTENUMPROCW efproc,
603 LPARAM lParam, DWORD dwUnicode)
605 INT ret = 1, ret2;
606 DC *dc = get_dc_ptr( hDC );
607 fontEnum32 fe32;
608 BOOL enum_gdi_fonts;
610 if (!dc) return 0;
612 if (plf)
613 TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName),
614 plf->lfCharSet);
615 fe32.lpLogFontParam = plf;
616 fe32.lpEnumFunc = efproc;
617 fe32.lpData = lParam;
618 fe32.dwFlags = dwUnicode;
619 fe32.hdc = hDC;
621 enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE;
623 if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
625 ret = 0;
626 goto done;
629 if (enum_gdi_fonts)
630 ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 );
631 fe32.dwFlags &= ~ENUM_CALLED;
632 if (ret && dc->funcs->pEnumDeviceFonts) {
633 ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 );
634 if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
635 ret = ret2;
637 done:
638 release_dc_ptr( dc );
639 return ret;
642 /***********************************************************************
643 * EnumFontFamiliesExW (GDI32.@)
645 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
646 FONTENUMPROCW efproc,
647 LPARAM lParam, DWORD dwFlags )
649 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE );
652 /***********************************************************************
653 * EnumFontFamiliesExA (GDI32.@)
655 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
656 FONTENUMPROCA efproc,
657 LPARAM lParam, DWORD dwFlags)
659 LOGFONTW lfW, *plfW;
661 if (plf)
663 FONT_LogFontAToW( plf, &lfW );
664 plfW = &lfW;
666 else plfW = NULL;
668 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, 0);
671 /***********************************************************************
672 * EnumFontFamiliesA (GDI32.@)
674 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
675 FONTENUMPROCA efproc, LPARAM lpData )
677 LOGFONTA lf, *plf;
679 if (lpFamily)
681 if (!*lpFamily) return 1;
682 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
683 lf.lfCharSet = DEFAULT_CHARSET;
684 lf.lfPitchAndFamily = 0;
685 plf = &lf;
687 else plf = NULL;
689 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
692 /***********************************************************************
693 * EnumFontFamiliesW (GDI32.@)
695 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
696 FONTENUMPROCW efproc, LPARAM lpData )
698 LOGFONTW lf, *plf;
700 if (lpFamily)
702 if (!*lpFamily) return 1;
703 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
704 lf.lfCharSet = DEFAULT_CHARSET;
705 lf.lfPitchAndFamily = 0;
706 plf = &lf;
708 else plf = NULL;
710 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
713 /***********************************************************************
714 * EnumFontsA (GDI32.@)
716 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
717 LPARAM lpData )
719 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
722 /***********************************************************************
723 * EnumFontsW (GDI32.@)
725 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
726 LPARAM lpData )
728 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
732 /***********************************************************************
733 * GetTextCharacterExtra (GDI32.@)
735 INT WINAPI GetTextCharacterExtra( HDC hdc )
737 INT ret;
738 DC *dc = get_dc_ptr( hdc );
739 if (!dc) return 0x80000000;
740 ret = dc->charExtra;
741 release_dc_ptr( dc );
742 return ret;
746 /***********************************************************************
747 * SetTextCharacterExtra (GDI32.@)
749 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
751 INT prev;
752 DC * dc = get_dc_ptr( hdc );
753 if (!dc) return 0x80000000;
754 if (dc->funcs->pSetTextCharacterExtra)
755 prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra );
756 else
758 prev = dc->charExtra;
759 dc->charExtra = extra;
761 release_dc_ptr( dc );
762 return prev;
766 /***********************************************************************
767 * SetTextJustification (GDI32.@)
769 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
771 BOOL ret = TRUE;
772 DC * dc = get_dc_ptr( hdc );
773 if (!dc) return FALSE;
774 if (dc->funcs->pSetTextJustification)
775 ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks );
776 else
778 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
779 if (!extra) breaks = 0;
780 if (breaks)
782 dc->breakExtra = extra / breaks;
783 dc->breakRem = extra - (breaks * dc->breakExtra);
785 else
787 dc->breakExtra = 0;
788 dc->breakRem = 0;
791 release_dc_ptr( dc );
792 return ret;
796 /***********************************************************************
797 * GetTextFaceA (GDI32.@)
799 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
801 INT res = GetTextFaceW(hdc, 0, NULL);
802 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
803 GetTextFaceW( hdc, res, nameW );
805 if (name)
807 if (count)
809 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
810 if (res == 0)
811 res = count;
812 name[count-1] = 0;
813 /* GetTextFaceA does NOT include the nul byte in the return count. */
814 res--;
816 else
817 res = 0;
819 else
820 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
821 HeapFree( GetProcessHeap(), 0, nameW );
822 return res;
825 /***********************************************************************
826 * GetTextFaceW (GDI32.@)
828 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
830 FONTOBJ *font;
831 INT ret = 0;
833 DC * dc = get_dc_ptr( hdc );
834 if (!dc) return 0;
836 if(dc->gdiFont)
837 ret = WineEngGetTextFace(dc->gdiFont, count, name);
838 else if ((font = GDI_GetObjPtr( dc->hFont, OBJ_FONT )))
840 INT n = strlenW(font->logfont.lfFaceName) + 1;
841 if (name)
843 lstrcpynW( name, font->logfont.lfFaceName, count );
844 ret = min(count, n);
846 else ret = n;
847 GDI_ReleaseObj( dc->hFont );
849 release_dc_ptr( dc );
850 return ret;
854 /***********************************************************************
855 * GetTextExtentPoint32A (GDI32.@)
857 * See GetTextExtentPoint32W.
859 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
860 LPSIZE size )
862 BOOL ret = FALSE;
863 INT wlen;
864 LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
866 if (p) {
867 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
868 HeapFree( GetProcessHeap(), 0, p );
871 TRACE("(%p %s %d %p): returning %d x %d\n",
872 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
873 return ret;
877 /***********************************************************************
878 * GetTextExtentPoint32W [GDI32.@]
880 * Computes width/height for a string.
882 * Computes width and height of the specified string.
884 * RETURNS
885 * Success: TRUE
886 * Failure: FALSE
888 BOOL WINAPI GetTextExtentPoint32W(
889 HDC hdc, /* [in] Handle of device context */
890 LPCWSTR str, /* [in] Address of text string */
891 INT count, /* [in] Number of characters in string */
892 LPSIZE size) /* [out] Address of structure for string size */
894 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
897 /***********************************************************************
898 * GetTextExtentExPointI [GDI32.@]
900 * Computes width and height of the array of glyph indices.
902 * PARAMS
903 * hdc [I] Handle of device context.
904 * indices [I] Glyph index array.
905 * count [I] Number of glyphs in array.
906 * max_ext [I] Maximum width in glyphs.
907 * nfit [O] Maximum number of characters.
908 * dxs [O] Partial string widths.
909 * size [O] Returned string size.
911 * RETURNS
912 * Success: TRUE
913 * Failure: FALSE
915 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
916 LPINT nfit, LPINT dxs, LPSIZE size )
918 BOOL ret = FALSE;
919 DC * dc = get_dc_ptr( hdc );
920 if (!dc) return FALSE;
922 if(dc->gdiFont) {
923 ret = WineEngGetTextExtentExPointI(dc->gdiFont, indices, count, max_ext, nfit, dxs, size);
924 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
925 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
926 size->cx += count * dc->charExtra;
928 else if(dc->funcs->pGetTextExtentExPoint) {
929 FIXME("calling GetTextExtentExPoint\n");
930 ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, indices, count,
931 max_ext, nfit, dxs, size );
934 release_dc_ptr( dc );
936 TRACE("(%p %p %d %p): returning %d x %d\n",
937 hdc, indices, count, size, size->cx, size->cy );
938 return ret;
941 /***********************************************************************
942 * GetTextExtentPointI [GDI32.@]
944 * Computes width and height of the array of glyph indices.
946 * PARAMS
947 * hdc [I] Handle of device context.
948 * indices [I] Glyph index array.
949 * count [I] Number of glyphs in array.
950 * size [O] Returned string size.
952 * RETURNS
953 * Success: TRUE
954 * Failure: FALSE
956 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
958 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
962 /***********************************************************************
963 * GetTextExtentPointA (GDI32.@)
965 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
966 LPSIZE size )
968 TRACE("not bug compatible.\n");
969 return GetTextExtentPoint32A( hdc, str, count, size );
972 /***********************************************************************
973 * GetTextExtentPointW (GDI32.@)
975 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
976 LPSIZE size )
978 TRACE("not bug compatible.\n");
979 return GetTextExtentPoint32W( hdc, str, count, size );
983 /***********************************************************************
984 * GetTextExtentExPointA (GDI32.@)
986 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
987 INT maxExt, LPINT lpnFit,
988 LPINT alpDx, LPSIZE size )
990 BOOL ret;
991 INT wlen;
992 INT *walpDx = NULL;
993 LPWSTR p = NULL;
995 if (alpDx &&
996 NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
997 return FALSE;
999 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1000 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1001 if (walpDx)
1003 INT n = lpnFit ? *lpnFit : wlen;
1004 INT i, j;
1005 for(i = 0, j = 0; i < n; i++, j++)
1007 alpDx[j] = walpDx[i];
1008 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1011 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1012 HeapFree( GetProcessHeap(), 0, p );
1013 HeapFree( GetProcessHeap(), 0, walpDx );
1014 return ret;
1018 /***********************************************************************
1019 * GetTextExtentExPointW (GDI32.@)
1021 * Return the size of the string as it would be if it was output properly by
1022 * e.g. TextOut.
1024 * This should include
1025 * - Intercharacter spacing
1026 * - justification spacing (not yet done)
1027 * - kerning? see below
1029 * Kerning. Since kerning would be carried out by the rendering code it should
1030 * be done by the driver. However they don't support it yet. Also I am not
1031 * yet persuaded that (certainly under Win95) any kerning is actually done.
1033 * str: According to MSDN this should be null-terminated. That is not true; a
1034 * null will not terminate it early.
1035 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1036 * than count. I have seen it be either the size of the full string or
1037 * 1 less than the size of the full string. I have not seen it bear any
1038 * resemblance to the portion that would fit.
1039 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1040 * trailing intercharacter spacing and any trailing justification.
1042 * FIXME
1043 * Currently we do this by measuring each character etc. We should do it by
1044 * passing the request to the driver, perhaps by extending the
1045 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1046 * thinking about kerning issues and rounding issues in the justification.
1049 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1050 INT maxExt, LPINT lpnFit,
1051 LPINT alpDx, LPSIZE size )
1053 INT nFit = 0;
1054 LPINT dxs = NULL;
1055 DC *dc;
1056 BOOL ret = FALSE;
1057 TEXTMETRICW tm;
1059 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1061 dc = get_dc_ptr(hdc);
1062 if (! dc)
1063 return FALSE;
1065 GetTextMetricsW(hdc, &tm);
1067 /* If we need to calculate nFit, then we need the partial extents even if
1068 the user hasn't provided us with an array. */
1069 if (lpnFit)
1071 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1072 if (! dxs)
1074 release_dc_ptr(dc);
1075 SetLastError(ERROR_OUTOFMEMORY);
1076 return FALSE;
1079 else
1080 dxs = alpDx;
1082 if (dc->gdiFont)
1083 ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
1084 0, NULL, dxs, size);
1085 else if (dc->funcs->pGetTextExtentExPoint)
1086 ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
1087 0, NULL, dxs, size);
1089 /* Perform device size to world size transformations. */
1090 if (ret)
1092 INT extra = dc->charExtra,
1093 breakExtra = dc->breakExtra,
1094 breakRem = dc->breakRem,
1097 if (dxs)
1099 for (i = 0; i < count; ++i)
1101 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1102 dxs[i] += (i+1) * extra;
1103 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1105 dxs[i] += breakExtra;
1106 if (breakRem > 0)
1108 breakRem--;
1109 dxs[i]++;
1112 if (dxs[i] <= maxExt)
1113 ++nFit;
1115 breakRem = dc->breakRem;
1117 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1118 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1120 if (!dxs && count > 1 && (breakExtra || breakRem))
1122 for (i = 0; i < count; i++)
1124 if (str[i] == tm.tmBreakChar)
1126 size->cx += breakExtra;
1127 if (breakRem > 0)
1129 breakRem--;
1130 (size->cx)++;
1137 if (lpnFit)
1138 *lpnFit = nFit;
1140 if (! alpDx)
1141 HeapFree(GetProcessHeap(), 0, dxs);
1143 release_dc_ptr( dc );
1145 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1146 return ret;
1149 /***********************************************************************
1150 * GetTextMetricsA (GDI32.@)
1152 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1154 TEXTMETRICW tm32;
1156 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1157 FONT_TextMetricWToA( &tm32, metrics );
1158 return TRUE;
1161 /***********************************************************************
1162 * GetTextMetricsW (GDI32.@)
1164 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1166 BOOL ret = FALSE;
1167 DC * dc = get_dc_ptr( hdc );
1168 if (!dc) return FALSE;
1170 if (dc->gdiFont)
1171 ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1172 else if (dc->funcs->pGetTextMetrics)
1173 ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1175 if (ret)
1177 /* device layer returns values in device units
1178 * therefore we have to convert them to logical */
1180 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1181 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1183 #define WDPTOLP(x) ((x<0)? \
1184 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1185 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1186 #define HDPTOLP(y) ((y<0)? \
1187 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1188 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1190 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1191 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1192 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1193 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1194 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1195 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1196 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1197 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1198 ret = TRUE;
1199 #undef WDPTOLP
1200 #undef HDPTOLP
1201 TRACE("text metrics:\n"
1202 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1203 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1204 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1205 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1206 " PitchAndFamily = %02x\n"
1207 " --------------------\n"
1208 " InternalLeading = %i\n"
1209 " Ascent = %i\n"
1210 " Descent = %i\n"
1211 " Height = %i\n",
1212 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1213 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1214 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1215 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1216 metrics->tmPitchAndFamily,
1217 metrics->tmInternalLeading,
1218 metrics->tmAscent,
1219 metrics->tmDescent,
1220 metrics->tmHeight );
1222 release_dc_ptr( dc );
1223 return ret;
1227 /***********************************************************************
1228 * GetOutlineTextMetricsA (GDI32.@)
1229 * Gets metrics for TrueType fonts.
1231 * NOTES
1232 * If the supplied buffer isn't big enough Windows partially fills it up to
1233 * its given length and returns that length.
1235 * RETURNS
1236 * Success: Non-zero or size of required buffer
1237 * Failure: 0
1239 UINT WINAPI GetOutlineTextMetricsA(
1240 HDC hdc, /* [in] Handle of device context */
1241 UINT cbData, /* [in] Size of metric data array */
1242 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1244 char buf[512], *ptr;
1245 UINT ret, needed;
1246 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1247 OUTLINETEXTMETRICA *output = lpOTM;
1248 INT left, len;
1250 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1251 return 0;
1252 if(ret > sizeof(buf))
1253 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1254 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1256 needed = sizeof(OUTLINETEXTMETRICA);
1257 if(lpOTMW->otmpFamilyName)
1258 needed += WideCharToMultiByte(CP_ACP, 0,
1259 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1260 NULL, 0, NULL, NULL);
1261 if(lpOTMW->otmpFaceName)
1262 needed += WideCharToMultiByte(CP_ACP, 0,
1263 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1264 NULL, 0, NULL, NULL);
1265 if(lpOTMW->otmpStyleName)
1266 needed += WideCharToMultiByte(CP_ACP, 0,
1267 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1268 NULL, 0, NULL, NULL);
1269 if(lpOTMW->otmpFullName)
1270 needed += WideCharToMultiByte(CP_ACP, 0,
1271 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1272 NULL, 0, NULL, NULL);
1274 if(!lpOTM) {
1275 ret = needed;
1276 goto end;
1279 TRACE("needed = %d\n", needed);
1280 if(needed > cbData)
1281 /* Since the supplied buffer isn't big enough, we'll alloc one
1282 that is and memcpy the first cbData bytes into the lpOTM at
1283 the end. */
1284 output = HeapAlloc(GetProcessHeap(), 0, needed);
1286 ret = output->otmSize = min(needed, cbData);
1287 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1288 output->otmFiller = 0;
1289 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1290 output->otmfsSelection = lpOTMW->otmfsSelection;
1291 output->otmfsType = lpOTMW->otmfsType;
1292 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1293 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1294 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1295 output->otmEMSquare = lpOTMW->otmEMSquare;
1296 output->otmAscent = lpOTMW->otmAscent;
1297 output->otmDescent = lpOTMW->otmDescent;
1298 output->otmLineGap = lpOTMW->otmLineGap;
1299 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1300 output->otmsXHeight = lpOTMW->otmsXHeight;
1301 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1302 output->otmMacAscent = lpOTMW->otmMacAscent;
1303 output->otmMacDescent = lpOTMW->otmMacDescent;
1304 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1305 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1306 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1307 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1308 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1309 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1310 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1311 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1312 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1313 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1316 ptr = (char*)(output + 1);
1317 left = needed - sizeof(*output);
1319 if(lpOTMW->otmpFamilyName) {
1320 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1321 len = WideCharToMultiByte(CP_ACP, 0,
1322 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1323 ptr, left, NULL, NULL);
1324 left -= len;
1325 ptr += len;
1326 } else
1327 output->otmpFamilyName = 0;
1329 if(lpOTMW->otmpFaceName) {
1330 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1331 len = WideCharToMultiByte(CP_ACP, 0,
1332 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1333 ptr, left, NULL, NULL);
1334 left -= len;
1335 ptr += len;
1336 } else
1337 output->otmpFaceName = 0;
1339 if(lpOTMW->otmpStyleName) {
1340 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1341 len = WideCharToMultiByte(CP_ACP, 0,
1342 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1343 ptr, left, NULL, NULL);
1344 left -= len;
1345 ptr += len;
1346 } else
1347 output->otmpStyleName = 0;
1349 if(lpOTMW->otmpFullName) {
1350 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1351 len = WideCharToMultiByte(CP_ACP, 0,
1352 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1353 ptr, left, NULL, NULL);
1354 left -= len;
1355 } else
1356 output->otmpFullName = 0;
1358 assert(left == 0);
1360 if(output != lpOTM) {
1361 memcpy(lpOTM, output, cbData);
1362 HeapFree(GetProcessHeap(), 0, output);
1364 /* check if the string offsets really fit into the provided size */
1365 /* FIXME: should we check string length as well? */
1366 /* make sure that we don't read/write beyond the provided buffer */
1367 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1369 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1370 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1373 /* make sure that we don't read/write beyond the provided buffer */
1374 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1376 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1377 lpOTM->otmpFaceName = 0; /* doesn't fit */
1380 /* make sure that we don't read/write beyond the provided buffer */
1381 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1383 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1384 lpOTM->otmpStyleName = 0; /* doesn't fit */
1387 /* make sure that we don't read/write beyond the provided buffer */
1388 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1390 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1391 lpOTM->otmpFullName = 0; /* doesn't fit */
1395 end:
1396 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1397 HeapFree(GetProcessHeap(), 0, lpOTMW);
1399 return ret;
1403 /***********************************************************************
1404 * GetOutlineTextMetricsW [GDI32.@]
1406 UINT WINAPI GetOutlineTextMetricsW(
1407 HDC hdc, /* [in] Handle of device context */
1408 UINT cbData, /* [in] Size of metric data array */
1409 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1411 DC *dc = get_dc_ptr( hdc );
1412 OUTLINETEXTMETRICW *output = lpOTM;
1413 UINT ret;
1415 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1416 if(!dc) return 0;
1418 if(dc->gdiFont) {
1419 ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1420 if(lpOTM && ret) {
1421 if(ret > cbData) {
1422 output = HeapAlloc(GetProcessHeap(), 0, ret);
1423 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1426 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1427 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1429 #define WDPTOLP(x) ((x<0)? \
1430 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1431 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1432 #define HDPTOLP(y) ((y<0)? \
1433 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1434 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1436 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1437 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1438 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1439 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1440 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1441 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1442 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1443 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1444 output->otmAscent = HDPTOLP(output->otmAscent);
1445 output->otmDescent = HDPTOLP(output->otmDescent);
1446 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1447 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1448 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1449 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1450 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1451 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1452 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1453 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1454 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1455 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1456 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1457 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1458 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1459 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1460 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1461 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1462 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1463 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1464 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1465 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1466 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1467 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1468 #undef WDPTOLP
1469 #undef HDPTOLP
1470 if(output != lpOTM) {
1471 memcpy(lpOTM, output, cbData);
1472 HeapFree(GetProcessHeap(), 0, output);
1473 ret = cbData;
1478 else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1479 but really this should just be a return 0. */
1481 ret = sizeof(*lpOTM);
1482 if (lpOTM) {
1483 if(cbData < ret)
1484 ret = 0;
1485 else {
1486 memset(lpOTM, 0, ret);
1487 lpOTM->otmSize = sizeof(*lpOTM);
1488 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1490 Further fill of the structure not implemented,
1491 Needs real values for the structure members
1496 release_dc_ptr(dc);
1497 return ret;
1501 /***********************************************************************
1502 * GetCharWidthW (GDI32.@)
1503 * GetCharWidth32W (GDI32.@)
1505 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1506 LPINT buffer )
1508 UINT i;
1509 BOOL ret = FALSE;
1510 DC * dc = get_dc_ptr( hdc );
1511 if (!dc) return FALSE;
1513 if (dc->gdiFont)
1514 ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1515 else if (dc->funcs->pGetCharWidth)
1516 ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1518 if (ret)
1520 /* convert device units to logical */
1521 for( i = firstChar; i <= lastChar; i++, buffer++ )
1522 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1523 ret = TRUE;
1525 release_dc_ptr( dc );
1526 return ret;
1530 /***********************************************************************
1531 * GetCharWidthA (GDI32.@)
1532 * GetCharWidth32A (GDI32.@)
1534 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1535 LPINT buffer )
1537 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
1538 LPSTR str;
1539 LPWSTR wstr;
1540 BOOL ret = TRUE;
1542 if(count <= 0) return FALSE;
1544 str = HeapAlloc(GetProcessHeap(), 0, count);
1545 for(i = 0; i < count; i++)
1546 str[i] = (BYTE)(firstChar + i);
1548 wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1550 for(i = 0; i < wlen; i++)
1552 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1554 ret = FALSE;
1555 break;
1557 buffer++;
1560 HeapFree(GetProcessHeap(), 0, str);
1561 HeapFree(GetProcessHeap(), 0, wstr);
1563 return ret;
1567 /***********************************************************************
1568 * ExtTextOutA (GDI32.@)
1570 * See ExtTextOutW.
1572 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1573 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1575 INT wlen;
1576 UINT codepage;
1577 LPWSTR p;
1578 BOOL ret;
1579 LPINT lpDxW = NULL;
1581 if (flags & ETO_GLYPH_INDEX)
1582 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1584 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1586 if (lpDx) {
1587 unsigned int i = 0, j = 0;
1589 /* allocate enough for a ETO_PDY */
1590 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
1591 while(i < count) {
1592 if(IsDBCSLeadByteEx(codepage, str[i]))
1594 if(flags & ETO_PDY)
1596 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
1597 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
1599 else
1600 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
1601 i = i + 2;
1603 else
1605 if(flags & ETO_PDY)
1607 lpDxW[j++] = lpDx[i * 2];
1608 lpDxW[j++] = lpDx[i * 2 + 1];
1610 else
1611 lpDxW[j++] = lpDx[i];
1612 i = i + 1;
1617 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1619 HeapFree( GetProcessHeap(), 0, p );
1620 HeapFree( GetProcessHeap(), 0, lpDxW );
1621 return ret;
1625 /***********************************************************************
1626 * ExtTextOutW (GDI32.@)
1628 * Draws text using the currently selected font, background color, and text color.
1631 * PARAMS
1632 * x,y [I] coordinates of string
1633 * flags [I]
1634 * ETO_GRAYED - undocumented on MSDN
1635 * ETO_OPAQUE - use background color for fill the rectangle
1636 * ETO_CLIPPED - clipping text to the rectangle
1637 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1638 * than encoded characters. Implies ETO_IGNORELANGUAGE
1639 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1640 * Affects BiDi ordering
1641 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1642 * ETO_PDY - unimplemented
1643 * ETO_NUMERICSLATIN - unimplemented always assumed -
1644 * do not translate numbers into locale representations
1645 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1646 * lprect [I] dimensions for clipping or/and opaquing
1647 * str [I] text string
1648 * count [I] number of symbols in string
1649 * lpDx [I] optional parameter with distance between drawing characters
1651 * RETURNS
1652 * Success: TRUE
1653 * Failure: FALSE
1655 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1656 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1658 BOOL ret = FALSE;
1659 LPWSTR reordered_str = (LPWSTR)str;
1660 WORD *glyphs = NULL;
1661 UINT align = GetTextAlign( hdc );
1662 POINT pt;
1663 TEXTMETRICW tm;
1664 LOGFONTW lf;
1665 double cosEsc, sinEsc;
1666 INT char_extra;
1667 SIZE sz;
1668 RECT rc;
1669 BOOL done_extents = FALSE;
1670 POINT *deltas = NULL, width = {0, 0};
1671 DWORD type;
1672 DC * dc = get_dc_ptr( hdc );
1673 INT breakRem;
1674 static int quietfixme = 0;
1676 if (!dc) return FALSE;
1678 breakRem = dc->breakRem;
1680 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
1682 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
1683 quietfixme = 1;
1685 if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1687 release_dc_ptr( dc );
1688 return ret;
1691 update_dc( dc );
1692 type = GetObjectType(hdc);
1693 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1695 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1696 release_dc_ptr( dc );
1697 return ret;
1700 if (!lprect)
1701 flags &= ~ETO_CLIPPED;
1703 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
1705 INT cGlyphs;
1706 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1708 BIDI_Reorder( hdc, str, count, GCP_REORDER,
1709 ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
1710 WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
1711 reordered_str, count, NULL, &glyphs, &cGlyphs);
1713 flags |= ETO_IGNORELANGUAGE;
1714 if (glyphs)
1716 flags |= ETO_GLYPH_INDEX;
1717 if (cGlyphs != count)
1718 count = cGlyphs;
1721 else if(flags & ETO_GLYPH_INDEX)
1722 glyphs = reordered_str;
1724 TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
1725 lprect, debugstr_wn(str, count), count, lpDx);
1727 if(lprect)
1728 TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
1729 lprect->bottom);
1730 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1732 if(align & TA_UPDATECP)
1734 GetCurrentPositionEx( hdc, &pt );
1735 x = pt.x;
1736 y = pt.y;
1739 GetTextMetricsW(hdc, &tm);
1740 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1742 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1743 lf.lfEscapement = 0;
1745 if(lf.lfEscapement != 0)
1747 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1748 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1750 else
1752 cosEsc = 1;
1753 sinEsc = 0;
1756 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1758 if(!lprect)
1760 if(flags & ETO_GLYPH_INDEX)
1761 GetTextExtentPointI(hdc, glyphs, count, &sz);
1762 else
1763 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1765 done_extents = TRUE;
1766 rc.left = x;
1767 rc.top = y;
1768 rc.right = x + sz.cx;
1769 rc.bottom = y + sz.cy;
1771 else
1773 rc = *lprect;
1776 LPtoDP(hdc, (POINT*)&rc, 2);
1778 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1779 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1782 if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1783 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1785 if(count == 0)
1787 ret = TRUE;
1788 goto done;
1791 pt.x = x;
1792 pt.y = y;
1793 LPtoDP(hdc, &pt, 1);
1794 x = pt.x;
1795 y = pt.y;
1797 char_extra = GetTextCharacterExtra(hdc);
1798 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
1800 UINT i;
1801 SIZE tmpsz;
1802 POINT total = {0, 0}, desired[2];
1804 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
1805 for(i = 0; i < count; i++)
1807 if(lpDx)
1809 if(flags & ETO_PDY)
1811 deltas[i].x = lpDx[i * 2] + char_extra;
1812 deltas[i].y = -lpDx[i * 2 + 1];
1814 else
1816 deltas[i].x = lpDx[i] + char_extra;
1817 deltas[i].y = 0;
1821 else
1823 if(flags & ETO_GLYPH_INDEX)
1824 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1825 else
1826 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
1828 deltas[i].x = tmpsz.cx;
1829 deltas[i].y = 0;
1832 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
1834 deltas[i].x = deltas[i].x + dc->breakExtra;
1835 if (breakRem > 0)
1837 breakRem--;
1838 deltas[i].x++;
1841 total.x += deltas[i].x;
1842 total.y += deltas[i].y;
1844 desired[0].x = desired[0].y = 0;
1846 desired[1].x = cosEsc * total.x + sinEsc * total.y;
1847 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
1849 LPtoDP(hdc, desired, 2);
1850 desired[1].x -= desired[0].x;
1851 desired[1].y -= desired[0].y;
1853 deltas[i].x = desired[1].x - width.x;
1854 deltas[i].y = desired[1].y - width.y;
1856 width = desired[1];
1858 flags |= ETO_PDY;
1860 else
1862 if(!done_extents)
1864 if(flags & ETO_GLYPH_INDEX)
1865 GetTextExtentPointI(hdc, glyphs, count, &sz);
1866 else
1867 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1868 done_extents = TRUE;
1870 width.x = INTERNAL_XWSTODS(dc, sz.cx);
1871 width.y = 0;
1874 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
1875 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
1876 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
1878 case TA_LEFT:
1879 if (align & TA_UPDATECP)
1881 pt.x = x + width.x;
1882 pt.y = y - width.y;
1883 DPtoLP(hdc, &pt, 1);
1884 MoveToEx(hdc, pt.x, pt.y, NULL);
1886 break;
1888 case TA_CENTER:
1889 x -= width.x / 2;
1890 y += width.y / 2;
1891 break;
1893 case TA_RIGHT:
1894 x -= width.x;
1895 y += width.y;
1896 if (align & TA_UPDATECP)
1898 pt.x = x;
1899 pt.y = y;
1900 DPtoLP(hdc, &pt, 1);
1901 MoveToEx(hdc, pt.x, pt.y, NULL);
1903 break;
1906 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
1908 case TA_TOP:
1909 y += tm.tmAscent * cosEsc;
1910 x += tm.tmAscent * sinEsc;
1911 break;
1913 case TA_BOTTOM:
1914 y -= tm.tmDescent * cosEsc;
1915 x -= tm.tmDescent * sinEsc;
1916 break;
1918 case TA_BASELINE:
1919 break;
1922 if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
1924 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
1926 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width.x >= rc.right ||
1927 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
1929 RECT rc;
1930 rc.left = x;
1931 rc.right = x + width.x;
1932 rc.top = y - tm.tmAscent;
1933 rc.bottom = y + tm.tmDescent;
1934 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1939 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
1941 HFONT orig_font = dc->hFont, cur_font;
1942 UINT glyph;
1943 INT span = 0;
1944 POINT *offsets = NULL;
1945 unsigned int i;
1947 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1948 for(i = 0; i < count; i++)
1950 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
1951 if(cur_font != dc->hFont)
1953 if(!offsets)
1955 unsigned int j;
1956 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
1957 offsets[0].x = offsets[0].y = 0;
1959 if(!deltas)
1961 SIZE tmpsz;
1962 for(j = 1; j < count; j++)
1964 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
1965 offsets[j].x = offsets[j - 1].x + INTERNAL_XWSTODS(dc, tmpsz.cx);
1966 offsets[j].y = 0;
1969 else
1971 for(j = 1; j < count; j++)
1973 offsets[j].x = offsets[j - 1].x + deltas[j].x;
1974 offsets[j].y = offsets[j - 1].y + deltas[j].y;
1978 if(span)
1980 if (PATH_IsPathOpen(dc->path))
1981 ret = PATH_ExtTextOut(dc, x + offsets[i - span].x, y + offsets[i - span].y,
1982 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1983 glyphs, span, deltas ? (INT*)(deltas + (i - span)) : NULL);
1984 else
1985 dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span].x, y + offsets[i - span].y,
1986 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1987 glyphs, span, deltas ? (INT*)(deltas + (i - span)) : NULL);
1988 span = 0;
1990 SelectObject(hdc, cur_font);
1992 glyphs[span++] = glyph;
1994 if(i == count - 1)
1996 if (PATH_IsPathOpen(dc->path))
1997 ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span].x : 0),
1998 y + (offsets ? offsets[count - span].y : 0),
1999 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2000 glyphs, span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2001 else
2002 ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span].x : 0),
2003 y + (offsets ? offsets[count - span].y : 0),
2004 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2005 glyphs, span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2006 SelectObject(hdc, orig_font);
2007 HeapFree(GetProcessHeap(), 0, offsets);
2011 else
2013 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2015 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2016 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2017 flags |= ETO_GLYPH_INDEX;
2020 if (PATH_IsPathOpen(dc->path))
2021 ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
2022 glyphs ? glyphs : reordered_str, count, (INT*)deltas);
2023 else
2024 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
2025 glyphs ? glyphs : reordered_str, count, (INT*)deltas);
2028 done:
2029 HeapFree(GetProcessHeap(), 0, deltas);
2030 if(glyphs != reordered_str)
2031 HeapFree(GetProcessHeap(), 0, glyphs);
2032 if(reordered_str != str)
2033 HeapFree(GetProcessHeap(), 0, reordered_str);
2035 release_dc_ptr( dc );
2037 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2039 int underlinePos, strikeoutPos;
2040 int underlineWidth, strikeoutWidth;
2041 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2042 OUTLINETEXTMETRICW* otm = NULL;
2044 if(!size)
2046 underlinePos = 0;
2047 underlineWidth = tm.tmAscent / 20 + 1;
2048 strikeoutPos = tm.tmAscent / 2;
2049 strikeoutWidth = underlineWidth;
2051 else
2053 otm = HeapAlloc(GetProcessHeap(), 0, size);
2054 GetOutlineTextMetricsW(hdc, size, otm);
2055 underlinePos = otm->otmsUnderscorePosition;
2056 underlineWidth = otm->otmsUnderscoreSize;
2057 strikeoutPos = otm->otmsStrikeoutPosition;
2058 strikeoutWidth = otm->otmsStrikeoutSize;
2059 HeapFree(GetProcessHeap(), 0, otm);
2062 if (PATH_IsPathOpen(dc->path))
2064 POINT pts[5];
2065 HPEN hpen;
2066 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2068 hbrush = SelectObject(hdc, hbrush);
2069 hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2071 if (lf.lfUnderline)
2073 pts[0].x = x - underlinePos * sinEsc;
2074 pts[0].y = y - underlinePos * cosEsc;
2075 pts[1].x = x + width.x - underlinePos * sinEsc;
2076 pts[1].y = y - width.y - underlinePos * cosEsc;
2077 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2078 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2079 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2080 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2081 pts[4].x = pts[0].x;
2082 pts[4].y = pts[0].y;
2083 DPtoLP(hdc, pts, 5);
2084 Polygon(hdc, pts, 5);
2087 if (lf.lfStrikeOut)
2089 pts[0].x = x - strikeoutPos * sinEsc;
2090 pts[0].y = y - strikeoutPos * cosEsc;
2091 pts[1].x = x + width.x - strikeoutPos * sinEsc;
2092 pts[1].y = y - width.y - strikeoutPos * cosEsc;
2093 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2094 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2095 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2096 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2097 pts[4].x = pts[0].x;
2098 pts[4].y = pts[0].y;
2099 DPtoLP(hdc, pts, 5);
2100 Polygon(hdc, pts, 5);
2103 SelectObject(hdc, hpen);
2104 hbrush = SelectObject(hdc, hbrush);
2105 DeleteObject(hbrush);
2107 else
2109 POINT pts[2], oldpt;
2110 HPEN hpen;
2112 if (lf.lfUnderline)
2114 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2115 hpen = SelectObject(hdc, hpen);
2116 pts[0].x = x;
2117 pts[0].y = y;
2118 pts[1].x = x + width.x;
2119 pts[1].y = y - width.y;
2120 DPtoLP(hdc, pts, 2);
2121 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2122 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2123 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2124 DeleteObject(SelectObject(hdc, hpen));
2127 if (lf.lfStrikeOut)
2129 hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
2130 hpen = SelectObject(hdc, hpen);
2131 pts[0].x = x;
2132 pts[0].y = y;
2133 pts[1].x = x + width.x;
2134 pts[1].y = y - width.y;
2135 DPtoLP(hdc, pts, 2);
2136 MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2137 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2138 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2139 DeleteObject(SelectObject(hdc, hpen));
2144 return ret;
2148 /***********************************************************************
2149 * TextOutA (GDI32.@)
2151 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2153 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2157 /***********************************************************************
2158 * TextOutW (GDI32.@)
2160 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2162 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2166 /***********************************************************************
2167 * PolyTextOutA (GDI32.@)
2169 * See PolyTextOutW.
2171 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2173 for (; cStrings>0; cStrings--, pptxt++)
2174 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2175 return FALSE;
2176 return TRUE;
2181 /***********************************************************************
2182 * PolyTextOutW (GDI32.@)
2184 * Draw several Strings
2186 * RETURNS
2187 * TRUE: Success.
2188 * FALSE: Failure.
2190 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2192 for (; cStrings>0; cStrings--, pptxt++)
2193 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2194 return FALSE;
2195 return TRUE;
2199 /* FIXME: all following APIs ******************************************/
2202 /***********************************************************************
2203 * SetMapperFlags (GDI32.@)
2205 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2207 DC *dc = get_dc_ptr( hDC );
2208 DWORD ret = 0;
2209 if(!dc) return 0;
2210 if(dc->funcs->pSetMapperFlags)
2212 ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2213 /* FIXME: ret is just a success flag, we should return a proper value */
2215 else
2216 FIXME("(%p, 0x%08x): stub - harmless\n", hDC, dwFlag);
2217 release_dc_ptr( dc );
2218 return ret;
2221 /***********************************************************************
2222 * GetAspectRatioFilterEx (GDI32.@)
2224 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2226 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2227 return FALSE;
2231 /***********************************************************************
2232 * GetCharABCWidthsA (GDI32.@)
2234 * See GetCharABCWidthsW.
2236 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2237 LPABC abc )
2239 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
2240 LPSTR str;
2241 LPWSTR wstr;
2242 BOOL ret = TRUE;
2244 if(count <= 0) return FALSE;
2246 str = HeapAlloc(GetProcessHeap(), 0, count);
2247 for(i = 0; i < count; i++)
2248 str[i] = (BYTE)(firstChar + i);
2250 wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
2252 for(i = 0; i < wlen; i++)
2254 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2256 ret = FALSE;
2257 break;
2259 abc++;
2262 HeapFree(GetProcessHeap(), 0, str);
2263 HeapFree(GetProcessHeap(), 0, wstr);
2265 return ret;
2269 /******************************************************************************
2270 * GetCharABCWidthsW [GDI32.@]
2272 * Retrieves widths of characters in range.
2274 * PARAMS
2275 * hdc [I] Handle of device context
2276 * firstChar [I] First character in range to query
2277 * lastChar [I] Last character in range to query
2278 * abc [O] Address of character-width structure
2280 * NOTES
2281 * Only works with TrueType fonts
2283 * RETURNS
2284 * Success: TRUE
2285 * Failure: FALSE
2287 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2288 LPABC abc )
2290 DC *dc = get_dc_ptr(hdc);
2291 unsigned int i;
2292 BOOL ret = FALSE;
2294 if (!dc) return FALSE;
2296 if (!abc)
2298 release_dc_ptr( dc );
2299 return FALSE;
2302 if(dc->gdiFont)
2303 ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2304 else
2305 FIXME(": stub\n");
2307 if (ret)
2309 /* convert device units to logical */
2310 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2311 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2312 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2313 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2315 ret = TRUE;
2318 release_dc_ptr( dc );
2319 return ret;
2323 /******************************************************************************
2324 * GetCharABCWidthsI [GDI32.@]
2326 * Retrieves widths of characters in range.
2328 * PARAMS
2329 * hdc [I] Handle of device context
2330 * firstChar [I] First glyphs in range to query
2331 * count [I] Last glyphs in range to query
2332 * pgi [i] Array of glyphs to query
2333 * abc [O] Address of character-width structure
2335 * NOTES
2336 * Only works with TrueType fonts
2338 * RETURNS
2339 * Success: TRUE
2340 * Failure: FALSE
2342 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2343 LPWORD pgi, LPABC abc)
2345 DC *dc = get_dc_ptr(hdc);
2346 unsigned int i;
2347 BOOL ret = FALSE;
2349 if (!dc) return FALSE;
2351 if (!abc)
2353 release_dc_ptr( dc );
2354 return FALSE;
2357 if(dc->gdiFont)
2358 ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2359 else
2360 FIXME(": stub\n");
2362 if (ret)
2364 /* convert device units to logical */
2365 for( i = 0; i < count; i++, abc++ ) {
2366 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2367 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2368 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2370 ret = TRUE;
2373 release_dc_ptr( dc );
2374 return ret;
2378 /***********************************************************************
2379 * GetGlyphOutlineA (GDI32.@)
2381 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2382 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2383 LPVOID lpBuffer, const MAT2 *lpmat2 )
2385 LPWSTR p = NULL;
2386 DWORD ret;
2387 UINT c;
2389 if (!lpmat2) return GDI_ERROR;
2391 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2392 int len;
2393 char mbchs[2];
2394 if(uChar > 0xff) { /* but, 2 bytes character only */
2395 len = 2;
2396 mbchs[0] = (uChar & 0xff00) >> 8;
2397 mbchs[1] = (uChar & 0xff);
2398 } else {
2399 len = 1;
2400 mbchs[0] = (uChar & 0xff);
2402 p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
2403 c = p[0];
2404 } else
2405 c = uChar;
2406 ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
2407 lpmat2);
2408 HeapFree(GetProcessHeap(), 0, p);
2409 return ret;
2412 /***********************************************************************
2413 * GetGlyphOutlineW (GDI32.@)
2415 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2416 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2417 LPVOID lpBuffer, const MAT2 *lpmat2 )
2419 DC *dc;
2420 DWORD ret;
2422 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2423 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2425 if (!lpmat2) return GDI_ERROR;
2427 dc = get_dc_ptr(hdc);
2428 if(!dc) return GDI_ERROR;
2430 if(dc->gdiFont)
2431 ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2432 cbBuffer, lpBuffer, lpmat2);
2433 else
2434 ret = GDI_ERROR;
2436 release_dc_ptr( dc );
2437 return ret;
2441 /***********************************************************************
2442 * CreateScalableFontResourceA (GDI32.@)
2444 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2445 LPCSTR lpszResourceFile,
2446 LPCSTR lpszFontFile,
2447 LPCSTR lpszCurrentPath )
2449 LPWSTR lpszResourceFileW = NULL;
2450 LPWSTR lpszFontFileW = NULL;
2451 LPWSTR lpszCurrentPathW = NULL;
2452 int len;
2453 BOOL ret;
2455 if (lpszResourceFile)
2457 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2458 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2459 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2462 if (lpszFontFile)
2464 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2465 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2466 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2469 if (lpszCurrentPath)
2471 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2472 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2473 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2476 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2477 lpszFontFileW, lpszCurrentPathW);
2479 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2480 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2481 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2483 return ret;
2486 /***********************************************************************
2487 * CreateScalableFontResourceW (GDI32.@)
2489 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2490 LPCWSTR lpszResourceFile,
2491 LPCWSTR lpszFontFile,
2492 LPCWSTR lpszCurrentPath )
2494 HANDLE f;
2495 FIXME("(%d,%s,%s,%s): stub\n",
2496 fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
2497 debugstr_w(lpszCurrentPath) );
2499 /* fHidden=1 - only visible for the calling app, read-only, not
2500 * enumerated with EnumFonts/EnumFontFamilies
2501 * lpszCurrentPath can be NULL
2504 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2505 if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2506 CloseHandle(f);
2507 SetLastError(ERROR_FILE_EXISTS);
2508 return FALSE;
2510 return FALSE; /* create failed */
2513 /*************************************************************************
2514 * GetKerningPairsA (GDI32.@)
2516 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2517 LPKERNINGPAIR kern_pairA )
2519 UINT cp;
2520 CPINFO cpi;
2521 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2522 KERNINGPAIR *kern_pairW;
2524 if (!cPairs && kern_pairA)
2526 SetLastError(ERROR_INVALID_PARAMETER);
2527 return 0;
2530 cp = GdiGetCodePage(hDC);
2532 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2533 * to fail on an invalid character for CP_SYMBOL.
2535 cpi.DefaultChar[0] = 0;
2536 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2538 FIXME("Can't find codepage %u info\n", cp);
2539 return 0;
2542 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2543 if (!total_kern_pairs) return 0;
2545 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2546 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2548 for (i = 0; i < total_kern_pairs; i++)
2550 char first, second;
2552 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2553 continue;
2555 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2556 continue;
2558 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2559 continue;
2561 if (kern_pairA)
2563 if (kern_pairs_copied >= cPairs) break;
2565 kern_pairA->wFirst = (BYTE)first;
2566 kern_pairA->wSecond = (BYTE)second;
2567 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2568 kern_pairA++;
2570 kern_pairs_copied++;
2573 HeapFree(GetProcessHeap(), 0, kern_pairW);
2575 return kern_pairs_copied;
2578 /*************************************************************************
2579 * GetKerningPairsW (GDI32.@)
2581 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2582 LPKERNINGPAIR lpKerningPairs )
2584 DC *dc;
2585 DWORD ret = 0;
2587 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2589 if (!cPairs && lpKerningPairs)
2591 SetLastError(ERROR_INVALID_PARAMETER);
2592 return 0;
2595 dc = get_dc_ptr(hDC);
2596 if (!dc) return 0;
2598 if (dc->gdiFont)
2599 ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
2601 release_dc_ptr( dc );
2602 return ret;
2605 /*************************************************************************
2606 * TranslateCharsetInfo [GDI32.@]
2608 * Fills a CHARSETINFO structure for a character set, code page, or
2609 * font. This allows making the correspondence between different labels
2610 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2611 * of the same encoding.
2613 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2614 * only one codepage should be set in *lpSrc.
2616 * RETURNS
2617 * TRUE on success, FALSE on failure.
2620 BOOL WINAPI TranslateCharsetInfo(
2621 LPDWORD lpSrc, /* [in]
2622 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2623 if flags == TCI_SRCCHARSET: a character set value
2624 if flags == TCI_SRCCODEPAGE: a code page value
2626 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2627 DWORD flags /* [in] determines interpretation of lpSrc */)
2629 int index = 0;
2630 switch (flags) {
2631 case TCI_SRCFONTSIG:
2632 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2633 break;
2634 case TCI_SRCCODEPAGE:
2635 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2636 break;
2637 case TCI_SRCCHARSET:
2638 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2639 break;
2640 default:
2641 return FALSE;
2643 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2644 *lpCs = FONT_tci[index];
2645 return TRUE;
2648 /*************************************************************************
2649 * GetFontLanguageInfo (GDI32.@)
2651 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2653 FONTSIGNATURE fontsig;
2654 static const DWORD GCP_DBCS_MASK=0x003F0000,
2655 GCP_DIACRITIC_MASK=0x00000000,
2656 FLI_GLYPHS_MASK=0x00000000,
2657 GCP_GLYPHSHAPE_MASK=0x00000040,
2658 GCP_KASHIDA_MASK=0x00000000,
2659 GCP_LIGATE_MASK=0x00000000,
2660 GCP_USEKERNING_MASK=0x00000000,
2661 GCP_REORDER_MASK=0x00000060;
2663 DWORD result=0;
2665 GetTextCharsetInfo( hdc, &fontsig, 0 );
2666 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2668 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2669 result|=GCP_DBCS;
2671 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2672 result|=GCP_DIACRITIC;
2674 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2675 result|=FLI_GLYPHS;
2677 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2678 result|=GCP_GLYPHSHAPE;
2680 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2681 result|=GCP_KASHIDA;
2683 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2684 result|=GCP_LIGATE;
2686 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2687 result|=GCP_USEKERNING;
2689 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2690 if( GetTextAlign( hdc) & TA_RTLREADING )
2691 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2692 result|=GCP_REORDER;
2694 return result;
2698 /*************************************************************************
2699 * GetFontData [GDI32.@]
2701 * Retrieve data for TrueType font.
2703 * RETURNS
2705 * success: Number of bytes returned
2706 * failure: GDI_ERROR
2708 * NOTES
2710 * Calls SetLastError()
2713 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2714 LPVOID buffer, DWORD length)
2716 DC *dc = get_dc_ptr(hdc);
2717 DWORD ret = GDI_ERROR;
2719 if(!dc) return GDI_ERROR;
2721 if(dc->gdiFont)
2722 ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2724 release_dc_ptr( dc );
2725 return ret;
2728 /*************************************************************************
2729 * GetGlyphIndicesA [GDI32.@]
2731 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2732 LPWORD pgi, DWORD flags)
2734 DWORD ret;
2735 WCHAR *lpstrW;
2736 INT countW;
2738 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2739 hdc, debugstr_an(lpstr, count), count, pgi, flags);
2741 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
2742 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2743 HeapFree(GetProcessHeap(), 0, lpstrW);
2745 return ret;
2748 /*************************************************************************
2749 * GetGlyphIndicesW [GDI32.@]
2751 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2752 LPWORD pgi, DWORD flags)
2754 DC *dc = get_dc_ptr(hdc);
2755 DWORD ret = GDI_ERROR;
2757 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2758 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2760 if(!dc) return GDI_ERROR;
2762 if(dc->gdiFont)
2763 ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2765 release_dc_ptr( dc );
2766 return ret;
2769 /*************************************************************************
2770 * GetCharacterPlacementA [GDI32.@]
2772 * See GetCharacterPlacementW.
2774 * NOTES:
2775 * the web browser control of ie4 calls this with dwFlags=0
2777 DWORD WINAPI
2778 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2779 INT nMaxExtent, GCP_RESULTSA *lpResults,
2780 DWORD dwFlags)
2782 WCHAR *lpStringW;
2783 INT uCountW;
2784 GCP_RESULTSW resultsW;
2785 DWORD ret;
2786 UINT font_cp;
2788 TRACE("%s, %d, %d, 0x%08x\n",
2789 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2791 /* both structs are equal in size */
2792 memcpy(&resultsW, lpResults, sizeof(resultsW));
2794 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
2795 if(lpResults->lpOutString)
2796 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2798 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2800 lpResults->nGlyphs = resultsW.nGlyphs;
2801 lpResults->nMaxFit = resultsW.nMaxFit;
2803 if(lpResults->lpOutString) {
2804 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
2805 lpResults->lpOutString, uCount, NULL, NULL );
2808 HeapFree(GetProcessHeap(), 0, lpStringW);
2809 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2811 return ret;
2814 /*************************************************************************
2815 * GetCharacterPlacementW [GDI32.@]
2817 * Retrieve information about a string. This includes the width, reordering,
2818 * Glyphing and so on.
2820 * RETURNS
2822 * The width and height of the string if successful, 0 if failed.
2824 * BUGS
2826 * All flags except GCP_REORDER are not yet implemented.
2827 * Reordering is not 100% compliant to the Windows BiDi method.
2828 * Caret positioning is not yet implemented for BiDi.
2829 * Classes are not yet implemented.
2832 DWORD WINAPI
2833 GetCharacterPlacementW(
2834 HDC hdc, /* [in] Device context for which the rendering is to be done */
2835 LPCWSTR lpString, /* [in] The string for which information is to be returned */
2836 INT uCount, /* [in] Number of WORDS in string. */
2837 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
2838 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
2839 DWORD dwFlags /* [in] Flags specifying how to process the string */
2842 DWORD ret=0;
2843 SIZE size;
2844 UINT i, nSet;
2846 TRACE("%s, %d, %d, 0x%08x\n",
2847 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2849 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
2850 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2851 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
2852 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
2853 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
2855 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
2856 if(lpResults->lpClass) FIXME("classes not implemented\n");
2857 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
2858 FIXME("Caret positions for complex scripts not implemented\n");
2860 nSet = (UINT)uCount;
2861 if(nSet > lpResults->nGlyphs)
2862 nSet = lpResults->nGlyphs;
2864 /* return number of initialized fields */
2865 lpResults->nGlyphs = nSet;
2867 if((dwFlags&GCP_REORDER)==0 )
2869 /* Treat the case where no special handling was requested in a fastpath way */
2870 /* copy will do if the GCP_REORDER flag is not set */
2871 if(lpResults->lpOutString)
2872 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
2874 if(lpResults->lpOrder)
2876 for(i = 0; i < nSet; i++)
2877 lpResults->lpOrder[i] = i;
2879 } else
2881 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
2882 nSet, lpResults->lpOrder, NULL, NULL );
2885 /* FIXME: Will use the placement chars */
2886 if (lpResults->lpDx)
2888 int c;
2889 for (i = 0; i < nSet; i++)
2891 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
2892 lpResults->lpDx[i]= c;
2896 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
2898 int pos = 0;
2900 lpResults->lpCaretPos[0] = 0;
2901 for (i = 1; i < nSet; i++)
2902 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
2903 lpResults->lpCaretPos[i] = (pos += size.cx);
2906 if(lpResults->lpGlyphs)
2907 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
2909 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
2910 ret = MAKELONG(size.cx, size.cy);
2912 return ret;
2915 /*************************************************************************
2916 * GetCharABCWidthsFloatA [GDI32.@]
2918 * See GetCharABCWidthsFloatW.
2920 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2922 INT i, wlen, count = (INT)(last - first + 1);
2923 LPSTR str;
2924 LPWSTR wstr;
2925 BOOL ret = TRUE;
2927 if (count <= 0) return FALSE;
2929 str = HeapAlloc(GetProcessHeap(), 0, count);
2931 for(i = 0; i < count; i++)
2932 str[i] = (BYTE)(first + i);
2934 wstr = FONT_mbtowc( hdc, str, count, &wlen, NULL );
2936 for (i = 0; i < wlen; i++)
2938 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
2940 ret = FALSE;
2941 break;
2943 abcf++;
2946 HeapFree( GetProcessHeap(), 0, str );
2947 HeapFree( GetProcessHeap(), 0, wstr );
2949 return ret;
2952 /*************************************************************************
2953 * GetCharABCWidthsFloatW [GDI32.@]
2955 * Retrieves widths of a range of characters.
2957 * PARAMS
2958 * hdc [I] Handle to device context.
2959 * first [I] First character in range to query.
2960 * last [I] Last character in range to query.
2961 * abcf [O] Array of LPABCFLOAT structures.
2963 * RETURNS
2964 * Success: TRUE
2965 * Failure: FALSE
2967 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2969 UINT i;
2970 BOOL ret = FALSE;
2971 DC *dc = get_dc_ptr( hdc );
2973 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
2975 if (!dc) return FALSE;
2977 if (!abcf)
2979 release_dc_ptr( dc );
2980 return FALSE;
2983 if (dc->gdiFont)
2984 ret = WineEngGetCharABCWidthsFloat( dc->gdiFont, first, last, abcf );
2985 else
2986 FIXME("stub\n");
2988 if (ret)
2990 /* convert device units to logical */
2991 for (i = first; i <= last; i++, abcf++)
2993 abcf->abcfA = abcf->abcfA * dc->xformVport2World.eM11;
2994 abcf->abcfB = abcf->abcfB * dc->xformVport2World.eM11;
2995 abcf->abcfC = abcf->abcfC * dc->xformVport2World.eM11;
2999 release_dc_ptr( dc );
3000 return ret;
3003 /*************************************************************************
3004 * GetCharWidthFloatA [GDI32.@]
3006 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3007 UINT iLastChar, PFLOAT pxBuffer)
3009 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3010 return 0;
3013 /*************************************************************************
3014 * GetCharWidthFloatW [GDI32.@]
3016 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3017 UINT iLastChar, PFLOAT pxBuffer)
3019 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3020 return 0;
3024 /***********************************************************************
3026 * Font Resource API *
3028 ***********************************************************************/
3030 /***********************************************************************
3031 * AddFontResourceA (GDI32.@)
3033 INT WINAPI AddFontResourceA( LPCSTR str )
3035 return AddFontResourceExA( str, 0, NULL);
3038 /***********************************************************************
3039 * AddFontResourceW (GDI32.@)
3041 INT WINAPI AddFontResourceW( LPCWSTR str )
3043 return AddFontResourceExW(str, 0, NULL);
3047 /***********************************************************************
3048 * AddFontResourceExA (GDI32.@)
3050 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3052 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3053 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3054 INT ret;
3056 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3057 ret = AddFontResourceExW(strW, fl, pdv);
3058 HeapFree(GetProcessHeap(), 0, strW);
3059 return ret;
3062 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3064 HRSRC rsrc = FindResourceW(hModule, name, type);
3065 HGLOBAL hMem = LoadResource(hModule, rsrc);
3066 LPVOID *pMem = LockResource(hMem);
3067 int *num_total = (int *)lParam;
3068 DWORD num_in_res;
3070 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3071 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3073 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3074 return FALSE;
3077 *num_total += num_in_res;
3078 return TRUE;
3081 /***********************************************************************
3082 * AddFontResourceExW (GDI32.@)
3084 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3086 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3087 if (ret == 0)
3089 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3090 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3091 if (hModule != NULL)
3093 int num_resources = 0;
3094 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3096 TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3097 wine_dbgstr_w(str));
3098 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3099 ret = num_resources;
3100 FreeLibrary(hModule);
3103 return ret;
3106 /***********************************************************************
3107 * RemoveFontResourceA (GDI32.@)
3109 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3111 return RemoveFontResourceExA(str, 0, 0);
3114 /***********************************************************************
3115 * RemoveFontResourceW (GDI32.@)
3117 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3119 return RemoveFontResourceExW(str, 0, 0);
3122 /***********************************************************************
3123 * AddFontMemResourceEx (GDI32.@)
3125 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3127 return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts);
3130 /***********************************************************************
3131 * RemoveFontMemResourceEx (GDI32.@)
3133 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3135 FIXME("(%p) stub\n", fh);
3136 return TRUE;
3139 /***********************************************************************
3140 * RemoveFontResourceExA (GDI32.@)
3142 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3144 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3145 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3146 INT ret;
3148 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3149 ret = RemoveFontResourceExW(strW, fl, pdv);
3150 HeapFree(GetProcessHeap(), 0, strW);
3151 return ret;
3154 /***********************************************************************
3155 * RemoveFontResourceExW (GDI32.@)
3157 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3159 return WineEngRemoveFontResourceEx(str, fl, pdv);
3162 /***********************************************************************
3163 * GetTextCharset (GDI32.@)
3165 UINT WINAPI GetTextCharset(HDC hdc)
3167 /* MSDN docs say this is equivalent */
3168 return GetTextCharsetInfo(hdc, NULL, 0);
3171 /***********************************************************************
3172 * GetTextCharsetInfo (GDI32.@)
3174 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3176 UINT ret = DEFAULT_CHARSET;
3177 DC *dc = get_dc_ptr(hdc);
3179 if (dc)
3181 if (dc->gdiFont)
3182 ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3184 release_dc_ptr( dc );
3187 if (ret == DEFAULT_CHARSET && fs)
3188 memset(fs, 0, sizeof(FONTSIGNATURE));
3189 return ret;
3192 /***********************************************************************
3193 * GdiGetCharDimensions (GDI32.@)
3195 * Gets the average width of the characters in the English alphabet.
3197 * PARAMS
3198 * hdc [I] Handle to the device context to measure on.
3199 * lptm [O] Pointer to memory to store the text metrics into.
3200 * height [O] On exit, the maximum height of characters in the English alphabet.
3202 * RETURNS
3203 * The average width of characters in the English alphabet.
3205 * NOTES
3206 * This function is used by the dialog manager to get the size of a dialog
3207 * unit. It should also be used by other pieces of code that need to know
3208 * the size of a dialog unit in logical units without having access to the
3209 * window handle of the dialog.
3210 * Windows caches the font metrics from this function, but we don't and
3211 * there doesn't appear to be an immediate advantage to do so.
3213 * SEE ALSO
3214 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3216 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3218 SIZE sz;
3219 static const WCHAR alphabet[] = {
3220 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3221 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3222 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3224 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3226 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3228 if (height) *height = sz.cy;
3229 return (sz.cx / 26 + 1) / 2;
3232 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3234 FIXME("(%d): stub\n", fEnableEUDC);
3235 return FALSE;
3238 /***********************************************************************
3239 * GetCharWidthI (GDI32.@)
3241 * Retrieve widths of characters.
3243 * PARAMS
3244 * hdc [I] Handle to a device context.
3245 * first [I] First glyph in range to query.
3246 * count [I] Number of glyph indices to query.
3247 * glyphs [I] Array of glyphs to query.
3248 * buffer [O] Buffer to receive character widths.
3250 * NOTES
3251 * Only works with TrueType fonts.
3253 * RETURNS
3254 * Success: TRUE
3255 * Failure: FALSE
3257 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3259 ABC *abc;
3260 unsigned int i;
3262 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3264 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3265 return FALSE;
3267 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3269 HeapFree(GetProcessHeap(), 0, abc);
3270 return FALSE;
3273 for (i = 0; i < count; i++)
3274 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3276 HeapFree(GetProcessHeap(), 0, abc);
3277 return TRUE;
3280 /***********************************************************************
3281 * GetFontUnicodeRanges (GDI32.@)
3283 * Retrieve a list of supported Unicode characters in a font.
3285 * PARAMS
3286 * hdc [I] Handle to a device context.
3287 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3289 * RETURNS
3290 * Success: Number of bytes written to the buffer pointed to by lpgs.
3291 * Failure: 0
3294 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3296 DWORD ret = 0;
3297 DC *dc = get_dc_ptr(hdc);
3299 TRACE("(%p, %p)\n", hdc, lpgs);
3301 if (!dc) return 0;
3303 if (dc->gdiFont) ret = WineEngGetFontUnicodeRanges(dc->gdiFont, lpgs);
3304 release_dc_ptr(dc);
3305 return ret;
3309 /*************************************************************
3310 * FontIsLinked (GDI32.@)
3312 BOOL WINAPI FontIsLinked(HDC hdc)
3314 DC *dc = get_dc_ptr(hdc);
3315 BOOL ret = FALSE;
3317 if (!dc) return FALSE;
3318 if (dc->gdiFont) ret = WineEngFontIsLinked(dc->gdiFont);
3319 release_dc_ptr(dc);
3320 TRACE("returning %d\n", ret);
3321 return ret;
3324 /*************************************************************
3325 * GdiRealizationInfo (GDI32.@)
3327 * Returns a structure that contains some font information.
3329 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3331 DC *dc = get_dc_ptr(hdc);
3332 BOOL ret = FALSE;
3334 if (!dc) return FALSE;
3335 if (dc->gdiFont) ret = WineEngRealizationInfo(dc->gdiFont, info);
3336 release_dc_ptr(dc);
3338 return ret;