rpcrt4: Use the thread pool in the RPC server for processing packets.
[wine/multimedia.git] / dlls / gdi / font.c
blob33a03f6c376f1b7f57c2fa661f440922ae01bb6a
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 BOOL ret = FALSE;
1057 DC * dc = DC_GetDCPtr( hdc );
1058 if (!dc) return FALSE;
1060 if(dc->gdiFont)
1061 ret = WineEngGetTextExtentPoint(dc->gdiFont, str, count, size);
1062 else if(dc->funcs->pGetTextExtentPoint)
1063 ret = dc->funcs->pGetTextExtentPoint( dc->physDev, str, count, size );
1065 if (ret)
1067 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1068 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1069 size->cx += count * dc->charExtra + dc->breakRem;
1072 GDI_ReleaseObj( hdc );
1074 TRACE("(%p %s %d %p): returning %ld x %ld\n",
1075 hdc, debugstr_wn (str, count), count, size, size->cx, size->cy );
1076 return ret;
1079 /***********************************************************************
1080 * GetTextExtentPointI [GDI32.@]
1082 * Computes width and height of the array of glyph indices.
1084 * RETURNS
1085 * Success: TRUE
1086 * Failure: FALSE
1088 BOOL WINAPI GetTextExtentPointI(
1089 HDC hdc, /* [in] Handle of device context */
1090 const WORD *indices, /* [in] Address of glyph index array */
1091 INT count, /* [in] Number of glyphs in array */
1092 LPSIZE size) /* [out] Address of structure for string size */
1094 BOOL ret = FALSE;
1095 DC * dc = DC_GetDCPtr( hdc );
1096 if (!dc) return FALSE;
1098 if(dc->gdiFont) {
1099 ret = WineEngGetTextExtentPointI(dc->gdiFont, indices, count, size);
1100 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1101 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1102 size->cx += count * dc->charExtra;
1104 else if(dc->funcs->pGetTextExtentPoint) {
1105 FIXME("calling GetTextExtentPoint\n");
1106 ret = dc->funcs->pGetTextExtentPoint( dc->physDev, (LPCWSTR)indices, count, size );
1109 GDI_ReleaseObj( hdc );
1111 TRACE("(%p %p %d %p): returning %ld x %ld\n",
1112 hdc, indices, count, size, size->cx, size->cy );
1113 return ret;
1117 /***********************************************************************
1118 * GetTextExtentPointA (GDI32.@)
1120 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1121 LPSIZE size )
1123 TRACE("not bug compatible.\n");
1124 return GetTextExtentPoint32A( hdc, str, count, size );
1127 /***********************************************************************
1128 * GetTextExtentPointW (GDI32.@)
1130 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1131 LPSIZE size )
1133 TRACE("not bug compatible.\n");
1134 return GetTextExtentPoint32W( hdc, str, count, size );
1138 /***********************************************************************
1139 * GetTextExtentExPointA (GDI32.@)
1141 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1142 INT maxExt, LPINT lpnFit,
1143 LPINT alpDx, LPSIZE size )
1145 BOOL ret;
1146 INT wlen;
1147 INT *walpDx = NULL;
1148 LPWSTR p = NULL;
1150 if (alpDx &&
1151 NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
1152 return FALSE;
1154 p = FONT_mbtowc(str, count, &wlen);
1155 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1156 if (walpDx)
1158 INT n = lpnFit ? *lpnFit : wlen;
1159 INT i, j;
1160 for(i = 0, j = 0; i < n; i++, j++)
1162 alpDx[j] = walpDx[i];
1163 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1166 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1167 HeapFree( GetProcessHeap(), 0, p );
1168 HeapFree( GetProcessHeap(), 0, walpDx );
1169 return ret;
1173 /***********************************************************************
1174 * GetTextExtentExPointW (GDI32.@)
1176 * Return the size of the string as it would be if it was output properly by
1177 * e.g. TextOut.
1179 * This should include
1180 * - Intercharacter spacing
1181 * - justification spacing (not yet done)
1182 * - kerning? see below
1184 * Kerning. Since kerning would be carried out by the rendering code it should
1185 * be done by the driver. However they don't support it yet. Also I am not
1186 * yet persuaded that (certainly under Win95) any kerning is actually done.
1188 * str: According to MSDN this should be null-terminated. That is not true; a
1189 * null will not terminate it early.
1190 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1191 * than count. I have seen it be either the size of the full string or
1192 * 1 less than the size of the full string. I have not seen it bear any
1193 * resemblance to the portion that would fit.
1194 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1195 * trailing intercharacter spacing and any trailing justification.
1197 * FIXME
1198 * Currently we do this by measuring each character etc. We should do it by
1199 * passing the request to the driver, perhaps by extending the
1200 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1201 * thinking about kerning issues and rounding issues in the justification.
1204 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1205 INT maxExt, LPINT lpnFit,
1206 LPINT alpDx, LPSIZE size )
1208 int index, nFit, extent;
1209 SIZE tSize;
1210 BOOL ret = FALSE;
1212 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1214 size->cx = size->cy = nFit = extent = 0;
1215 for(index = 0; index < count; index++)
1217 if(!GetTextExtentPoint32W( hdc, str, index + 1, &tSize )) goto done;
1218 /* GetTextExtentPoint includes intercharacter spacing. */
1219 /* FIXME - justification needs doing yet. Remember that the base
1220 * data will not be in logical coordinates.
1222 extent = tSize.cx;
1223 if( !lpnFit || extent <= maxExt )
1224 /* It is allowed to be equal. */
1226 nFit++;
1227 if( alpDx ) alpDx[index] = extent;
1229 if( tSize.cy > size->cy ) size->cy = tSize.cy;
1231 size->cx = extent;
1232 if(lpnFit) *lpnFit = nFit;
1233 ret = TRUE;
1235 TRACE("returning %d %ld x %ld\n",nFit,size->cx,size->cy);
1237 done:
1238 return ret;
1241 /***********************************************************************
1242 * GetTextMetricsA (GDI32.@)
1244 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1246 TEXTMETRICW tm32;
1248 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1249 FONT_TextMetricWToA( &tm32, metrics );
1250 return TRUE;
1253 /***********************************************************************
1254 * GetTextMetricsW (GDI32.@)
1256 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1258 BOOL ret = FALSE;
1259 DC * dc = DC_GetDCPtr( hdc );
1260 if (!dc) return FALSE;
1262 if (dc->gdiFont)
1263 ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
1264 else if (dc->funcs->pGetTextMetrics)
1265 ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1267 if (ret)
1269 /* device layer returns values in device units
1270 * therefore we have to convert them to logical */
1272 #define WDPTOLP(x) ((x<0)? \
1273 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1274 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1275 #define HDPTOLP(y) ((y<0)? \
1276 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1277 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1279 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1280 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1281 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1282 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1283 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1284 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1285 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1286 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1287 ret = TRUE;
1288 #undef WDPTOLP
1289 #undef HDPTOLP
1290 TRACE("text metrics:\n"
1291 " Weight = %03li\t FirstChar = %i\t AveCharWidth = %li\n"
1292 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %li\n"
1293 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %li\n"
1294 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1295 " PitchAndFamily = %02x\n"
1296 " --------------------\n"
1297 " InternalLeading = %li\n"
1298 " Ascent = %li\n"
1299 " Descent = %li\n"
1300 " Height = %li\n",
1301 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1302 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1303 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1304 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1305 metrics->tmPitchAndFamily,
1306 metrics->tmInternalLeading,
1307 metrics->tmAscent,
1308 metrics->tmDescent,
1309 metrics->tmHeight );
1311 GDI_ReleaseObj( hdc );
1312 return ret;
1316 /***********************************************************************
1317 * GetOutlineTextMetrics [GDI.308] Gets metrics for TrueType fonts.
1319 * NOTES
1320 * lpOTM should be LPOUTLINETEXTMETRIC
1322 * RETURNS
1323 * Success: Non-zero or size of required buffer
1324 * Failure: 0
1326 UINT16 WINAPI GetOutlineTextMetrics16(
1327 HDC16 hdc, /* [in] Handle of device context */
1328 UINT16 cbData, /* [in] Size of metric data array */
1329 LPOUTLINETEXTMETRIC16 lpOTM) /* [out] Address of metric data array */
1331 FIXME("(%04x,%04x,%p): stub\n", hdc,cbData,lpOTM);
1332 return 0;
1336 /***********************************************************************
1337 * GetOutlineTextMetricsA (GDI32.@)
1338 * Gets metrics for TrueType fonts.
1340 * NOTES
1341 * If the supplied buffer isn't big enough Windows partially fills it up to
1342 * its given length and returns that length.
1344 * RETURNS
1345 * Success: Non-zero or size of required buffer
1346 * Failure: 0
1348 UINT WINAPI GetOutlineTextMetricsA(
1349 HDC hdc, /* [in] Handle of device context */
1350 UINT cbData, /* [in] Size of metric data array */
1351 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1353 char buf[512], *ptr;
1354 UINT ret, needed;
1355 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1356 OUTLINETEXTMETRICA *output = lpOTM;
1357 INT left, len;
1359 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1360 return 0;
1361 if(ret > sizeof(buf))
1362 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1363 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1365 needed = sizeof(OUTLINETEXTMETRICA);
1366 if(lpOTMW->otmpFamilyName)
1367 needed += WideCharToMultiByte(CP_ACP, 0,
1368 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1369 NULL, 0, NULL, NULL);
1370 if(lpOTMW->otmpFaceName)
1371 needed += WideCharToMultiByte(CP_ACP, 0,
1372 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1373 NULL, 0, NULL, NULL);
1374 if(lpOTMW->otmpStyleName)
1375 needed += WideCharToMultiByte(CP_ACP, 0,
1376 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1377 NULL, 0, NULL, NULL);
1378 if(lpOTMW->otmpFullName)
1379 needed += WideCharToMultiByte(CP_ACP, 0,
1380 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1381 NULL, 0, NULL, NULL);
1383 if(!lpOTM) {
1384 ret = needed;
1385 goto end;
1388 TRACE("needed = %d\n", needed);
1389 if(needed > cbData)
1390 /* Since the supplied buffer isn't big enough, we'll alloc one
1391 that is and memcpy the first cbData bytes into the lpOTM at
1392 the end. */
1393 output = HeapAlloc(GetProcessHeap(), 0, needed);
1395 ret = output->otmSize = min(needed, cbData);
1396 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1397 output->otmFiller = 0;
1398 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1399 output->otmfsSelection = lpOTMW->otmfsSelection;
1400 output->otmfsType = lpOTMW->otmfsType;
1401 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1402 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1403 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1404 output->otmEMSquare = lpOTMW->otmEMSquare;
1405 output->otmAscent = lpOTMW->otmAscent;
1406 output->otmDescent = lpOTMW->otmDescent;
1407 output->otmLineGap = lpOTMW->otmLineGap;
1408 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1409 output->otmsXHeight = lpOTMW->otmsXHeight;
1410 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1411 output->otmMacAscent = lpOTMW->otmMacAscent;
1412 output->otmMacDescent = lpOTMW->otmMacDescent;
1413 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1414 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1415 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1416 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1417 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1418 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1419 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1420 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1421 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1422 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1425 ptr = (char*)(output + 1);
1426 left = needed - sizeof(*output);
1428 if(lpOTMW->otmpFamilyName) {
1429 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1430 len = WideCharToMultiByte(CP_ACP, 0,
1431 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1432 ptr, left, NULL, NULL);
1433 left -= len;
1434 ptr += len;
1435 } else
1436 output->otmpFamilyName = 0;
1438 if(lpOTMW->otmpFaceName) {
1439 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1440 len = WideCharToMultiByte(CP_ACP, 0,
1441 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1442 ptr, left, NULL, NULL);
1443 left -= len;
1444 ptr += len;
1445 } else
1446 output->otmpFaceName = 0;
1448 if(lpOTMW->otmpStyleName) {
1449 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1450 len = WideCharToMultiByte(CP_ACP, 0,
1451 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1452 ptr, left, NULL, NULL);
1453 left -= len;
1454 ptr += len;
1455 } else
1456 output->otmpStyleName = 0;
1458 if(lpOTMW->otmpFullName) {
1459 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1460 len = WideCharToMultiByte(CP_ACP, 0,
1461 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1462 ptr, left, NULL, NULL);
1463 left -= len;
1464 } else
1465 output->otmpFullName = 0;
1467 assert(left == 0);
1469 if(output != lpOTM) {
1470 memcpy(lpOTM, output, cbData);
1471 HeapFree(GetProcessHeap(), 0, output);
1474 end:
1475 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1476 HeapFree(GetProcessHeap(), 0, lpOTMW);
1478 return ret;
1482 /***********************************************************************
1483 * GetOutlineTextMetricsW [GDI32.@]
1485 UINT WINAPI GetOutlineTextMetricsW(
1486 HDC hdc, /* [in] Handle of device context */
1487 UINT cbData, /* [in] Size of metric data array */
1488 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1490 DC *dc = DC_GetDCPtr( hdc );
1491 OUTLINETEXTMETRICW *output = lpOTM;
1492 UINT ret;
1494 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1495 if(!dc) return 0;
1497 if(dc->gdiFont) {
1498 ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
1499 if(lpOTM && ret) {
1500 if(ret > cbData) {
1501 output = HeapAlloc(GetProcessHeap(), 0, ret);
1502 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
1505 #define WDPTOLP(x) ((x<0)? \
1506 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1507 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1508 #define HDPTOLP(y) ((y<0)? \
1509 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1510 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1512 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1513 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1514 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1515 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1516 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1517 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1518 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1519 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1520 output->otmAscent = HDPTOLP(output->otmAscent);
1521 output->otmDescent = HDPTOLP(output->otmDescent);
1522 output->otmLineGap = HDPTOLP(output->otmLineGap);
1523 output->otmsCapEmHeight = HDPTOLP(output->otmsCapEmHeight);
1524 output->otmsXHeight = HDPTOLP(output->otmsXHeight);
1525 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1526 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1527 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1528 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1529 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1530 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1531 output->otmMacLineGap = HDPTOLP(output->otmMacLineGap);
1532 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1533 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1534 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1535 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1536 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1537 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1538 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1539 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1540 output->otmsStrikeoutSize = HDPTOLP(output->otmsStrikeoutSize);
1541 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1542 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1543 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1544 #undef WDPTOLP
1545 #undef HDPTOLP
1546 if(output != lpOTM) {
1547 memcpy(lpOTM, output, cbData);
1548 HeapFree(GetProcessHeap(), 0, output);
1549 ret = cbData;
1554 else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here
1555 but really this should just be a return 0. */
1557 ret = sizeof(*lpOTM);
1558 if (lpOTM) {
1559 if(cbData < ret)
1560 ret = 0;
1561 else {
1562 memset(lpOTM, 0, ret);
1563 lpOTM->otmSize = sizeof(*lpOTM);
1564 GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
1566 Further fill of the structure not implemented,
1567 Needs real values for the structure members
1572 GDI_ReleaseObj(hdc);
1573 return ret;
1577 /***********************************************************************
1578 * GetCharWidthW (GDI32.@)
1579 * GetCharWidth32W (GDI32.@)
1581 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1582 LPINT buffer )
1584 UINT i;
1585 BOOL ret = FALSE;
1586 DC * dc = DC_GetDCPtr( hdc );
1587 if (!dc) return FALSE;
1589 if (dc->gdiFont)
1590 ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
1591 else if (dc->funcs->pGetCharWidth)
1592 ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1594 if (ret)
1596 /* convert device units to logical */
1597 for( i = firstChar; i <= lastChar; i++, buffer++ )
1598 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1599 ret = TRUE;
1601 GDI_ReleaseObj( hdc );
1602 return ret;
1606 /***********************************************************************
1607 * GetCharWidthA (GDI32.@)
1608 * GetCharWidth32A (GDI32.@)
1610 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1611 LPINT buffer )
1613 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
1614 LPSTR str;
1615 LPWSTR wstr;
1616 BOOL ret = TRUE;
1618 if(count <= 0) return FALSE;
1620 str = HeapAlloc(GetProcessHeap(), 0, count);
1621 for(i = 0; i < count; i++)
1622 str[i] = (BYTE)(firstChar + i);
1624 wstr = FONT_mbtowc(str, count, &wlen);
1626 for(i = 0; i < wlen; i++)
1628 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1630 ret = FALSE;
1631 break;
1633 buffer++;
1636 HeapFree(GetProcessHeap(), 0, str);
1637 HeapFree(GetProcessHeap(), 0, wstr);
1639 return ret;
1643 /***********************************************************************
1644 * ExtTextOutA (GDI32.@)
1646 * See ExtTextOutW.
1648 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1649 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1651 INT wlen;
1652 LPWSTR p;
1653 BOOL ret;
1654 LPINT lpDxW = NULL;
1656 if (flags & ETO_GLYPH_INDEX)
1657 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1659 p = FONT_mbtowc(str, count, &wlen);
1661 if (lpDx) {
1662 unsigned int i = 0, j = 0;
1664 lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT));
1665 while(i < count) {
1666 if(IsDBCSLeadByte(str[i])) {
1667 lpDxW[j++] = lpDx[i] + lpDx[i+1];
1668 i = i + 2;
1669 } else {
1670 lpDxW[j++] = lpDx[i];
1671 i = i + 1;
1676 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
1678 HeapFree( GetProcessHeap(), 0, p );
1679 HeapFree( GetProcessHeap(), 0, lpDxW );
1680 return ret;
1684 /***********************************************************************
1685 * ExtTextOutW (GDI32.@)
1687 * Draws text using the currently selected font, background color, and text color.
1690 * PARAMS
1691 * x,y [I] coordinates of string
1692 * flags [I]
1693 * ETO_GRAYED - undocumented on MSDN
1694 * ETO_OPAQUE - use background color for fill the rectangle
1695 * ETO_CLIPPED - clipping text to the rectangle
1696 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
1697 * than encoded characters. Implies ETO_IGNORELANGUAGE
1698 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
1699 * Affects BiDi ordering
1700 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
1701 * ETO_PDY - unimplemented
1702 * ETO_NUMERICSLATIN - unimplemented always assumed -
1703 * do not translate numbers into locale representations
1704 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
1705 * lprect [I] dimensions for clipping or/and opaquing
1706 * str [I] text string
1707 * count [I] number of symbols in string
1708 * lpDx [I] optional parameter with distance between drawing characters
1710 * RETURNS
1711 * Success: TRUE
1712 * Failure: FALSE
1714 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
1715 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
1717 BOOL ret = FALSE;
1718 LPWSTR reordered_str = (LPWSTR)str;
1719 WORD *glyphs = NULL;
1720 UINT align = GetTextAlign( hdc );
1721 POINT pt;
1722 TEXTMETRICW tm;
1723 LOGFONTW lf;
1724 double cosEsc, sinEsc;
1725 INT *deltas = NULL, char_extra;
1726 SIZE sz;
1727 RECT rc;
1728 BOOL done_extents = FALSE;
1729 INT width, xwidth = 0, ywidth = 0;
1730 DWORD type;
1731 DC * dc = DC_GetDCUpdate( hdc );
1733 if (!dc) return FALSE;
1735 if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
1736 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
1738 if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1740 GDI_ReleaseObj( hdc );
1741 return ret;
1744 type = GetObjectType(hdc);
1745 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
1747 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1748 GDI_ReleaseObj( hdc );
1749 return ret;
1752 if (!lprect)
1753 flags &= ~ETO_CLIPPED;
1755 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && BidiAvail && count > 0 )
1757 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
1759 BIDI_Reorder( str, count, GCP_REORDER,
1760 ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
1761 WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
1762 reordered_str, count, NULL );
1764 flags |= ETO_IGNORELANGUAGE;
1767 TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
1768 lprect, debugstr_wn(str, count), count, lpDx);
1770 if(flags & ETO_GLYPH_INDEX)
1771 glyphs = reordered_str;
1773 if(lprect)
1774 TRACE("rect: %ld,%ld - %ld,%ld\n", lprect->left, lprect->top, lprect->right,
1775 lprect->bottom);
1776 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
1778 if(align & TA_UPDATECP)
1780 GetCurrentPositionEx( hdc, &pt );
1781 x = pt.x;
1782 y = pt.y;
1785 GetTextMetricsW(hdc, &tm);
1786 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1788 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1789 lf.lfEscapement = 0;
1791 if(lf.lfEscapement != 0)
1793 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1794 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1796 else
1798 cosEsc = 1;
1799 sinEsc = 0;
1802 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
1804 if(!lprect)
1806 if(flags & ETO_GLYPH_INDEX)
1807 GetTextExtentPointI(hdc, glyphs, count, &sz);
1808 else
1809 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1811 done_extents = TRUE;
1812 rc.left = x;
1813 rc.top = y;
1814 rc.right = x + sz.cx;
1815 rc.bottom = y + sz.cy;
1817 else
1819 rc = *lprect;
1822 LPtoDP(hdc, (POINT*)&rc, 2);
1824 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1825 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1828 if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1829 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1831 if(count == 0)
1833 ret = TRUE;
1834 goto done;
1837 pt.x = x;
1838 pt.y = y;
1839 LPtoDP(hdc, &pt, 1);
1840 x = pt.x;
1841 y = pt.y;
1843 char_extra = GetTextCharacterExtra(hdc);
1844 width = 0;
1845 if(char_extra || dc->breakExtra || lpDx)
1847 UINT i;
1848 SIZE tmpsz;
1849 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
1850 for(i = 0; i < count; i++)
1852 if(lpDx && (flags & ETO_PDY))
1853 deltas[i] = lpDx[i*2] + char_extra;
1854 else if(lpDx)
1855 deltas[i] = lpDx[i] + char_extra;
1856 else
1858 if(flags & ETO_GLYPH_INDEX)
1859 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1860 else
1861 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
1863 deltas[i] = tmpsz.cx;
1866 if (!(flags & ETO_GLYPH_INDEX) && dc->breakExtra && reordered_str[i] == tm.tmBreakChar)
1868 deltas[i] = deltas[i] + dc->breakExtra;
1870 deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
1871 width += deltas[i];
1874 else
1876 if(!done_extents)
1878 if(flags & ETO_GLYPH_INDEX)
1879 GetTextExtentPointI(hdc, glyphs, count, &sz);
1880 else
1881 GetTextExtentPointW(hdc, reordered_str, count, &sz);
1882 done_extents = TRUE;
1884 width = INTERNAL_XWSTODS(dc, sz.cx);
1886 xwidth = width * cosEsc;
1887 ywidth = width * sinEsc;
1889 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
1890 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
1891 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
1893 case TA_LEFT:
1894 if (align & TA_UPDATECP)
1896 pt.x = x + xwidth;
1897 pt.y = y - ywidth;
1898 DPtoLP(hdc, &pt, 1);
1899 MoveToEx(hdc, pt.x, pt.y, NULL);
1901 break;
1903 case TA_CENTER:
1904 x -= xwidth / 2;
1905 y += ywidth / 2;
1906 break;
1908 case TA_RIGHT:
1909 x -= xwidth;
1910 y += ywidth;
1911 if (align & TA_UPDATECP)
1913 pt.x = x;
1914 pt.y = y;
1915 DPtoLP(hdc, &pt, 1);
1916 MoveToEx(hdc, pt.x, pt.y, NULL);
1918 break;
1921 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
1923 case TA_TOP:
1924 y += tm.tmAscent * cosEsc;
1925 x += tm.tmAscent * sinEsc;
1926 break;
1928 case TA_BOTTOM:
1929 y -= tm.tmDescent * cosEsc;
1930 x -= tm.tmDescent * sinEsc;
1931 break;
1933 case TA_BASELINE:
1934 break;
1937 if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
1939 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
1941 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
1942 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
1944 RECT rc;
1945 rc.left = x;
1946 rc.right = x + width;
1947 rc.top = y - tm.tmAscent;
1948 rc.bottom = y + tm.tmDescent;
1949 dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1954 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
1956 HFONT orig_font = dc->hFont, cur_font;
1957 UINT glyph;
1958 INT span = 0, *offsets = NULL, i;
1960 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1961 for(i = 0; i < count; i++)
1963 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
1964 if(cur_font != dc->hFont)
1966 if(!offsets)
1968 int j;
1969 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
1970 offsets[0] = 0;
1971 if(!deltas)
1973 SIZE tmpsz;
1974 for(j = 1; j < count; j++)
1976 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
1977 offsets[j] = offsets[j-1] + INTERNAL_XWSTODS(dc, tmpsz.cx);
1980 else
1982 for(j = 1; j < count; j++)
1983 offsets[j] = offsets[j-1] + deltas[j];
1986 if(span)
1988 if (PATH_IsPathOpen(dc->path))
1989 ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
1990 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1991 glyphs, span, deltas ? deltas + i - span : NULL);
1992 else
1993 dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
1994 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
1995 glyphs, span, deltas ? deltas + i - span : NULL);
1996 span = 0;
1998 SelectObject(hdc, cur_font);
2000 glyphs[span++] = glyph;
2002 if(i == count - 1)
2004 if (PATH_IsPathOpen(dc->path))
2005 ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
2006 y - (offsets ? offsets[count - span] * sinEsc : 0),
2007 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2008 glyphs, span, deltas ? deltas + count - span : NULL);
2009 else
2010 ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
2011 y - (offsets ? offsets[count - span] * sinEsc : 0),
2012 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
2013 glyphs, span, deltas ? deltas + count - span : NULL);
2014 SelectObject(hdc, orig_font);
2015 HeapFree(GetProcessHeap(), 0, offsets);
2019 else
2021 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2023 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2024 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2025 flags |= ETO_GLYPH_INDEX;
2028 if (PATH_IsPathOpen(dc->path))
2029 ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
2030 glyphs ? glyphs : reordered_str, count, deltas);
2031 else
2032 ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
2033 glyphs ? glyphs : reordered_str, count, deltas);
2036 done:
2037 HeapFree(GetProcessHeap(), 0, deltas);
2038 if(glyphs != reordered_str)
2039 HeapFree(GetProcessHeap(), 0, glyphs);
2040 if(reordered_str != str)
2041 HeapFree(GetProcessHeap(), 0, reordered_str);
2043 GDI_ReleaseObj( hdc );
2045 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2047 int underlinePos, strikeoutPos;
2048 int underlineWidth, strikeoutWidth;
2049 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2050 OUTLINETEXTMETRICW* otm = NULL;
2052 if(!size)
2054 underlinePos = 0;
2055 underlineWidth = tm.tmAscent / 20 + 1;
2056 strikeoutPos = tm.tmAscent / 2;
2057 strikeoutWidth = underlineWidth;
2059 else
2061 otm = HeapAlloc(GetProcessHeap(), 0, size);
2062 GetOutlineTextMetricsW(hdc, size, otm);
2063 underlinePos = otm->otmsUnderscorePosition;
2064 underlineWidth = otm->otmsUnderscoreSize;
2065 strikeoutPos = otm->otmsStrikeoutPosition;
2066 strikeoutWidth = otm->otmsStrikeoutSize;
2067 HeapFree(GetProcessHeap(), 0, otm);
2070 if (PATH_IsPathOpen(dc->path))
2072 POINT pts[5];
2073 HPEN hpen;
2074 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2076 hbrush = SelectObject(hdc, hbrush);
2077 hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2079 if (lf.lfUnderline)
2081 pts[0].x = x - underlinePos * sinEsc;
2082 pts[0].y = y - underlinePos * cosEsc;
2083 pts[1].x = x + xwidth - underlinePos * sinEsc;
2084 pts[1].y = y - ywidth - underlinePos * cosEsc;
2085 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2086 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2087 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2088 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2089 pts[4].x = pts[0].x;
2090 pts[4].y = pts[0].y;
2091 DPtoLP(hdc, pts, 5);
2092 Polygon(hdc, pts, 5);
2095 if (lf.lfStrikeOut)
2097 pts[0].x = x - strikeoutPos * sinEsc;
2098 pts[0].y = y - strikeoutPos * cosEsc;
2099 pts[1].x = x + xwidth - strikeoutPos * sinEsc;
2100 pts[1].y = y - ywidth - strikeoutPos * cosEsc;
2101 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2102 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2103 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2104 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2105 pts[4].x = pts[0].x;
2106 pts[4].y = pts[0].y;
2107 DPtoLP(hdc, pts, 5);
2108 Polygon(hdc, pts, 5);
2111 SelectObject(hdc, hpen);
2112 hbrush = SelectObject(hdc, hbrush);
2113 DeleteObject(hbrush);
2115 else
2117 POINT pts[2], oldpt;
2118 HPEN hpen;
2120 if (lf.lfUnderline)
2122 hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
2123 hpen = SelectObject(hdc, hpen);
2124 pts[0].x = x;
2125 pts[0].y = y;
2126 pts[1].x = x + xwidth;
2127 pts[1].y = y - ywidth;
2128 DPtoLP(hdc, pts, 2);
2129 MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
2130 LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
2131 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2132 DeleteObject(SelectObject(hdc, hpen));
2135 if (lf.lfStrikeOut)
2137 hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
2138 hpen = SelectObject(hdc, hpen);
2139 pts[0].x = x;
2140 pts[0].y = y;
2141 pts[1].x = x + xwidth;
2142 pts[1].y = y - ywidth;
2143 DPtoLP(hdc, pts, 2);
2144 MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
2145 LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
2146 MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
2147 DeleteObject(SelectObject(hdc, hpen));
2152 return ret;
2156 /***********************************************************************
2157 * TextOutA (GDI32.@)
2159 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2161 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2165 /***********************************************************************
2166 * TextOutW (GDI32.@)
2168 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2170 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2174 /***********************************************************************
2175 * PolyTextOutA (GDI32.@)
2177 * See PolyTextOutW.
2179 BOOL WINAPI PolyTextOutA ( HDC hdc, /* [in] Handle to device context */
2180 PPOLYTEXTA pptxt, /* [in] Array of strings */
2181 INT cStrings ) /* [in] Number of strings in array */
2183 for (; cStrings>0; cStrings--, pptxt++)
2184 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2185 return FALSE;
2186 return TRUE;
2191 /***********************************************************************
2192 * PolyTextOutW (GDI32.@)
2194 * Draw several Strings
2196 * RETURNS
2197 * TRUE: Success.
2198 * FALSE: Failure.
2200 BOOL WINAPI PolyTextOutW ( HDC hdc, /* [in] Handle to device context */
2201 PPOLYTEXTW pptxt, /* [in] Array of strings */
2202 INT cStrings ) /* [in] Number of strings in array */
2204 for (; cStrings>0; cStrings--, pptxt++)
2205 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2206 return FALSE;
2207 return TRUE;
2211 /* FIXME: all following APIs ******************************************/
2214 /***********************************************************************
2215 * SetMapperFlags (GDI32.@)
2217 DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
2219 DC *dc = DC_GetDCPtr( hDC );
2220 DWORD ret = 0;
2221 if(!dc) return 0;
2222 if(dc->funcs->pSetMapperFlags)
2224 ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2225 /* FIXME: ret is just a success flag, we should return a proper value */
2227 else
2228 FIXME("(%p, 0x%08lx): stub - harmless\n", hDC, dwFlag);
2229 GDI_ReleaseObj( hDC );
2230 return ret;
2233 /***********************************************************************
2234 * GetAspectRatioFilterEx (GDI.486)
2236 BOOL16 WINAPI GetAspectRatioFilterEx16( HDC16 hdc, LPSIZE16 pAspectRatio )
2238 FIXME("(%04x, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2239 return FALSE;
2242 /***********************************************************************
2243 * GetAspectRatioFilterEx (GDI32.@)
2245 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2247 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2248 return FALSE;
2252 /***********************************************************************
2253 * GetCharABCWidthsA (GDI32.@)
2255 * See GetCharABCWidthsW.
2257 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2258 LPABC abc )
2260 INT i, wlen, count = (INT)(lastChar - firstChar + 1);
2261 LPSTR str;
2262 LPWSTR wstr;
2263 BOOL ret = TRUE;
2265 if(count <= 0) return FALSE;
2267 str = HeapAlloc(GetProcessHeap(), 0, count);
2268 for(i = 0; i < count; i++)
2269 str[i] = (BYTE)(firstChar + i);
2271 wstr = FONT_mbtowc(str, count, &wlen);
2273 for(i = 0; i < wlen; i++)
2275 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2277 ret = FALSE;
2278 break;
2280 abc++;
2283 HeapFree(GetProcessHeap(), 0, str);
2284 HeapFree(GetProcessHeap(), 0, wstr);
2286 return ret;
2290 /******************************************************************************
2291 * GetCharABCWidthsW [GDI32.@]
2293 * Retrieves widths of characters in range.
2295 * PARAMS
2296 * hdc [I] Handle of device context
2297 * firstChar [I] First character in range to query
2298 * lastChar [I] Last character in range to query
2299 * abc [O] Address of character-width structure
2301 * NOTES
2302 * Only works with TrueType fonts
2304 * RETURNS
2305 * Success: TRUE
2306 * Failure: FALSE
2308 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2309 LPABC abc )
2311 DC *dc = DC_GetDCPtr(hdc);
2312 unsigned int i;
2313 BOOL ret = FALSE;
2315 if (!dc) return FALSE;
2317 if(dc->gdiFont)
2318 ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc );
2319 else
2320 FIXME(": stub\n");
2322 if (ret)
2324 /* convert device units to logical */
2325 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2326 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2327 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2328 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2330 ret = TRUE;
2333 GDI_ReleaseObj(hdc);
2334 return ret;
2338 /******************************************************************************
2339 * GetCharABCWidthsI [GDI32.@]
2341 * Retrieves widths of characters in range.
2343 * PARAMS
2344 * hdc [I] Handle of device context
2345 * firstChar [I] First glyphs in range to query
2346 * count [I] Last glyphs in range to query
2347 * pgi [i] Array of glyphs to query
2348 * abc [O] Address of character-width structure
2350 * NOTES
2351 * Only works with TrueType fonts
2353 * RETURNS
2354 * Success: TRUE
2355 * Failure: FALSE
2357 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2358 LPWORD pgi, LPABC abc)
2360 DC *dc = DC_GetDCPtr(hdc);
2361 unsigned int i;
2362 BOOL ret = FALSE;
2364 if (!dc) return FALSE;
2366 if(dc->gdiFont)
2367 ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
2368 else
2369 FIXME(": stub\n");
2371 if (ret)
2373 /* convert device units to logical */
2374 for( i = firstChar; i <= count; i++, abc++ ) {
2375 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2376 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2377 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2379 ret = TRUE;
2382 GDI_ReleaseObj(hdc);
2383 return ret;
2387 /***********************************************************************
2388 * GetGlyphOutlineA (GDI32.@)
2390 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2391 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2392 LPVOID lpBuffer, const MAT2 *lpmat2 )
2394 LPWSTR p = NULL;
2395 DWORD ret;
2396 UINT c;
2398 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2399 int len;
2400 char mbchs[2];
2401 if(uChar > 0xff) { /* but, 2 bytes character only */
2402 len = 2;
2403 mbchs[0] = (uChar & 0xff00) >> 8;
2404 mbchs[1] = (uChar & 0xff);
2405 } else {
2406 len = 1;
2407 mbchs[0] = (uChar & 0xff);
2409 p = FONT_mbtowc(mbchs, len, NULL);
2410 c = p[0];
2411 } else
2412 c = uChar;
2413 ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
2414 lpmat2);
2415 HeapFree(GetProcessHeap(), 0, p);
2416 return ret;
2419 /***********************************************************************
2420 * GetGlyphOutlineW (GDI32.@)
2422 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2423 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2424 LPVOID lpBuffer, const MAT2 *lpmat2 )
2426 DC *dc = DC_GetDCPtr(hdc);
2427 DWORD ret;
2429 TRACE("(%p, %04x, %04x, %p, %ld, %p, %p)\n",
2430 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2432 if(!dc) return GDI_ERROR;
2434 if(dc->gdiFont)
2435 ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
2436 cbBuffer, lpBuffer, lpmat2);
2437 else
2438 ret = GDI_ERROR;
2440 GDI_ReleaseObj(hdc);
2441 return ret;
2445 /***********************************************************************
2446 * CreateScalableFontResourceA (GDI32.@)
2448 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2449 LPCSTR lpszResourceFile,
2450 LPCSTR lpszFontFile,
2451 LPCSTR lpszCurrentPath )
2453 HANDLE f;
2455 /* fHidden=1 - only visible for the calling app, read-only, not
2456 * enumbered with EnumFonts/EnumFontFamilies
2457 * lpszCurrentPath can be NULL
2459 FIXME("(%ld,%s,%s,%s): stub\n",
2460 fHidden, debugstr_a(lpszResourceFile), debugstr_a(lpszFontFile),
2461 debugstr_a(lpszCurrentPath) );
2463 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2464 if ((f = CreateFileA(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2465 CloseHandle(f);
2466 SetLastError(ERROR_FILE_EXISTS);
2467 return FALSE;
2469 return FALSE; /* create failed */
2472 /***********************************************************************
2473 * CreateScalableFontResourceW (GDI32.@)
2475 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2476 LPCWSTR lpszResourceFile,
2477 LPCWSTR lpszFontFile,
2478 LPCWSTR lpszCurrentPath )
2480 FIXME("(%ld,%p,%p,%p): stub\n",
2481 fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath );
2482 return FALSE; /* create failed */
2485 /*************************************************************************
2486 * GetKerningPairsA (GDI32.@)
2488 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2489 LPKERNINGPAIR lpKerningPairs )
2491 return GetKerningPairsW( hDC, cPairs, lpKerningPairs );
2495 /*************************************************************************
2496 * GetKerningPairsW (GDI32.@)
2498 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2499 LPKERNINGPAIR lpKerningPairs )
2501 unsigned int i;
2502 FIXME("(%p,%ld,%p): almost empty stub!\n", hDC, cPairs, lpKerningPairs);
2504 if(!lpKerningPairs) /* return the number of kerning pairs */
2505 return 0;
2507 for (i = 0; i < cPairs; i++)
2508 lpKerningPairs[i].iKernAmount = 0;
2509 return 0;
2512 /*************************************************************************
2513 * TranslateCharsetInfo [GDI32.@]
2515 * Fills a CHARSETINFO structure for a character set, code page, or
2516 * font. This allows making the correspondance between different labelings
2517 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2518 * of the same encoding.
2520 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2521 * only one codepage should be set in *lpSrc.
2523 * RETURNS
2524 * TRUE on success, FALSE on failure.
2527 BOOL WINAPI TranslateCharsetInfo(
2528 LPDWORD lpSrc, /* [in]
2529 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2530 if flags == TCI_SRCCHARSET: a character set value
2531 if flags == TCI_SRCCODEPAGE: a code page value
2533 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2534 DWORD flags /* [in] determines interpretation of lpSrc */)
2536 int index = 0;
2537 switch (flags) {
2538 case TCI_SRCFONTSIG:
2539 while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
2540 break;
2541 case TCI_SRCCODEPAGE:
2542 while ((UINT) (lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
2543 break;
2544 case TCI_SRCCHARSET:
2545 while ((UINT) (lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
2546 break;
2547 default:
2548 return FALSE;
2550 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2551 memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO));
2552 return TRUE;
2555 /*************************************************************************
2556 * GetFontLanguageInfo (GDI32.@)
2558 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
2560 FONTSIGNATURE fontsig;
2561 static const DWORD GCP_DBCS_MASK=0x003F0000,
2562 GCP_DIACRITIC_MASK=0x00000000,
2563 FLI_GLYPHS_MASK=0x00000000,
2564 GCP_GLYPHSHAPE_MASK=0x00000040,
2565 GCP_KASHIDA_MASK=0x00000000,
2566 GCP_LIGATE_MASK=0x00000000,
2567 GCP_USEKERNING_MASK=0x00000000,
2568 GCP_REORDER_MASK=0x00000060;
2570 DWORD result=0;
2572 GetTextCharsetInfo( hdc, &fontsig, 0 );
2573 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
2575 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
2576 result|=GCP_DBCS;
2578 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
2579 result|=GCP_DIACRITIC;
2581 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
2582 result|=FLI_GLYPHS;
2584 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
2585 result|=GCP_GLYPHSHAPE;
2587 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
2588 result|=GCP_KASHIDA;
2590 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
2591 result|=GCP_LIGATE;
2593 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
2594 result|=GCP_USEKERNING;
2596 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
2597 if( GetTextAlign( hdc) & TA_RTLREADING )
2598 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
2599 result|=GCP_REORDER;
2601 return result;
2605 /*************************************************************************
2606 * GetFontData [GDI32.@]
2608 * Retrieve data for TrueType font.
2610 * RETURNS
2612 * success: Number of bytes returned
2613 * failure: GDI_ERROR
2615 * NOTES
2617 * Calls SetLastError()
2620 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
2621 LPVOID buffer, DWORD length)
2623 DC *dc = DC_GetDCPtr(hdc);
2624 DWORD ret = GDI_ERROR;
2626 if(!dc) return GDI_ERROR;
2628 if(dc->gdiFont)
2629 ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);
2631 GDI_ReleaseObj(hdc);
2632 return ret;
2635 /*************************************************************************
2636 * GetGlyphIndicesA [GDI32.@]
2638 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
2639 LPWORD pgi, DWORD flags)
2641 DWORD ret;
2642 WCHAR *lpstrW;
2643 INT countW;
2645 TRACE("(%p, %s, %d, %p, 0x%lx)\n",
2646 hdc, debugstr_an(lpstr, count), count, pgi, flags);
2648 lpstrW = FONT_mbtowc(lpstr, count, &countW);
2649 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
2650 HeapFree(GetProcessHeap(), 0, lpstrW);
2652 return ret;
2655 /*************************************************************************
2656 * GetGlyphIndicesW [GDI32.@]
2658 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
2659 LPWORD pgi, DWORD flags)
2661 DC *dc = DC_GetDCPtr(hdc);
2662 DWORD ret = GDI_ERROR;
2664 TRACE("(%p, %s, %d, %p, 0x%lx)\n",
2665 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2667 if(!dc) return GDI_ERROR;
2669 if(dc->gdiFont)
2670 ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);
2672 GDI_ReleaseObj(hdc);
2673 return ret;
2676 /*************************************************************************
2677 * GetCharacterPlacementA [GDI32.@]
2679 * See GetCharacterPlacementW.
2681 * NOTES:
2682 * the web browser control of ie4 calls this with dwFlags=0
2684 DWORD WINAPI
2685 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
2686 INT nMaxExtent, GCP_RESULTSA *lpResults,
2687 DWORD dwFlags)
2689 WCHAR *lpStringW;
2690 INT uCountW;
2691 GCP_RESULTSW resultsW;
2692 DWORD ret;
2694 TRACE("%s, %d, %d, 0x%08lx\n",
2695 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2697 /* both structs are equal in size */
2698 memcpy(&resultsW, lpResults, sizeof(resultsW));
2700 lpStringW = FONT_mbtowc(lpString, uCount, &uCountW);
2701 if(lpResults->lpOutString)
2702 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2704 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
2706 lpResults->nGlyphs = resultsW.nGlyphs;
2707 lpResults->nMaxFit = resultsW.nMaxFit;
2709 if(lpResults->lpOutString) {
2710 WideCharToMultiByte(CP_ACP, 0, resultsW.lpOutString, uCountW,
2711 lpResults->lpOutString, uCount, NULL, NULL );
2714 HeapFree(GetProcessHeap(), 0, lpStringW);
2715 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2717 return ret;
2720 /*************************************************************************
2721 * GetCharacterPlacementW [GDI32.@]
2723 * Retrieve information about a string. This includes the width, reordering,
2724 * Glyphing and so on.
2726 * RETURNS
2728 * The width and height of the string if successful, 0 if failed.
2730 * BUGS
2732 * All flags except GCP_REORDER are not yet implemented.
2733 * Reordering is not 100% complient to the Windows BiDi method.
2734 * Caret positioning is not yet implemented for BiDi.
2735 * Classes are not yet implemented.
2738 DWORD WINAPI
2739 GetCharacterPlacementW(
2740 HDC hdc, /* [in] Device context for which the rendering is to be done */
2741 LPCWSTR lpString, /* [in] The string for which information is to be returned */
2742 INT uCount, /* [in] Number of WORDS in string. */
2743 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
2744 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
2745 DWORD dwFlags /* [in] Flags specifying how to process the string */
2748 DWORD ret=0;
2749 SIZE size;
2750 UINT i, nSet;
2752 TRACE("%s, %d, %d, 0x%08lx\n",
2753 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2755 TRACE("lStructSize=%ld, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
2756 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2757 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
2758 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
2759 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
2761 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08lx ignored\n", dwFlags);
2762 if(lpResults->lpClass) FIXME("classes not implemented\n");
2763 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
2764 FIXME("Caret positions for complex scripts not implemented\n");
2766 nSet = (UINT)uCount;
2767 if(nSet > lpResults->nGlyphs)
2768 nSet = lpResults->nGlyphs;
2770 /* return number of initialized fields */
2771 lpResults->nGlyphs = nSet;
2773 if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
2775 /* Treat the case where no special handling was requested in a fastpath way */
2776 /* copy will do if the GCP_REORDER flag is not set */
2777 if(lpResults->lpOutString)
2778 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
2780 if(lpResults->lpOrder)
2782 for(i = 0; i < nSet; i++)
2783 lpResults->lpOrder[i] = i;
2785 } else
2787 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
2788 nSet, lpResults->lpOrder );
2791 /* FIXME: Will use the placement chars */
2792 if (lpResults->lpDx)
2794 int c;
2795 for (i = 0; i < nSet; i++)
2797 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
2798 lpResults->lpDx[i]= c;
2802 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
2804 int pos = 0;
2806 lpResults->lpCaretPos[0] = 0;
2807 for (i = 1; i < nSet; i++)
2808 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
2809 lpResults->lpCaretPos[i] = (pos += size.cx);
2812 if(lpResults->lpGlyphs)
2813 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
2815 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
2816 ret = MAKELONG(size.cx, size.cy);
2818 return ret;
2821 /*************************************************************************
2822 * GetCharABCWidthsFloatA [GDI32.@]
2824 * See GetCharABCWidthsFloatW.
2826 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2828 INT i, wlen, count = (INT)(last - first + 1);
2829 LPSTR str;
2830 LPWSTR wstr;
2831 BOOL ret = TRUE;
2833 if (count <= 0) return FALSE;
2835 str = HeapAlloc(GetProcessHeap(), 0, count);
2837 for(i = 0; i < count; i++)
2838 str[i] = (BYTE)(first + i);
2840 wstr = FONT_mbtowc(str, count, &wlen);
2842 for (i = 0; i < wlen; i++)
2844 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
2846 ret = FALSE;
2847 break;
2849 abcf++;
2852 HeapFree( GetProcessHeap(), 0, str );
2853 HeapFree( GetProcessHeap(), 0, wstr );
2855 return ret;
2858 /*************************************************************************
2859 * GetCharABCWidthsFloatW [GDI32.@]
2861 * Retrieves widths of a range of characters.
2863 * PARAMS
2864 * hdc [I] Handle to device context.
2865 * first [I] First character in range to query.
2866 * last [I] Last character in range to query.
2867 * abcf [O] Array of LPABCFLOAT structures.
2869 * RETURNS
2870 * Success: TRUE
2871 * Failure: FALSE
2873 * BUGS
2874 * Only works with TrueType fonts. It also doesn't return real
2875 * floats but converted integers because it's implemented on
2876 * top of GetCharABCWidthsW.
2878 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2880 ABC *abc;
2881 unsigned int i, size = sizeof(ABC) * (last - first + 1);
2882 BOOL ret;
2884 TRACE("%p, %d, %d, %p - partial stub\n", hdc, first, last, abcf);
2886 abc = HeapAlloc( GetProcessHeap(), 0, size );
2887 if (!abc) return FALSE;
2889 ret = GetCharABCWidthsW( hdc, first, last, abc );
2890 if (ret)
2892 for (i = first; i <= last; i++, abc++, abcf++)
2894 abcf->abcfA = abc->abcA;
2895 abcf->abcfB = abc->abcB;
2896 abcf->abcfC = abc->abcC;
2899 HeapFree( GetProcessHeap(), 0, abc );
2900 return ret;
2903 /*************************************************************************
2904 * GetCharWidthFloatA [GDI32.@]
2906 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
2907 UINT iLastChar, PFLOAT pxBuffer)
2909 FIXME_(gdi)("GetCharWidthFloatA, stub\n");
2910 return 0;
2913 /*************************************************************************
2914 * GetCharWidthFloatW [GDI32.@]
2916 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
2917 UINT iLastChar, PFLOAT pxBuffer)
2919 FIXME_(gdi)("GetCharWidthFloatW, stub\n");
2920 return 0;
2924 /***********************************************************************
2926 * Font Resource API *
2928 ***********************************************************************/
2930 /***********************************************************************
2931 * AddFontResourceA (GDI32.@)
2933 INT WINAPI AddFontResourceA( LPCSTR str )
2935 return AddFontResourceExA( str, 0, NULL);
2938 /***********************************************************************
2939 * AddFontResourceW (GDI32.@)
2941 INT WINAPI AddFontResourceW( LPCWSTR str )
2943 return AddFontResourceExW(str, 0, NULL);
2947 /***********************************************************************
2948 * AddFontResourceExA (GDI32.@)
2950 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
2952 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
2953 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2954 INT ret;
2956 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
2957 ret = AddFontResourceExW(strW, fl, pdv);
2958 HeapFree(GetProcessHeap(), 0, strW);
2959 return ret;
2962 /***********************************************************************
2963 * AddFontResourceExW (GDI32.@)
2965 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
2967 return WineEngAddFontResourceEx(str, fl, pdv);
2970 /***********************************************************************
2971 * RemoveFontResourceA (GDI32.@)
2973 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
2975 return RemoveFontResourceExA(str, 0, 0);
2978 /***********************************************************************
2979 * RemoveFontResourceW (GDI32.@)
2981 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
2983 return RemoveFontResourceExW(str, 0, 0);
2986 /***********************************************************************
2987 * AddFontMemResourceEx (GDI32.@)
2989 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2991 FIXME("(%p,%08lx,%p,%p): stub\n", pbFont, cbFont, pdv, pcFonts);
2992 return NULL;
2995 /***********************************************************************
2996 * RemoveFontResourceExA (GDI32.@)
2998 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3000 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3001 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3002 INT ret;
3004 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3005 ret = RemoveFontResourceExW(strW, fl, pdv);
3006 HeapFree(GetProcessHeap(), 0, strW);
3007 return ret;
3010 /***********************************************************************
3011 * RemoveFontResourceExW (GDI32.@)
3013 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3015 return WineEngRemoveFontResourceEx(str, fl, pdv);
3018 /***********************************************************************
3019 * GetTextCharset (GDI32.@)
3021 UINT WINAPI GetTextCharset(HDC hdc)
3023 /* MSDN docs say this is equivalent */
3024 return GetTextCharsetInfo(hdc, NULL, 0);
3027 /***********************************************************************
3028 * GetTextCharsetInfo (GDI32.@)
3030 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3032 UINT ret = DEFAULT_CHARSET;
3033 DC *dc = DC_GetDCPtr(hdc);
3035 if (!dc) goto done;
3037 if (dc->gdiFont)
3038 ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3040 GDI_ReleaseObj(hdc);
3042 done:
3043 if (ret == DEFAULT_CHARSET && fs)
3044 memset(fs, 0, sizeof(FONTSIGNATURE));
3045 return ret;
3048 /***********************************************************************
3049 * GdiGetCharDimensions (GDI32.@)
3051 * Gets the average width of the characters in the English alphabet.
3053 * PARAMS
3054 * hdc [I] Handle to the device context to measure on.
3055 * lptm [O] Pointer to memory to store the text metrics into.
3056 * height [O] On exit, the maximum height of characters in the English alphabet.
3058 * RETURNS
3059 * The average width of characters in the English alphabet.
3061 * NOTES
3062 * This function is used by the dialog manager to get the size of a dialog
3063 * unit. It should also be used by other pieces of code that need to know
3064 * the size of a dialog unit in logical units without having access to the
3065 * window handle of the dialog.
3066 * Windows caches the font metrics from this function, but we don't and
3067 * there doesn't appear to be an immediate advantage to do so.
3069 * SEE ALSO
3070 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3072 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3074 SIZE sz;
3075 static const WCHAR alphabet[] = {
3076 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3077 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3078 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3080 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3082 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3084 if (height) *height = sz.cy;
3085 return (sz.cx / 26 + 1) / 2;
3088 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3090 FIXME("(%d): stub\n", fEnableEUDC);
3091 return FALSE;
3094 /***********************************************************************
3095 * GetCharWidthI (GDI32.@)
3097 BOOL WINAPI GetCharWidthI(HDC hdc, UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer)
3099 FIXME("(%p, %d, %d, %p, %p): stub\n", hdc, giFirst, cgi, pgi, lpBuffer);
3100 return FALSE;
3103 /***********************************************************************
3104 * GetFontUnicodeRanges (GDI32.@)
3106 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3108 FIXME("(%p, %p): stub\n", hdc, lpgs);
3109 return 0;