wininet: Support the Cache-Control max-age directive for setting url cache entry...
[wine/testsucceed.git] / dlls / gdi32 / font.c
blobc92b6e37538913a53e306fdd29a427fe6a88047d
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 "gdi_private.h"
35 #include "wine/exception.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( &fontW->elfLogFont, &fontA->elfLogFont );
185 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
186 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
187 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
188 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
189 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
190 fontA->elfStyle[LF_FACESIZE-1] = '\0';
191 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
192 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
193 fontA->elfScript[LF_FACESIZE-1] = '\0';
196 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
198 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
200 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
201 fontW->elfFullName, LF_FULLFACESIZE );
202 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
203 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
204 fontW->elfStyle, LF_FACESIZE );
205 fontW->elfStyle[LF_FACESIZE-1] = '\0';
206 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
207 fontW->elfScript, LF_FACESIZE );
208 fontW->elfScript[LF_FACESIZE-1] = '\0';
211 /***********************************************************************
212 * TEXTMETRIC conversion functions.
214 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
216 ptmA->tmHeight = ptmW->tmHeight;
217 ptmA->tmAscent = ptmW->tmAscent;
218 ptmA->tmDescent = ptmW->tmDescent;
219 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
220 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
221 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
222 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
223 ptmA->tmWeight = ptmW->tmWeight;
224 ptmA->tmOverhang = ptmW->tmOverhang;
225 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
226 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
227 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
228 if (ptmW->tmCharSet == SYMBOL_CHARSET)
230 ptmA->tmFirstChar = 0x1e;
231 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
233 else
235 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
236 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
238 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
239 ptmA->tmBreakChar = ptmW->tmBreakChar;
240 ptmA->tmItalic = ptmW->tmItalic;
241 ptmA->tmUnderlined = ptmW->tmUnderlined;
242 ptmA->tmStruckOut = ptmW->tmStruckOut;
243 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
244 ptmA->tmCharSet = ptmW->tmCharSet;
248 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
250 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
251 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
252 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
253 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
254 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
255 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
259 /***********************************************************************
260 * GdiGetCodePage (GDI32.@)
262 DWORD WINAPI GdiGetCodePage( HDC hdc )
264 UINT cp = CP_ACP;
265 DC *dc = get_dc_ptr( hdc );
267 if (dc)
269 cp = dc->font_code_page;
270 release_dc_ptr( dc );
272 return cp;
275 /***********************************************************************
276 * FONT_mbtowc
278 * Returns a Unicode translation of str using the charset of the
279 * currently selected font in hdc. If count is -1 then str is assumed
280 * to be '\0' terminated, otherwise it contains the number of bytes to
281 * convert. If plenW is non-NULL, on return it will point to the
282 * number of WCHARs that have been written. If pCP is non-NULL, on
283 * return it will point to the codepage used in the conversion. The
284 * caller should free the returned LPWSTR from the process heap
285 * itself.
287 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
289 UINT cp;
290 INT lenW;
291 LPWSTR strW;
293 cp = GdiGetCodePage( hdc );
295 if(count == -1) count = strlen(str);
296 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
297 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
298 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
299 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
300 if(plenW) *plenW = lenW;
301 if(pCP) *pCP = cp;
302 return strW;
305 /***********************************************************************
306 * CreateFontIndirectExA (GDI32.@)
308 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
310 ENUMLOGFONTEXDVW enumexW;
312 if (!penumexA) return 0;
314 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
315 enumexW.elfDesignVector = penumexA->elfDesignVector;
316 return CreateFontIndirectExW( &enumexW );
319 /***********************************************************************
320 * CreateFontIndirectExW (GDI32.@)
322 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
324 HFONT hFont;
325 FONTOBJ *fontPtr;
326 const LOGFONTW *plf;
328 if (!penumex) return 0;
330 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
331 penumex->elfEnumLogfontEx.elfStyle[0] ||
332 penumex->elfEnumLogfontEx.elfScript[0])
334 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
335 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
336 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
337 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
340 plf = &penumex->elfEnumLogfontEx.elfLogFont;
341 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
343 fontPtr->logfont = *plf;
345 if (plf->lfEscapement != plf->lfOrientation)
347 /* this should really depend on whether GM_ADVANCED is set */
348 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
349 WARN("orientation angle %f set to "
350 "escapement angle %f for new font %p\n",
351 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
354 if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs )))
356 HeapFree( GetProcessHeap(), 0, fontPtr );
357 return 0;
360 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
361 plf->lfHeight, plf->lfWidth,
362 plf->lfEscapement, plf->lfOrientation,
363 plf->lfPitchAndFamily,
364 plf->lfOutPrecision, plf->lfClipPrecision,
365 plf->lfQuality, plf->lfCharSet,
366 debugstr_w(plf->lfFaceName),
367 plf->lfWeight > 400 ? "Bold" : "",
368 plf->lfItalic ? "Italic" : "",
369 plf->lfUnderline ? "Underline" : "", hFont);
371 return hFont;
374 /***********************************************************************
375 * CreateFontIndirectA (GDI32.@)
377 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
379 LOGFONTW lfW;
381 if (!plfA) return 0;
383 FONT_LogFontAToW( plfA, &lfW );
384 return CreateFontIndirectW( &lfW );
387 /***********************************************************************
388 * CreateFontIndirectW (GDI32.@)
390 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
392 ENUMLOGFONTEXDVW exdv;
394 if (!plf) return 0;
396 exdv.elfEnumLogfontEx.elfLogFont = *plf;
397 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
398 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
399 exdv.elfEnumLogfontEx.elfScript[0] = 0;
400 return CreateFontIndirectExW( &exdv );
403 /*************************************************************************
404 * CreateFontA (GDI32.@)
406 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
407 INT orient, INT weight, DWORD italic,
408 DWORD underline, DWORD strikeout, DWORD charset,
409 DWORD outpres, DWORD clippres, DWORD quality,
410 DWORD pitch, LPCSTR name )
412 LOGFONTA logfont;
414 logfont.lfHeight = height;
415 logfont.lfWidth = width;
416 logfont.lfEscapement = esc;
417 logfont.lfOrientation = orient;
418 logfont.lfWeight = weight;
419 logfont.lfItalic = italic;
420 logfont.lfUnderline = underline;
421 logfont.lfStrikeOut = strikeout;
422 logfont.lfCharSet = charset;
423 logfont.lfOutPrecision = outpres;
424 logfont.lfClipPrecision = clippres;
425 logfont.lfQuality = quality;
426 logfont.lfPitchAndFamily = pitch;
428 if (name)
429 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
430 else
431 logfont.lfFaceName[0] = '\0';
433 return CreateFontIndirectA( &logfont );
436 /*************************************************************************
437 * CreateFontW (GDI32.@)
439 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
440 INT orient, INT weight, DWORD italic,
441 DWORD underline, DWORD strikeout, DWORD charset,
442 DWORD outpres, DWORD clippres, DWORD quality,
443 DWORD pitch, LPCWSTR name )
445 LOGFONTW logfont;
447 logfont.lfHeight = height;
448 logfont.lfWidth = width;
449 logfont.lfEscapement = esc;
450 logfont.lfOrientation = orient;
451 logfont.lfWeight = weight;
452 logfont.lfItalic = italic;
453 logfont.lfUnderline = underline;
454 logfont.lfStrikeOut = strikeout;
455 logfont.lfCharSet = charset;
456 logfont.lfOutPrecision = outpres;
457 logfont.lfClipPrecision = clippres;
458 logfont.lfQuality = quality;
459 logfont.lfPitchAndFamily = pitch;
461 if (name)
462 lstrcpynW(logfont.lfFaceName, name,
463 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
464 else
465 logfont.lfFaceName[0] = '\0';
467 return CreateFontIndirectW( &logfont );
470 static void update_font_code_page( DC *dc )
472 CHARSETINFO csi;
473 int charset = DEFAULT_CHARSET;
475 if (dc->gdiFont)
476 charset = WineEngGetTextCharsetInfo( dc->gdiFont, NULL, 0 );
478 /* Hmm, nicely designed api this one! */
479 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
480 dc->font_code_page = csi.ciACP;
481 else {
482 switch(charset) {
483 case OEM_CHARSET:
484 dc->font_code_page = GetOEMCP();
485 break;
486 case DEFAULT_CHARSET:
487 dc->font_code_page = GetACP();
488 break;
490 case VISCII_CHARSET:
491 case TCVN_CHARSET:
492 case KOI8_CHARSET:
493 case ISO3_CHARSET:
494 case ISO4_CHARSET:
495 case ISO10_CHARSET:
496 case CELTIC_CHARSET:
497 /* FIXME: These have no place here, but because x11drv
498 enumerates fonts with these (made up) charsets some apps
499 might use them and then the FIXME below would become
500 annoying. Now we could pick the intended codepage for
501 each of these, but since it's broken anyway we'll just
502 use CP_ACP and hope it'll go away...
504 dc->font_code_page = CP_ACP;
505 break;
507 default:
508 FIXME("Can't find codepage for charset %d\n", charset);
509 dc->font_code_page = CP_ACP;
510 break;
514 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
517 /***********************************************************************
518 * FONT_SelectObject
520 * If the driver supports vector fonts we create a gdi font first and
521 * then call the driver to give it a chance to supply its own device
522 * font. If the driver wants to do this it returns TRUE and we can
523 * delete the gdi font, if the driver wants to use the gdi font it
524 * should return FALSE, to signal an error return GDI_ERROR. For
525 * drivers that don't support vector fonts they must supply their own
526 * font.
528 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
530 HGDIOBJ ret = 0;
531 DC *dc = get_dc_ptr( hdc );
533 if (!dc) return 0;
535 if (!GDI_inc_ref_count( handle ))
537 release_dc_ptr( dc );
538 return 0;
541 if (GetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_VA_ABLE)
542 dc->gdiFont = WineEngCreateFontInstance( dc, handle );
544 if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont );
546 if (ret && dc->gdiFont) dc->gdiFont = 0;
548 if (ret == HGDI_ERROR)
550 GDI_dec_ref_count( handle );
551 ret = 0; /* SelectObject returns 0 on error */
553 else
555 ret = dc->hFont;
556 dc->hFont = handle;
557 update_font_code_page( dc );
558 GDI_dec_ref_count( ret );
560 release_dc_ptr( dc );
561 return ret;
565 /***********************************************************************
566 * FONT_GetObjectA
568 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
570 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
571 LOGFONTA lfA;
573 if (!font) return 0;
574 if (buffer)
576 FONT_LogFontWToA( &font->logfont, &lfA );
577 if (count > sizeof(lfA)) count = sizeof(lfA);
578 memcpy( buffer, &lfA, count );
580 else count = sizeof(lfA);
581 GDI_ReleaseObj( handle );
582 return count;
585 /***********************************************************************
586 * FONT_GetObjectW
588 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
590 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
592 if (!font) return 0;
593 if (buffer)
595 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
596 memcpy( buffer, &font->logfont, count );
598 else count = sizeof(LOGFONTW);
599 GDI_ReleaseObj( handle );
600 return count;
604 /***********************************************************************
605 * FONT_DeleteObject
607 static BOOL FONT_DeleteObject( HGDIOBJ handle )
609 FONTOBJ *obj;
611 WineEngDestroyFontInstance( handle );
613 if (!(obj = free_gdi_handle( handle ))) return FALSE;
614 return HeapFree( GetProcessHeap(), 0, obj );
618 /***********************************************************************
619 * FONT_EnumInstance
621 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
622 * We have to use other types because of the FONTENUMPROCW definition.
624 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
625 DWORD fType, LPARAM lp )
627 fontEnum32 *pfe = (fontEnum32*)lp;
628 INT ret = 1;
630 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
631 if ((!pfe->lpLogFontParam ||
632 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
633 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
634 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
636 /* convert font metrics */
637 ENUMLOGFONTEXA logfont;
638 NEWTEXTMETRICEXA tmA;
640 pfe->dwFlags |= ENUM_CALLED;
641 if (!(pfe->dwFlags & ENUM_UNICODE))
643 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
644 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
645 plf = (LOGFONTW *)&logfont.elfLogFont;
646 ptm = (TEXTMETRICW *)&tmA;
649 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
651 return ret;
654 /***********************************************************************
655 * FONT_EnumFontFamiliesEx
657 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf,
658 FONTENUMPROCW efproc,
659 LPARAM lParam, DWORD dwUnicode)
661 INT ret = 1, ret2;
662 DC *dc = get_dc_ptr( hDC );
663 fontEnum32 fe32;
664 BOOL enum_gdi_fonts;
666 if (!dc) return 0;
668 if (plf)
669 TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName),
670 plf->lfCharSet);
671 fe32.lpLogFontParam = plf;
672 fe32.lpEnumFunc = efproc;
673 fe32.lpData = lParam;
674 fe32.dwFlags = dwUnicode;
675 fe32.hdc = hDC;
677 enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE;
679 if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
681 ret = 0;
682 goto done;
685 if (enum_gdi_fonts)
686 ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 );
687 fe32.dwFlags &= ~ENUM_CALLED;
688 if (ret && dc->funcs->pEnumDeviceFonts) {
689 ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 );
690 if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
691 ret = ret2;
693 done:
694 release_dc_ptr( dc );
695 return ret;
698 /***********************************************************************
699 * EnumFontFamiliesExW (GDI32.@)
701 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
702 FONTENUMPROCW efproc,
703 LPARAM lParam, DWORD dwFlags )
705 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE );
708 /***********************************************************************
709 * EnumFontFamiliesExA (GDI32.@)
711 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
712 FONTENUMPROCA efproc,
713 LPARAM lParam, DWORD dwFlags)
715 LOGFONTW lfW, *plfW;
717 if (plf)
719 FONT_LogFontAToW( plf, &lfW );
720 plfW = &lfW;
722 else plfW = NULL;
724 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, 0);
727 /***********************************************************************
728 * EnumFontFamiliesA (GDI32.@)
730 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
731 FONTENUMPROCA efproc, LPARAM lpData )
733 LOGFONTA lf, *plf;
735 if (lpFamily)
737 if (!*lpFamily) return 1;
738 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
739 lf.lfCharSet = DEFAULT_CHARSET;
740 lf.lfPitchAndFamily = 0;
741 plf = &lf;
743 else plf = NULL;
745 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
748 /***********************************************************************
749 * EnumFontFamiliesW (GDI32.@)
751 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
752 FONTENUMPROCW efproc, LPARAM lpData )
754 LOGFONTW lf, *plf;
756 if (lpFamily)
758 if (!*lpFamily) return 1;
759 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
760 lf.lfCharSet = DEFAULT_CHARSET;
761 lf.lfPitchAndFamily = 0;
762 plf = &lf;
764 else plf = NULL;
766 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
769 /***********************************************************************
770 * EnumFontsA (GDI32.@)
772 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
773 LPARAM lpData )
775 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
778 /***********************************************************************
779 * EnumFontsW (GDI32.@)
781 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
782 LPARAM lpData )
784 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
788 /***********************************************************************
789 * GetTextCharacterExtra (GDI32.@)
791 INT WINAPI GetTextCharacterExtra( HDC hdc )
793 INT ret;
794 DC *dc = get_dc_ptr( hdc );
795 if (!dc) return 0x80000000;
796 ret = dc->charExtra;
797 release_dc_ptr( dc );
798 return ret;
802 /***********************************************************************
803 * SetTextCharacterExtra (GDI32.@)
805 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
807 INT prev;
808 DC * dc = get_dc_ptr( hdc );
809 if (!dc) return 0x80000000;
810 if (dc->funcs->pSetTextCharacterExtra)
811 prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra );
812 else
814 prev = dc->charExtra;
815 dc->charExtra = extra;
817 release_dc_ptr( dc );
818 return prev;
822 /***********************************************************************
823 * SetTextJustification (GDI32.@)
825 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
827 BOOL ret = TRUE;
828 DC * dc = get_dc_ptr( hdc );
829 if (!dc) return FALSE;
830 if (dc->funcs->pSetTextJustification)
831 ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks );
832 else
834 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
835 if (!extra) breaks = 0;
836 if (breaks)
838 dc->breakExtra = extra / breaks;
839 dc->breakRem = extra - (breaks * dc->breakExtra);
841 else
843 dc->breakExtra = 0;
844 dc->breakRem = 0;
847 release_dc_ptr( dc );
848 return ret;
852 /***********************************************************************
853 * GetTextFaceA (GDI32.@)
855 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
857 INT res = GetTextFaceW(hdc, 0, NULL);
858 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
859 GetTextFaceW( hdc, res, nameW );
861 if (name)
863 if (count)
865 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
866 if (res == 0)
867 res = count;
868 name[count-1] = 0;
869 /* GetTextFaceA does NOT include the nul byte in the return count. */
870 res--;
872 else
873 res = 0;
875 else
876 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
877 HeapFree( GetProcessHeap(), 0, nameW );
878 return res;
881 /***********************************************************************
882 * GetTextFaceW (GDI32.@)
884 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
886 FONTOBJ *font;
887 INT ret = 0;
889 DC * dc = get_dc_ptr( hdc );
890 if (!dc) return 0;
892 if(dc->gdiFont)
893 ret = WineEngGetTextFace(dc->gdiFont, count, name);
894 else if ((font = GDI_GetObjPtr( dc->hFont, OBJ_FONT )))
896 INT n = strlenW(font->logfont.lfFaceName) + 1;
897 if (name)
899 lstrcpynW( name, font->logfont.lfFaceName, count );
900 ret = min(count, n);
902 else ret = n;
903 GDI_ReleaseObj( dc->hFont );
905 release_dc_ptr( dc );
906 return ret;
910 /***********************************************************************
911 * GetTextExtentPoint32A (GDI32.@)
913 * See GetTextExtentPoint32W.
915 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
916 LPSIZE size )
918 BOOL ret = FALSE;
919 INT wlen;
920 LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
922 if (p) {
923 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
924 HeapFree( GetProcessHeap(), 0, p );
927 TRACE("(%p %s %d %p): returning %d x %d\n",
928 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
929 return ret;
933 /***********************************************************************
934 * GetTextExtentPoint32W [GDI32.@]
936 * Computes width/height for a string.
938 * Computes width and height of the specified string.
940 * RETURNS
941 * Success: TRUE
942 * Failure: FALSE
944 BOOL WINAPI GetTextExtentPoint32W(
945 HDC hdc, /* [in] Handle of device context */
946 LPCWSTR str, /* [in] Address of text string */
947 INT count, /* [in] Number of characters in string */
948 LPSIZE size) /* [out] Address of structure for string size */
950 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
953 /***********************************************************************
954 * GetTextExtentExPointI [GDI32.@]
956 * Computes width and height of the array of glyph indices.
958 * PARAMS
959 * hdc [I] Handle of device context.
960 * indices [I] Glyph index array.
961 * count [I] Number of glyphs in array.
962 * max_ext [I] Maximum width in glyphs.
963 * nfit [O] Maximum number of characters.
964 * dxs [O] Partial string widths.
965 * size [O] Returned string size.
967 * RETURNS
968 * Success: TRUE
969 * Failure: FALSE
971 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
972 LPINT nfit, LPINT dxs, LPSIZE size )
974 BOOL ret = FALSE;
975 DC * dc = get_dc_ptr( hdc );
976 if (!dc) return FALSE;
978 if(dc->gdiFont) {
979 ret = WineEngGetTextExtentExPointI(dc->gdiFont, indices, count, max_ext, nfit, dxs, size);
980 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
981 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
982 size->cx += count * dc->charExtra;
984 else if(dc->funcs->pGetTextExtentExPoint) {
985 FIXME("calling GetTextExtentExPoint\n");
986 ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, indices, count,
987 max_ext, nfit, dxs, size );
990 release_dc_ptr( dc );
992 TRACE("(%p %p %d %p): returning %d x %d\n",
993 hdc, indices, count, size, size->cx, size->cy );
994 return ret;
997 /***********************************************************************
998 * GetTextExtentPointI [GDI32.@]
1000 * Computes width and height of the array of glyph indices.
1002 * PARAMS
1003 * hdc [I] Handle of device context.
1004 * indices [I] Glyph index array.
1005 * count [I] Number of glyphs in array.
1006 * size [O] Returned string size.
1008 * RETURNS
1009 * Success: TRUE
1010 * Failure: FALSE
1012 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1014 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1018 /***********************************************************************
1019 * GetTextExtentPointA (GDI32.@)
1021 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1022 LPSIZE size )
1024 TRACE("not bug compatible.\n");
1025 return GetTextExtentPoint32A( hdc, str, count, size );
1028 /***********************************************************************
1029 * GetTextExtentPointW (GDI32.@)
1031 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1032 LPSIZE size )
1034 TRACE("not bug compatible.\n");
1035 return GetTextExtentPoint32W( hdc, str, count, size );
1039 /***********************************************************************
1040 * GetTextExtentExPointA (GDI32.@)
1042 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1043 INT maxExt, LPINT lpnFit,
1044 LPINT alpDx, LPSIZE size )
1046 BOOL ret;
1047 INT wlen;
1048 INT *walpDx = NULL;
1049 LPWSTR p = NULL;
1051 if (alpDx &&
1052 NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
1053 return FALSE;
1055 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1056 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1057 if (walpDx)
1059 INT n = lpnFit ? *lpnFit : wlen;
1060 INT i, j;
1061 for(i = 0, j = 0; i < n; i++, j++)
1063 alpDx[j] = walpDx[i];
1064 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1067 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1068 HeapFree( GetProcessHeap(), 0, p );
1069 HeapFree( GetProcessHeap(), 0, walpDx );
1070 return ret;
1074 /***********************************************************************
1075 * GetTextExtentExPointW (GDI32.@)
1077 * Return the size of the string as it would be if it was output properly by
1078 * e.g. TextOut.
1080 * This should include
1081 * - Intercharacter spacing
1082 * - justification spacing (not yet done)
1083 * - kerning? see below
1085 * Kerning. Since kerning would be carried out by the rendering code it should
1086 * be done by the driver. However they don't support it yet. Also I am not
1087 * yet persuaded that (certainly under Win95) any kerning is actually done.
1089 * str: According to MSDN this should be null-terminated. That is not true; a
1090 * null will not terminate it early.
1091 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1092 * than count. I have seen it be either the size of the full string or
1093 * 1 less than the size of the full string. I have not seen it bear any
1094 * resemblance to the portion that would fit.
1095 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1096 * trailing intercharacter spacing and any trailing justification.
1098 * FIXME
1099 * Currently we do this by measuring each character etc. We should do it by
1100 * passing the request to the driver, perhaps by extending the
1101 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1102 * thinking about kerning issues and rounding issues in the justification.
1105 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1106 INT maxExt, LPINT lpnFit,
1107 LPINT alpDx, LPSIZE size )
1109 INT nFit = 0;
1110 LPINT dxs = NULL;
1111 DC *dc;
1112 BOOL ret = FALSE;
1113 TEXTMETRICW tm;
1115 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1117 dc = get_dc_ptr(hdc);
1118 if (! dc)
1119 return FALSE;
1121 GetTextMetricsW(hdc, &tm);
1123 /* If we need to calculate nFit, then we need the partial extents even if
1124 the user hasn't provided us with an array. */
1125 if (lpnFit)
1127 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1128 if (! dxs)
1130 release_dc_ptr(dc);
1131 SetLastError(ERROR_OUTOFMEMORY);
1132 return FALSE;
1135 else
1136 dxs = alpDx;
1138 if (dc->gdiFont)
1139 ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
1140 0, NULL, dxs, size);
1141 else if (dc->funcs->pGetTextExtentExPoint)
1142 ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
1143 0, NULL, dxs, size);
1145 /* Perform device size to world size transformations. */
1146 if (ret)
1148 INT extra = dc->charExtra,
1149 breakExtra = dc->breakExtra,
1150 breakRem = dc->breakRem,
1153 if (dxs)
1155 for (i = 0; i < count; ++i)
1157 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1158 dxs[i] += (i+1) * extra;
1159 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1161 dxs[i] += breakExtra;
1162 if (breakRem > 0)
1164 breakRem--;
1165 dxs[i]++;
1168 if (dxs[i] <= maxExt)
1169 ++nFit;
1171 breakRem = dc->breakRem;
1173 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1174 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1176 if (!dxs && count > 1 && (breakExtra || breakRem))
1178 for (i = 0; i < count; i++)
1180 if (str[i] == tm.tmBreakChar)
1182 size->cx += breakExtra;
1183 if (breakRem > 0)
1185 breakRem--;
1186 (size->cx)++;
1193 if (lpnFit)
1194 *lpnFit = nFit;
1196 if (! alpDx)
1197 HeapFree(GetProcessHeap(), 0, dxs);
1199 release_dc_ptr( dc );
1201 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1202 return ret;
1205 /***********************************************************************
1206 * GetTextMetricsA (GDI32.@)
1208 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1210 TEXTMETRICW tm32;
1212 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1213 FONT_TextMetricWToA( &tm32, metrics );
1214 return TRUE;
1217 /***********************************************************************
1218 * GetTextMetricsW (GDI32.@)
1220 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1222 BOOL ret = FALSE;
1223 DC * dc = get_dc_ptr( hdc );
1224 if (!dc) return FALSE;
1226 if (dc->gdiFont)
1227 ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1228 else if (dc->funcs->pGetTextMetrics)
1229 ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1231 if (ret)
1233 /* device layer returns values in device units
1234 * therefore we have to convert them to logical */
1236 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1237 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1239 #define WDPTOLP(x) ((x<0)? \
1240 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1241 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1242 #define HDPTOLP(y) ((y<0)? \
1243 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1244 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1246 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1247 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1248 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1249 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1250 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1251 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1252 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1253 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1254 ret = TRUE;
1255 #undef WDPTOLP
1256 #undef HDPTOLP
1257 TRACE("text metrics:\n"
1258 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1259 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1260 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1261 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1262 " PitchAndFamily = %02x\n"
1263 " --------------------\n"
1264 " InternalLeading = %i\n"
1265 " Ascent = %i\n"
1266 " Descent = %i\n"
1267 " Height = %i\n",
1268 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1269 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1270 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1271 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1272 metrics->tmPitchAndFamily,
1273 metrics->tmInternalLeading,
1274 metrics->tmAscent,
1275 metrics->tmDescent,
1276 metrics->tmHeight );
1278 release_dc_ptr( dc );
1279 return ret;
1283 /***********************************************************************
1284 * GetOutlineTextMetricsA (GDI32.@)
1285 * Gets metrics for TrueType fonts.
1287 * NOTES
1288 * If the supplied buffer isn't big enough Windows partially fills it up to
1289 * its given length and returns that length.
1291 * RETURNS
1292 * Success: Non-zero or size of required buffer
1293 * Failure: 0
1295 UINT WINAPI GetOutlineTextMetricsA(
1296 HDC hdc, /* [in] Handle of device context */
1297 UINT cbData, /* [in] Size of metric data array */
1298 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1300 char buf[512], *ptr;
1301 UINT ret, needed;
1302 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1303 OUTLINETEXTMETRICA *output = lpOTM;
1304 INT left, len;
1306 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1307 return 0;
1308 if(ret > sizeof(buf))
1309 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1310 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1312 needed = sizeof(OUTLINETEXTMETRICA);
1313 if(lpOTMW->otmpFamilyName)
1314 needed += WideCharToMultiByte(CP_ACP, 0,
1315 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1316 NULL, 0, NULL, NULL);
1317 if(lpOTMW->otmpFaceName)
1318 needed += WideCharToMultiByte(CP_ACP, 0,
1319 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1320 NULL, 0, NULL, NULL);
1321 if(lpOTMW->otmpStyleName)
1322 needed += WideCharToMultiByte(CP_ACP, 0,
1323 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1324 NULL, 0, NULL, NULL);
1325 if(lpOTMW->otmpFullName)
1326 needed += WideCharToMultiByte(CP_ACP, 0,
1327 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1328 NULL, 0, NULL, NULL);
1330 if(!lpOTM) {
1331 ret = needed;
1332 goto end;
1335 TRACE("needed = %d\n", needed);
1336 if(needed > cbData)
1337 /* Since the supplied buffer isn't big enough, we'll alloc one
1338 that is and memcpy the first cbData bytes into the lpOTM at
1339 the end. */
1340 output = HeapAlloc(GetProcessHeap(), 0, needed);
1342 ret = output->otmSize = min(needed, cbData);
1343 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1344 output->otmFiller = 0;
1345 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1346 output->otmfsSelection = lpOTMW->otmfsSelection;
1347 output->otmfsType = lpOTMW->otmfsType;
1348 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1349 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1350 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1351 output->otmEMSquare = lpOTMW->otmEMSquare;
1352 output->otmAscent = lpOTMW->otmAscent;
1353 output->otmDescent = lpOTMW->otmDescent;
1354 output->otmLineGap = lpOTMW->otmLineGap;
1355 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1356 output->otmsXHeight = lpOTMW->otmsXHeight;
1357 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1358 output->otmMacAscent = lpOTMW->otmMacAscent;
1359 output->otmMacDescent = lpOTMW->otmMacDescent;
1360 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1361 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1362 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1363 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1364 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1365 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1366 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1367 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1368 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1369 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1372 ptr = (char*)(output + 1);
1373 left = needed - sizeof(*output);
1375 if(lpOTMW->otmpFamilyName) {
1376 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1377 len = WideCharToMultiByte(CP_ACP, 0,
1378 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1379 ptr, left, NULL, NULL);
1380 left -= len;
1381 ptr += len;
1382 } else
1383 output->otmpFamilyName = 0;
1385 if(lpOTMW->otmpFaceName) {
1386 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1387 len = WideCharToMultiByte(CP_ACP, 0,
1388 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1389 ptr, left, NULL, NULL);
1390 left -= len;
1391 ptr += len;
1392 } else
1393 output->otmpFaceName = 0;
1395 if(lpOTMW->otmpStyleName) {
1396 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1397 len = WideCharToMultiByte(CP_ACP, 0,
1398 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1399 ptr, left, NULL, NULL);
1400 left -= len;
1401 ptr += len;
1402 } else
1403 output->otmpStyleName = 0;
1405 if(lpOTMW->otmpFullName) {
1406 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1407 len = WideCharToMultiByte(CP_ACP, 0,
1408 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1409 ptr, left, NULL, NULL);
1410 left -= len;
1411 } else
1412 output->otmpFullName = 0;
1414 assert(left == 0);
1416 if(output != lpOTM) {
1417 memcpy(lpOTM, output, cbData);
1418 HeapFree(GetProcessHeap(), 0, output);
1420 /* check if the string offsets really fit into the provided size */
1421 /* FIXME: should we check string length as well? */
1422 /* make sure that we don't read/write beyond the provided buffer */
1423 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1425 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1426 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1429 /* make sure that we don't read/write beyond the provided buffer */
1430 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1432 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1433 lpOTM->otmpFaceName = 0; /* doesn't fit */
1436 /* make sure that we don't read/write beyond the provided buffer */
1437 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1439 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1440 lpOTM->otmpStyleName = 0; /* doesn't fit */
1443 /* make sure that we don't read/write beyond the provided buffer */
1444 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1446 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1447 lpOTM->otmpFullName = 0; /* doesn't fit */
1451 end:
1452 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1453 HeapFree(GetProcessHeap(), 0, lpOTMW);
1455 return ret;
1459 /***********************************************************************
1460 * GetOutlineTextMetricsW [GDI32.@]
1462 UINT WINAPI GetOutlineTextMetricsW(
1463 HDC hdc, /* [in] Handle of device context */
1464 UINT cbData, /* [in] Size of metric data array */
1465 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1467 DC *dc = get_dc_ptr( hdc );
1468 OUTLINETEXTMETRICW *output = lpOTM;
1469 UINT ret;
1471 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1472 if(!dc) return 0;
1474 if(dc->gdiFont) {
1475 ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1476 if(lpOTM && ret) {
1477 if(ret > cbData) {
1478 output = HeapAlloc(GetProcessHeap(), 0, ret);
1479 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1482 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1483 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1485 #define WDPTOLP(x) ((x<0)? \
1486 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1487 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1488 #define HDPTOLP(y) ((y<0)? \
1489 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1490 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1492 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1493 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1494 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1495 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1496 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1497 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1498 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1499 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1500 output->otmAscent = HDPTOLP(output->otmAscent);
1501 output->otmDescent = HDPTOLP(output->otmDescent);
1502 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1503 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1504 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1505 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1506 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1507 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1508 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1509 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1510 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1511 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1512 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1513 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1514 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1515 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1516 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1517 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1518 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1519 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1520 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1521 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1522 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1523 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1524 #undef WDPTOLP
1525 #undef HDPTOLP
1526 if(output != lpOTM) {
1527 memcpy(lpOTM, output, cbData);
1528 HeapFree(GetProcessHeap(), 0, output);
1529 ret = cbData;
1534 else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1535 but really this should just be a return 0. */
1537 ret = sizeof(*lpOTM);
1538 if (lpOTM) {
1539 if(cbData < ret)
1540 ret = 0;
1541 else {
1542 memset(lpOTM, 0, ret);
1543 lpOTM->otmSize = sizeof(*lpOTM);
1544 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1546 Further fill of the structure not implemented,
1547 Needs real values for the structure members
1552 release_dc_ptr(dc);
1553 return ret;
1556 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1558 INT i, count = lastChar - firstChar + 1;
1559 UINT c;
1560 LPSTR str;
1562 if (count <= 0)
1563 return NULL;
1565 switch (GdiGetCodePage(hdc))
1567 case 932:
1568 case 936:
1569 case 949:
1570 case 950:
1571 case 1361:
1572 if (lastChar > 0xffff)
1573 return NULL;
1574 if ((firstChar ^ lastChar) > 0xff)
1575 return NULL;
1576 break;
1577 default:
1578 if (lastChar > 0xff)
1579 return NULL;
1580 break;
1583 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1584 if (str == NULL)
1585 return NULL;
1587 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1589 if (c > 0xff)
1590 str[i++] = (BYTE)(c >> 8);
1591 str[i] = (BYTE)c;
1593 str[i] = '\0';
1595 *pByteLen = i;
1597 return str;
1600 /***********************************************************************
1601 * GetCharWidthW (GDI32.@)
1602 * GetCharWidth32W (GDI32.@)
1604 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1605 LPINT buffer )
1607 UINT i;
1608 BOOL ret = FALSE;
1609 DC * dc = get_dc_ptr( hdc );
1610 if (!dc) return FALSE;
1612 if (dc->gdiFont)
1613 ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1614 else if (dc->funcs->pGetCharWidth)
1615 ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1617 if (ret)
1619 /* convert device units to logical */
1620 for( i = firstChar; i <= lastChar; i++, buffer++ )
1621 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1622 ret = TRUE;
1624 release_dc_ptr( dc );
1625 return ret;
1629 /***********************************************************************
1630 * GetCharWidthA (GDI32.@)
1631 * GetCharWidth32A (GDI32.@)
1633 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1634 LPINT buffer )
1636 INT i, wlen;
1637 LPSTR str;
1638 LPWSTR wstr;
1639 BOOL ret = TRUE;
1641 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1642 if(str == NULL)
1643 return FALSE;
1645 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1647 for(i = 0; i < wlen; i++)
1649 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1651 ret = FALSE;
1652 break;
1654 buffer++;
1657 HeapFree(GetProcessHeap(), 0, str);
1658 HeapFree(GetProcessHeap(), 0, wstr);
1660 return ret;
1664 /***********************************************************************
1665 * ExtTextOutA (GDI32.@)
1667 * See ExtTextOutW.
1669 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1670 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1672 INT wlen;
1673 UINT codepage;
1674 LPWSTR p;
1675 BOOL ret;
1676 LPINT lpDxW = NULL;
1678 if (flags & ETO_GLYPH_INDEX)
1679 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1681 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1683 if (lpDx) {
1684 unsigned int i = 0, j = 0;
1686 /* allocate enough for a ETO_PDY */
1687 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
1688 while(i < count) {
1689 if(IsDBCSLeadByteEx(codepage, str[i]))
1691 if(flags & ETO_PDY)
1693 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
1694 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
1696 else
1697 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
1698 i = i + 2;
1700 else
1702 if(flags & ETO_PDY)
1704 lpDxW[j++] = lpDx[i * 2];
1705 lpDxW[j++] = lpDx[i * 2 + 1];
1707 else
1708 lpDxW[j++] = lpDx[i];
1709 i = i + 1;
1714 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1716 HeapFree( GetProcessHeap(), 0, p );
1717 HeapFree( GetProcessHeap(), 0, lpDxW );
1718 return ret;
1722 /***********************************************************************
1723 * ExtTextOutW (GDI32.@)
1725 * Draws text using the currently selected font, background color, and text color.
1728 * PARAMS
1729 * x,y [I] coordinates of string
1730 * flags [I]
1731 * ETO_GRAYED - undocumented on MSDN
1732 * ETO_OPAQUE - use background color for fill the rectangle
1733 * ETO_CLIPPED - clipping text to the rectangle
1734 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1735 * than encoded characters. Implies ETO_IGNORELANGUAGE
1736 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1737 * Affects BiDi ordering
1738 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1739 * ETO_PDY - unimplemented
1740 * ETO_NUMERICSLATIN - unimplemented always assumed -
1741 * do not translate numbers into locale representations
1742 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1743 * lprect [I] dimensions for clipping or/and opaquing
1744 * str [I] text string
1745 * count [I] number of symbols in string
1746 * lpDx [I] optional parameter with distance between drawing characters
1748 * RETURNS
1749 * Success: TRUE
1750 * Failure: FALSE
1752 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1753 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1755 BOOL ret = FALSE;
1756 LPWSTR reordered_str = (LPWSTR)str;
1757 WORD *glyphs = NULL;
1758 UINT align = GetTextAlign( hdc );
1759 DWORD layout = GetLayout( hdc );
1760 POINT pt;
1761 TEXTMETRICW tm;
1762 LOGFONTW lf;
1763 double cosEsc, sinEsc;
1764 INT char_extra;
1765 SIZE sz;
1766 RECT rc;
1767 BOOL done_extents = FALSE;
1768 POINT *deltas = NULL, width = {0, 0};
1769 DWORD type;
1770 DC * dc = get_dc_ptr( hdc );
1771 INT breakRem;
1772 static int quietfixme = 0;
1774 if (!dc) return FALSE;
1776 breakRem = dc->breakRem;
1778 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
1780 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
1781 quietfixme = 1;
1783 if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1785 release_dc_ptr( dc );
1786 return ret;
1789 update_dc( dc );
1790 type = GetObjectType(hdc);
1791 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1793 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1794 release_dc_ptr( dc );
1795 return ret;
1798 if (!lprect)
1799 flags &= ~ETO_CLIPPED;
1801 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
1802 if (layout & LAYOUT_RTL)
1804 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
1805 align ^= TA_RTLREADING;
1808 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
1810 INT cGlyphs;
1811 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1813 BIDI_Reorder( hdc, str, count, GCP_REORDER,
1814 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
1815 reordered_str, count, NULL, &glyphs, &cGlyphs);
1817 flags |= ETO_IGNORELANGUAGE;
1818 if (glyphs)
1820 flags |= ETO_GLYPH_INDEX;
1821 if (cGlyphs != count)
1822 count = cGlyphs;
1825 else if(flags & ETO_GLYPH_INDEX)
1826 glyphs = reordered_str;
1828 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
1829 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
1830 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1832 if(align & TA_UPDATECP)
1834 GetCurrentPositionEx( hdc, &pt );
1835 x = pt.x;
1836 y = pt.y;
1839 GetTextMetricsW(hdc, &tm);
1840 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1842 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1843 lf.lfEscapement = 0;
1845 if(lf.lfEscapement != 0)
1847 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1848 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1850 else
1852 cosEsc = 1;
1853 sinEsc = 0;
1856 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1858 if(!lprect)
1860 if(flags & ETO_GLYPH_INDEX)
1861 GetTextExtentPointI(hdc, glyphs, count, &sz);
1862 else
1863 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1865 done_extents = TRUE;
1866 rc.left = x;
1867 rc.top = y;
1868 rc.right = x + sz.cx;
1869 rc.bottom = y + sz.cy;
1871 else
1873 rc = *lprect;
1876 LPtoDP(hdc, (POINT*)&rc, 2);
1878 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1879 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1882 if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1883 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1885 if(count == 0)
1887 ret = TRUE;
1888 goto done;
1891 pt.x = x;
1892 pt.y = y;
1893 LPtoDP(hdc, &pt, 1);
1894 x = pt.x;
1895 y = pt.y;
1897 char_extra = GetTextCharacterExtra(hdc);
1898 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
1900 UINT i;
1901 SIZE tmpsz;
1902 POINT total = {0, 0}, desired[2];
1904 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
1905 for(i = 0; i < count; i++)
1907 if(lpDx)
1909 if(flags & ETO_PDY)
1911 deltas[i].x = lpDx[i * 2] + char_extra;
1912 deltas[i].y = -lpDx[i * 2 + 1];
1914 else
1916 deltas[i].x = lpDx[i] + char_extra;
1917 deltas[i].y = 0;
1921 else
1923 if(flags & ETO_GLYPH_INDEX)
1924 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1925 else
1926 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
1928 deltas[i].x = tmpsz.cx;
1929 deltas[i].y = 0;
1932 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
1934 deltas[i].x = deltas[i].x + dc->breakExtra;
1935 if (breakRem > 0)
1937 breakRem--;
1938 deltas[i].x++;
1941 total.x += deltas[i].x;
1942 total.y += deltas[i].y;
1944 desired[0].x = desired[0].y = 0;
1946 desired[1].x = cosEsc * total.x + sinEsc * total.y;
1947 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
1949 LPtoDP(hdc, desired, 2);
1950 desired[1].x -= desired[0].x;
1951 desired[1].y -= desired[0].y;
1952 if (layout & LAYOUT_RTL) desired[1].x = -desired[1].x;
1954 deltas[i].x = desired[1].x - width.x;
1955 deltas[i].y = desired[1].y - width.y;
1957 width = desired[1];
1959 flags |= ETO_PDY;
1961 else
1963 if(!done_extents)
1965 if(flags & ETO_GLYPH_INDEX)
1966 GetTextExtentPointI(hdc, glyphs, count, &sz);
1967 else
1968 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1969 done_extents = TRUE;
1971 width.x = abs(INTERNAL_XWSTODS(dc, sz.cx));
1972 width.y = 0;
1975 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
1976 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
1977 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
1979 case TA_LEFT:
1980 if (align & TA_UPDATECP)
1982 pt.x = x + width.x;
1983 pt.y = y + width.y;
1984 DPtoLP(hdc, &pt, 1);
1985 MoveToEx(hdc, pt.x, pt.y, NULL);
1987 break;
1989 case TA_CENTER:
1990 x -= width.x / 2;
1991 y -= width.y / 2;
1992 break;
1994 case TA_RIGHT:
1995 x -= width.x;
1996 y -= width.y;
1997 if (align & TA_UPDATECP)
1999 pt.x = x;
2000 pt.y = y;
2001 DPtoLP(hdc, &pt, 1);
2002 MoveToEx(hdc, pt.x, pt.y, NULL);
2004 break;
2007 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2009 case TA_TOP:
2010 y += tm.tmAscent * cosEsc;
2011 x += tm.tmAscent * sinEsc;
2012 break;
2014 case TA_BOTTOM:
2015 y -= tm.tmDescent * cosEsc;
2016 x -= tm.tmDescent * sinEsc;
2017 break;
2019 case TA_BASELINE:
2020 break;
2023 if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
2025 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2027 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width.x >= rc.right ||
2028 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2030 RECT rc;
2031 rc.left = x;
2032 rc.right = x + width.x;
2033 rc.top = y - tm.tmAscent;
2034 rc.bottom = y + tm.tmDescent;
2036 if(flags & ETO_CLIPPED)
2038 rc.left = max(lprect->left, rc.left);
2039 rc.right = min(lprect->right, rc.right);
2040 rc.top = max(lprect->top, rc.top);
2041 rc.bottom = min(lprect->bottom, rc.bottom);
2043 if(rc.left < rc.right && rc.top < rc.bottom)
2044 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
2049 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
2051 HFONT orig_font = dc->hFont, cur_font;
2052 UINT glyph;
2053 INT span = 0;
2054 POINT *offsets = NULL;
2055 unsigned int i;
2057 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2058 for(i = 0; i < count; i++)
2060 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
2061 if(cur_font != dc->hFont)
2063 if(!offsets)
2065 unsigned int j;
2066 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2067 offsets[0].x = offsets[0].y = 0;
2069 if(!deltas)
2071 SIZE tmpsz;
2072 for(j = 1; j < count; j++)
2074 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
2075 offsets[j].x = offsets[j - 1].x + abs(INTERNAL_XWSTODS(dc, tmpsz.cx));
2076 offsets[j].y = 0;
2079 else
2081 for(j = 1; j < count; j++)
2083 offsets[j].x = offsets[j - 1].x + deltas[j].x;
2084 offsets[j].y = offsets[j - 1].y + deltas[j].y;
2088 if(span)
2090 if (PATH_IsPathOpen(dc->path))
2091 ret = PATH_ExtTextOut(dc, x + offsets[i - span].x, y + offsets[i - span].y,
2092 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2093 glyphs, span, deltas ? (INT*)(deltas + (i - span)) : NULL);
2094 else
2095 dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span].x, y + offsets[i - span].y,
2096 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2097 glyphs, span, deltas ? (INT*)(deltas + (i - span)) : NULL);
2098 span = 0;
2100 SelectObject(hdc, cur_font);
2102 glyphs[span++] = glyph;
2104 if(i == count - 1)
2106 if (PATH_IsPathOpen(dc->path))
2107 ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span].x : 0),
2108 y + (offsets ? offsets[count - span].y : 0),
2109 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2110 glyphs, span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2111 else
2112 ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span].x : 0),
2113 y + (offsets ? offsets[count - span].y : 0),
2114 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2115 glyphs, span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2116 SelectObject(hdc, orig_font);
2117 HeapFree(GetProcessHeap(), 0, offsets);
2121 else
2123 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2125 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2126 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2127 flags |= ETO_GLYPH_INDEX;
2130 if (PATH_IsPathOpen(dc->path))
2131 ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
2132 glyphs ? glyphs : reordered_str, count, (INT*)deltas);
2133 else
2134 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
2135 glyphs ? glyphs : reordered_str, count, (INT*)deltas);
2138 done:
2139 HeapFree(GetProcessHeap(), 0, deltas);
2140 if(glyphs != reordered_str)
2141 HeapFree(GetProcessHeap(), 0, glyphs);
2142 if(reordered_str != str)
2143 HeapFree(GetProcessHeap(), 0, reordered_str);
2145 release_dc_ptr( dc );
2147 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2149 int underlinePos, strikeoutPos;
2150 int underlineWidth, strikeoutWidth;
2151 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2152 OUTLINETEXTMETRICW* otm = NULL;
2154 if(!size)
2156 underlinePos = 0;
2157 underlineWidth = tm.tmAscent / 20 + 1;
2158 strikeoutPos = tm.tmAscent / 2;
2159 strikeoutWidth = underlineWidth;
2161 else
2163 otm = HeapAlloc(GetProcessHeap(), 0, size);
2164 GetOutlineTextMetricsW(hdc, size, otm);
2165 underlinePos = otm->otmsUnderscorePosition;
2166 underlineWidth = otm->otmsUnderscoreSize;
2167 strikeoutPos = otm->otmsStrikeoutPosition;
2168 strikeoutWidth = otm->otmsStrikeoutSize;
2169 HeapFree(GetProcessHeap(), 0, otm);
2172 if (PATH_IsPathOpen(dc->path))
2174 POINT pts[5];
2175 HPEN hpen;
2176 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2178 hbrush = SelectObject(hdc, hbrush);
2179 hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2181 if (lf.lfUnderline)
2183 pts[0].x = x - underlinePos * sinEsc;
2184 pts[0].y = y - underlinePos * cosEsc;
2185 pts[1].x = x + width.x - underlinePos * sinEsc;
2186 pts[1].y = y + width.y - underlinePos * cosEsc;
2187 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2188 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2189 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2190 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2191 pts[4].x = pts[0].x;
2192 pts[4].y = pts[0].y;
2193 DPtoLP(hdc, pts, 5);
2194 Polygon(hdc, pts, 5);
2197 if (lf.lfStrikeOut)
2199 pts[0].x = x - strikeoutPos * sinEsc;
2200 pts[0].y = y - strikeoutPos * cosEsc;
2201 pts[1].x = x + width.x - strikeoutPos * sinEsc;
2202 pts[1].y = y + width.y - strikeoutPos * cosEsc;
2203 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2204 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2205 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2206 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2207 pts[4].x = pts[0].x;
2208 pts[4].y = pts[0].y;
2209 DPtoLP(hdc, pts, 5);
2210 Polygon(hdc, pts, 5);
2213 SelectObject(hdc, hpen);
2214 hbrush = SelectObject(hdc, hbrush);
2215 DeleteObject(hbrush);
2217 else
2219 POINT pts[2], oldpt;
2220 HPEN hpen;
2222 if (lf.lfUnderline)
2224 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2225 hpen = SelectObject(hdc, hpen);
2226 pts[0].x = x;
2227 pts[0].y = y;
2228 pts[1].x = x + width.x;
2229 pts[1].y = y + width.y;
2230 DPtoLP(hdc, pts, 2);
2231 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2232 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2233 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2234 DeleteObject(SelectObject(hdc, hpen));
2237 if (lf.lfStrikeOut)
2239 hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
2240 hpen = SelectObject(hdc, hpen);
2241 pts[0].x = x;
2242 pts[0].y = y;
2243 pts[1].x = x + width.x;
2244 pts[1].y = y + width.y;
2245 DPtoLP(hdc, pts, 2);
2246 MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2247 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2248 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2249 DeleteObject(SelectObject(hdc, hpen));
2254 return ret;
2258 /***********************************************************************
2259 * TextOutA (GDI32.@)
2261 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2263 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2267 /***********************************************************************
2268 * TextOutW (GDI32.@)
2270 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2272 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2276 /***********************************************************************
2277 * PolyTextOutA (GDI32.@)
2279 * See PolyTextOutW.
2281 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2283 for (; cStrings>0; cStrings--, pptxt++)
2284 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2285 return FALSE;
2286 return TRUE;
2291 /***********************************************************************
2292 * PolyTextOutW (GDI32.@)
2294 * Draw several Strings
2296 * RETURNS
2297 * TRUE: Success.
2298 * FALSE: Failure.
2300 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2302 for (; cStrings>0; cStrings--, pptxt++)
2303 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2304 return FALSE;
2305 return TRUE;
2309 /* FIXME: all following APIs ******************************************/
2312 /***********************************************************************
2313 * SetMapperFlags (GDI32.@)
2315 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2317 DC *dc = get_dc_ptr( hDC );
2318 DWORD ret = 0;
2319 if(!dc) return 0;
2320 if(dc->funcs->pSetMapperFlags)
2322 ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2323 /* FIXME: ret is just a success flag, we should return a proper value */
2325 else
2326 FIXME("(%p, 0x%08x): stub - harmless\n", hDC, dwFlag);
2327 release_dc_ptr( dc );
2328 return ret;
2331 /***********************************************************************
2332 * GetAspectRatioFilterEx (GDI32.@)
2334 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2336 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2337 return FALSE;
2341 /***********************************************************************
2342 * GetCharABCWidthsA (GDI32.@)
2344 * See GetCharABCWidthsW.
2346 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2347 LPABC abc )
2349 INT i, wlen;
2350 LPSTR str;
2351 LPWSTR wstr;
2352 BOOL ret = TRUE;
2354 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2355 if (str == NULL)
2356 return FALSE;
2358 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2359 if (wstr == NULL)
2361 HeapFree(GetProcessHeap(), 0, str);
2362 return FALSE;
2365 for(i = 0; i < wlen; i++)
2367 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2369 ret = FALSE;
2370 break;
2372 abc++;
2375 HeapFree(GetProcessHeap(), 0, str);
2376 HeapFree(GetProcessHeap(), 0, wstr);
2378 return ret;
2382 /******************************************************************************
2383 * GetCharABCWidthsW [GDI32.@]
2385 * Retrieves widths of characters in range.
2387 * PARAMS
2388 * hdc [I] Handle of device context
2389 * firstChar [I] First character in range to query
2390 * lastChar [I] Last character in range to query
2391 * abc [O] Address of character-width structure
2393 * NOTES
2394 * Only works with TrueType fonts
2396 * RETURNS
2397 * Success: TRUE
2398 * Failure: FALSE
2400 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2401 LPABC abc )
2403 DC *dc = get_dc_ptr(hdc);
2404 unsigned int i;
2405 BOOL ret = FALSE;
2407 if (!dc) return FALSE;
2409 if (!abc)
2411 release_dc_ptr( dc );
2412 return FALSE;
2415 if(dc->gdiFont)
2416 ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2417 else
2418 FIXME(": stub\n");
2420 if (ret)
2422 /* convert device units to logical */
2423 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2424 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2425 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2426 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2428 ret = TRUE;
2431 release_dc_ptr( dc );
2432 return ret;
2436 /******************************************************************************
2437 * GetCharABCWidthsI [GDI32.@]
2439 * Retrieves widths of characters in range.
2441 * PARAMS
2442 * hdc [I] Handle of device context
2443 * firstChar [I] First glyphs in range to query
2444 * count [I] Last glyphs in range to query
2445 * pgi [i] Array of glyphs to query
2446 * abc [O] Address of character-width structure
2448 * NOTES
2449 * Only works with TrueType fonts
2451 * RETURNS
2452 * Success: TRUE
2453 * Failure: FALSE
2455 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2456 LPWORD pgi, LPABC abc)
2458 DC *dc = get_dc_ptr(hdc);
2459 unsigned int i;
2460 BOOL ret = FALSE;
2462 if (!dc) return FALSE;
2464 if (!abc)
2466 release_dc_ptr( dc );
2467 return FALSE;
2470 if(dc->gdiFont)
2471 ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2472 else
2473 FIXME(": stub\n");
2475 if (ret)
2477 /* convert device units to logical */
2478 for( i = 0; i < count; i++, abc++ ) {
2479 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2480 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2481 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2483 ret = TRUE;
2486 release_dc_ptr( dc );
2487 return ret;
2491 /***********************************************************************
2492 * GetGlyphOutlineA (GDI32.@)
2494 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2495 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2496 LPVOID lpBuffer, const MAT2 *lpmat2 )
2498 if (!lpmat2) return GDI_ERROR;
2500 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2501 UINT cp;
2502 int len;
2503 char mbchs[2];
2505 cp = GdiGetCodePage(hdc);
2506 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2507 len = 2;
2508 mbchs[0] = (uChar & 0xff00) >> 8;
2509 mbchs[1] = (uChar & 0xff);
2510 } else {
2511 len = 1;
2512 mbchs[0] = (uChar & 0xff);
2514 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2517 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2518 lpmat2);
2521 /***********************************************************************
2522 * GetGlyphOutlineW (GDI32.@)
2524 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2525 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2526 LPVOID lpBuffer, const MAT2 *lpmat2 )
2528 DC *dc;
2529 DWORD ret;
2531 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2532 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2534 if (!lpmat2) return GDI_ERROR;
2536 dc = get_dc_ptr(hdc);
2537 if(!dc) return GDI_ERROR;
2539 if(dc->gdiFont)
2540 ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2541 cbBuffer, lpBuffer, lpmat2);
2542 else
2543 ret = GDI_ERROR;
2545 release_dc_ptr( dc );
2546 return ret;
2550 /***********************************************************************
2551 * CreateScalableFontResourceA (GDI32.@)
2553 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2554 LPCSTR lpszResourceFile,
2555 LPCSTR lpszFontFile,
2556 LPCSTR lpszCurrentPath )
2558 LPWSTR lpszResourceFileW = NULL;
2559 LPWSTR lpszFontFileW = NULL;
2560 LPWSTR lpszCurrentPathW = NULL;
2561 int len;
2562 BOOL ret;
2564 if (lpszResourceFile)
2566 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2567 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2568 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2571 if (lpszFontFile)
2573 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2574 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2575 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2578 if (lpszCurrentPath)
2580 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2581 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2582 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2585 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2586 lpszFontFileW, lpszCurrentPathW);
2588 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2589 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2590 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2592 return ret;
2595 /***********************************************************************
2596 * CreateScalableFontResourceW (GDI32.@)
2598 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2599 LPCWSTR lpszResourceFile,
2600 LPCWSTR lpszFontFile,
2601 LPCWSTR lpszCurrentPath )
2603 HANDLE f;
2604 FIXME("(%d,%s,%s,%s): stub\n",
2605 fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
2606 debugstr_w(lpszCurrentPath) );
2608 /* fHidden=1 - only visible for the calling app, read-only, not
2609 * enumerated with EnumFonts/EnumFontFamilies
2610 * lpszCurrentPath can be NULL
2613 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2614 if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2615 CloseHandle(f);
2616 SetLastError(ERROR_FILE_EXISTS);
2617 return FALSE;
2619 return FALSE; /* create failed */
2622 /*************************************************************************
2623 * GetKerningPairsA (GDI32.@)
2625 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2626 LPKERNINGPAIR kern_pairA )
2628 UINT cp;
2629 CPINFO cpi;
2630 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2631 KERNINGPAIR *kern_pairW;
2633 if (!cPairs && kern_pairA)
2635 SetLastError(ERROR_INVALID_PARAMETER);
2636 return 0;
2639 cp = GdiGetCodePage(hDC);
2641 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2642 * to fail on an invalid character for CP_SYMBOL.
2644 cpi.DefaultChar[0] = 0;
2645 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2647 FIXME("Can't find codepage %u info\n", cp);
2648 return 0;
2651 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2652 if (!total_kern_pairs) return 0;
2654 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2655 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2657 for (i = 0; i < total_kern_pairs; i++)
2659 char first, second;
2661 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2662 continue;
2664 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2665 continue;
2667 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2668 continue;
2670 if (kern_pairA)
2672 if (kern_pairs_copied >= cPairs) break;
2674 kern_pairA->wFirst = (BYTE)first;
2675 kern_pairA->wSecond = (BYTE)second;
2676 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2677 kern_pairA++;
2679 kern_pairs_copied++;
2682 HeapFree(GetProcessHeap(), 0, kern_pairW);
2684 return kern_pairs_copied;
2687 /*************************************************************************
2688 * GetKerningPairsW (GDI32.@)
2690 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2691 LPKERNINGPAIR lpKerningPairs )
2693 DC *dc;
2694 DWORD ret = 0;
2696 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2698 if (!cPairs && lpKerningPairs)
2700 SetLastError(ERROR_INVALID_PARAMETER);
2701 return 0;
2704 dc = get_dc_ptr(hDC);
2705 if (!dc) return 0;
2707 if (dc->gdiFont)
2708 ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
2710 release_dc_ptr( dc );
2711 return ret;
2714 /*************************************************************************
2715 * TranslateCharsetInfo [GDI32.@]
2717 * Fills a CHARSETINFO structure for a character set, code page, or
2718 * font. This allows making the correspondence between different labels
2719 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2720 * of the same encoding.
2722 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2723 * only one codepage should be set in *lpSrc.
2725 * RETURNS
2726 * TRUE on success, FALSE on failure.
2729 BOOL WINAPI TranslateCharsetInfo(
2730 LPDWORD lpSrc, /* [in]
2731 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2732 if flags == TCI_SRCCHARSET: a character set value
2733 if flags == TCI_SRCCODEPAGE: a code page value
2735 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2736 DWORD flags /* [in] determines interpretation of lpSrc */)
2738 int index = 0;
2739 switch (flags) {
2740 case TCI_SRCFONTSIG:
2741 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2742 break;
2743 case TCI_SRCCODEPAGE:
2744 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2745 break;
2746 case TCI_SRCCHARSET:
2747 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
2748 break;
2749 default:
2750 return FALSE;
2752 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2753 *lpCs = FONT_tci[index];
2754 return TRUE;
2757 /*************************************************************************
2758 * GetFontLanguageInfo (GDI32.@)
2760 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2762 FONTSIGNATURE fontsig;
2763 static const DWORD GCP_DBCS_MASK=0x003F0000,
2764 GCP_DIACRITIC_MASK=0x00000000,
2765 FLI_GLYPHS_MASK=0x00000000,
2766 GCP_GLYPHSHAPE_MASK=0x00000040,
2767 GCP_KASHIDA_MASK=0x00000000,
2768 GCP_LIGATE_MASK=0x00000000,
2769 GCP_USEKERNING_MASK=0x00000000,
2770 GCP_REORDER_MASK=0x00000060;
2772 DWORD result=0;
2774 GetTextCharsetInfo( hdc, &fontsig, 0 );
2775 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2777 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2778 result|=GCP_DBCS;
2780 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2781 result|=GCP_DIACRITIC;
2783 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2784 result|=FLI_GLYPHS;
2786 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2787 result|=GCP_GLYPHSHAPE;
2789 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2790 result|=GCP_KASHIDA;
2792 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2793 result|=GCP_LIGATE;
2795 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2796 result|=GCP_USEKERNING;
2798 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2799 if( GetTextAlign( hdc) & TA_RTLREADING )
2800 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2801 result|=GCP_REORDER;
2803 return result;
2807 /*************************************************************************
2808 * GetFontData [GDI32.@]
2810 * Retrieve data for TrueType font.
2812 * RETURNS
2814 * success: Number of bytes returned
2815 * failure: GDI_ERROR
2817 * NOTES
2819 * Calls SetLastError()
2822 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2823 LPVOID buffer, DWORD length)
2825 DC *dc = get_dc_ptr(hdc);
2826 DWORD ret = GDI_ERROR;
2828 if(!dc) return GDI_ERROR;
2830 if(dc->gdiFont)
2831 ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2833 release_dc_ptr( dc );
2834 return ret;
2837 /*************************************************************************
2838 * GetGlyphIndicesA [GDI32.@]
2840 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2841 LPWORD pgi, DWORD flags)
2843 DWORD ret;
2844 WCHAR *lpstrW;
2845 INT countW;
2847 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2848 hdc, debugstr_an(lpstr, count), count, pgi, flags);
2850 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
2851 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2852 HeapFree(GetProcessHeap(), 0, lpstrW);
2854 return ret;
2857 /*************************************************************************
2858 * GetGlyphIndicesW [GDI32.@]
2860 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2861 LPWORD pgi, DWORD flags)
2863 DC *dc = get_dc_ptr(hdc);
2864 DWORD ret = GDI_ERROR;
2866 TRACE("(%p, %s, %d, %p, 0x%x)\n",
2867 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2869 if(!dc) return GDI_ERROR;
2871 if(dc->gdiFont)
2872 ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2874 release_dc_ptr( dc );
2875 return ret;
2878 /*************************************************************************
2879 * GetCharacterPlacementA [GDI32.@]
2881 * See GetCharacterPlacementW.
2883 * NOTES:
2884 * the web browser control of ie4 calls this with dwFlags=0
2886 DWORD WINAPI
2887 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2888 INT nMaxExtent, GCP_RESULTSA *lpResults,
2889 DWORD dwFlags)
2891 WCHAR *lpStringW;
2892 INT uCountW;
2893 GCP_RESULTSW resultsW;
2894 DWORD ret;
2895 UINT font_cp;
2897 TRACE("%s, %d, %d, 0x%08x\n",
2898 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2900 /* both structs are equal in size */
2901 memcpy(&resultsW, lpResults, sizeof(resultsW));
2903 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
2904 if(lpResults->lpOutString)
2905 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2907 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2909 lpResults->nGlyphs = resultsW.nGlyphs;
2910 lpResults->nMaxFit = resultsW.nMaxFit;
2912 if(lpResults->lpOutString) {
2913 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
2914 lpResults->lpOutString, uCount, NULL, NULL );
2917 HeapFree(GetProcessHeap(), 0, lpStringW);
2918 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2920 return ret;
2923 /*************************************************************************
2924 * GetCharacterPlacementW [GDI32.@]
2926 * Retrieve information about a string. This includes the width, reordering,
2927 * Glyphing and so on.
2929 * RETURNS
2931 * The width and height of the string if successful, 0 if failed.
2933 * BUGS
2935 * All flags except GCP_REORDER are not yet implemented.
2936 * Reordering is not 100% compliant to the Windows BiDi method.
2937 * Caret positioning is not yet implemented for BiDi.
2938 * Classes are not yet implemented.
2941 DWORD WINAPI
2942 GetCharacterPlacementW(
2943 HDC hdc, /* [in] Device context for which the rendering is to be done */
2944 LPCWSTR lpString, /* [in] The string for which information is to be returned */
2945 INT uCount, /* [in] Number of WORDS in string. */
2946 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
2947 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
2948 DWORD dwFlags /* [in] Flags specifying how to process the string */
2951 DWORD ret=0;
2952 SIZE size;
2953 UINT i, nSet;
2955 TRACE("%s, %d, %d, 0x%08x\n",
2956 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2958 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
2959 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2960 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
2961 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
2962 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
2964 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
2965 if(lpResults->lpClass) FIXME("classes not implemented\n");
2966 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
2967 FIXME("Caret positions for complex scripts not implemented\n");
2969 nSet = (UINT)uCount;
2970 if(nSet > lpResults->nGlyphs)
2971 nSet = lpResults->nGlyphs;
2973 /* return number of initialized fields */
2974 lpResults->nGlyphs = nSet;
2976 if((dwFlags&GCP_REORDER)==0 )
2978 /* Treat the case where no special handling was requested in a fastpath way */
2979 /* copy will do if the GCP_REORDER flag is not set */
2980 if(lpResults->lpOutString)
2981 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
2983 if(lpResults->lpOrder)
2985 for(i = 0; i < nSet; i++)
2986 lpResults->lpOrder[i] = i;
2988 } else
2990 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
2991 nSet, lpResults->lpOrder, NULL, NULL );
2994 /* FIXME: Will use the placement chars */
2995 if (lpResults->lpDx)
2997 int c;
2998 for (i = 0; i < nSet; i++)
3000 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3001 lpResults->lpDx[i]= c;
3005 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3007 int pos = 0;
3009 lpResults->lpCaretPos[0] = 0;
3010 for (i = 1; i < nSet; i++)
3011 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3012 lpResults->lpCaretPos[i] = (pos += size.cx);
3015 if(lpResults->lpGlyphs)
3016 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3018 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3019 ret = MAKELONG(size.cx, size.cy);
3021 return ret;
3024 /*************************************************************************
3025 * GetCharABCWidthsFloatA [GDI32.@]
3027 * See GetCharABCWidthsFloatW.
3029 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3031 INT i, wlen;
3032 LPSTR str;
3033 LPWSTR wstr;
3034 BOOL ret = TRUE;
3036 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3037 if (str == NULL)
3038 return FALSE;
3040 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3042 for (i = 0; i < wlen; i++)
3044 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3046 ret = FALSE;
3047 break;
3049 abcf++;
3052 HeapFree( GetProcessHeap(), 0, str );
3053 HeapFree( GetProcessHeap(), 0, wstr );
3055 return ret;
3058 /*************************************************************************
3059 * GetCharABCWidthsFloatW [GDI32.@]
3061 * Retrieves widths of a range of characters.
3063 * PARAMS
3064 * hdc [I] Handle to device context.
3065 * first [I] First character in range to query.
3066 * last [I] Last character in range to query.
3067 * abcf [O] Array of LPABCFLOAT structures.
3069 * RETURNS
3070 * Success: TRUE
3071 * Failure: FALSE
3073 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3075 UINT i;
3076 BOOL ret = FALSE;
3077 DC *dc = get_dc_ptr( hdc );
3079 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3081 if (!dc) return FALSE;
3083 if (!abcf)
3085 release_dc_ptr( dc );
3086 return FALSE;
3089 if (dc->gdiFont)
3090 ret = WineEngGetCharABCWidthsFloat( dc->gdiFont, first, last, abcf );
3091 else
3092 FIXME("stub\n");
3094 if (ret)
3096 /* convert device units to logical */
3097 for (i = first; i <= last; i++, abcf++)
3099 abcf->abcfA = abcf->abcfA * dc->xformVport2World.eM11;
3100 abcf->abcfB = abcf->abcfB * dc->xformVport2World.eM11;
3101 abcf->abcfC = abcf->abcfC * dc->xformVport2World.eM11;
3105 release_dc_ptr( dc );
3106 return ret;
3109 /*************************************************************************
3110 * GetCharWidthFloatA [GDI32.@]
3112 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3113 UINT iLastChar, PFLOAT pxBuffer)
3115 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3116 return 0;
3119 /*************************************************************************
3120 * GetCharWidthFloatW [GDI32.@]
3122 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3123 UINT iLastChar, PFLOAT pxBuffer)
3125 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3126 return 0;
3130 /***********************************************************************
3132 * Font Resource API *
3134 ***********************************************************************/
3136 /***********************************************************************
3137 * AddFontResourceA (GDI32.@)
3139 INT WINAPI AddFontResourceA( LPCSTR str )
3141 return AddFontResourceExA( str, 0, NULL);
3144 /***********************************************************************
3145 * AddFontResourceW (GDI32.@)
3147 INT WINAPI AddFontResourceW( LPCWSTR str )
3149 return AddFontResourceExW(str, 0, NULL);
3153 /***********************************************************************
3154 * AddFontResourceExA (GDI32.@)
3156 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3158 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3159 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3160 INT ret;
3162 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3163 ret = AddFontResourceExW(strW, fl, pdv);
3164 HeapFree(GetProcessHeap(), 0, strW);
3165 return ret;
3168 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3170 HRSRC rsrc = FindResourceW(hModule, name, type);
3171 HGLOBAL hMem = LoadResource(hModule, rsrc);
3172 LPVOID *pMem = LockResource(hMem);
3173 int *num_total = (int *)lParam;
3174 DWORD num_in_res;
3176 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3177 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3179 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3180 return FALSE;
3183 *num_total += num_in_res;
3184 return TRUE;
3187 /***********************************************************************
3188 * AddFontResourceExW (GDI32.@)
3190 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3192 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3193 if (ret == 0)
3195 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3196 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3197 if (hModule != NULL)
3199 int num_resources = 0;
3200 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3202 TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3203 wine_dbgstr_w(str));
3204 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3205 ret = num_resources;
3206 FreeLibrary(hModule);
3209 return ret;
3212 /***********************************************************************
3213 * RemoveFontResourceA (GDI32.@)
3215 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3217 return RemoveFontResourceExA(str, 0, 0);
3220 /***********************************************************************
3221 * RemoveFontResourceW (GDI32.@)
3223 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3225 return RemoveFontResourceExW(str, 0, 0);
3228 /***********************************************************************
3229 * AddFontMemResourceEx (GDI32.@)
3231 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3233 HANDLE ret;
3234 DWORD num_fonts;
3236 if (!pbFont || !cbFont || !pcFonts)
3238 SetLastError(ERROR_INVALID_PARAMETER);
3239 return NULL;
3242 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3243 if (ret)
3245 __TRY
3247 *pcFonts = num_fonts;
3249 __EXCEPT_PAGE_FAULT
3251 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3252 RemoveFontMemResourceEx(ret);
3253 ret = 0;
3255 __ENDTRY
3257 return ret;
3260 /***********************************************************************
3261 * RemoveFontMemResourceEx (GDI32.@)
3263 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3265 FIXME("(%p) stub\n", fh);
3266 return TRUE;
3269 /***********************************************************************
3270 * RemoveFontResourceExA (GDI32.@)
3272 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3274 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3275 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3276 INT ret;
3278 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3279 ret = RemoveFontResourceExW(strW, fl, pdv);
3280 HeapFree(GetProcessHeap(), 0, strW);
3281 return ret;
3284 /***********************************************************************
3285 * RemoveFontResourceExW (GDI32.@)
3287 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3289 return WineEngRemoveFontResourceEx(str, fl, pdv);
3292 /***********************************************************************
3293 * GetTextCharset (GDI32.@)
3295 UINT WINAPI GetTextCharset(HDC hdc)
3297 /* MSDN docs say this is equivalent */
3298 return GetTextCharsetInfo(hdc, NULL, 0);
3301 /***********************************************************************
3302 * GetTextCharsetInfo (GDI32.@)
3304 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3306 UINT ret = DEFAULT_CHARSET;
3307 DC *dc = get_dc_ptr(hdc);
3309 if (dc)
3311 if (dc->gdiFont)
3312 ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3314 release_dc_ptr( dc );
3317 if (ret == DEFAULT_CHARSET && fs)
3318 memset(fs, 0, sizeof(FONTSIGNATURE));
3319 return ret;
3322 /***********************************************************************
3323 * GdiGetCharDimensions (GDI32.@)
3325 * Gets the average width of the characters in the English alphabet.
3327 * PARAMS
3328 * hdc [I] Handle to the device context to measure on.
3329 * lptm [O] Pointer to memory to store the text metrics into.
3330 * height [O] On exit, the maximum height of characters in the English alphabet.
3332 * RETURNS
3333 * The average width of characters in the English alphabet.
3335 * NOTES
3336 * This function is used by the dialog manager to get the size of a dialog
3337 * unit. It should also be used by other pieces of code that need to know
3338 * the size of a dialog unit in logical units without having access to the
3339 * window handle of the dialog.
3340 * Windows caches the font metrics from this function, but we don't and
3341 * there doesn't appear to be an immediate advantage to do so.
3343 * SEE ALSO
3344 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3346 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3348 SIZE sz;
3349 static const WCHAR alphabet[] = {
3350 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3351 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3352 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3354 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3356 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3358 if (height) *height = sz.cy;
3359 return (sz.cx / 26 + 1) / 2;
3362 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3364 FIXME("(%d): stub\n", fEnableEUDC);
3365 return FALSE;
3368 /***********************************************************************
3369 * GetCharWidthI (GDI32.@)
3371 * Retrieve widths of characters.
3373 * PARAMS
3374 * hdc [I] Handle to a device context.
3375 * first [I] First glyph in range to query.
3376 * count [I] Number of glyph indices to query.
3377 * glyphs [I] Array of glyphs to query.
3378 * buffer [O] Buffer to receive character widths.
3380 * NOTES
3381 * Only works with TrueType fonts.
3383 * RETURNS
3384 * Success: TRUE
3385 * Failure: FALSE
3387 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3389 ABC *abc;
3390 unsigned int i;
3392 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3394 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3395 return FALSE;
3397 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3399 HeapFree(GetProcessHeap(), 0, abc);
3400 return FALSE;
3403 for (i = 0; i < count; i++)
3404 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3406 HeapFree(GetProcessHeap(), 0, abc);
3407 return TRUE;
3410 /***********************************************************************
3411 * GetFontUnicodeRanges (GDI32.@)
3413 * Retrieve a list of supported Unicode characters in a font.
3415 * PARAMS
3416 * hdc [I] Handle to a device context.
3417 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3419 * RETURNS
3420 * Success: Number of bytes written to the buffer pointed to by lpgs.
3421 * Failure: 0
3424 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3426 DWORD ret = 0;
3427 DC *dc = get_dc_ptr(hdc);
3429 TRACE("(%p, %p)\n", hdc, lpgs);
3431 if (!dc) return 0;
3433 if (dc->gdiFont) ret = WineEngGetFontUnicodeRanges(dc->gdiFont, lpgs);
3434 release_dc_ptr(dc);
3435 return ret;
3439 /*************************************************************
3440 * FontIsLinked (GDI32.@)
3442 BOOL WINAPI FontIsLinked(HDC hdc)
3444 DC *dc = get_dc_ptr(hdc);
3445 BOOL ret = FALSE;
3447 if (!dc) return FALSE;
3448 if (dc->gdiFont) ret = WineEngFontIsLinked(dc->gdiFont);
3449 release_dc_ptr(dc);
3450 TRACE("returning %d\n", ret);
3451 return ret;
3454 /*************************************************************
3455 * GdiRealizationInfo (GDI32.@)
3457 * Returns a structure that contains some font information.
3459 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3461 DC *dc = get_dc_ptr(hdc);
3462 BOOL ret = FALSE;
3464 if (!dc) return FALSE;
3465 if (dc->gdiFont) ret = WineEngRealizationInfo(dc->gdiFont, info);
3466 release_dc_ptr(dc);
3468 return ret;