usp10: Remove unnecessary casts in test suite.
[wine/hacks.git] / dlls / gdi / font.c
blobec9074d5b0d22723d876997888da9985527fe6f4
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include "winerror.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "wownt32.h"
35 #include "gdi.h"
36 #include "gdi_private.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(font);
41 WINE_DECLARE_DEBUG_CHANNEL(gdi);
43 /* Device -> World size conversion */
45 /* Performs a device to world transformation on the specified width (which
46 * is in integer format).
48 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
50 FLOAT floatWidth;
52 /* Perform operation with floating point */
53 floatWidth = (FLOAT)width * dc->xformVport2World.eM11;
54 /* Round to integers */
55 return GDI_ROUND(floatWidth);
58 /* Performs a device to world transformation on the specified size (which
59 * is in integer format).
61 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
63 FLOAT floatHeight;
65 /* Perform operation with floating point */
66 floatHeight = (FLOAT)height * dc->xformVport2World.eM22;
67 /* Round to integers */
68 return GDI_ROUND(floatHeight);
71 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
73 POINT pt[2];
74 pt[0].x = pt[0].y = 0;
75 pt[1].x = width;
76 pt[1].y = 0;
77 LPtoDP(dc->hSelf, pt, 2);
78 return pt[1].x - pt[0].x;
81 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
83 POINT pt[2];
84 pt[0].x = pt[0].y = 0;
85 pt[1].x = 0;
86 pt[1].y = height;
87 LPtoDP(dc->hSelf, pt, 2);
88 return pt[1].y - pt[0].y;
91 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, void *obj, HDC hdc );
92 static INT FONT_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
93 static INT FONT_GetObjectA( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
94 static INT FONT_GetObjectW( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
95 static BOOL FONT_DeleteObject( HGDIOBJ handle, void *obj );
97 static const struct gdi_obj_funcs font_funcs =
99 FONT_SelectObject, /* pSelectObject */
100 FONT_GetObject16, /* pGetObject16 */
101 FONT_GetObjectA, /* pGetObjectA */
102 FONT_GetObjectW, /* pGetObjectW */
103 NULL, /* pUnrealizeObject */
104 FONT_DeleteObject /* pDeleteObject */
107 #define ENUM_UNICODE 0x00000001
108 #define ENUM_CALLED 0x00000002
110 typedef struct
112 GDIOBJHDR header;
113 LOGFONTW logfont;
114 } FONTOBJ;
116 typedef struct
118 LPLOGFONT16 lpLogFontParam;
119 FONTENUMPROC16 lpEnumFunc;
120 LPARAM lpData;
122 LPNEWTEXTMETRICEX16 lpTextMetric;
123 LPENUMLOGFONTEX16 lpLogFont;
124 SEGPTR segTextMetric;
125 SEGPTR segLogFont;
126 DWORD dwFlags;
127 HDC hdc;
128 DC *dc;
129 PHYSDEV physDev;
130 } fontEnum16;
132 typedef struct
134 LPLOGFONTW lpLogFontParam;
135 FONTENUMPROCW lpEnumFunc;
136 LPARAM lpData;
137 DWORD dwFlags;
138 HDC hdc;
139 DC *dc;
140 PHYSDEV physDev;
141 } fontEnum32;
144 * For TranslateCharsetInfo
146 #define FS(x) {{0,0,0,0},{0x1<<(x),0}}
147 #define MAXTCIINDEX 32
148 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
149 /* ANSI */
150 { ANSI_CHARSET, 1252, FS(0)},
151 { EASTEUROPE_CHARSET, 1250, FS(1)},
152 { RUSSIAN_CHARSET, 1251, FS(2)},
153 { GREEK_CHARSET, 1253, FS(3)},
154 { TURKISH_CHARSET, 1254, FS(4)},
155 { HEBREW_CHARSET, 1255, FS(5)},
156 { ARABIC_CHARSET, 1256, FS(6)},
157 { BALTIC_CHARSET, 1257, FS(7)},
158 { VIETNAMESE_CHARSET, 1258, FS(8)},
159 /* reserved by ANSI */
160 { DEFAULT_CHARSET, 0, FS(0)},
161 { DEFAULT_CHARSET, 0, FS(0)},
162 { DEFAULT_CHARSET, 0, FS(0)},
163 { DEFAULT_CHARSET, 0, FS(0)},
164 { DEFAULT_CHARSET, 0, FS(0)},
165 { DEFAULT_CHARSET, 0, FS(0)},
166 { DEFAULT_CHARSET, 0, FS(0)},
167 /* ANSI and OEM */
168 { THAI_CHARSET, 874, FS(16)},
169 { SHIFTJIS_CHARSET, 932, FS(17)},
170 { GB2312_CHARSET, 936, FS(18)},
171 { HANGEUL_CHARSET, 949, FS(19)},
172 { CHINESEBIG5_CHARSET, 950, FS(20)},
173 { JOHAB_CHARSET, 1361, FS(21)},
174 /* reserved for alternate ANSI and OEM */
175 { DEFAULT_CHARSET, 0, FS(0)},
176 { DEFAULT_CHARSET, 0, FS(0)},
177 { DEFAULT_CHARSET, 0, FS(0)},
178 { DEFAULT_CHARSET, 0, FS(0)},
179 { DEFAULT_CHARSET, 0, FS(0)},
180 { DEFAULT_CHARSET, 0, FS(0)},
181 { DEFAULT_CHARSET, 0, FS(0)},
182 { DEFAULT_CHARSET, 0, FS(0)},
183 /* reserved for system */
184 { DEFAULT_CHARSET, 0, FS(0)},
185 { SYMBOL_CHARSET, CP_SYMBOL, FS(31)},
188 /***********************************************************************
189 * LOGFONT conversion functions.
191 static void FONT_LogFontWTo16( const LOGFONTW* font32, LPLOGFONT16 font16 )
193 font16->lfHeight = font32->lfHeight;
194 font16->lfWidth = font32->lfWidth;
195 font16->lfEscapement = font32->lfEscapement;
196 font16->lfOrientation = font32->lfOrientation;
197 font16->lfWeight = font32->lfWeight;
198 font16->lfItalic = font32->lfItalic;
199 font16->lfUnderline = font32->lfUnderline;
200 font16->lfStrikeOut = font32->lfStrikeOut;
201 font16->lfCharSet = font32->lfCharSet;
202 font16->lfOutPrecision = font32->lfOutPrecision;
203 font16->lfClipPrecision = font32->lfClipPrecision;
204 font16->lfQuality = font32->lfQuality;
205 font16->lfPitchAndFamily = font32->lfPitchAndFamily;
206 WideCharToMultiByte( CP_ACP, 0, font32->lfFaceName, -1,
207 font16->lfFaceName, LF_FACESIZE, NULL, NULL );
208 font16->lfFaceName[LF_FACESIZE-1] = 0;
211 static void FONT_LogFont16ToW( const LOGFONT16 *font16, LPLOGFONTW font32 )
213 font32->lfHeight = font16->lfHeight;
214 font32->lfWidth = font16->lfWidth;
215 font32->lfEscapement = font16->lfEscapement;
216 font32->lfOrientation = font16->lfOrientation;
217 font32->lfWeight = font16->lfWeight;
218 font32->lfItalic = font16->lfItalic;
219 font32->lfUnderline = font16->lfUnderline;
220 font32->lfStrikeOut = font16->lfStrikeOut;
221 font32->lfCharSet = font16->lfCharSet;
222 font32->lfOutPrecision = font16->lfOutPrecision;
223 font32->lfClipPrecision = font16->lfClipPrecision;
224 font32->lfQuality = font16->lfQuality;
225 font32->lfPitchAndFamily = font16->lfPitchAndFamily;
226 MultiByteToWideChar( CP_ACP, 0, font16->lfFaceName, -1, font32->lfFaceName, LF_FACESIZE );
227 font32->lfFaceName[LF_FACESIZE-1] = 0;
230 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
232 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
233 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
234 LF_FACESIZE);
235 fontW->lfFaceName[LF_FACESIZE-1] = 0;
238 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
240 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
241 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
242 LF_FACESIZE, NULL, NULL);
243 fontA->lfFaceName[LF_FACESIZE-1] = 0;
246 static void FONT_EnumLogFontExWTo16( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEX16 font16 )
248 FONT_LogFontWTo16( (LPLOGFONTW)fontW, (LPLOGFONT16)font16);
250 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
251 (LPSTR) font16->elfFullName, LF_FULLFACESIZE, NULL, NULL );
252 font16->elfFullName[LF_FULLFACESIZE-1] = '\0';
253 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
254 (LPSTR) font16->elfStyle, LF_FACESIZE, NULL, NULL );
255 font16->elfStyle[LF_FACESIZE-1] = '\0';
256 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
257 (LPSTR) font16->elfScript, LF_FACESIZE, NULL, NULL );
258 font16->elfScript[LF_FACESIZE-1] = '\0';
261 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
263 FONT_LogFontWToA( (LPLOGFONTW)fontW, (LPLOGFONTA)fontA);
265 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
266 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
267 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
268 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
269 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
270 fontA->elfStyle[LF_FACESIZE-1] = '\0';
271 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
272 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
273 fontA->elfScript[LF_FACESIZE-1] = '\0';
276 /***********************************************************************
277 * TEXTMETRIC conversion functions.
279 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
281 ptmA->tmHeight = ptmW->tmHeight;
282 ptmA->tmAscent = ptmW->tmAscent;
283 ptmA->tmDescent = ptmW->tmDescent;
284 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
285 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
286 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
287 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
288 ptmA->tmWeight = ptmW->tmWeight;
289 ptmA->tmOverhang = ptmW->tmOverhang;
290 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
291 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
292 ptmA->tmFirstChar = ptmW->tmFirstChar > 255 ? 255 : ptmW->tmFirstChar;
293 ptmA->tmLastChar = ptmW->tmLastChar > 255 ? 255 : ptmW->tmLastChar;
294 ptmA->tmDefaultChar = ptmW->tmDefaultChar > 255 ? 255 : ptmW->tmDefaultChar;
295 ptmA->tmBreakChar = ptmW->tmBreakChar > 255 ? 255 : ptmW->tmBreakChar;
296 ptmA->tmItalic = ptmW->tmItalic;
297 ptmA->tmUnderlined = ptmW->tmUnderlined;
298 ptmA->tmStruckOut = ptmW->tmStruckOut;
299 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
300 ptmA->tmCharSet = ptmW->tmCharSet;
304 static void FONT_NewTextMetricExWTo16(const NEWTEXTMETRICEXW *ptmW, LPNEWTEXTMETRICEX16 ptm16 )
306 ptm16->ntmTm.tmHeight = ptmW->ntmTm.tmHeight;
307 ptm16->ntmTm.tmAscent = ptmW->ntmTm.tmAscent;
308 ptm16->ntmTm.tmDescent = ptmW->ntmTm.tmDescent;
309 ptm16->ntmTm.tmInternalLeading = ptmW->ntmTm.tmInternalLeading;
310 ptm16->ntmTm.tmExternalLeading = ptmW->ntmTm.tmExternalLeading;
311 ptm16->ntmTm.tmAveCharWidth = ptmW->ntmTm.tmAveCharWidth;
312 ptm16->ntmTm.tmMaxCharWidth = ptmW->ntmTm.tmMaxCharWidth;
313 ptm16->ntmTm.tmWeight = ptmW->ntmTm.tmWeight;
314 ptm16->ntmTm.tmOverhang = ptmW->ntmTm.tmOverhang;
315 ptm16->ntmTm.tmDigitizedAspectX = ptmW->ntmTm.tmDigitizedAspectX;
316 ptm16->ntmTm.tmDigitizedAspectY = ptmW->ntmTm.tmDigitizedAspectY;
317 ptm16->ntmTm.tmFirstChar = ptmW->ntmTm.tmFirstChar > 255 ? 255 : ptmW->ntmTm.tmFirstChar;
318 ptm16->ntmTm.tmLastChar = ptmW->ntmTm.tmLastChar > 255 ? 255 : ptmW->ntmTm.tmLastChar;
319 ptm16->ntmTm.tmDefaultChar = ptmW->ntmTm.tmDefaultChar > 255 ? 255 : ptmW->ntmTm.tmDefaultChar;
320 ptm16->ntmTm.tmBreakChar = ptmW->ntmTm.tmBreakChar > 255 ? 255 : ptmW->ntmTm.tmBreakChar;
321 ptm16->ntmTm.tmItalic = ptmW->ntmTm.tmItalic;
322 ptm16->ntmTm.tmUnderlined = ptmW->ntmTm.tmUnderlined;
323 ptm16->ntmTm.tmStruckOut = ptmW->ntmTm.tmStruckOut;
324 ptm16->ntmTm.tmPitchAndFamily = ptmW->ntmTm.tmPitchAndFamily;
325 ptm16->ntmTm.tmCharSet = ptmW->ntmTm.tmCharSet;
326 ptm16->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
327 ptm16->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
328 ptm16->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
329 ptm16->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
330 memcpy(&ptm16->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
333 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
335 FONT_TextMetricWToA((LPTEXTMETRICW)ptmW, (LPTEXTMETRICA)ptmA);
336 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
337 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
338 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
339 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
340 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
344 /***********************************************************************
345 * FONT_mbtowc
347 * Returns a Unicode translation of str. If count is -1 then str is
348 * assumed to be '\0' terminated, otherwise it contains the number of
349 * bytes to convert. If plenW is non-NULL, on return it will point to
350 * the number of WCHARs that have been written. The caller should free
351 * the returned LPWSTR from the process heap itself.
353 static LPWSTR FONT_mbtowc(LPCSTR str, INT count, INT *plenW)
355 UINT cp = CP_ACP;
356 INT lenW;
357 LPWSTR strW;
359 if(count == -1) count = strlen(str);
360 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
361 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
362 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
363 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
364 if(plenW) *plenW = lenW;
365 return strW;
369 /***********************************************************************
370 * CreateFontIndirectA (GDI32.@)
372 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
374 LOGFONTW lfW;
376 if (plfA) {
377 FONT_LogFontAToW( plfA, &lfW );
378 return CreateFontIndirectW( &lfW );
379 } else
380 return CreateFontIndirectW( NULL );
384 /***********************************************************************
385 * CreateFontIndirectW (GDI32.@)
387 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
389 HFONT hFont = 0;
391 if (plf)
393 FONTOBJ* fontPtr;
394 if ((fontPtr = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC,
395 (HGDIOBJ *)&hFont, &font_funcs )))
397 static const WCHAR ItalicW[] = {' ','I','t','a','l','i','c','\0'};
398 static const WCHAR BoldW[] = {' ','B','o','l','d','\0'};
399 WCHAR *pFaceNameItalicSuffix, *pFaceNameBoldSuffix;
400 WCHAR* pFaceNameSuffix = NULL;
402 memcpy( &fontPtr->logfont, plf, sizeof(LOGFONTW) );
404 TRACE("(%ld %ld %ld %ld %x %d %x %d %d) %s %s %s %s => %p\n",
405 plf->lfHeight, plf->lfWidth,
406 plf->lfEscapement, plf->lfOrientation,
407 plf->lfPitchAndFamily,
408 plf->lfOutPrecision, plf->lfClipPrecision,
409 plf->lfQuality, plf->lfCharSet,
410 debugstr_w(plf->lfFaceName),
411 plf->lfWeight > 400 ? "Bold" : "",
412 plf->lfItalic ? "Italic" : "",
413 plf->lfUnderline ? "Underline" : "", hFont);
415 if (plf->lfEscapement != plf->lfOrientation) {
416 /* this should really depend on whether GM_ADVANCED is set */
417 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
418 WARN("orientation angle %f set to "
419 "escapement angle %f for new font %p\n",
420 plf->lfOrientation/10., plf->lfEscapement/10., hFont);
423 pFaceNameItalicSuffix = strstrW(fontPtr->logfont.lfFaceName, ItalicW);
424 if (pFaceNameItalicSuffix) {
425 fontPtr->logfont.lfItalic = TRUE;
426 pFaceNameSuffix = pFaceNameItalicSuffix;
429 pFaceNameBoldSuffix = strstrW(fontPtr->logfont.lfFaceName, BoldW);
430 if (pFaceNameBoldSuffix) {
431 if (fontPtr->logfont.lfWeight < FW_BOLD) {
432 fontPtr->logfont.lfWeight = FW_BOLD;
434 if (!pFaceNameSuffix ||
435 (pFaceNameBoldSuffix < pFaceNameSuffix)) {
436 pFaceNameSuffix = pFaceNameBoldSuffix;
440 if (pFaceNameSuffix) *pFaceNameSuffix = 0;
442 GDI_ReleaseObj( hFont );
445 else WARN("(NULL) => NULL\n");
447 return hFont;
450 /*************************************************************************
451 * CreateFontA (GDI32.@)
453 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
454 INT orient, INT weight, DWORD italic,
455 DWORD underline, DWORD strikeout, DWORD charset,
456 DWORD outpres, DWORD clippres, DWORD quality,
457 DWORD pitch, LPCSTR name )
459 LOGFONTA logfont;
461 logfont.lfHeight = height;
462 logfont.lfWidth = width;
463 logfont.lfEscapement = esc;
464 logfont.lfOrientation = orient;
465 logfont.lfWeight = weight;
466 logfont.lfItalic = italic;
467 logfont.lfUnderline = underline;
468 logfont.lfStrikeOut = strikeout;
469 logfont.lfCharSet = charset;
470 logfont.lfOutPrecision = outpres;
471 logfont.lfClipPrecision = clippres;
472 logfont.lfQuality = quality;
473 logfont.lfPitchAndFamily = pitch;
475 if (name)
476 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
477 else
478 logfont.lfFaceName[0] = '\0';
480 return CreateFontIndirectA( &logfont );
483 /*************************************************************************
484 * CreateFontW (GDI32.@)
486 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
487 INT orient, INT weight, DWORD italic,
488 DWORD underline, DWORD strikeout, DWORD charset,
489 DWORD outpres, DWORD clippres, DWORD quality,
490 DWORD pitch, LPCWSTR name )
492 LOGFONTW logfont;
494 logfont.lfHeight = height;
495 logfont.lfWidth = width;
496 logfont.lfEscapement = esc;
497 logfont.lfOrientation = orient;
498 logfont.lfWeight = weight;
499 logfont.lfItalic = italic;
500 logfont.lfUnderline = underline;
501 logfont.lfStrikeOut = strikeout;
502 logfont.lfCharSet = charset;
503 logfont.lfOutPrecision = outpres;
504 logfont.lfClipPrecision = clippres;
505 logfont.lfQuality = quality;
506 logfont.lfPitchAndFamily = pitch;
508 if (name)
509 lstrcpynW(logfont.lfFaceName, name,
510 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
511 else
512 logfont.lfFaceName[0] = '\0';
514 return CreateFontIndirectW( &logfont );
518 /***********************************************************************
519 * FONT_SelectObject
521 * If the driver supports vector fonts we create a gdi font first and
522 * then call the driver to give it a chance to supply its own device
523 * font. If the driver wants to do this it returns TRUE and we can
524 * delete the gdi font, if the driver wants to use the gdi font it
525 * should return FALSE, to signal an error return GDI_ERROR. For
526 * drivers that don't support vector fonts they must supply their own
527 * font.
529 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, void *obj, HDC hdc )
531 HGDIOBJ ret = 0;
532 DC *dc = DC_GetDCPtr( hdc );
534 if (!dc) return 0;
536 if (dc->hFont != handle || dc->gdiFont == NULL)
538 if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE)
539 dc->gdiFont = WineEngCreateFontInstance(dc, handle);
542 if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont );
544 if (ret && dc->gdiFont) dc->gdiFont = 0;
546 if (ret == HGDI_ERROR)
547 ret = 0; /* SelectObject returns 0 on error */
548 else
550 ret = dc->hFont;
551 dc->hFont = handle;
553 GDI_ReleaseObj( hdc );
554 return ret;
558 /***********************************************************************
559 * FONT_GetObject16
561 static INT FONT_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
563 FONTOBJ *font = obj;
564 LOGFONT16 lf16;
566 FONT_LogFontWTo16( &font->logfont, &lf16 );
568 if (count > sizeof(LOGFONT16)) count = sizeof(LOGFONT16);
569 memcpy( buffer, &lf16, count );
570 return count;
573 /***********************************************************************
574 * FONT_GetObjectA
576 static INT FONT_GetObjectA( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
578 FONTOBJ *font = obj;
579 LOGFONTA lfA;
581 if(!buffer)
582 return sizeof(lfA);
583 FONT_LogFontWToA( &font->logfont, &lfA );
585 if (count > sizeof(lfA)) count = sizeof(lfA);
586 memcpy( buffer, &lfA, count );
587 return count;
590 /***********************************************************************
591 * FONT_GetObjectW
593 static INT FONT_GetObjectW( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
595 FONTOBJ *font = obj;
596 if(!buffer)
597 return sizeof(LOGFONTW);
598 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
599 memcpy( buffer, &font->logfont, count );
600 return count;
604 /***********************************************************************
605 * FONT_DeleteObject
607 static BOOL FONT_DeleteObject( HGDIOBJ handle, void *obj )
609 WineEngDestroyFontInstance( handle );
610 return GDI_FreeObject( handle, obj );
614 /***********************************************************************
615 * FONT_EnumInstance16
617 * Called by the device driver layer to pass font info
618 * down to the application.
620 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
621 * We have to use other types because of the FONTENUMPROCW definition.
623 static INT CALLBACK FONT_EnumInstance16( const LOGFONTW *plf, const TEXTMETRICW *ptm,
624 DWORD fType, LPARAM lp )
626 fontEnum16 *pfe = (fontEnum16*)lp;
627 INT ret = 1;
628 DC *dc;
630 if( pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
631 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet )
633 WORD args[7];
634 DWORD result;
636 FONT_EnumLogFontExWTo16((const ENUMLOGFONTEXW *)plf, pfe->lpLogFont);
637 FONT_NewTextMetricExWTo16((const NEWTEXTMETRICEXW *)ptm, pfe->lpTextMetric);
638 pfe->dwFlags |= ENUM_CALLED;
639 GDI_ReleaseObj( pfe->hdc ); /* release the GDI lock */
641 args[6] = SELECTOROF(pfe->segLogFont);
642 args[5] = OFFSETOF(pfe->segLogFont);
643 args[4] = SELECTOROF(pfe->segTextMetric);
644 args[3] = OFFSETOF(pfe->segTextMetric);
645 args[2] = fType;
646 args[1] = HIWORD(pfe->lpData);
647 args[0] = LOWORD(pfe->lpData);
648 WOWCallback16Ex( (DWORD)pfe->lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &result );
649 ret = LOWORD(result);
651 /* get the lock again and make sure the DC is still valid */
652 dc = DC_GetDCPtr( pfe->hdc );
653 if (!dc || dc != pfe->dc || dc->physDev != pfe->physDev)
655 if (dc) GDI_ReleaseObj( pfe->hdc );
656 pfe->hdc = 0; /* make sure we don't try to release it later on */
657 ret = 0;
660 return ret;
663 /***********************************************************************
664 * FONT_EnumInstance
666 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
667 * We have to use other types because of the FONTENUMPROCW definition.
669 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
670 DWORD fType, LPARAM lp )
672 fontEnum32 *pfe = (fontEnum32*)lp;
673 INT ret = 1;
674 DC *dc;
676 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
677 if((pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
678 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
679 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
681 /* convert font metrics */
682 ENUMLOGFONTEXA logfont;
683 NEWTEXTMETRICEXA tmA;
685 pfe->dwFlags |= ENUM_CALLED;
686 if (!(pfe->dwFlags & ENUM_UNICODE))
688 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
689 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
690 plf = (LOGFONTW *)&logfont.elfLogFont;
691 ptm = (TEXTMETRICW *)&tmA;
693 GDI_ReleaseObj( pfe->hdc ); /* release the GDI lock */
695 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
697 /* get the lock again and make sure the DC is still valid */
698 dc = DC_GetDCPtr( pfe->hdc );
699 if (!dc || dc != pfe->dc || dc->physDev != pfe->physDev)
701 if (dc) GDI_ReleaseObj( pfe->hdc );
702 pfe->hdc = 0; /* make sure we don't try to release it later on */
703 ret = 0;
706 return ret;
709 /***********************************************************************
710 * EnumFontFamiliesEx (GDI.613)
712 INT16 WINAPI EnumFontFamiliesEx16( HDC16 hDC, LPLOGFONT16 plf,
713 FONTENUMPROC16 efproc, LPARAM lParam,
714 DWORD dwFlags)
716 fontEnum16 fe16;
717 INT16 ret = 1, ret2;
718 DC* dc = DC_GetDCPtr( HDC_32(hDC) );
719 NEWTEXTMETRICEX16 tm16;
720 ENUMLOGFONTEX16 lf16;
721 LOGFONTW lfW;
722 BOOL enum_gdi_fonts;
724 if (!dc) return 0;
725 FONT_LogFont16ToW(plf, &lfW);
727 fe16.hdc = HDC_32(hDC);
728 fe16.dc = dc;
729 fe16.physDev = dc->physDev;
730 fe16.lpLogFontParam = plf;
731 fe16.lpEnumFunc = efproc;
732 fe16.lpData = lParam;
733 fe16.lpTextMetric = &tm16;
734 fe16.lpLogFont = &lf16;
735 fe16.segTextMetric = MapLS( &tm16 );
736 fe16.segLogFont = MapLS( &lf16 );
737 fe16.dwFlags = 0;
739 enum_gdi_fonts = GetDeviceCaps(fe16.hdc, TEXTCAPS) & TC_VA_ABLE;
741 if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
743 ret = 0;
744 goto done;
747 if (enum_gdi_fonts)
748 ret = WineEngEnumFonts( &lfW, FONT_EnumInstance16, (LPARAM)&fe16 );
749 fe16.dwFlags &= ~ENUM_CALLED;
750 if (ret && dc->funcs->pEnumDeviceFonts) {
751 ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, &lfW, FONT_EnumInstance16, (LPARAM)&fe16 );
752 if(fe16.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
753 ret = ret2;
755 done:
756 UnMapLS( fe16.segTextMetric );
757 UnMapLS( fe16.segLogFont );
758 if (fe16.hdc) GDI_ReleaseObj( fe16.hdc );
759 return ret;
762 /***********************************************************************
763 * FONT_EnumFontFamiliesEx
765 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf,
766 FONTENUMPROCW efproc,
767 LPARAM lParam, DWORD dwUnicode)
769 INT ret = 1, ret2;
770 DC *dc = DC_GetDCPtr( hDC );
771 fontEnum32 fe32;
772 BOOL enum_gdi_fonts;
774 if (!dc) return 0;
776 TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName),
777 plf->lfCharSet);
778 fe32.lpLogFontParam = plf;
779 fe32.lpEnumFunc = efproc;
780 fe32.lpData = lParam;
781 fe32.dwFlags = dwUnicode;
782 fe32.hdc = hDC;
783 fe32.dc = dc;
784 fe32.physDev = dc->physDev;
786 enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE;
788 if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
790 ret = 0;
791 goto done;
794 if (enum_gdi_fonts)
795 ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 );
796 fe32.dwFlags &= ~ENUM_CALLED;
797 if (ret && dc->funcs->pEnumDeviceFonts) {
798 ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 );
799 if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
800 ret = ret2;
802 done:
803 if (fe32.hdc) GDI_ReleaseObj( fe32.hdc );
804 return ret;
807 /***********************************************************************
808 * EnumFontFamiliesExW (GDI32.@)
810 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
811 FONTENUMPROCW efproc,
812 LPARAM lParam, DWORD dwFlags )
814 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE );
817 /***********************************************************************
818 * EnumFontFamiliesExA (GDI32.@)
820 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
821 FONTENUMPROCA efproc,
822 LPARAM lParam, DWORD dwFlags)
824 LOGFONTW lfW;
825 FONT_LogFontAToW( plf, &lfW );
827 return FONT_EnumFontFamiliesEx( hDC, &lfW, (FONTENUMPROCW)efproc, lParam, 0);
830 /***********************************************************************
831 * EnumFontFamilies (GDI.330)
833 INT16 WINAPI EnumFontFamilies16( HDC16 hDC, LPCSTR lpFamily,
834 FONTENUMPROC16 efproc, LPARAM lpData )
836 LOGFONT16 lf;
838 lf.lfCharSet = DEFAULT_CHARSET;
839 if( lpFamily ) lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
840 else lf.lfFaceName[0] = '\0';
842 return EnumFontFamiliesEx16( hDC, &lf, efproc, lpData, 0 );
845 /***********************************************************************
846 * EnumFontFamiliesA (GDI32.@)
848 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
849 FONTENUMPROCA efproc, LPARAM lpData )
851 LOGFONTA lf;
853 lf.lfCharSet = DEFAULT_CHARSET;
854 if( lpFamily ) lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
855 else lf.lfFaceName[0] = lf.lfFaceName[1] = '\0';
857 return EnumFontFamiliesExA( hDC, &lf, efproc, lpData, 0 );
860 /***********************************************************************
861 * EnumFontFamiliesW (GDI32.@)
863 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
864 FONTENUMPROCW efproc, LPARAM lpData )
866 LOGFONTW lf;
868 lf.lfCharSet = DEFAULT_CHARSET;
869 if( lpFamily ) lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
870 else lf.lfFaceName[0] = 0;
872 return EnumFontFamiliesExW( hDC, &lf, efproc, lpData, 0 );
875 /***********************************************************************
876 * EnumFonts (GDI.70)
878 INT16 WINAPI EnumFonts16( HDC16 hDC, LPCSTR lpName, FONTENUMPROC16 efproc,
879 LPARAM lpData )
881 return EnumFontFamilies16( hDC, lpName, efproc, lpData );
884 /***********************************************************************
885 * EnumFontsA (GDI32.@)
887 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
888 LPARAM lpData )
890 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
893 /***********************************************************************
894 * EnumFontsW (GDI32.@)
896 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
897 LPARAM lpData )
899 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
903 /***********************************************************************
904 * GetTextCharacterExtra (GDI32.@)
906 INT WINAPI GetTextCharacterExtra( HDC hdc )
908 INT ret;
909 DC *dc = DC_GetDCPtr( hdc );
910 if (!dc) return 0x80000000;
911 ret = dc->charExtra;
912 GDI_ReleaseObj( hdc );
913 return ret;
917 /***********************************************************************
918 * SetTextCharacterExtra (GDI32.@)
920 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
922 INT prev;
923 DC * dc = DC_GetDCPtr( hdc );
924 if (!dc) return 0x80000000;
925 if (dc->funcs->pSetTextCharacterExtra)
926 prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra );
927 else
929 prev = dc->charExtra;
930 dc->charExtra = extra;
932 GDI_ReleaseObj( hdc );
933 return prev;
937 /***********************************************************************
938 * SetTextJustification (GDI32.@)
940 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
942 BOOL ret = TRUE;
943 DC * dc = DC_GetDCPtr( hdc );
944 if (!dc) return FALSE;
945 if (dc->funcs->pSetTextJustification)
946 ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks );
947 else
949 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
950 if (!extra) breaks = 0;
951 if (breaks)
953 dc->breakExtra = extra / breaks;
954 dc->breakRem = extra - (breaks * dc->breakExtra);
956 else
958 dc->breakExtra = 0;
959 dc->breakRem = 0;
962 GDI_ReleaseObj( hdc );
963 return ret;
967 /***********************************************************************
968 * GetTextFaceA (GDI32.@)
970 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
972 INT res = GetTextFaceW(hdc, 0, NULL);
973 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
974 GetTextFaceW( hdc, res, nameW );
976 if (name)
978 if (count && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, count, NULL, NULL))
979 name[count-1] = 0;
980 res = strlen(name);
982 else
983 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
984 HeapFree( GetProcessHeap(), 0, nameW );
985 return res;
988 /***********************************************************************
989 * GetTextFaceW (GDI32.@)
991 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
993 FONTOBJ *font;
994 INT ret = 0;
996 DC * dc = DC_GetDCPtr( hdc );
997 if (!dc) return 0;
999 if(dc->gdiFont)
1000 ret = WineEngGetTextFace(dc->gdiFont, count, name);
1001 else if ((font = (FONTOBJ *) GDI_GetObjPtr( dc->hFont, FONT_MAGIC )))
1003 if (name)
1005 lstrcpynW( name, font->logfont.lfFaceName, count );
1006 ret = strlenW(name);
1008 else ret = strlenW(font->logfont.lfFaceName) + 1;
1009 GDI_ReleaseObj( dc->hFont );
1011 GDI_ReleaseObj( hdc );
1012 return ret;
1016 /***********************************************************************
1017 * GetTextExtentPoint32A (GDI32.@)
1019 * See GetTextExtentPoint32W.
1021 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
1022 LPSIZE size )
1024 BOOL ret = FALSE;
1025 INT wlen;
1026 LPWSTR p = FONT_mbtowc(str, count, &wlen);
1028 if (p) {
1029 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
1030 HeapFree( GetProcessHeap(), 0, p );
1033 TRACE("(%p %s %d %p): returning %ld x %ld\n",
1034 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
1035 return ret;
1039 /***********************************************************************
1040 * GetTextExtentPoint32W [GDI32.@]
1042 * Computes width/height for a string.
1044 * Computes width and height of the specified string.
1046 * RETURNS
1047 * Success: TRUE
1048 * Failure: FALSE
1050 BOOL WINAPI GetTextExtentPoint32W(
1051 HDC hdc, /* [in] Handle of device context */
1052 LPCWSTR str, /* [in] Address of text string */
1053 INT count, /* [in] Number of characters in string */
1054 LPSIZE size) /* [out] Address of structure for string size */
1056 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1059 /***********************************************************************
1060 * GetTextExtentPointI [GDI32.@]
1062 * Computes width and height of the array of glyph indices.
1064 * RETURNS
1065 * Success: TRUE
1066 * Failure: FALSE
1068 BOOL WINAPI GetTextExtentPointI(
1069 HDC hdc, /* [in] Handle of device context */
1070 const WORD *indices, /* [in] Address of glyph index array */
1071 INT count, /* [in] Number of glyphs in array */
1072 LPSIZE size) /* [out] Address of structure for string size */
1074 BOOL ret = FALSE;
1075 DC * dc = DC_GetDCPtr( hdc );
1076 if (!dc) return FALSE;
1078 if(dc->gdiFont) {
1079 ret = WineEngGetTextExtentPointI(dc->gdiFont, indices, count, size);
1080 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1081 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1082 size->cx += count * dc->charExtra;
1084 else if(dc->funcs->pGetTextExtentExPoint) {
1085 FIXME("calling GetTextExtentExPoint\n");
1086 ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, (LPCWSTR)indices,
1087 count, 0, NULL, NULL, size );
1090 GDI_ReleaseObj( hdc );
1092 TRACE("(%p %p %d %p): returning %ld x %ld\n",
1093 hdc, indices, count, size, size->cx, size->cy );
1094 return ret;
1098 /***********************************************************************
1099 * GetTextExtentPointA (GDI32.@)
1101 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1102 LPSIZE size )
1104 TRACE("not bug compatible.\n");
1105 return GetTextExtentPoint32A( hdc, str, count, size );
1108 /***********************************************************************
1109 * GetTextExtentPointW (GDI32.@)
1111 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1112 LPSIZE size )
1114 TRACE("not bug compatible.\n");
1115 return GetTextExtentPoint32W( hdc, str, count, size );
1119 /***********************************************************************
1120 * GetTextExtentExPointA (GDI32.@)
1122 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1123 INT maxExt, LPINT lpnFit,
1124 LPINT alpDx, LPSIZE size )
1126 BOOL ret;
1127 INT wlen;
1128 INT *walpDx = NULL;
1129 LPWSTR p = NULL;
1131 if (alpDx &&
1132 NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
1133 return FALSE;
1135 p = FONT_mbtowc(str, count, &wlen);
1136 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1137 if (walpDx)
1139 INT n = lpnFit ? *lpnFit : wlen;
1140 INT i, j;
1141 for(i = 0, j = 0; i < n; i++, j++)
1143 alpDx[j] = walpDx[i];
1144 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1147 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1148 HeapFree( GetProcessHeap(), 0, p );
1149 HeapFree( GetProcessHeap(), 0, walpDx );
1150 return ret;
1154 /***********************************************************************
1155 * GetTextExtentExPointW (GDI32.@)
1157 * Return the size of the string as it would be if it was output properly by
1158 * e.g. TextOut.
1160 * This should include
1161 * - Intercharacter spacing
1162 * - justification spacing (not yet done)
1163 * - kerning? see below
1165 * Kerning. Since kerning would be carried out by the rendering code it should
1166 * be done by the driver. However they don't support it yet. Also I am not
1167 * yet persuaded that (certainly under Win95) any kerning is actually done.
1169 * str: According to MSDN this should be null-terminated. That is not true; a
1170 * null will not terminate it early.
1171 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1172 * than count. I have seen it be either the size of the full string or
1173 * 1 less than the size of the full string. I have not seen it bear any
1174 * resemblance to the portion that would fit.
1175 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1176 * trailing intercharacter spacing and any trailing justification.
1178 * FIXME
1179 * Currently we do this by measuring each character etc. We should do it by
1180 * passing the request to the driver, perhaps by extending the
1181 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1182 * thinking about kerning issues and rounding issues in the justification.
1185 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1186 INT maxExt, LPINT lpnFit,
1187 LPINT alpDx, LPSIZE size )
1189 INT nFit = 0;
1190 LPINT dxs = NULL;
1191 DC *dc;
1192 BOOL ret = FALSE;
1194 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1196 dc = DC_GetDCPtr(hdc);
1197 if (! dc)
1198 return FALSE;
1200 /* If we need to calculate nFit, then we need the partial extents even if
1201 the user hasn't provided us with an array. */
1202 if (lpnFit)
1204 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1205 if (! dxs)
1207 GDI_ReleaseObj(hdc);
1208 SetLastError(ERROR_OUTOFMEMORY);
1209 return FALSE;
1212 else
1213 dxs = alpDx;
1215 if (dc->gdiFont)
1216 ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
1217 0, NULL, dxs, size);
1218 else if (dc->funcs->pGetTextExtentExPoint)
1219 ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
1220 0, NULL, dxs, size);
1222 /* Perform device size to world size transformations. */
1223 if (ret)
1225 INT extra = dc->charExtra, breakRem = dc->breakRem;
1227 if (dxs)
1229 INT i;
1230 for (i = 0; i < count; ++i)
1232 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1233 dxs[i] += (i+1) * extra + breakRem;
1234 if (dxs[i] <= maxExt)
1235 ++nFit;
1238 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1239 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1240 size->cx += count * extra + breakRem;
1243 if (lpnFit)
1244 *lpnFit = nFit;
1246 if (! alpDx)
1247 HeapFree(GetProcessHeap(), 0, dxs);
1249 GDI_ReleaseObj( hdc );
1251 TRACE("returning %d %ld x %ld\n",nFit,size->cx,size->cy);
1252 return ret;
1255 /***********************************************************************
1256 * GetTextMetricsA (GDI32.@)
1258 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1260 TEXTMETRICW tm32;
1262 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1263 FONT_TextMetricWToA( &tm32, metrics );
1264 return TRUE;
1267 /***********************************************************************
1268 * GetTextMetricsW (GDI32.@)
1270 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1272 BOOL ret = FALSE;
1273 DC * dc = DC_GetDCPtr( hdc );
1274 if (!dc) return FALSE;
1276 if (dc->gdiFont)
1277 ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1278 else if (dc->funcs->pGetTextMetrics)
1279 ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1281 if (ret)
1283 /* device layer returns values in device units
1284 * therefore we have to convert them to logical */
1286 #define WDPTOLP(x) ((x<0)? \
1287 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1288 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1289 #define HDPTOLP(y) ((y<0)? \
1290 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1291 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1293 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1294 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1295 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1296 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1297 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1298 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1299 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1300 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1301 ret = TRUE;
1302 #undef WDPTOLP
1303 #undef HDPTOLP
1304 TRACE("text metrics:\n"
1305 " Weight = %03li\t FirstChar = %i\t AveCharWidth = %li\n"
1306 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %li\n"
1307 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %li\n"
1308 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1309 " PitchAndFamily = %02x\n"
1310 " --------------------\n"
1311 " InternalLeading = %li\n"
1312 " Ascent = %li\n"
1313 " Descent = %li\n"
1314 " Height = %li\n",
1315 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1316 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1317 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1318 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1319 metrics->tmPitchAndFamily,
1320 metrics->tmInternalLeading,
1321 metrics->tmAscent,
1322 metrics->tmDescent,
1323 metrics->tmHeight );
1325 GDI_ReleaseObj( hdc );
1326 return ret;
1330 /***********************************************************************
1331 * GetOutlineTextMetrics [GDI.308] Gets metrics for TrueType fonts.
1333 * NOTES
1334 * lpOTM should be LPOUTLINETEXTMETRIC
1336 * RETURNS
1337 * Success: Non-zero or size of required buffer
1338 * Failure: 0
1340 UINT16 WINAPI GetOutlineTextMetrics16(
1341 HDC16 hdc, /* [in] Handle of device context */
1342 UINT16 cbData, /* [in] Size of metric data array */
1343 LPOUTLINETEXTMETRIC16 lpOTM) /* [out] Address of metric data array */
1345 FIXME("(%04x,%04x,%p): stub\n", hdc,cbData,lpOTM);
1346 return 0;
1350 /***********************************************************************
1351 * GetOutlineTextMetricsA (GDI32.@)
1352 * Gets metrics for TrueType fonts.
1354 * NOTES
1355 * If the supplied buffer isn't big enough Windows partially fills it up to
1356 * its given length and returns that length.
1358 * RETURNS
1359 * Success: Non-zero or size of required buffer
1360 * Failure: 0
1362 UINT WINAPI GetOutlineTextMetricsA(
1363 HDC hdc, /* [in] Handle of device context */
1364 UINT cbData, /* [in] Size of metric data array */
1365 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1367 char buf[512], *ptr;
1368 UINT ret, needed;
1369 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1370 OUTLINETEXTMETRICA *output = lpOTM;
1371 INT left, len;
1373 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1374 return 0;
1375 if(ret > sizeof(buf))
1376 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1377 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1379 needed = sizeof(OUTLINETEXTMETRICA);
1380 if(lpOTMW->otmpFamilyName)
1381 needed += WideCharToMultiByte(CP_ACP, 0,
1382 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1383 NULL, 0, NULL, NULL);
1384 if(lpOTMW->otmpFaceName)
1385 needed += WideCharToMultiByte(CP_ACP, 0,
1386 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1387 NULL, 0, NULL, NULL);
1388 if(lpOTMW->otmpStyleName)
1389 needed += WideCharToMultiByte(CP_ACP, 0,
1390 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1391 NULL, 0, NULL, NULL);
1392 if(lpOTMW->otmpFullName)
1393 needed += WideCharToMultiByte(CP_ACP, 0,
1394 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1395 NULL, 0, NULL, NULL);
1397 if(!lpOTM) {
1398 ret = needed;
1399 goto end;
1402 TRACE("needed = %d\n", needed);
1403 if(needed > cbData)
1404 /* Since the supplied buffer isn't big enough, we'll alloc one
1405 that is and memcpy the first cbData bytes into the lpOTM at
1406 the end. */
1407 output = HeapAlloc(GetProcessHeap(), 0, needed);
1409 ret = output->otmSize = min(needed, cbData);
1410 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1411 output->otmFiller = 0;
1412 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1413 output->otmfsSelection = lpOTMW->otmfsSelection;
1414 output->otmfsType = lpOTMW->otmfsType;
1415 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1416 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1417 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1418 output->otmEMSquare = lpOTMW->otmEMSquare;
1419 output->otmAscent = lpOTMW->otmAscent;
1420 output->otmDescent = lpOTMW->otmDescent;
1421 output->otmLineGap = lpOTMW->otmLineGap;
1422 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1423 output->otmsXHeight = lpOTMW->otmsXHeight;
1424 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1425 output->otmMacAscent = lpOTMW->otmMacAscent;
1426 output->otmMacDescent = lpOTMW->otmMacDescent;
1427 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1428 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1429 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1430 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1431 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1432 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1433 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1434 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1435 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1436 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1439 ptr = (char*)(output + 1);
1440 left = needed - sizeof(*output);
1442 if(lpOTMW->otmpFamilyName) {
1443 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1444 len = WideCharToMultiByte(CP_ACP, 0,
1445 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1446 ptr, left, NULL, NULL);
1447 left -= len;
1448 ptr += len;
1449 } else
1450 output->otmpFamilyName = 0;
1452 if(lpOTMW->otmpFaceName) {
1453 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1454 len = WideCharToMultiByte(CP_ACP, 0,
1455 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1456 ptr, left, NULL, NULL);
1457 left -= len;
1458 ptr += len;
1459 } else
1460 output->otmpFaceName = 0;
1462 if(lpOTMW->otmpStyleName) {
1463 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1464 len = WideCharToMultiByte(CP_ACP, 0,
1465 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1466 ptr, left, NULL, NULL);
1467 left -= len;
1468 ptr += len;
1469 } else
1470 output->otmpStyleName = 0;
1472 if(lpOTMW->otmpFullName) {
1473 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1474 len = WideCharToMultiByte(CP_ACP, 0,
1475 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1476 ptr, left, NULL, NULL);
1477 left -= len;
1478 } else
1479 output->otmpFullName = 0;
1481 assert(left == 0);
1483 if(output != lpOTM) {
1484 memcpy(lpOTM, output, cbData);
1485 HeapFree(GetProcessHeap(), 0, output);
1488 end:
1489 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1490 HeapFree(GetProcessHeap(), 0, lpOTMW);
1492 return ret;
1496 /***********************************************************************
1497 * GetOutlineTextMetricsW [GDI32.@]
1499 UINT WINAPI GetOutlineTextMetricsW(
1500 HDC hdc, /* [in] Handle of device context */
1501 UINT cbData, /* [in] Size of metric data array */
1502 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1504 DC *dc = DC_GetDCPtr( hdc );
1505 OUTLINETEXTMETRICW *output = lpOTM;
1506 UINT ret;
1508 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1509 if(!dc) return 0;
1511 if(dc->gdiFont) {
1512 ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1513 if(lpOTM && ret) {
1514 if(ret > cbData) {
1515 output = HeapAlloc(GetProcessHeap(), 0, ret);
1516 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1519 #define WDPTOLP(x) ((x<0)? \
1520 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1521 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1522 #define HDPTOLP(y) ((y<0)? \
1523 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1524 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1526 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1527 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1528 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1529 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1530 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1531 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1532 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1533 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1534 output->otmAscent = HDPTOLP(output->otmAscent);
1535 output->otmDescent = HDPTOLP(output->otmDescent);
1536 output->otmLineGap = HDPTOLP(output->otmLineGap);
1537 output->otmsCapEmHeight = HDPTOLP(output->otmsCapEmHeight);
1538 output->otmsXHeight = HDPTOLP(output->otmsXHeight);
1539 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1540 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1541 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1542 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1543 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1544 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1545 output->otmMacLineGap = HDPTOLP(output->otmMacLineGap);
1546 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1547 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1548 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1549 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1550 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1551 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1552 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1553 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1554 output->otmsStrikeoutSize = HDPTOLP(output->otmsStrikeoutSize);
1555 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1556 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1557 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1558 #undef WDPTOLP
1559 #undef HDPTOLP
1560 if(output != lpOTM) {
1561 memcpy(lpOTM, output, cbData);
1562 HeapFree(GetProcessHeap(), 0, output);
1563 ret = cbData;
1568 else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1569 but really this should just be a return 0. */
1571 ret = sizeof(*lpOTM);
1572 if (lpOTM) {
1573 if(cbData < ret)
1574 ret = 0;
1575 else {
1576 memset(lpOTM, 0, ret);
1577 lpOTM->otmSize = sizeof(*lpOTM);
1578 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1580 Further fill of the structure not implemented,
1581 Needs real values for the structure members
1586 GDI_ReleaseObj(hdc);
1587 return ret;
1591 /***********************************************************************
1592 * GetCharWidthW (GDI32.@)
1593 * GetCharWidth32W (GDI32.@)
1595 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1596 LPINT buffer )
1598 UINT i;
1599 BOOL ret = FALSE;
1600 DC * dc = DC_GetDCPtr( hdc );
1601 if (!dc) return FALSE;
1603 if (dc->gdiFont)
1604 ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1605 else if (dc->funcs->pGetCharWidth)
1606 ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1608 if (ret)
1610 /* convert device units to logical */
1611 for( i = firstChar; i <= lastChar; i++, buffer++ )
1612 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1613 ret = TRUE;
1615 GDI_ReleaseObj( hdc );
1616 return ret;
1620 /***********************************************************************
1621 * GetCharWidthA (GDI32.@)
1622 * GetCharWidth32A (GDI32.@)
1624 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1625 LPINT buffer )
1627 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
1628 LPSTR str;
1629 LPWSTR wstr;
1630 BOOL ret = TRUE;
1632 if(count <= 0) return FALSE;
1634 str = HeapAlloc(GetProcessHeap(), 0, count);
1635 for(i = 0; i < count; i++)
1636 str[i] = (BYTE)(firstChar + i);
1638 wstr = FONT_mbtowc(str, count, &wlen);
1640 for(i = 0; i < wlen; i++)
1642 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1644 ret = FALSE;
1645 break;
1647 buffer++;
1650 HeapFree(GetProcessHeap(), 0, str);
1651 HeapFree(GetProcessHeap(), 0, wstr);
1653 return ret;
1657 /***********************************************************************
1658 * ExtTextOutA (GDI32.@)
1660 * See ExtTextOutW.
1662 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1663 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1665 INT wlen;
1666 LPWSTR p;
1667 BOOL ret;
1668 LPINT lpDxW = NULL;
1670 if (flags & ETO_GLYPH_INDEX)
1671 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1673 p = FONT_mbtowc(str, count, &wlen);
1675 if (lpDx) {
1676 unsigned int i = 0, j = 0;
1678 lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT));
1679 while(i < count) {
1680 if(IsDBCSLeadByte(str[i])) {
1681 lpDxW[j++] = lpDx[i] + lpDx[i+1];
1682 i = i + 2;
1683 } else {
1684 lpDxW[j++] = lpDx[i];
1685 i = i + 1;
1690 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1692 HeapFree( GetProcessHeap(), 0, p );
1693 HeapFree( GetProcessHeap(), 0, lpDxW );
1694 return ret;
1698 /***********************************************************************
1699 * ExtTextOutW (GDI32.@)
1701 * Draws text using the currently selected font, background color, and text color.
1704 * PARAMS
1705 * x,y [I] coordinates of string
1706 * flags [I]
1707 * ETO_GRAYED - undocumented on MSDN
1708 * ETO_OPAQUE - use background color for fill the rectangle
1709 * ETO_CLIPPED - clipping text to the rectangle
1710 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1711 * than encoded characters. Implies ETO_IGNORELANGUAGE
1712 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1713 * Affects BiDi ordering
1714 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1715 * ETO_PDY - unimplemented
1716 * ETO_NUMERICSLATIN - unimplemented always assumed -
1717 * do not translate numbers into locale representations
1718 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1719 * lprect [I] dimensions for clipping or/and opaquing
1720 * str [I] text string
1721 * count [I] number of symbols in string
1722 * lpDx [I] optional parameter with distance between drawing characters
1724 * RETURNS
1725 * Success: TRUE
1726 * Failure: FALSE
1728 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1729 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1731 BOOL ret = FALSE;
1732 LPWSTR reordered_str = (LPWSTR)str;
1733 WORD *glyphs = NULL;
1734 UINT align = GetTextAlign( hdc );
1735 POINT pt;
1736 TEXTMETRICW tm;
1737 LOGFONTW lf;
1738 double cosEsc, sinEsc;
1739 INT *deltas = NULL, char_extra;
1740 SIZE sz;
1741 RECT rc;
1742 BOOL done_extents = FALSE;
1743 INT width, xwidth = 0, ywidth = 0;
1744 DWORD type;
1745 DC * dc = DC_GetDCUpdate( hdc );
1747 if (!dc) return FALSE;
1749 if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
1750 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
1752 if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1754 GDI_ReleaseObj( hdc );
1755 return ret;
1758 type = GetObjectType(hdc);
1759 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1761 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1762 GDI_ReleaseObj( hdc );
1763 return ret;
1766 if (!lprect)
1767 flags &= ~ETO_CLIPPED;
1769 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && BidiAvail && count > 0 )
1771 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1773 BIDI_Reorder( str, count, GCP_REORDER,
1774 ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
1775 WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
1776 reordered_str, count, NULL );
1778 flags |= ETO_IGNORELANGUAGE;
1781 TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
1782 lprect, debugstr_wn(str, count), count, lpDx);
1784 if(flags & ETO_GLYPH_INDEX)
1785 glyphs = reordered_str;
1787 if(lprect)
1788 TRACE("rect: %ld,%ld - %ld,%ld\n", lprect->left, lprect->top, lprect->right,
1789 lprect->bottom);
1790 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1792 if(align & TA_UPDATECP)
1794 GetCurrentPositionEx( hdc, &pt );
1795 x = pt.x;
1796 y = pt.y;
1799 GetTextMetricsW(hdc, &tm);
1800 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1802 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1803 lf.lfEscapement = 0;
1805 if(lf.lfEscapement != 0)
1807 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1808 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1810 else
1812 cosEsc = 1;
1813 sinEsc = 0;
1816 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1818 if(!lprect)
1820 if(flags & ETO_GLYPH_INDEX)
1821 GetTextExtentPointI(hdc, glyphs, count, &sz);
1822 else
1823 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1825 done_extents = TRUE;
1826 rc.left = x;
1827 rc.top = y;
1828 rc.right = x + sz.cx;
1829 rc.bottom = y + sz.cy;
1831 else
1833 rc = *lprect;
1836 LPtoDP(hdc, (POINT*)&rc, 2);
1838 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1839 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1842 if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1843 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1845 if(count == 0)
1847 ret = TRUE;
1848 goto done;
1851 pt.x = x;
1852 pt.y = y;
1853 LPtoDP(hdc, &pt, 1);
1854 x = pt.x;
1855 y = pt.y;
1857 char_extra = GetTextCharacterExtra(hdc);
1858 width = 0;
1859 if(char_extra || dc->breakExtra || lpDx)
1861 UINT i;
1862 SIZE tmpsz;
1863 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
1864 for(i = 0; i < count; i++)
1866 if(lpDx && (flags & ETO_PDY))
1867 deltas[i] = lpDx[i*2] + char_extra;
1868 else if(lpDx)
1869 deltas[i] = lpDx[i] + char_extra;
1870 else
1872 if(flags & ETO_GLYPH_INDEX)
1873 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1874 else
1875 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
1877 deltas[i] = tmpsz.cx;
1880 if (!(flags & ETO_GLYPH_INDEX) && dc->breakExtra && reordered_str[i] == tm.tmBreakChar)
1882 deltas[i] = deltas[i] + dc->breakExtra;
1884 deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
1885 width += deltas[i];
1888 else
1890 if(!done_extents)
1892 if(flags & ETO_GLYPH_INDEX)
1893 GetTextExtentPointI(hdc, glyphs, count, &sz);
1894 else
1895 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1896 done_extents = TRUE;
1898 width = INTERNAL_XWSTODS(dc, sz.cx);
1900 xwidth = width * cosEsc;
1901 ywidth = width * sinEsc;
1903 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
1904 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
1905 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
1907 case TA_LEFT:
1908 if (align & TA_UPDATECP)
1910 pt.x = x + xwidth;
1911 pt.y = y - ywidth;
1912 DPtoLP(hdc, &pt, 1);
1913 MoveToEx(hdc, pt.x, pt.y, NULL);
1915 break;
1917 case TA_CENTER:
1918 x -= xwidth / 2;
1919 y += ywidth / 2;
1920 break;
1922 case TA_RIGHT:
1923 x -= xwidth;
1924 y += ywidth;
1925 if (align & TA_UPDATECP)
1927 pt.x = x;
1928 pt.y = y;
1929 DPtoLP(hdc, &pt, 1);
1930 MoveToEx(hdc, pt.x, pt.y, NULL);
1932 break;
1935 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
1937 case TA_TOP:
1938 y += tm.tmAscent * cosEsc;
1939 x += tm.tmAscent * sinEsc;
1940 break;
1942 case TA_BOTTOM:
1943 y -= tm.tmDescent * cosEsc;
1944 x -= tm.tmDescent * sinEsc;
1945 break;
1947 case TA_BASELINE:
1948 break;
1951 if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
1953 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
1955 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
1956 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
1958 RECT rc;
1959 rc.left = x;
1960 rc.right = x + width;
1961 rc.top = y - tm.tmAscent;
1962 rc.bottom = y + tm.tmDescent;
1963 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1968 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
1970 HFONT orig_font = dc->hFont, cur_font;
1971 UINT glyph;
1972 INT span = 0, *offsets = NULL, i;
1974 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1975 for(i = 0; i < count; i++)
1977 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
1978 if(cur_font != dc->hFont)
1980 if(!offsets)
1982 int j;
1983 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
1984 offsets[0] = 0;
1985 if(!deltas)
1987 SIZE tmpsz;
1988 for(j = 1; j < count; j++)
1990 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
1991 offsets[j] = offsets[j-1] + INTERNAL_XWSTODS(dc, tmpsz.cx);
1994 else
1996 for(j = 1; j < count; j++)
1997 offsets[j] = offsets[j-1] + deltas[j];
2000 if(span)
2002 if (PATH_IsPathOpen(dc->path))
2003 ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
2004 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2005 glyphs, span, deltas ? deltas + i - span : NULL);
2006 else
2007 dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
2008 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2009 glyphs, span, deltas ? deltas + i - span : NULL);
2010 span = 0;
2012 SelectObject(hdc, cur_font);
2014 glyphs[span++] = glyph;
2016 if(i == count - 1)
2018 if (PATH_IsPathOpen(dc->path))
2019 ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
2020 y - (offsets ? offsets[count - span] * sinEsc : 0),
2021 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2022 glyphs, span, deltas ? deltas + count - span : NULL);
2023 else
2024 ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
2025 y - (offsets ? offsets[count - span] * sinEsc : 0),
2026 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2027 glyphs, span, deltas ? deltas + count - span : NULL);
2028 SelectObject(hdc, orig_font);
2029 HeapFree(GetProcessHeap(), 0, offsets);
2033 else
2035 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2037 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2038 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2039 flags |= ETO_GLYPH_INDEX;
2042 if (PATH_IsPathOpen(dc->path))
2043 ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
2044 glyphs ? glyphs : reordered_str, count, deltas);
2045 else
2046 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
2047 glyphs ? glyphs : reordered_str, count, deltas);
2050 done:
2051 HeapFree(GetProcessHeap(), 0, deltas);
2052 if(glyphs != reordered_str)
2053 HeapFree(GetProcessHeap(), 0, glyphs);
2054 if(reordered_str != str)
2055 HeapFree(GetProcessHeap(), 0, reordered_str);
2057 GDI_ReleaseObj( hdc );
2059 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2061 int underlinePos, strikeoutPos;
2062 int underlineWidth, strikeoutWidth;
2063 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2064 OUTLINETEXTMETRICW* otm = NULL;
2066 if(!size)
2068 underlinePos = 0;
2069 underlineWidth = tm.tmAscent / 20 + 1;
2070 strikeoutPos = tm.tmAscent / 2;
2071 strikeoutWidth = underlineWidth;
2073 else
2075 otm = HeapAlloc(GetProcessHeap(), 0, size);
2076 GetOutlineTextMetricsW(hdc, size, otm);
2077 underlinePos = otm->otmsUnderscorePosition;
2078 underlineWidth = otm->otmsUnderscoreSize;
2079 strikeoutPos = otm->otmsStrikeoutPosition;
2080 strikeoutWidth = otm->otmsStrikeoutSize;
2081 HeapFree(GetProcessHeap(), 0, otm);
2084 if (PATH_IsPathOpen(dc->path))
2086 POINT pts[5];
2087 HPEN hpen;
2088 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2090 hbrush = SelectObject(hdc, hbrush);
2091 hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2093 if (lf.lfUnderline)
2095 pts[0].x = x - underlinePos * sinEsc;
2096 pts[0].y = y - underlinePos * cosEsc;
2097 pts[1].x = x + xwidth - underlinePos * sinEsc;
2098 pts[1].y = y - ywidth - underlinePos * cosEsc;
2099 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2100 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2101 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2102 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2103 pts[4].x = pts[0].x;
2104 pts[4].y = pts[0].y;
2105 DPtoLP(hdc, pts, 5);
2106 Polygon(hdc, pts, 5);
2109 if (lf.lfStrikeOut)
2111 pts[0].x = x - strikeoutPos * sinEsc;
2112 pts[0].y = y - strikeoutPos * cosEsc;
2113 pts[1].x = x + xwidth - strikeoutPos * sinEsc;
2114 pts[1].y = y - ywidth - strikeoutPos * cosEsc;
2115 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2116 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2117 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2118 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2119 pts[4].x = pts[0].x;
2120 pts[4].y = pts[0].y;
2121 DPtoLP(hdc, pts, 5);
2122 Polygon(hdc, pts, 5);
2125 SelectObject(hdc, hpen);
2126 hbrush = SelectObject(hdc, hbrush);
2127 DeleteObject(hbrush);
2129 else
2131 POINT pts[2], oldpt;
2132 HPEN hpen;
2134 if (lf.lfUnderline)
2136 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2137 hpen = SelectObject(hdc, hpen);
2138 pts[0].x = x;
2139 pts[0].y = y;
2140 pts[1].x = x + xwidth;
2141 pts[1].y = y - ywidth;
2142 DPtoLP(hdc, pts, 2);
2143 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2144 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2145 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2146 DeleteObject(SelectObject(hdc, hpen));
2149 if (lf.lfStrikeOut)
2151 hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
2152 hpen = SelectObject(hdc, hpen);
2153 pts[0].x = x;
2154 pts[0].y = y;
2155 pts[1].x = x + xwidth;
2156 pts[1].y = y - ywidth;
2157 DPtoLP(hdc, pts, 2);
2158 MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2159 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2160 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2161 DeleteObject(SelectObject(hdc, hpen));
2166 return ret;
2170 /***********************************************************************
2171 * TextOutA (GDI32.@)
2173 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2175 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2179 /***********************************************************************
2180 * TextOutW (GDI32.@)
2182 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2184 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2188 /***********************************************************************
2189 * PolyTextOutA (GDI32.@)
2191 * See PolyTextOutW.
2193 BOOL WINAPI PolyTextOutA ( HDC hdc, /* [in] Handle to device context */
2194 PPOLYTEXTA pptxt, /* [in] Array of strings */
2195 INT cStrings ) /* [in] Number of strings in array */
2197 for (; cStrings>0; cStrings--, pptxt++)
2198 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2199 return FALSE;
2200 return TRUE;
2205 /***********************************************************************
2206 * PolyTextOutW (GDI32.@)
2208 * Draw several Strings
2210 * RETURNS
2211 * TRUE: Success.
2212 * FALSE: Failure.
2214 BOOL WINAPI PolyTextOutW ( HDC hdc, /* [in] Handle to device context */
2215 PPOLYTEXTW pptxt, /* [in] Array of strings */
2216 INT cStrings ) /* [in] Number of strings in array */
2218 for (; cStrings>0; cStrings--, pptxt++)
2219 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2220 return FALSE;
2221 return TRUE;
2225 /* FIXME: all following APIs ******************************************/
2228 /***********************************************************************
2229 * SetMapperFlags (GDI32.@)
2231 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2233 DC *dc = DC_GetDCPtr( hDC );
2234 DWORD ret = 0;
2235 if(!dc) return 0;
2236 if(dc->funcs->pSetMapperFlags)
2238 ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2239 /* FIXME: ret is just a success flag, we should return a proper value */
2241 else
2242 FIXME("(%p, 0x%08lx): stub - harmless\n", hDC, dwFlag);
2243 GDI_ReleaseObj( hDC );
2244 return ret;
2247 /***********************************************************************
2248 * GetAspectRatioFilterEx (GDI.486)
2250 BOOL16 WINAPI GetAspectRatioFilterEx16( HDC16 hdc, LPSIZE16 pAspectRatio )
2252 FIXME("(%04x, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2253 return FALSE;
2256 /***********************************************************************
2257 * GetAspectRatioFilterEx (GDI32.@)
2259 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2261 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2262 return FALSE;
2266 /***********************************************************************
2267 * GetCharABCWidthsA (GDI32.@)
2269 * See GetCharABCWidthsW.
2271 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2272 LPABC abc )
2274 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
2275 LPSTR str;
2276 LPWSTR wstr;
2277 BOOL ret = TRUE;
2279 if(count <= 0) return FALSE;
2281 str = HeapAlloc(GetProcessHeap(), 0, count);
2282 for(i = 0; i < count; i++)
2283 str[i] = (BYTE)(firstChar + i);
2285 wstr = FONT_mbtowc(str, count, &wlen);
2287 for(i = 0; i < wlen; i++)
2289 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2291 ret = FALSE;
2292 break;
2294 abc++;
2297 HeapFree(GetProcessHeap(), 0, str);
2298 HeapFree(GetProcessHeap(), 0, wstr);
2300 return ret;
2304 /******************************************************************************
2305 * GetCharABCWidthsW [GDI32.@]
2307 * Retrieves widths of characters in range.
2309 * PARAMS
2310 * hdc [I] Handle of device context
2311 * firstChar [I] First character in range to query
2312 * lastChar [I] Last character in range to query
2313 * abc [O] Address of character-width structure
2315 * NOTES
2316 * Only works with TrueType fonts
2318 * RETURNS
2319 * Success: TRUE
2320 * Failure: FALSE
2322 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2323 LPABC abc )
2325 DC *dc = DC_GetDCPtr(hdc);
2326 unsigned int i;
2327 BOOL ret = FALSE;
2329 if (!dc) return FALSE;
2331 if(dc->gdiFont)
2332 ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2333 else
2334 FIXME(": stub\n");
2336 if (ret)
2338 /* convert device units to logical */
2339 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2340 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2341 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2342 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2344 ret = TRUE;
2347 GDI_ReleaseObj(hdc);
2348 return ret;
2352 /******************************************************************************
2353 * GetCharABCWidthsI [GDI32.@]
2355 * Retrieves widths of characters in range.
2357 * PARAMS
2358 * hdc [I] Handle of device context
2359 * firstChar [I] First glyphs in range to query
2360 * count [I] Last glyphs in range to query
2361 * pgi [i] Array of glyphs to query
2362 * abc [O] Address of character-width structure
2364 * NOTES
2365 * Only works with TrueType fonts
2367 * RETURNS
2368 * Success: TRUE
2369 * Failure: FALSE
2371 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2372 LPWORD pgi, LPABC abc)
2374 DC *dc = DC_GetDCPtr(hdc);
2375 unsigned int i;
2376 BOOL ret = FALSE;
2378 if (!dc) return FALSE;
2380 if(dc->gdiFont)
2381 ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2382 else
2383 FIXME(": stub\n");
2385 if (ret)
2387 /* convert device units to logical */
2388 for( i = 0; i < count; i++, abc++ ) {
2389 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2390 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2391 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2393 ret = TRUE;
2396 GDI_ReleaseObj(hdc);
2397 return ret;
2401 /***********************************************************************
2402 * GetGlyphOutlineA (GDI32.@)
2404 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2405 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2406 LPVOID lpBuffer, const MAT2 *lpmat2 )
2408 LPWSTR p = NULL;
2409 DWORD ret;
2410 UINT c;
2412 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2413 int len;
2414 char mbchs[2];
2415 if(uChar > 0xff) { /* but, 2 bytes character only */
2416 len = 2;
2417 mbchs[0] = (uChar & 0xff00) >> 8;
2418 mbchs[1] = (uChar & 0xff);
2419 } else {
2420 len = 1;
2421 mbchs[0] = (uChar & 0xff);
2423 p = FONT_mbtowc(mbchs, len, NULL);
2424 c = p[0];
2425 } else
2426 c = uChar;
2427 ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
2428 lpmat2);
2429 HeapFree(GetProcessHeap(), 0, p);
2430 return ret;
2433 /***********************************************************************
2434 * GetGlyphOutlineW (GDI32.@)
2436 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2437 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2438 LPVOID lpBuffer, const MAT2 *lpmat2 )
2440 DC *dc = DC_GetDCPtr(hdc);
2441 DWORD ret;
2443 TRACE("(%p, %04x, %04x, %p, %ld, %p, %p)\n",
2444 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2446 if(!dc) return GDI_ERROR;
2448 if(dc->gdiFont)
2449 ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2450 cbBuffer, lpBuffer, lpmat2);
2451 else
2452 ret = GDI_ERROR;
2454 GDI_ReleaseObj(hdc);
2455 return ret;
2459 /***********************************************************************
2460 * CreateScalableFontResourceA (GDI32.@)
2462 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2463 LPCSTR lpszResourceFile,
2464 LPCSTR lpszFontFile,
2465 LPCSTR lpszCurrentPath )
2467 HANDLE f;
2469 /* fHidden=1 - only visible for the calling app, read-only, not
2470 * enumbered with EnumFonts/EnumFontFamilies
2471 * lpszCurrentPath can be NULL
2473 FIXME("(%ld,%s,%s,%s): stub\n",
2474 fHidden, debugstr_a(lpszResourceFile), debugstr_a(lpszFontFile),
2475 debugstr_a(lpszCurrentPath) );
2477 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2478 if ((f = CreateFileA(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2479 CloseHandle(f);
2480 SetLastError(ERROR_FILE_EXISTS);
2481 return FALSE;
2483 return FALSE; /* create failed */
2486 /***********************************************************************
2487 * CreateScalableFontResourceW (GDI32.@)
2489 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2490 LPCWSTR lpszResourceFile,
2491 LPCWSTR lpszFontFile,
2492 LPCWSTR lpszCurrentPath )
2494 FIXME("(%ld,%p,%p,%p): stub\n",
2495 fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath );
2496 return FALSE; /* create failed */
2499 /*************************************************************************
2500 * GetKerningPairsA (GDI32.@)
2502 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2503 LPKERNINGPAIR lpKerningPairs )
2505 return GetKerningPairsW( hDC, cPairs, lpKerningPairs );
2509 /*************************************************************************
2510 * GetKerningPairsW (GDI32.@)
2512 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2513 LPKERNINGPAIR lpKerningPairs )
2515 unsigned int i;
2516 FIXME("(%p,%ld,%p): almost empty stub!\n", hDC, cPairs, lpKerningPairs);
2518 if(!lpKerningPairs) /* return the number of kerning pairs */
2519 return 0;
2521 for (i = 0; i < cPairs; i++)
2522 lpKerningPairs[i].iKernAmount = 0;
2523 return 0;
2526 /*************************************************************************
2527 * TranslateCharsetInfo [GDI32.@]
2529 * Fills a CHARSETINFO structure for a character set, code page, or
2530 * font. This allows making the correspondance between different labelings
2531 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2532 * of the same encoding.
2534 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2535 * only one codepage should be set in *lpSrc.
2537 * RETURNS
2538 * TRUE on success, FALSE on failure.
2541 BOOL WINAPI TranslateCharsetInfo(
2542 LPDWORD lpSrc, /* [in]
2543 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2544 if flags == TCI_SRCCHARSET: a character set value
2545 if flags == TCI_SRCCODEPAGE: a code page value
2547 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2548 DWORD flags /* [in] determines interpretation of lpSrc */)
2550 int index = 0;
2551 switch (flags) {
2552 case TCI_SRCFONTSIG:
2553 while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
2554 break;
2555 case TCI_SRCCODEPAGE:
2556 while ((UINT) (lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
2557 break;
2558 case TCI_SRCCHARSET:
2559 while ((UINT) (lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
2560 break;
2561 default:
2562 return FALSE;
2564 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2565 memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO));
2566 return TRUE;
2569 /*************************************************************************
2570 * GetFontLanguageInfo (GDI32.@)
2572 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2574 FONTSIGNATURE fontsig;
2575 static const DWORD GCP_DBCS_MASK=0x003F0000,
2576 GCP_DIACRITIC_MASK=0x00000000,
2577 FLI_GLYPHS_MASK=0x00000000,
2578 GCP_GLYPHSHAPE_MASK=0x00000040,
2579 GCP_KASHIDA_MASK=0x00000000,
2580 GCP_LIGATE_MASK=0x00000000,
2581 GCP_USEKERNING_MASK=0x00000000,
2582 GCP_REORDER_MASK=0x00000060;
2584 DWORD result=0;
2586 GetTextCharsetInfo( hdc, &fontsig, 0 );
2587 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2589 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2590 result|=GCP_DBCS;
2592 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2593 result|=GCP_DIACRITIC;
2595 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2596 result|=FLI_GLYPHS;
2598 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2599 result|=GCP_GLYPHSHAPE;
2601 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2602 result|=GCP_KASHIDA;
2604 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2605 result|=GCP_LIGATE;
2607 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2608 result|=GCP_USEKERNING;
2610 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2611 if( GetTextAlign( hdc) & TA_RTLREADING )
2612 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2613 result|=GCP_REORDER;
2615 return result;
2619 /*************************************************************************
2620 * GetFontData [GDI32.@]
2622 * Retrieve data for TrueType font.
2624 * RETURNS
2626 * success: Number of bytes returned
2627 * failure: GDI_ERROR
2629 * NOTES
2631 * Calls SetLastError()
2634 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2635 LPVOID buffer, DWORD length)
2637 DC *dc = DC_GetDCPtr(hdc);
2638 DWORD ret = GDI_ERROR;
2640 if(!dc) return GDI_ERROR;
2642 if(dc->gdiFont)
2643 ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2645 GDI_ReleaseObj(hdc);
2646 return ret;
2649 /*************************************************************************
2650 * GetGlyphIndicesA [GDI32.@]
2652 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2653 LPWORD pgi, DWORD flags)
2655 DWORD ret;
2656 WCHAR *lpstrW;
2657 INT countW;
2659 TRACE("(%p, %s, %d, %p, 0x%lx)\n",
2660 hdc, debugstr_an(lpstr, count), count, pgi, flags);
2662 lpstrW = FONT_mbtowc(lpstr, count, &countW);
2663 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2664 HeapFree(GetProcessHeap(), 0, lpstrW);
2666 return ret;
2669 /*************************************************************************
2670 * GetGlyphIndicesW [GDI32.@]
2672 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2673 LPWORD pgi, DWORD flags)
2675 DC *dc = DC_GetDCPtr(hdc);
2676 DWORD ret = GDI_ERROR;
2678 TRACE("(%p, %s, %d, %p, 0x%lx)\n",
2679 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2681 if(!dc) return GDI_ERROR;
2683 if(dc->gdiFont)
2684 ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2686 GDI_ReleaseObj(hdc);
2687 return ret;
2690 /*************************************************************************
2691 * GetCharacterPlacementA [GDI32.@]
2693 * See GetCharacterPlacementW.
2695 * NOTES:
2696 * the web browser control of ie4 calls this with dwFlags=0
2698 DWORD WINAPI
2699 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2700 INT nMaxExtent, GCP_RESULTSA *lpResults,
2701 DWORD dwFlags)
2703 WCHAR *lpStringW;
2704 INT uCountW;
2705 GCP_RESULTSW resultsW;
2706 DWORD ret;
2708 TRACE("%s, %d, %d, 0x%08lx\n",
2709 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2711 /* both structs are equal in size */
2712 memcpy(&resultsW, lpResults, sizeof(resultsW));
2714 lpStringW = FONT_mbtowc(lpString, uCount, &uCountW);
2715 if(lpResults->lpOutString)
2716 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2718 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2720 lpResults->nGlyphs = resultsW.nGlyphs;
2721 lpResults->nMaxFit = resultsW.nMaxFit;
2723 if(lpResults->lpOutString) {
2724 WideCharToMultiByte(CP_ACP, 0, resultsW.lpOutString, uCountW,
2725 lpResults->lpOutString, uCount, NULL, NULL );
2728 HeapFree(GetProcessHeap(), 0, lpStringW);
2729 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2731 return ret;
2734 /*************************************************************************
2735 * GetCharacterPlacementW [GDI32.@]
2737 * Retrieve information about a string. This includes the width, reordering,
2738 * Glyphing and so on.
2740 * RETURNS
2742 * The width and height of the string if successful, 0 if failed.
2744 * BUGS
2746 * All flags except GCP_REORDER are not yet implemented.
2747 * Reordering is not 100% complient to the Windows BiDi method.
2748 * Caret positioning is not yet implemented for BiDi.
2749 * Classes are not yet implemented.
2752 DWORD WINAPI
2753 GetCharacterPlacementW(
2754 HDC hdc, /* [in] Device context for which the rendering is to be done */
2755 LPCWSTR lpString, /* [in] The string for which information is to be returned */
2756 INT uCount, /* [in] Number of WORDS in string. */
2757 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
2758 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
2759 DWORD dwFlags /* [in] Flags specifying how to process the string */
2762 DWORD ret=0;
2763 SIZE size;
2764 UINT i, nSet;
2766 TRACE("%s, %d, %d, 0x%08lx\n",
2767 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2769 TRACE("lStructSize=%ld, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
2770 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2771 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
2772 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
2773 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
2775 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08lx ignored\n", dwFlags);
2776 if(lpResults->lpClass) FIXME("classes not implemented\n");
2777 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
2778 FIXME("Caret positions for complex scripts not implemented\n");
2780 nSet = (UINT)uCount;
2781 if(nSet > lpResults->nGlyphs)
2782 nSet = lpResults->nGlyphs;
2784 /* return number of initialized fields */
2785 lpResults->nGlyphs = nSet;
2787 if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
2789 /* Treat the case where no special handling was requested in a fastpath way */
2790 /* copy will do if the GCP_REORDER flag is not set */
2791 if(lpResults->lpOutString)
2792 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
2794 if(lpResults->lpOrder)
2796 for(i = 0; i < nSet; i++)
2797 lpResults->lpOrder[i] = i;
2799 } else
2801 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
2802 nSet, lpResults->lpOrder );
2805 /* FIXME: Will use the placement chars */
2806 if (lpResults->lpDx)
2808 int c;
2809 for (i = 0; i < nSet; i++)
2811 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
2812 lpResults->lpDx[i]= c;
2816 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
2818 int pos = 0;
2820 lpResults->lpCaretPos[0] = 0;
2821 for (i = 1; i < nSet; i++)
2822 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
2823 lpResults->lpCaretPos[i] = (pos += size.cx);
2826 if(lpResults->lpGlyphs)
2827 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
2829 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
2830 ret = MAKELONG(size.cx, size.cy);
2832 return ret;
2835 /*************************************************************************
2836 * GetCharABCWidthsFloatA [GDI32.@]
2838 * See GetCharABCWidthsFloatW.
2840 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2842 INT i, wlen, count = (INT)(last - first + 1);
2843 LPSTR str;
2844 LPWSTR wstr;
2845 BOOL ret = TRUE;
2847 if (count <= 0) return FALSE;
2849 str = HeapAlloc(GetProcessHeap(), 0, count);
2851 for(i = 0; i < count; i++)
2852 str[i] = (BYTE)(first + i);
2854 wstr = FONT_mbtowc(str, count, &wlen);
2856 for (i = 0; i < wlen; i++)
2858 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
2860 ret = FALSE;
2861 break;
2863 abcf++;
2866 HeapFree( GetProcessHeap(), 0, str );
2867 HeapFree( GetProcessHeap(), 0, wstr );
2869 return ret;
2872 /*************************************************************************
2873 * GetCharABCWidthsFloatW [GDI32.@]
2875 * Retrieves widths of a range of characters.
2877 * PARAMS
2878 * hdc [I] Handle to device context.
2879 * first [I] First character in range to query.
2880 * last [I] Last character in range to query.
2881 * abcf [O] Array of LPABCFLOAT structures.
2883 * RETURNS
2884 * Success: TRUE
2885 * Failure: FALSE
2887 * BUGS
2888 * Only works with TrueType fonts. It also doesn't return real
2889 * floats but converted integers because it's implemented on
2890 * top of GetCharABCWidthsW.
2892 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2894 ABC *abc;
2895 unsigned int i, size = sizeof(ABC) * (last - first + 1);
2896 BOOL ret;
2898 TRACE("%p, %d, %d, %p - partial stub\n", hdc, first, last, abcf);
2900 abc = HeapAlloc( GetProcessHeap(), 0, size );
2901 if (!abc) return FALSE;
2903 ret = GetCharABCWidthsW( hdc, first, last, abc );
2904 if (ret)
2906 for (i = first; i <= last; i++, abc++, abcf++)
2908 abcf->abcfA = abc->abcA;
2909 abcf->abcfB = abc->abcB;
2910 abcf->abcfC = abc->abcC;
2913 HeapFree( GetProcessHeap(), 0, abc );
2914 return ret;
2917 /*************************************************************************
2918 * GetCharWidthFloatA [GDI32.@]
2920 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
2921 UINT iLastChar, PFLOAT pxBuffer)
2923 FIXME_(gdi)("GetCharWidthFloatA, stub\n");
2924 return 0;
2927 /*************************************************************************
2928 * GetCharWidthFloatW [GDI32.@]
2930 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
2931 UINT iLastChar, PFLOAT pxBuffer)
2933 FIXME_(gdi)("GetCharWidthFloatW, stub\n");
2934 return 0;
2938 /***********************************************************************
2940 * Font Resource API *
2942 ***********************************************************************/
2944 /***********************************************************************
2945 * AddFontResourceA (GDI32.@)
2947 INT WINAPI AddFontResourceA( LPCSTR str )
2949 return AddFontResourceExA( str, 0, NULL);
2952 /***********************************************************************
2953 * AddFontResourceW (GDI32.@)
2955 INT WINAPI AddFontResourceW( LPCWSTR str )
2957 return AddFontResourceExW(str, 0, NULL);
2961 /***********************************************************************
2962 * AddFontResourceExA (GDI32.@)
2964 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
2966 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
2967 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2968 INT ret;
2970 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
2971 ret = AddFontResourceExW(strW, fl, pdv);
2972 HeapFree(GetProcessHeap(), 0, strW);
2973 return ret;
2976 /***********************************************************************
2977 * AddFontResourceExW (GDI32.@)
2979 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
2981 return WineEngAddFontResourceEx(str, fl, pdv);
2984 /***********************************************************************
2985 * RemoveFontResourceA (GDI32.@)
2987 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
2989 return RemoveFontResourceExA(str, 0, 0);
2992 /***********************************************************************
2993 * RemoveFontResourceW (GDI32.@)
2995 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
2997 return RemoveFontResourceExW(str, 0, 0);
3000 /***********************************************************************
3001 * AddFontMemResourceEx (GDI32.@)
3003 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3005 FIXME("(%p,%08lx,%p,%p): stub\n", pbFont, cbFont, pdv, pcFonts);
3006 return NULL;
3009 /***********************************************************************
3010 * RemoveFontResourceExA (GDI32.@)
3012 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3014 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3015 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3016 INT ret;
3018 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3019 ret = RemoveFontResourceExW(strW, fl, pdv);
3020 HeapFree(GetProcessHeap(), 0, strW);
3021 return ret;
3024 /***********************************************************************
3025 * RemoveFontResourceExW (GDI32.@)
3027 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3029 return WineEngRemoveFontResourceEx(str, fl, pdv);
3032 /***********************************************************************
3033 * GetTextCharset (GDI32.@)
3035 UINT WINAPI GetTextCharset(HDC hdc)
3037 /* MSDN docs say this is equivalent */
3038 return GetTextCharsetInfo(hdc, NULL, 0);
3041 /***********************************************************************
3042 * GetTextCharsetInfo (GDI32.@)
3044 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3046 UINT ret = DEFAULT_CHARSET;
3047 DC *dc = DC_GetDCPtr(hdc);
3049 if (!dc) goto done;
3051 if (dc->gdiFont)
3052 ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3054 GDI_ReleaseObj(hdc);
3056 done:
3057 if (ret == DEFAULT_CHARSET && fs)
3058 memset(fs, 0, sizeof(FONTSIGNATURE));
3059 return ret;
3062 /***********************************************************************
3063 * GdiGetCharDimensions (GDI32.@)
3065 * Gets the average width of the characters in the English alphabet.
3067 * PARAMS
3068 * hdc [I] Handle to the device context to measure on.
3069 * lptm [O] Pointer to memory to store the text metrics into.
3070 * height [O] On exit, the maximum height of characters in the English alphabet.
3072 * RETURNS
3073 * The average width of characters in the English alphabet.
3075 * NOTES
3076 * This function is used by the dialog manager to get the size of a dialog
3077 * unit. It should also be used by other pieces of code that need to know
3078 * the size of a dialog unit in logical units without having access to the
3079 * window handle of the dialog.
3080 * Windows caches the font metrics from this function, but we don't and
3081 * there doesn't appear to be an immediate advantage to do so.
3083 * SEE ALSO
3084 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3086 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3088 SIZE sz;
3089 static const WCHAR alphabet[] = {
3090 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3091 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3092 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3094 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3096 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3098 if (height) *height = sz.cy;
3099 return (sz.cx / 26 + 1) / 2;
3102 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3104 FIXME("(%d): stub\n", fEnableEUDC);
3105 return FALSE;
3108 /***********************************************************************
3109 * GetCharWidthI (GDI32.@)
3111 BOOL WINAPI GetCharWidthI(HDC hdc, UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer)
3113 FIXME("(%p, %d, %d, %p, %p): stub\n", hdc, giFirst, cgi, pgi, lpBuffer);
3114 return FALSE;
3117 /***********************************************************************
3118 * GetFontUnicodeRanges (GDI32.@)
3120 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3122 FIXME("(%p, %p): stub\n", hdc, lpgs);
3123 return 0;