gdi32: GetCharABCWidthsFloatW must succeed with non-TrueType fonts.
[wine/multimedia.git] / dlls / gdi32 / font.c
blobd2dfd449f77be7ff60b022aff26114da1515b531
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 <limits.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include "winerror.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "gdi_private.h"
37 #include "wine/exception.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 #ifdef WORDS_BIGENDIAN
42 #define get_be_word(x) (x)
43 #else
44 #define get_be_word(x) RtlUshortByteSwap(x)
45 #endif
47 WINE_DEFAULT_DEBUG_CHANNEL(font);
49 /* Device -> World size conversion */
51 /* Performs a device to world transformation on the specified width (which
52 * is in integer format).
54 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
56 double floatWidth;
58 /* Perform operation with floating point */
59 floatWidth = (double)width * dc->xformVport2World.eM11;
60 /* Round to integers */
61 return GDI_ROUND(floatWidth);
64 /* Performs a device to world transformation on the specified size (which
65 * is in integer format).
67 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
69 double floatHeight;
71 /* Perform operation with floating point */
72 floatHeight = (double)height * dc->xformVport2World.eM22;
73 /* Round to integers */
74 return GDI_ROUND(floatHeight);
77 static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
79 POINT pt[2];
80 pt[0].x = pt[0].y = 0;
81 pt[1].x = width;
82 pt[1].y = 0;
83 LPtoDP(dc->hSelf, pt, 2);
84 return pt[1].x - pt[0].x;
87 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
89 POINT pt[2];
90 pt[0].x = pt[0].y = 0;
91 pt[1].x = 0;
92 pt[1].y = height;
93 LPtoDP(dc->hSelf, pt, 2);
94 return pt[1].y - pt[0].y;
97 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
98 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
99 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
100 static BOOL FONT_DeleteObject( HGDIOBJ handle );
102 static const struct gdi_obj_funcs font_funcs =
104 FONT_SelectObject, /* pSelectObject */
105 FONT_GetObjectA, /* pGetObjectA */
106 FONT_GetObjectW, /* pGetObjectW */
107 NULL, /* pUnrealizeObject */
108 FONT_DeleteObject /* pDeleteObject */
111 typedef struct
113 GDIOBJHDR header;
114 LOGFONTW logfont;
115 } FONTOBJ;
117 struct font_enum
119 LPLOGFONTW lpLogFontParam;
120 FONTENUMPROCW lpEnumFunc;
121 LPARAM lpData;
122 BOOL unicode;
123 HDC hdc;
127 * For TranslateCharsetInfo
129 #define MAXTCIINDEX 32
130 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
131 /* ANSI */
132 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
133 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
134 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
135 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
136 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
137 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
138 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
139 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
140 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
141 /* reserved by ANSI */
142 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
145 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
146 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
147 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
148 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
149 /* ANSI and OEM */
150 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
151 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
152 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
153 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
154 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
155 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
156 /* reserved for alternate ANSI and OEM */
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
161 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
162 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
163 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
164 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
165 /* reserved for system */
166 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
167 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
170 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
172 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
173 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
174 LF_FACESIZE);
175 fontW->lfFaceName[LF_FACESIZE-1] = 0;
178 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
180 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
181 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
182 LF_FACESIZE, NULL, NULL);
183 fontA->lfFaceName[LF_FACESIZE-1] = 0;
186 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
188 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
190 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
191 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
192 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
193 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
194 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
195 fontA->elfStyle[LF_FACESIZE-1] = '\0';
196 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
197 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
198 fontA->elfScript[LF_FACESIZE-1] = '\0';
201 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
203 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
205 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
206 fontW->elfFullName, LF_FULLFACESIZE );
207 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
208 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
209 fontW->elfStyle, LF_FACESIZE );
210 fontW->elfStyle[LF_FACESIZE-1] = '\0';
211 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
212 fontW->elfScript, LF_FACESIZE );
213 fontW->elfScript[LF_FACESIZE-1] = '\0';
216 /***********************************************************************
217 * TEXTMETRIC conversion functions.
219 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
221 ptmA->tmHeight = ptmW->tmHeight;
222 ptmA->tmAscent = ptmW->tmAscent;
223 ptmA->tmDescent = ptmW->tmDescent;
224 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
225 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
226 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
227 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
228 ptmA->tmWeight = ptmW->tmWeight;
229 ptmA->tmOverhang = ptmW->tmOverhang;
230 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
231 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
232 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
233 if (ptmW->tmCharSet == SYMBOL_CHARSET)
235 ptmA->tmFirstChar = 0x1e;
236 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
238 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
240 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
241 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
243 else
245 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
246 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
248 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
249 ptmA->tmBreakChar = ptmW->tmBreakChar;
250 ptmA->tmItalic = ptmW->tmItalic;
251 ptmA->tmUnderlined = ptmW->tmUnderlined;
252 ptmA->tmStruckOut = ptmW->tmStruckOut;
253 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
254 ptmA->tmCharSet = ptmW->tmCharSet;
258 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
260 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
261 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
262 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
263 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
264 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
265 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
268 static DWORD get_font_ppem( HDC hdc )
270 TEXTMETRICW tm;
271 DWORD ppem;
272 DC *dc = get_dc_ptr( hdc );
274 if (!dc) return GDI_ERROR;
276 GetTextMetricsW( hdc, &tm );
277 ppem = abs( INTERNAL_YWSTODS( dc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading ) );
278 release_dc_ptr( dc );
279 return ppem;
282 #define GASP_GRIDFIT 0x01
283 #define GASP_DOGRAY 0x02
285 static BOOL get_gasp_flags( HDC hdc, WORD *flags )
287 DWORD size, gasp_tag = 0x70736167;
288 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
289 WORD *alloced = NULL, *ptr = buf;
290 WORD num_recs, version;
291 DWORD ppem = get_font_ppem( hdc );
292 BOOL ret = FALSE;
294 *flags = 0;
295 if (ppem == GDI_ERROR) return FALSE;
297 size = GetFontData( hdc, gasp_tag, 0, NULL, 0 );
298 if (size == GDI_ERROR) return FALSE;
299 if (size < 4 * sizeof(WORD)) return FALSE;
300 if (size > sizeof(buf))
302 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
303 if (!ptr) return FALSE;
306 GetFontData( hdc, gasp_tag, 0, ptr, size );
308 version = get_be_word( *ptr++ );
309 num_recs = get_be_word( *ptr++ );
311 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
313 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
314 goto done;
317 while (num_recs--)
319 *flags = get_be_word( *(ptr + 1) );
320 if (ppem <= get_be_word( *ptr )) break;
321 ptr += 2;
323 TRACE( "got flags %04x for ppem %d\n", *flags, ppem );
324 ret = TRUE;
326 done:
327 HeapFree( GetProcessHeap(), 0, alloced );
328 return ret;
331 UINT get_font_aa_flags( HDC hdc )
333 LOGFONTW lf;
334 WORD gasp_flags;
336 if (GetObjectType( hdc ) == OBJ_MEMDC)
338 BITMAP bm;
339 GetObjectW( GetCurrentObject( hdc, OBJ_BITMAP ), sizeof(bm), &bm );
340 if (bm.bmBitsPixel <= 8) return GGO_BITMAP;
342 else if (GetDeviceCaps( hdc, BITSPIXEL ) <= 8) return GGO_BITMAP;
344 GetObjectW( GetCurrentObject( hdc, OBJ_FONT ), sizeof(lf), &lf );
345 if (lf.lfQuality == NONANTIALIASED_QUALITY) return GGO_BITMAP;
347 if (get_gasp_flags( hdc, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
348 return GGO_BITMAP;
350 /* FIXME, check user prefs */
351 return GGO_GRAY4_BITMAP;
354 /***********************************************************************
355 * GdiGetCodePage (GDI32.@)
357 DWORD WINAPI GdiGetCodePage( HDC hdc )
359 UINT cp = CP_ACP;
360 DC *dc = get_dc_ptr( hdc );
362 if (dc)
364 cp = dc->font_code_page;
365 release_dc_ptr( dc );
367 return cp;
370 /***********************************************************************
371 * FONT_mbtowc
373 * Returns a Unicode translation of str using the charset of the
374 * currently selected font in hdc. If count is -1 then str is assumed
375 * to be '\0' terminated, otherwise it contains the number of bytes to
376 * convert. If plenW is non-NULL, on return it will point to the
377 * number of WCHARs that have been written. If pCP is non-NULL, on
378 * return it will point to the codepage used in the conversion. The
379 * caller should free the returned LPWSTR from the process heap
380 * itself.
382 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
384 UINT cp;
385 INT lenW;
386 LPWSTR strW;
388 cp = GdiGetCodePage( hdc );
390 if(count == -1) count = strlen(str);
391 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
392 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
393 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
394 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
395 if(plenW) *plenW = lenW;
396 if(pCP) *pCP = cp;
397 return strW;
400 /***********************************************************************
401 * CreateFontIndirectExA (GDI32.@)
403 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
405 ENUMLOGFONTEXDVW enumexW;
407 if (!penumexA) return 0;
409 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
410 enumexW.elfDesignVector = penumexA->elfDesignVector;
411 return CreateFontIndirectExW( &enumexW );
414 /***********************************************************************
415 * CreateFontIndirectExW (GDI32.@)
417 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
419 HFONT hFont;
420 FONTOBJ *fontPtr;
421 const LOGFONTW *plf;
423 if (!penumex) return 0;
425 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
426 penumex->elfEnumLogfontEx.elfStyle[0] ||
427 penumex->elfEnumLogfontEx.elfScript[0])
429 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
430 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
431 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
432 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
435 plf = &penumex->elfEnumLogfontEx.elfLogFont;
436 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
438 fontPtr->logfont = *plf;
440 if (plf->lfEscapement != plf->lfOrientation)
442 /* this should really depend on whether GM_ADVANCED is set */
443 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
444 WARN("orientation angle %f set to "
445 "escapement angle %f for new font %p\n",
446 plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
449 if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs )))
451 HeapFree( GetProcessHeap(), 0, fontPtr );
452 return 0;
455 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
456 plf->lfHeight, plf->lfWidth,
457 plf->lfEscapement, plf->lfOrientation,
458 plf->lfPitchAndFamily,
459 plf->lfOutPrecision, plf->lfClipPrecision,
460 plf->lfQuality, plf->lfCharSet,
461 debugstr_w(plf->lfFaceName),
462 plf->lfWeight > 400 ? "Bold" : "",
463 plf->lfItalic ? "Italic" : "",
464 plf->lfUnderline ? "Underline" : "", hFont);
466 return hFont;
469 /***********************************************************************
470 * CreateFontIndirectA (GDI32.@)
472 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
474 LOGFONTW lfW;
476 if (!plfA) return 0;
478 FONT_LogFontAToW( plfA, &lfW );
479 return CreateFontIndirectW( &lfW );
482 /***********************************************************************
483 * CreateFontIndirectW (GDI32.@)
485 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
487 ENUMLOGFONTEXDVW exdv;
489 if (!plf) return 0;
491 exdv.elfEnumLogfontEx.elfLogFont = *plf;
492 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
493 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
494 exdv.elfEnumLogfontEx.elfScript[0] = 0;
495 return CreateFontIndirectExW( &exdv );
498 /*************************************************************************
499 * CreateFontA (GDI32.@)
501 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
502 INT orient, INT weight, DWORD italic,
503 DWORD underline, DWORD strikeout, DWORD charset,
504 DWORD outpres, DWORD clippres, DWORD quality,
505 DWORD pitch, LPCSTR name )
507 LOGFONTA logfont;
509 logfont.lfHeight = height;
510 logfont.lfWidth = width;
511 logfont.lfEscapement = esc;
512 logfont.lfOrientation = orient;
513 logfont.lfWeight = weight;
514 logfont.lfItalic = italic;
515 logfont.lfUnderline = underline;
516 logfont.lfStrikeOut = strikeout;
517 logfont.lfCharSet = charset;
518 logfont.lfOutPrecision = outpres;
519 logfont.lfClipPrecision = clippres;
520 logfont.lfQuality = quality;
521 logfont.lfPitchAndFamily = pitch;
523 if (name)
524 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
525 else
526 logfont.lfFaceName[0] = '\0';
528 return CreateFontIndirectA( &logfont );
531 /*************************************************************************
532 * CreateFontW (GDI32.@)
534 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
535 INT orient, INT weight, DWORD italic,
536 DWORD underline, DWORD strikeout, DWORD charset,
537 DWORD outpres, DWORD clippres, DWORD quality,
538 DWORD pitch, LPCWSTR name )
540 LOGFONTW logfont;
542 logfont.lfHeight = height;
543 logfont.lfWidth = width;
544 logfont.lfEscapement = esc;
545 logfont.lfOrientation = orient;
546 logfont.lfWeight = weight;
547 logfont.lfItalic = italic;
548 logfont.lfUnderline = underline;
549 logfont.lfStrikeOut = strikeout;
550 logfont.lfCharSet = charset;
551 logfont.lfOutPrecision = outpres;
552 logfont.lfClipPrecision = clippres;
553 logfont.lfQuality = quality;
554 logfont.lfPitchAndFamily = pitch;
556 if (name)
557 lstrcpynW(logfont.lfFaceName, name,
558 sizeof(logfont.lfFaceName) / sizeof(WCHAR));
559 else
560 logfont.lfFaceName[0] = '\0';
562 return CreateFontIndirectW( &logfont );
565 static void update_font_code_page( DC *dc )
567 CHARSETINFO csi;
568 int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
570 /* Hmm, nicely designed api this one! */
571 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
572 dc->font_code_page = csi.ciACP;
573 else {
574 switch(charset) {
575 case OEM_CHARSET:
576 dc->font_code_page = GetOEMCP();
577 break;
578 case DEFAULT_CHARSET:
579 dc->font_code_page = GetACP();
580 break;
582 case VISCII_CHARSET:
583 case TCVN_CHARSET:
584 case KOI8_CHARSET:
585 case ISO3_CHARSET:
586 case ISO4_CHARSET:
587 case ISO10_CHARSET:
588 case CELTIC_CHARSET:
589 /* FIXME: These have no place here, but because x11drv
590 enumerates fonts with these (made up) charsets some apps
591 might use them and then the FIXME below would become
592 annoying. Now we could pick the intended codepage for
593 each of these, but since it's broken anyway we'll just
594 use CP_ACP and hope it'll go away...
596 dc->font_code_page = CP_ACP;
597 break;
599 default:
600 FIXME("Can't find codepage for charset %d\n", charset);
601 dc->font_code_page = CP_ACP;
602 break;
606 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
609 /***********************************************************************
610 * FONT_SelectObject
612 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
614 HGDIOBJ ret = 0;
615 DC *dc = get_dc_ptr( hdc );
616 PHYSDEV physdev;
618 if (!dc) return 0;
620 if (!GDI_inc_ref_count( handle ))
622 release_dc_ptr( dc );
623 return 0;
626 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
627 if (physdev->funcs->pSelectFont( physdev, handle ))
629 ret = dc->hFont;
630 dc->hFont = handle;
631 update_font_code_page( dc );
632 GDI_dec_ref_count( ret );
634 else GDI_dec_ref_count( handle );
636 release_dc_ptr( dc );
637 return ret;
641 /***********************************************************************
642 * FONT_GetObjectA
644 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
646 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
647 LOGFONTA lfA;
649 if (!font) return 0;
650 if (buffer)
652 FONT_LogFontWToA( &font->logfont, &lfA );
653 if (count > sizeof(lfA)) count = sizeof(lfA);
654 memcpy( buffer, &lfA, count );
656 else count = sizeof(lfA);
657 GDI_ReleaseObj( handle );
658 return count;
661 /***********************************************************************
662 * FONT_GetObjectW
664 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
666 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
668 if (!font) return 0;
669 if (buffer)
671 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
672 memcpy( buffer, &font->logfont, count );
674 else count = sizeof(LOGFONTW);
675 GDI_ReleaseObj( handle );
676 return count;
680 /***********************************************************************
681 * FONT_DeleteObject
683 static BOOL FONT_DeleteObject( HGDIOBJ handle )
685 FONTOBJ *obj;
687 WineEngDestroyFontInstance( handle );
689 if (!(obj = free_gdi_handle( handle ))) return FALSE;
690 return HeapFree( GetProcessHeap(), 0, obj );
694 /***********************************************************************
695 * FONT_EnumInstance
697 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
698 * We have to use other types because of the FONTENUMPROCW definition.
700 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
701 DWORD fType, LPARAM lp )
703 struct font_enum *pfe = (struct font_enum *)lp;
704 INT ret = 1;
706 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
707 if ((!pfe->lpLogFontParam ||
708 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
709 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
710 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
712 /* convert font metrics */
713 ENUMLOGFONTEXA logfont;
714 NEWTEXTMETRICEXA tmA;
716 if (!pfe->unicode)
718 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
719 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
720 plf = (LOGFONTW *)&logfont.elfLogFont;
721 ptm = (TEXTMETRICW *)&tmA;
723 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
725 return ret;
728 /***********************************************************************
729 * FONT_EnumFontFamiliesEx
731 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
732 LPARAM lParam, BOOL unicode )
734 INT ret = 0;
735 DC *dc = get_dc_ptr( hDC );
736 struct font_enum fe;
738 if (dc)
740 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
742 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
743 fe.lpLogFontParam = plf;
744 fe.lpEnumFunc = efproc;
745 fe.lpData = lParam;
746 fe.unicode = unicode;
747 fe.hdc = hDC;
748 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
749 release_dc_ptr( dc );
751 return ret;
754 /***********************************************************************
755 * EnumFontFamiliesExW (GDI32.@)
757 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
758 FONTENUMPROCW efproc,
759 LPARAM lParam, DWORD dwFlags )
761 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
764 /***********************************************************************
765 * EnumFontFamiliesExA (GDI32.@)
767 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
768 FONTENUMPROCA efproc,
769 LPARAM lParam, DWORD dwFlags)
771 LOGFONTW lfW, *plfW;
773 if (plf)
775 FONT_LogFontAToW( plf, &lfW );
776 plfW = &lfW;
778 else plfW = NULL;
780 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
783 /***********************************************************************
784 * EnumFontFamiliesA (GDI32.@)
786 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
787 FONTENUMPROCA efproc, LPARAM lpData )
789 LOGFONTA lf, *plf;
791 if (lpFamily)
793 if (!*lpFamily) return 1;
794 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
795 lf.lfCharSet = DEFAULT_CHARSET;
796 lf.lfPitchAndFamily = 0;
797 plf = &lf;
799 else plf = NULL;
801 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
804 /***********************************************************************
805 * EnumFontFamiliesW (GDI32.@)
807 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
808 FONTENUMPROCW efproc, LPARAM lpData )
810 LOGFONTW lf, *plf;
812 if (lpFamily)
814 if (!*lpFamily) return 1;
815 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
816 lf.lfCharSet = DEFAULT_CHARSET;
817 lf.lfPitchAndFamily = 0;
818 plf = &lf;
820 else plf = NULL;
822 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
825 /***********************************************************************
826 * EnumFontsA (GDI32.@)
828 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
829 LPARAM lpData )
831 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
834 /***********************************************************************
835 * EnumFontsW (GDI32.@)
837 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
838 LPARAM lpData )
840 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
844 /***********************************************************************
845 * GetTextCharacterExtra (GDI32.@)
847 INT WINAPI GetTextCharacterExtra( HDC hdc )
849 INT ret;
850 DC *dc = get_dc_ptr( hdc );
851 if (!dc) return 0x80000000;
852 ret = dc->charExtra;
853 release_dc_ptr( dc );
854 return ret;
858 /***********************************************************************
859 * SetTextCharacterExtra (GDI32.@)
861 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
863 INT ret = 0x80000000;
864 DC * dc = get_dc_ptr( hdc );
866 if (dc)
868 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
869 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
870 if (extra != 0x80000000)
872 ret = dc->charExtra;
873 dc->charExtra = extra;
875 release_dc_ptr( dc );
877 return ret;
881 /***********************************************************************
882 * SetTextJustification (GDI32.@)
884 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
886 BOOL ret;
887 PHYSDEV physdev;
888 DC * dc = get_dc_ptr( hdc );
890 if (!dc) return FALSE;
892 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
893 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
894 if (ret)
896 extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
897 if (!extra) breaks = 0;
898 if (breaks)
900 dc->breakExtra = extra / breaks;
901 dc->breakRem = extra - (breaks * dc->breakExtra);
903 else
905 dc->breakExtra = 0;
906 dc->breakRem = 0;
909 release_dc_ptr( dc );
910 return ret;
914 /***********************************************************************
915 * GetTextFaceA (GDI32.@)
917 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
919 INT res = GetTextFaceW(hdc, 0, NULL);
920 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
921 GetTextFaceW( hdc, res, nameW );
923 if (name)
925 if (count)
927 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
928 if (res == 0)
929 res = count;
930 name[count-1] = 0;
931 /* GetTextFaceA does NOT include the nul byte in the return count. */
932 res--;
934 else
935 res = 0;
937 else
938 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
939 HeapFree( GetProcessHeap(), 0, nameW );
940 return res;
943 /***********************************************************************
944 * GetTextFaceW (GDI32.@)
946 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
948 PHYSDEV dev;
949 INT ret;
951 DC * dc = get_dc_ptr( hdc );
952 if (!dc) return 0;
954 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
955 ret = dev->funcs->pGetTextFace( dev, count, name );
956 release_dc_ptr( dc );
957 return ret;
961 /***********************************************************************
962 * GetTextExtentPoint32A (GDI32.@)
964 * See GetTextExtentPoint32W.
966 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
967 LPSIZE size )
969 BOOL ret = FALSE;
970 INT wlen;
971 LPWSTR p;
973 if (count < 0) return FALSE;
975 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
977 if (p)
979 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
980 HeapFree( GetProcessHeap(), 0, p );
983 TRACE("(%p %s %d %p): returning %d x %d\n",
984 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
985 return ret;
989 /***********************************************************************
990 * GetTextExtentPoint32W [GDI32.@]
992 * Computes width/height for a string.
994 * Computes width and height of the specified string.
996 * RETURNS
997 * Success: TRUE
998 * Failure: FALSE
1000 BOOL WINAPI GetTextExtentPoint32W(
1001 HDC hdc, /* [in] Handle of device context */
1002 LPCWSTR str, /* [in] Address of text string */
1003 INT count, /* [in] Number of characters in string */
1004 LPSIZE size) /* [out] Address of structure for string size */
1006 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
1009 /***********************************************************************
1010 * GetTextExtentExPointI [GDI32.@]
1012 * Computes width and height of the array of glyph indices.
1014 * PARAMS
1015 * hdc [I] Handle of device context.
1016 * indices [I] Glyph index array.
1017 * count [I] Number of glyphs in array.
1018 * max_ext [I] Maximum width in glyphs.
1019 * nfit [O] Maximum number of characters.
1020 * dxs [O] Partial string widths.
1021 * size [O] Returned string size.
1023 * RETURNS
1024 * Success: TRUE
1025 * Failure: FALSE
1027 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1028 LPINT nfit, LPINT dxs, LPSIZE size )
1030 PHYSDEV dev;
1031 BOOL ret;
1032 DC *dc;
1034 if (count < 0) return FALSE;
1036 dc = get_dc_ptr( hdc );
1037 if (!dc) return FALSE;
1039 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
1040 ret = dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, nfit, dxs, size );
1041 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1042 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1043 size->cx += count * dc->charExtra;
1044 release_dc_ptr( dc );
1046 TRACE("(%p %p %d %p): returning %d x %d\n",
1047 hdc, indices, count, size, size->cx, size->cy );
1048 return ret;
1051 /***********************************************************************
1052 * GetTextExtentPointI [GDI32.@]
1054 * Computes width and height of the array of glyph indices.
1056 * PARAMS
1057 * hdc [I] Handle of device context.
1058 * indices [I] Glyph index array.
1059 * count [I] Number of glyphs in array.
1060 * size [O] Returned string size.
1062 * RETURNS
1063 * Success: TRUE
1064 * Failure: FALSE
1066 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
1068 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1072 /***********************************************************************
1073 * GetTextExtentPointA (GDI32.@)
1075 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
1076 LPSIZE size )
1078 TRACE("not bug compatible.\n");
1079 return GetTextExtentPoint32A( hdc, str, count, size );
1082 /***********************************************************************
1083 * GetTextExtentPointW (GDI32.@)
1085 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
1086 LPSIZE size )
1088 TRACE("not bug compatible.\n");
1089 return GetTextExtentPoint32W( hdc, str, count, size );
1093 /***********************************************************************
1094 * GetTextExtentExPointA (GDI32.@)
1096 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1097 INT maxExt, LPINT lpnFit,
1098 LPINT alpDx, LPSIZE size )
1100 BOOL ret;
1101 INT wlen;
1102 INT *walpDx = NULL;
1103 LPWSTR p = NULL;
1105 if (count < 0) return FALSE;
1107 if (alpDx)
1109 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1110 if (!walpDx) return FALSE;
1113 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1114 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
1115 if (walpDx)
1117 INT n = lpnFit ? *lpnFit : wlen;
1118 INT i, j;
1119 for(i = 0, j = 0; i < n; i++, j++)
1121 alpDx[j] = walpDx[i];
1122 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
1125 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1126 HeapFree( GetProcessHeap(), 0, p );
1127 HeapFree( GetProcessHeap(), 0, walpDx );
1128 return ret;
1132 /***********************************************************************
1133 * GetTextExtentExPointW (GDI32.@)
1135 * Return the size of the string as it would be if it was output properly by
1136 * e.g. TextOut.
1138 * This should include
1139 * - Intercharacter spacing
1140 * - justification spacing (not yet done)
1141 * - kerning? see below
1143 * Kerning. Since kerning would be carried out by the rendering code it should
1144 * be done by the driver. However they don't support it yet. Also I am not
1145 * yet persuaded that (certainly under Win95) any kerning is actually done.
1147 * str: According to MSDN this should be null-terminated. That is not true; a
1148 * null will not terminate it early.
1149 * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less
1150 * than count. I have seen it be either the size of the full string or
1151 * 1 less than the size of the full string. I have not seen it bear any
1152 * resemblance to the portion that would fit.
1153 * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the
1154 * trailing intercharacter spacing and any trailing justification.
1156 * FIXME
1157 * Currently we do this by measuring each character etc. We should do it by
1158 * passing the request to the driver, perhaps by extending the
1159 * pGetTextExtentPoint function to take the alpDx argument. That would avoid
1160 * thinking about kerning issues and rounding issues in the justification.
1163 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
1164 INT maxExt, LPINT lpnFit,
1165 LPINT alpDx, LPSIZE size )
1167 INT nFit = 0;
1168 LPINT dxs = NULL;
1169 DC *dc;
1170 BOOL ret = FALSE;
1171 TEXTMETRICW tm;
1172 PHYSDEV dev;
1174 TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1176 if (count < 0) return FALSE;
1178 dc = get_dc_ptr(hdc);
1179 if (!dc) return FALSE;
1181 GetTextMetricsW(hdc, &tm);
1183 /* If we need to calculate nFit, then we need the partial extents even if
1184 the user hasn't provided us with an array. */
1185 if (lpnFit)
1187 dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
1188 if (! dxs)
1190 release_dc_ptr(dc);
1191 SetLastError(ERROR_OUTOFMEMORY);
1192 return FALSE;
1195 else
1196 dxs = alpDx;
1198 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
1199 ret = dev->funcs->pGetTextExtentExPoint(dev, str, count, 0, NULL, dxs, size);
1201 /* Perform device size to world size transformations. */
1202 if (ret)
1204 INT extra = dc->charExtra,
1205 breakExtra = dc->breakExtra,
1206 breakRem = dc->breakRem,
1209 if (dxs)
1211 for (i = 0; i < count; ++i)
1213 dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1214 dxs[i] += (i+1) * extra;
1215 if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
1217 dxs[i] += breakExtra;
1218 if (breakRem > 0)
1220 breakRem--;
1221 dxs[i]++;
1224 if (dxs[i] <= maxExt)
1225 ++nFit;
1227 breakRem = dc->breakRem;
1229 size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
1230 size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1232 if (!dxs && count > 1 && (breakExtra || breakRem))
1234 for (i = 0; i < count; i++)
1236 if (str[i] == tm.tmBreakChar)
1238 size->cx += breakExtra;
1239 if (breakRem > 0)
1241 breakRem--;
1242 (size->cx)++;
1249 if (lpnFit)
1250 *lpnFit = nFit;
1252 if (! alpDx)
1253 HeapFree(GetProcessHeap(), 0, dxs);
1255 release_dc_ptr( dc );
1257 TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1258 return ret;
1261 /***********************************************************************
1262 * GetTextMetricsA (GDI32.@)
1264 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1266 TEXTMETRICW tm32;
1268 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1269 FONT_TextMetricWToA( &tm32, metrics );
1270 return TRUE;
1273 /***********************************************************************
1274 * GetTextMetricsW (GDI32.@)
1276 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1278 PHYSDEV physdev;
1279 BOOL ret = FALSE;
1280 DC * dc = get_dc_ptr( hdc );
1281 if (!dc) return FALSE;
1283 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
1284 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1286 if (ret)
1288 /* device layer returns values in device units
1289 * therefore we have to convert them to logical */
1291 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1292 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1294 #define WDPTOLP(x) ((x<0)? \
1295 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1296 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1297 #define HDPTOLP(y) ((y<0)? \
1298 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1299 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1301 metrics->tmHeight = HDPTOLP(metrics->tmHeight);
1302 metrics->tmAscent = HDPTOLP(metrics->tmAscent);
1303 metrics->tmDescent = HDPTOLP(metrics->tmDescent);
1304 metrics->tmInternalLeading = HDPTOLP(metrics->tmInternalLeading);
1305 metrics->tmExternalLeading = HDPTOLP(metrics->tmExternalLeading);
1306 metrics->tmAveCharWidth = WDPTOLP(metrics->tmAveCharWidth);
1307 metrics->tmMaxCharWidth = WDPTOLP(metrics->tmMaxCharWidth);
1308 metrics->tmOverhang = WDPTOLP(metrics->tmOverhang);
1309 ret = TRUE;
1310 #undef WDPTOLP
1311 #undef HDPTOLP
1312 TRACE("text metrics:\n"
1313 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1314 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1315 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1316 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1317 " PitchAndFamily = %02x\n"
1318 " --------------------\n"
1319 " InternalLeading = %i\n"
1320 " Ascent = %i\n"
1321 " Descent = %i\n"
1322 " Height = %i\n",
1323 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
1324 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
1325 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
1326 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
1327 metrics->tmPitchAndFamily,
1328 metrics->tmInternalLeading,
1329 metrics->tmAscent,
1330 metrics->tmDescent,
1331 metrics->tmHeight );
1333 release_dc_ptr( dc );
1334 return ret;
1338 /***********************************************************************
1339 * GetOutlineTextMetricsA (GDI32.@)
1340 * Gets metrics for TrueType fonts.
1342 * NOTES
1343 * If the supplied buffer isn't big enough Windows partially fills it up to
1344 * its given length and returns that length.
1346 * RETURNS
1347 * Success: Non-zero or size of required buffer
1348 * Failure: 0
1350 UINT WINAPI GetOutlineTextMetricsA(
1351 HDC hdc, /* [in] Handle of device context */
1352 UINT cbData, /* [in] Size of metric data array */
1353 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
1355 char buf[512], *ptr;
1356 UINT ret, needed;
1357 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1358 OUTLINETEXTMETRICA *output = lpOTM;
1359 INT left, len;
1361 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1362 return 0;
1363 if(ret > sizeof(buf))
1364 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1365 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1367 needed = sizeof(OUTLINETEXTMETRICA);
1368 if(lpOTMW->otmpFamilyName)
1369 needed += WideCharToMultiByte(CP_ACP, 0,
1370 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1371 NULL, 0, NULL, NULL);
1372 if(lpOTMW->otmpFaceName)
1373 needed += WideCharToMultiByte(CP_ACP, 0,
1374 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1375 NULL, 0, NULL, NULL);
1376 if(lpOTMW->otmpStyleName)
1377 needed += WideCharToMultiByte(CP_ACP, 0,
1378 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1379 NULL, 0, NULL, NULL);
1380 if(lpOTMW->otmpFullName)
1381 needed += WideCharToMultiByte(CP_ACP, 0,
1382 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1383 NULL, 0, NULL, NULL);
1385 if(!lpOTM) {
1386 ret = needed;
1387 goto end;
1390 TRACE("needed = %d\n", needed);
1391 if(needed > cbData)
1392 /* Since the supplied buffer isn't big enough, we'll alloc one
1393 that is and memcpy the first cbData bytes into the lpOTM at
1394 the end. */
1395 output = HeapAlloc(GetProcessHeap(), 0, needed);
1397 ret = output->otmSize = min(needed, cbData);
1398 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1399 output->otmFiller = 0;
1400 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1401 output->otmfsSelection = lpOTMW->otmfsSelection;
1402 output->otmfsType = lpOTMW->otmfsType;
1403 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1404 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1405 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1406 output->otmEMSquare = lpOTMW->otmEMSquare;
1407 output->otmAscent = lpOTMW->otmAscent;
1408 output->otmDescent = lpOTMW->otmDescent;
1409 output->otmLineGap = lpOTMW->otmLineGap;
1410 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1411 output->otmsXHeight = lpOTMW->otmsXHeight;
1412 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1413 output->otmMacAscent = lpOTMW->otmMacAscent;
1414 output->otmMacDescent = lpOTMW->otmMacDescent;
1415 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1416 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1417 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1418 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1419 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1420 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1421 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1422 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1423 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1424 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1427 ptr = (char*)(output + 1);
1428 left = needed - sizeof(*output);
1430 if(lpOTMW->otmpFamilyName) {
1431 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1432 len = WideCharToMultiByte(CP_ACP, 0,
1433 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1434 ptr, left, NULL, NULL);
1435 left -= len;
1436 ptr += len;
1437 } else
1438 output->otmpFamilyName = 0;
1440 if(lpOTMW->otmpFaceName) {
1441 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1442 len = WideCharToMultiByte(CP_ACP, 0,
1443 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1444 ptr, left, NULL, NULL);
1445 left -= len;
1446 ptr += len;
1447 } else
1448 output->otmpFaceName = 0;
1450 if(lpOTMW->otmpStyleName) {
1451 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1452 len = WideCharToMultiByte(CP_ACP, 0,
1453 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1454 ptr, left, NULL, NULL);
1455 left -= len;
1456 ptr += len;
1457 } else
1458 output->otmpStyleName = 0;
1460 if(lpOTMW->otmpFullName) {
1461 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1462 len = WideCharToMultiByte(CP_ACP, 0,
1463 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1464 ptr, left, NULL, NULL);
1465 left -= len;
1466 } else
1467 output->otmpFullName = 0;
1469 assert(left == 0);
1471 if(output != lpOTM) {
1472 memcpy(lpOTM, output, cbData);
1473 HeapFree(GetProcessHeap(), 0, output);
1475 /* check if the string offsets really fit into the provided size */
1476 /* FIXME: should we check string length as well? */
1477 /* make sure that we don't read/write beyond the provided buffer */
1478 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
1480 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1481 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1484 /* make sure that we don't read/write beyond the provided buffer */
1485 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
1487 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1488 lpOTM->otmpFaceName = 0; /* doesn't fit */
1491 /* make sure that we don't read/write beyond the provided buffer */
1492 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
1494 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1495 lpOTM->otmpStyleName = 0; /* doesn't fit */
1498 /* make sure that we don't read/write beyond the provided buffer */
1499 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
1501 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1502 lpOTM->otmpFullName = 0; /* doesn't fit */
1506 end:
1507 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1508 HeapFree(GetProcessHeap(), 0, lpOTMW);
1510 return ret;
1514 /***********************************************************************
1515 * GetOutlineTextMetricsW [GDI32.@]
1517 UINT WINAPI GetOutlineTextMetricsW(
1518 HDC hdc, /* [in] Handle of device context */
1519 UINT cbData, /* [in] Size of metric data array */
1520 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
1522 DC *dc = get_dc_ptr( hdc );
1523 OUTLINETEXTMETRICW *output = lpOTM;
1524 PHYSDEV dev;
1525 UINT ret;
1527 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1528 if(!dc) return 0;
1530 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
1531 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1533 if (lpOTM && ret > cbData)
1535 output = HeapAlloc(GetProcessHeap(), 0, ret);
1536 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
1539 if (lpOTM && ret)
1541 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1542 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1544 #define WDPTOLP(x) ((x<0)? \
1545 (-abs(INTERNAL_XDSTOWS(dc, (x)))): \
1546 (abs(INTERNAL_XDSTOWS(dc, (x)))))
1547 #define HDPTOLP(y) ((y<0)? \
1548 (-abs(INTERNAL_YDSTOWS(dc, (y)))): \
1549 (abs(INTERNAL_YDSTOWS(dc, (y)))))
1551 output->otmTextMetrics.tmHeight = HDPTOLP(output->otmTextMetrics.tmHeight);
1552 output->otmTextMetrics.tmAscent = HDPTOLP(output->otmTextMetrics.tmAscent);
1553 output->otmTextMetrics.tmDescent = HDPTOLP(output->otmTextMetrics.tmDescent);
1554 output->otmTextMetrics.tmInternalLeading = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
1555 output->otmTextMetrics.tmExternalLeading = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
1556 output->otmTextMetrics.tmAveCharWidth = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
1557 output->otmTextMetrics.tmMaxCharWidth = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
1558 output->otmTextMetrics.tmOverhang = WDPTOLP(output->otmTextMetrics.tmOverhang);
1559 output->otmAscent = HDPTOLP(output->otmAscent);
1560 output->otmDescent = HDPTOLP(output->otmDescent);
1561 output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
1562 output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
1563 output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1564 output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
1565 output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
1566 output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
1567 output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
1568 output->otmMacAscent = HDPTOLP(output->otmMacAscent);
1569 output->otmMacDescent = HDPTOLP(output->otmMacDescent);
1570 output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1571 output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
1572 output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
1573 output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
1574 output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
1575 output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
1576 output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
1577 output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
1578 output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
1579 output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1580 output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
1581 output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
1582 output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1583 #undef WDPTOLP
1584 #undef HDPTOLP
1585 if(output != lpOTM)
1587 memcpy(lpOTM, output, cbData);
1588 HeapFree(GetProcessHeap(), 0, output);
1589 ret = cbData;
1592 release_dc_ptr(dc);
1593 return ret;
1596 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1598 INT i, count = lastChar - firstChar + 1;
1599 UINT c;
1600 LPSTR str;
1602 if (count <= 0)
1603 return NULL;
1605 switch (GdiGetCodePage(hdc))
1607 case 932:
1608 case 936:
1609 case 949:
1610 case 950:
1611 case 1361:
1612 if (lastChar > 0xffff)
1613 return NULL;
1614 if ((firstChar ^ lastChar) > 0xff)
1615 return NULL;
1616 break;
1617 default:
1618 if (lastChar > 0xff)
1619 return NULL;
1620 break;
1623 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
1624 if (str == NULL)
1625 return NULL;
1627 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
1629 if (c > 0xff)
1630 str[i++] = (BYTE)(c >> 8);
1631 str[i] = (BYTE)c;
1633 str[i] = '\0';
1635 *pByteLen = i;
1637 return str;
1640 /***********************************************************************
1641 * GetCharWidthW (GDI32.@)
1642 * GetCharWidth32W (GDI32.@)
1644 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1645 LPINT buffer )
1647 UINT i;
1648 BOOL ret;
1649 PHYSDEV dev;
1650 DC * dc = get_dc_ptr( hdc );
1652 if (!dc) return FALSE;
1654 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
1655 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1657 if (ret)
1659 /* convert device units to logical */
1660 for( i = firstChar; i <= lastChar; i++, buffer++ )
1661 *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1663 release_dc_ptr( dc );
1664 return ret;
1668 /***********************************************************************
1669 * GetCharWidthA (GDI32.@)
1670 * GetCharWidth32A (GDI32.@)
1672 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1673 LPINT buffer )
1675 INT i, wlen;
1676 LPSTR str;
1677 LPWSTR wstr;
1678 BOOL ret = TRUE;
1680 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1681 if(str == NULL)
1682 return FALSE;
1684 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1686 for(i = 0; i < wlen; i++)
1688 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
1690 ret = FALSE;
1691 break;
1693 buffer++;
1696 HeapFree(GetProcessHeap(), 0, str);
1697 HeapFree(GetProcessHeap(), 0, wstr);
1699 return ret;
1703 /* helper for nulldrv_ExtTextOut */
1704 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags,
1705 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
1707 UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
1708 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1709 UINT indices[3] = {0, 0, 0x20};
1710 int i;
1711 DWORD ret, size;
1712 int stride;
1714 indices[0] = index;
1716 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1718 index = indices[i];
1719 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
1720 if (ret != GDI_ERROR) break;
1723 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
1724 if (!image) return ERROR_SUCCESS;
1726 image->ptr = NULL;
1727 image->free = NULL;
1728 if (!ret) return ERROR_SUCCESS; /* empty glyph */
1730 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1731 size = metrics->gmBlackBoxY * stride;
1733 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
1734 image->is_copy = TRUE;
1735 image->free = free_heap_bits;
1737 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, image->ptr, &identity );
1738 if (ret == GDI_ERROR)
1740 HeapFree( GetProcessHeap(), 0, image->ptr );
1741 return ERROR_NOT_FOUND;
1743 return ERROR_SUCCESS;
1746 /* helper for nulldrv_ExtTextOut */
1747 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
1748 LPCWSTR str, UINT count, const INT *dx )
1750 int i;
1751 RECT rect;
1753 rect.left = rect.top = INT_MAX;
1754 rect.right = rect.bottom = INT_MIN;
1755 for (i = 0; i < count; i++)
1757 GLYPHMETRICS metrics;
1759 if (get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, NULL )) continue;
1761 rect.left = min( rect.left, x + metrics.gmptGlyphOrigin.x );
1762 rect.top = min( rect.top, y - metrics.gmptGlyphOrigin.y );
1763 rect.right = max( rect.right, x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX );
1764 rect.bottom = max( rect.bottom, y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY );
1766 if (dx)
1768 if (flags & ETO_PDY)
1770 x += dx[ i * 2 ];
1771 y += dx[ i * 2 + 1];
1773 else x += dx[ i ];
1775 else
1777 x += metrics.gmCellIncX;
1778 y += metrics.gmCellIncY;
1781 return rect;
1784 /* helper for nulldrv_ExtTextOut */
1785 static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
1786 const struct gdi_image_bits *image, const RECT *clip )
1788 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1789 UINT x, y, i, count;
1790 BYTE *ptr = image->ptr;
1791 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
1792 POINT *pts;
1793 RECT rect, clipped_rect;
1795 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
1796 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
1797 rect.right = rect.left + metrics->gmBlackBoxX;
1798 rect.bottom = rect.top + metrics->gmBlackBoxY;
1799 if (!clip) clipped_rect = rect;
1800 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
1802 pts = HeapAlloc( GetProcessHeap(), 0,
1803 max(2,metrics->gmBlackBoxX) * metrics->gmBlackBoxY * sizeof(*pts) );
1804 if (!pts) return;
1806 count = 0;
1807 ptr += (clipped_rect.top - rect.top) * stride;
1808 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
1810 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
1812 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
1813 pts[count].x = rect.left + x;
1814 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
1815 pts[count + 1].x = rect.left + x;
1816 if (pts[count + 1].x > pts[count].x)
1818 pts[count].y = pts[count + 1].y = y;
1819 count += 2;
1823 DPtoLP( hdc, pts, count );
1824 for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
1825 HeapFree( GetProcessHeap(), 0, pts );
1828 /***********************************************************************
1829 * nulldrv_ExtTextOut
1831 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
1832 LPCWSTR str, UINT count, const INT *dx )
1834 DC *dc = get_nulldrv_dc( dev );
1835 UINT aa_flags, i;
1836 DWORD err;
1837 HGDIOBJ orig;
1838 HPEN pen;
1840 if (flags & ETO_OPAQUE)
1842 RECT rc = *rect;
1843 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));
1845 if (brush)
1847 orig = SelectObject( dev->hdc, brush );
1848 DPtoLP( dev->hdc, (POINT *)&rc, 2 );
1849 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
1850 SelectObject( dev->hdc, orig );
1851 DeleteObject( brush );
1855 if (!count) return TRUE;
1857 aa_flags = get_font_aa_flags( dev->hdc );
1859 if (aa_flags != GGO_BITMAP)
1861 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1862 BITMAPINFO *info = (BITMAPINFO *)buffer;
1863 struct gdi_image_bits bits;
1864 struct bitblt_coords src, dst;
1865 PHYSDEV dst_dev;
1867 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
1868 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
1869 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1870 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1872 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
1873 src.x = src.visrect.left;
1874 src.y = src.visrect.top;
1875 src.width = src.visrect.right - src.visrect.left;
1876 src.height = src.visrect.bottom - src.visrect.top;
1877 dst = src;
1878 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
1879 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
1881 /* we can avoid the GetImage, just query the needed format */
1882 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
1883 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1884 info->bmiHeader.biWidth = src.width;
1885 info->bmiHeader.biHeight = -src.height;
1886 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, NULL, NULL, NULL, 0 );
1887 if (!err || err == ERROR_BAD_FORMAT)
1889 /* make the source rectangle relative to the source bits */
1890 src.x = src.y = 0;
1891 src.visrect.left = src.visrect.top = 0;
1892 src.visrect.right = src.width;
1893 src.visrect.bottom = src.height;
1895 bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1896 if (!bits.ptr) return ERROR_OUTOFMEMORY;
1897 bits.is_copy = TRUE;
1898 bits.free = free_heap_bits;
1899 err = ERROR_SUCCESS;
1902 else
1904 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
1905 err = src_dev->funcs->pGetImage( src_dev, 0, info, &bits, &src );
1906 if (!err && !bits.is_copy)
1908 void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
1909 if (!ptr)
1911 if (bits.free) bits.free( &bits );
1912 return ERROR_OUTOFMEMORY;
1914 memcpy( ptr, bits.ptr, get_dib_image_size( info ));
1915 if (bits.free) bits.free( &bits );
1916 bits.ptr = ptr;
1917 bits.is_copy = TRUE;
1918 bits.free = free_heap_bits;
1921 if (!err)
1923 /* make x,y relative to the image bits */
1924 x += src.visrect.left - dst.visrect.left;
1925 y += src.visrect.top - dst.visrect.top;
1926 render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
1927 aa_flags, str, count, dx );
1928 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, &bits, &src, &dst, SRCCOPY );
1929 if (bits.free) bits.free( &bits );
1930 return !err;
1934 pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
1935 orig = SelectObject( dev->hdc, pen );
1937 for (i = 0; i < count; i++)
1939 GLYPHMETRICS metrics;
1940 struct gdi_image_bits image;
1942 err = get_glyph_bitmap( dev->hdc, (UINT)str[i], GGO_BITMAP, &metrics, &image );
1943 if (err) continue;
1945 if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
1946 if (image.free) image.free( &image );
1948 if (dx)
1950 if (flags & ETO_PDY)
1952 x += dx[ i * 2 ];
1953 y += dx[ i * 2 + 1];
1955 else x += dx[ i ];
1957 else
1959 x += metrics.gmCellIncX;
1960 y += metrics.gmCellIncY;
1964 SelectObject( dev->hdc, orig );
1965 DeleteObject( pen );
1966 return TRUE;
1970 /***********************************************************************
1971 * ExtTextOutA (GDI32.@)
1973 * See ExtTextOutW.
1975 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
1976 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
1978 INT wlen;
1979 UINT codepage;
1980 LPWSTR p;
1981 BOOL ret;
1982 LPINT lpDxW = NULL;
1984 if (flags & ETO_GLYPH_INDEX)
1985 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
1987 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1989 if (lpDx) {
1990 unsigned int i = 0, j = 0;
1992 /* allocate enough for a ETO_PDY */
1993 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
1994 while(i < count) {
1995 if(IsDBCSLeadByteEx(codepage, str[i]))
1997 if(flags & ETO_PDY)
1999 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
2000 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
2002 else
2003 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2004 i = i + 2;
2006 else
2008 if(flags & ETO_PDY)
2010 lpDxW[j++] = lpDx[i * 2];
2011 lpDxW[j++] = lpDx[i * 2 + 1];
2013 else
2014 lpDxW[j++] = lpDx[i];
2015 i = i + 1;
2020 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
2022 HeapFree( GetProcessHeap(), 0, p );
2023 HeapFree( GetProcessHeap(), 0, lpDxW );
2024 return ret;
2028 /***********************************************************************
2029 * ExtTextOutW (GDI32.@)
2031 * Draws text using the currently selected font, background color, and text color.
2034 * PARAMS
2035 * x,y [I] coordinates of string
2036 * flags [I]
2037 * ETO_GRAYED - undocumented on MSDN
2038 * ETO_OPAQUE - use background color for fill the rectangle
2039 * ETO_CLIPPED - clipping text to the rectangle
2040 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2041 * than encoded characters. Implies ETO_IGNORELANGUAGE
2042 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2043 * Affects BiDi ordering
2044 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2045 * ETO_PDY - unimplemented
2046 * ETO_NUMERICSLATIN - unimplemented always assumed -
2047 * do not translate numbers into locale representations
2048 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2049 * lprect [I] dimensions for clipping or/and opaquing
2050 * str [I] text string
2051 * count [I] number of symbols in string
2052 * lpDx [I] optional parameter with distance between drawing characters
2054 * RETURNS
2055 * Success: TRUE
2056 * Failure: FALSE
2058 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
2059 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
2061 BOOL ret = FALSE;
2062 LPWSTR reordered_str = (LPWSTR)str;
2063 WORD *glyphs = NULL;
2064 UINT align = GetTextAlign( hdc );
2065 DWORD layout = GetLayout( hdc );
2066 POINT pt;
2067 TEXTMETRICW tm;
2068 LOGFONTW lf;
2069 double cosEsc, sinEsc;
2070 INT char_extra;
2071 SIZE sz;
2072 RECT rc;
2073 BOOL done_extents = FALSE;
2074 POINT *deltas = NULL, width = {0, 0};
2075 DWORD type;
2076 DC * dc = get_dc_ptr( hdc );
2077 PHYSDEV physdev;
2078 INT breakRem;
2079 static int quietfixme = 0;
2081 if (!dc) return FALSE;
2083 breakRem = dc->breakRem;
2085 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2087 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2088 quietfixme = 1;
2091 update_dc( dc );
2092 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2093 type = GetObjectType(hdc);
2094 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
2096 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2097 release_dc_ptr( dc );
2098 return ret;
2101 if (!lprect)
2102 flags &= ~ETO_CLIPPED;
2104 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
2105 if (layout & LAYOUT_RTL)
2107 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
2108 align ^= TA_RTLREADING;
2111 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2113 INT cGlyphs;
2114 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
2116 BIDI_Reorder( hdc, str, count, GCP_REORDER,
2117 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2118 reordered_str, count, NULL, &glyphs, &cGlyphs);
2120 flags |= ETO_IGNORELANGUAGE;
2121 if (glyphs)
2123 flags |= ETO_GLYPH_INDEX;
2124 if (cGlyphs != count)
2125 count = cGlyphs;
2128 else if(flags & ETO_GLYPH_INDEX)
2129 glyphs = reordered_str;
2131 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
2132 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2133 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
2135 if(align & TA_UPDATECP)
2137 GetCurrentPositionEx( hdc, &pt );
2138 x = pt.x;
2139 y = pt.y;
2142 GetTextMetricsW(hdc, &tm);
2143 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
2145 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
2146 lf.lfEscapement = 0;
2148 if(lf.lfEscapement != 0)
2150 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
2151 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
2153 else
2155 cosEsc = 1;
2156 sinEsc = 0;
2159 if(flags & (ETO_CLIPPED | ETO_OPAQUE))
2161 if(!lprect)
2163 if(flags & ETO_GLYPH_INDEX)
2164 GetTextExtentPointI(hdc, glyphs, count, &sz);
2165 else
2166 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2168 done_extents = TRUE;
2169 rc.left = x;
2170 rc.top = y;
2171 rc.right = x + sz.cx;
2172 rc.bottom = y + sz.cy;
2174 else
2176 rc = *lprect;
2179 LPtoDP(hdc, (POINT*)&rc, 2);
2181 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
2182 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
2185 if (flags & ETO_OPAQUE)
2186 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2188 if(count == 0)
2190 ret = TRUE;
2191 goto done;
2194 pt.x = x;
2195 pt.y = y;
2196 LPtoDP(hdc, &pt, 1);
2197 x = pt.x;
2198 y = pt.y;
2200 char_extra = GetTextCharacterExtra(hdc);
2201 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2203 UINT i;
2204 SIZE tmpsz;
2205 POINT total = {0, 0}, desired[2];
2207 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2208 for(i = 0; i < count; i++)
2210 if(lpDx)
2212 if(flags & ETO_PDY)
2214 deltas[i].x = lpDx[i * 2] + char_extra;
2215 deltas[i].y = -lpDx[i * 2 + 1];
2217 else
2219 deltas[i].x = lpDx[i] + char_extra;
2220 deltas[i].y = 0;
2224 else
2226 if(flags & ETO_GLYPH_INDEX)
2227 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
2228 else
2229 GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2231 deltas[i].x = tmpsz.cx;
2232 deltas[i].y = 0;
2235 if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2237 deltas[i].x = deltas[i].x + dc->breakExtra;
2238 if (breakRem > 0)
2240 breakRem--;
2241 deltas[i].x++;
2244 total.x += deltas[i].x;
2245 total.y += deltas[i].y;
2247 desired[0].x = desired[0].y = 0;
2249 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2250 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2252 LPtoDP(hdc, desired, 2);
2253 desired[1].x -= desired[0].x;
2254 desired[1].y -= desired[0].y;
2255 if (layout & LAYOUT_RTL) desired[1].x = -desired[1].x;
2257 deltas[i].x = desired[1].x - width.x;
2258 deltas[i].y = desired[1].y - width.y;
2260 width = desired[1];
2262 flags |= ETO_PDY;
2264 else
2266 if(!done_extents)
2268 if(flags & ETO_GLYPH_INDEX)
2269 GetTextExtentPointI(hdc, glyphs, count, &sz);
2270 else
2271 GetTextExtentPointW(hdc, reordered_str, count, &sz);
2272 done_extents = TRUE;
2274 width.x = abs(INTERNAL_XWSTODS(dc, sz.cx));
2275 width.y = 0;
2278 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
2279 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
2280 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
2282 case TA_LEFT:
2283 if (align & TA_UPDATECP)
2285 pt.x = x + width.x;
2286 pt.y = y + width.y;
2287 DPtoLP(hdc, &pt, 1);
2288 MoveToEx(hdc, pt.x, pt.y, NULL);
2290 break;
2292 case TA_CENTER:
2293 x -= width.x / 2;
2294 y -= width.y / 2;
2295 break;
2297 case TA_RIGHT:
2298 x -= width.x;
2299 y -= width.y;
2300 if (align & TA_UPDATECP)
2302 pt.x = x;
2303 pt.y = y;
2304 DPtoLP(hdc, &pt, 1);
2305 MoveToEx(hdc, pt.x, pt.y, NULL);
2307 break;
2310 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
2312 case TA_TOP:
2313 y += tm.tmAscent * cosEsc;
2314 x += tm.tmAscent * sinEsc;
2315 break;
2317 case TA_BOTTOM:
2318 y -= tm.tmDescent * cosEsc;
2319 x -= tm.tmDescent * sinEsc;
2320 break;
2322 case TA_BASELINE:
2323 break;
2326 if (GetBkMode(hdc) != TRANSPARENT)
2328 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2330 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width.x >= rc.right ||
2331 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2333 RECT rc;
2334 rc.left = x;
2335 rc.right = x + width.x;
2336 rc.top = y - tm.tmAscent;
2337 rc.bottom = y + tm.tmDescent;
2339 if(flags & ETO_CLIPPED)
2341 rc.left = max(lprect->left, rc.left);
2342 rc.right = min(lprect->right, rc.right);
2343 rc.top = max(lprect->top, rc.top);
2344 rc.bottom = min(lprect->bottom, rc.bottom);
2346 if(rc.left < rc.right && rc.top < rc.bottom)
2347 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2352 if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
2354 HFONT orig_font = dc->hFont, cur_font;
2355 UINT glyph;
2356 INT span = 0;
2357 POINT *offsets = NULL;
2358 unsigned int i;
2360 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2361 for(i = 0; i < count; i++)
2363 WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
2364 if(cur_font != dc->hFont)
2366 if(!offsets)
2368 unsigned int j;
2369 offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2370 offsets[0].x = offsets[0].y = 0;
2372 if(!deltas)
2374 SIZE tmpsz;
2375 for(j = 1; j < count; j++)
2377 GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
2378 offsets[j].x = offsets[j - 1].x + abs(INTERNAL_XWSTODS(dc, tmpsz.cx));
2379 offsets[j].y = 0;
2382 else
2384 for(j = 1; j < count; j++)
2386 offsets[j].x = offsets[j - 1].x + deltas[j].x;
2387 offsets[j].y = offsets[j - 1].y + deltas[j].y;
2391 if(span)
2393 physdev->funcs->pExtTextOut( physdev, x + offsets[i - span].x,
2394 y + offsets[i - span].y,
2395 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
2396 span, deltas ? (INT*)(deltas + (i - span)) : NULL);
2397 span = 0;
2399 SelectObject(hdc, cur_font);
2401 glyphs[span++] = glyph;
2403 if(i == count - 1)
2405 ret = physdev->funcs->pExtTextOut(physdev, x + (offsets ? offsets[count - span].x : 0),
2406 y + (offsets ? offsets[count - span].y : 0),
2407 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
2408 span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2409 SelectObject(hdc, orig_font);
2410 HeapFree(GetProcessHeap(), 0, offsets);
2414 else
2416 if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
2418 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2419 GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
2420 flags |= ETO_GLYPH_INDEX;
2422 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
2423 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2426 done:
2427 HeapFree(GetProcessHeap(), 0, deltas);
2428 if(glyphs != reordered_str)
2429 HeapFree(GetProcessHeap(), 0, glyphs);
2430 if(reordered_str != str)
2431 HeapFree(GetProcessHeap(), 0, reordered_str);
2433 release_dc_ptr( dc );
2435 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2437 int underlinePos, strikeoutPos;
2438 int underlineWidth, strikeoutWidth;
2439 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2440 OUTLINETEXTMETRICW* otm = NULL;
2441 POINT pts[5];
2442 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
2443 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2445 hbrush = SelectObject(hdc, hbrush);
2447 if(!size)
2449 underlinePos = 0;
2450 underlineWidth = tm.tmAscent / 20 + 1;
2451 strikeoutPos = tm.tmAscent / 2;
2452 strikeoutWidth = underlineWidth;
2454 else
2456 otm = HeapAlloc(GetProcessHeap(), 0, size);
2457 GetOutlineTextMetricsW(hdc, size, otm);
2458 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
2459 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2460 underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
2461 if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
2462 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
2463 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2464 strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2465 HeapFree(GetProcessHeap(), 0, otm);
2469 if (lf.lfUnderline)
2471 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2472 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2473 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2474 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2475 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2476 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2477 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2478 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2479 pts[4].x = pts[0].x;
2480 pts[4].y = pts[0].y;
2481 DPtoLP(hdc, pts, 5);
2482 Polygon(hdc, pts, 5);
2485 if (lf.lfStrikeOut)
2487 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2488 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2489 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2490 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2491 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2492 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2493 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2494 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2495 pts[4].x = pts[0].x;
2496 pts[4].y = pts[0].y;
2497 DPtoLP(hdc, pts, 5);
2498 Polygon(hdc, pts, 5);
2501 SelectObject(hdc, hpen);
2502 hbrush = SelectObject(hdc, hbrush);
2503 DeleteObject(hbrush);
2506 return ret;
2510 /***********************************************************************
2511 * TextOutA (GDI32.@)
2513 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
2515 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
2519 /***********************************************************************
2520 * TextOutW (GDI32.@)
2522 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
2524 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
2528 /***********************************************************************
2529 * PolyTextOutA (GDI32.@)
2531 * See PolyTextOutW.
2533 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2535 for (; cStrings>0; cStrings--, pptxt++)
2536 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2537 return FALSE;
2538 return TRUE;
2543 /***********************************************************************
2544 * PolyTextOutW (GDI32.@)
2546 * Draw several Strings
2548 * RETURNS
2549 * TRUE: Success.
2550 * FALSE: Failure.
2552 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2554 for (; cStrings>0; cStrings--, pptxt++)
2555 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
2556 return FALSE;
2557 return TRUE;
2561 /***********************************************************************
2562 * SetMapperFlags (GDI32.@)
2564 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
2566 DC *dc = get_dc_ptr( hdc );
2567 DWORD ret = GDI_ERROR;
2569 if (dc)
2571 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
2572 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
2573 if (flags != GDI_ERROR)
2575 ret = dc->mapperFlags;
2576 dc->mapperFlags = flags;
2578 release_dc_ptr( dc );
2580 return ret;
2583 /***********************************************************************
2584 * GetAspectRatioFilterEx (GDI32.@)
2586 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2588 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2589 return FALSE;
2593 /***********************************************************************
2594 * GetCharABCWidthsA (GDI32.@)
2596 * See GetCharABCWidthsW.
2598 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
2599 LPABC abc )
2601 INT i, wlen;
2602 LPSTR str;
2603 LPWSTR wstr;
2604 BOOL ret = TRUE;
2606 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2607 if (str == NULL)
2608 return FALSE;
2610 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2611 if (wstr == NULL)
2613 HeapFree(GetProcessHeap(), 0, str);
2614 return FALSE;
2617 for(i = 0; i < wlen; i++)
2619 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
2621 ret = FALSE;
2622 break;
2624 abc++;
2627 HeapFree(GetProcessHeap(), 0, str);
2628 HeapFree(GetProcessHeap(), 0, wstr);
2630 return ret;
2634 /******************************************************************************
2635 * GetCharABCWidthsW [GDI32.@]
2637 * Retrieves widths of characters in range.
2639 * PARAMS
2640 * hdc [I] Handle of device context
2641 * firstChar [I] First character in range to query
2642 * lastChar [I] Last character in range to query
2643 * abc [O] Address of character-width structure
2645 * NOTES
2646 * Only works with TrueType fonts
2648 * RETURNS
2649 * Success: TRUE
2650 * Failure: FALSE
2652 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
2653 LPABC abc )
2655 DC *dc = get_dc_ptr(hdc);
2656 PHYSDEV dev;
2657 unsigned int i;
2658 BOOL ret;
2659 TEXTMETRICW tm;
2661 if (!dc) return FALSE;
2663 if (!abc)
2665 release_dc_ptr( dc );
2666 return FALSE;
2669 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-TrueType fonts */
2670 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
2671 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_TRUETYPE))
2673 release_dc_ptr( dc );
2674 return FALSE;
2677 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
2678 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2679 if (ret)
2681 /* convert device units to logical */
2682 for( i = firstChar; i <= lastChar; i++, abc++ ) {
2683 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2684 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2685 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2689 release_dc_ptr( dc );
2690 return ret;
2694 /******************************************************************************
2695 * GetCharABCWidthsI [GDI32.@]
2697 * Retrieves widths of characters in range.
2699 * PARAMS
2700 * hdc [I] Handle of device context
2701 * firstChar [I] First glyphs in range to query
2702 * count [I] Last glyphs in range to query
2703 * pgi [i] Array of glyphs to query
2704 * abc [O] Address of character-width structure
2706 * NOTES
2707 * Only works with TrueType fonts
2709 * RETURNS
2710 * Success: TRUE
2711 * Failure: FALSE
2713 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
2714 LPWORD pgi, LPABC abc)
2716 DC *dc = get_dc_ptr(hdc);
2717 PHYSDEV dev;
2718 unsigned int i;
2719 BOOL ret;
2721 if (!dc) return FALSE;
2723 if (!abc)
2725 release_dc_ptr( dc );
2726 return FALSE;
2729 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
2730 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2731 if (ret)
2733 /* convert device units to logical */
2734 for( i = 0; i < count; i++, abc++ ) {
2735 abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2736 abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
2737 abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2741 release_dc_ptr( dc );
2742 return ret;
2746 /***********************************************************************
2747 * GetGlyphOutlineA (GDI32.@)
2749 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
2750 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2751 LPVOID lpBuffer, const MAT2 *lpmat2 )
2753 if (!lpmat2) return GDI_ERROR;
2755 if(!(fuFormat & GGO_GLYPH_INDEX)) {
2756 UINT cp;
2757 int len;
2758 char mbchs[2];
2760 cp = GdiGetCodePage(hdc);
2761 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2762 len = 2;
2763 mbchs[0] = (uChar & 0xff00) >> 8;
2764 mbchs[1] = (uChar & 0xff);
2765 } else {
2766 len = 1;
2767 mbchs[0] = (uChar & 0xff);
2769 uChar = 0;
2770 MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
2773 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
2774 lpmat2);
2777 /***********************************************************************
2778 * GetGlyphOutlineW (GDI32.@)
2780 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
2781 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
2782 LPVOID lpBuffer, const MAT2 *lpmat2 )
2784 DC *dc;
2785 DWORD ret;
2786 PHYSDEV dev;
2788 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2789 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2791 if (!lpmat2) return GDI_ERROR;
2793 dc = get_dc_ptr(hdc);
2794 if(!dc) return GDI_ERROR;
2796 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
2797 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2798 release_dc_ptr( dc );
2799 return ret;
2803 /***********************************************************************
2804 * CreateScalableFontResourceA (GDI32.@)
2806 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
2807 LPCSTR lpszResourceFile,
2808 LPCSTR lpszFontFile,
2809 LPCSTR lpszCurrentPath )
2811 LPWSTR lpszResourceFileW = NULL;
2812 LPWSTR lpszFontFileW = NULL;
2813 LPWSTR lpszCurrentPathW = NULL;
2814 int len;
2815 BOOL ret;
2817 if (lpszResourceFile)
2819 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
2820 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2821 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
2824 if (lpszFontFile)
2826 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
2827 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2828 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2831 if (lpszCurrentPath)
2833 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
2834 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2835 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
2838 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
2839 lpszFontFileW, lpszCurrentPathW);
2841 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
2842 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
2843 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
2845 return ret;
2848 /***********************************************************************
2849 * CreateScalableFontResourceW (GDI32.@)
2851 BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
2852 LPCWSTR lpszResourceFile,
2853 LPCWSTR lpszFontFile,
2854 LPCWSTR lpszCurrentPath )
2856 HANDLE f;
2857 FIXME("(%d,%s,%s,%s): stub\n",
2858 fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
2859 debugstr_w(lpszCurrentPath) );
2861 /* fHidden=1 - only visible for the calling app, read-only, not
2862 * enumerated with EnumFonts/EnumFontFamilies
2863 * lpszCurrentPath can be NULL
2866 /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2867 if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
2868 CloseHandle(f);
2869 SetLastError(ERROR_FILE_EXISTS);
2870 return FALSE;
2872 return FALSE; /* create failed */
2875 /*************************************************************************
2876 * GetKerningPairsA (GDI32.@)
2878 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2879 LPKERNINGPAIR kern_pairA )
2881 UINT cp;
2882 CPINFO cpi;
2883 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
2884 KERNINGPAIR *kern_pairW;
2886 if (!cPairs && kern_pairA)
2888 SetLastError(ERROR_INVALID_PARAMETER);
2889 return 0;
2892 cp = GdiGetCodePage(hDC);
2894 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2895 * to fail on an invalid character for CP_SYMBOL.
2897 cpi.DefaultChar[0] = 0;
2898 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2900 FIXME("Can't find codepage %u info\n", cp);
2901 return 0;
2904 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
2905 if (!total_kern_pairs) return 0;
2907 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
2908 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
2910 for (i = 0; i < total_kern_pairs; i++)
2912 char first, second;
2914 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2915 continue;
2917 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2918 continue;
2920 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
2921 continue;
2923 if (kern_pairA)
2925 if (kern_pairs_copied >= cPairs) break;
2927 kern_pairA->wFirst = (BYTE)first;
2928 kern_pairA->wSecond = (BYTE)second;
2929 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
2930 kern_pairA++;
2932 kern_pairs_copied++;
2935 HeapFree(GetProcessHeap(), 0, kern_pairW);
2937 return kern_pairs_copied;
2940 /*************************************************************************
2941 * GetKerningPairsW (GDI32.@)
2943 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
2944 LPKERNINGPAIR lpKerningPairs )
2946 DC *dc;
2947 DWORD ret;
2948 PHYSDEV dev;
2950 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2952 if (!cPairs && lpKerningPairs)
2954 SetLastError(ERROR_INVALID_PARAMETER);
2955 return 0;
2958 dc = get_dc_ptr(hDC);
2959 if (!dc) return 0;
2961 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
2962 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2963 release_dc_ptr( dc );
2964 return ret;
2967 /*************************************************************************
2968 * TranslateCharsetInfo [GDI32.@]
2970 * Fills a CHARSETINFO structure for a character set, code page, or
2971 * font. This allows making the correspondence between different labels
2972 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2973 * of the same encoding.
2975 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
2976 * only one codepage should be set in *lpSrc.
2978 * RETURNS
2979 * TRUE on success, FALSE on failure.
2982 BOOL WINAPI TranslateCharsetInfo(
2983 LPDWORD lpSrc, /* [in]
2984 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2985 if flags == TCI_SRCCHARSET: a character set value
2986 if flags == TCI_SRCCODEPAGE: a code page value
2988 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
2989 DWORD flags /* [in] determines interpretation of lpSrc */)
2991 int index = 0;
2992 switch (flags) {
2993 case TCI_SRCFONTSIG:
2994 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
2995 break;
2996 case TCI_SRCCODEPAGE:
2997 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
2998 break;
2999 case TCI_SRCCHARSET:
3000 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3001 break;
3002 default:
3003 return FALSE;
3005 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3006 *lpCs = FONT_tci[index];
3007 return TRUE;
3010 /*************************************************************************
3011 * GetFontLanguageInfo (GDI32.@)
3013 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
3015 FONTSIGNATURE fontsig;
3016 static const DWORD GCP_DBCS_MASK=0x003F0000,
3017 GCP_DIACRITIC_MASK=0x00000000,
3018 FLI_GLYPHS_MASK=0x00000000,
3019 GCP_GLYPHSHAPE_MASK=0x00000040,
3020 GCP_KASHIDA_MASK=0x00000000,
3021 GCP_LIGATE_MASK=0x00000000,
3022 GCP_USEKERNING_MASK=0x00000000,
3023 GCP_REORDER_MASK=0x00000060;
3025 DWORD result=0;
3027 GetTextCharsetInfo( hdc, &fontsig, 0 );
3028 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3030 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
3031 result|=GCP_DBCS;
3033 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
3034 result|=GCP_DIACRITIC;
3036 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
3037 result|=FLI_GLYPHS;
3039 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
3040 result|=GCP_GLYPHSHAPE;
3042 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
3043 result|=GCP_KASHIDA;
3045 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
3046 result|=GCP_LIGATE;
3048 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
3049 result|=GCP_USEKERNING;
3051 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3052 if( GetTextAlign( hdc) & TA_RTLREADING )
3053 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
3054 result|=GCP_REORDER;
3056 return result;
3060 /*************************************************************************
3061 * GetFontData [GDI32.@]
3063 * Retrieve data for TrueType font.
3065 * RETURNS
3067 * success: Number of bytes returned
3068 * failure: GDI_ERROR
3070 * NOTES
3072 * Calls SetLastError()
3075 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
3076 LPVOID buffer, DWORD length)
3078 DC *dc = get_dc_ptr(hdc);
3079 PHYSDEV dev;
3080 DWORD ret;
3082 if(!dc) return GDI_ERROR;
3084 dev = GET_DC_PHYSDEV( dc, pGetFontData );
3085 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3086 release_dc_ptr( dc );
3087 return ret;
3090 /*************************************************************************
3091 * GetGlyphIndicesA [GDI32.@]
3093 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
3094 LPWORD pgi, DWORD flags)
3096 DWORD ret;
3097 WCHAR *lpstrW;
3098 INT countW;
3100 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3101 hdc, debugstr_an(lpstr, count), count, pgi, flags);
3103 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3104 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
3105 HeapFree(GetProcessHeap(), 0, lpstrW);
3107 return ret;
3110 /*************************************************************************
3111 * GetGlyphIndicesW [GDI32.@]
3113 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
3114 LPWORD pgi, DWORD flags)
3116 DC *dc = get_dc_ptr(hdc);
3117 PHYSDEV dev;
3118 DWORD ret;
3120 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3121 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3123 if(!dc) return GDI_ERROR;
3125 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
3126 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3127 release_dc_ptr( dc );
3128 return ret;
3131 /*************************************************************************
3132 * GetCharacterPlacementA [GDI32.@]
3134 * See GetCharacterPlacementW.
3136 * NOTES:
3137 * the web browser control of ie4 calls this with dwFlags=0
3139 DWORD WINAPI
3140 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
3141 INT nMaxExtent, GCP_RESULTSA *lpResults,
3142 DWORD dwFlags)
3144 WCHAR *lpStringW;
3145 INT uCountW;
3146 GCP_RESULTSW resultsW;
3147 DWORD ret;
3148 UINT font_cp;
3150 TRACE("%s, %d, %d, 0x%08x\n",
3151 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3153 /* both structs are equal in size */
3154 memcpy(&resultsW, lpResults, sizeof(resultsW));
3156 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3157 if(lpResults->lpOutString)
3158 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3160 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
3162 lpResults->nGlyphs = resultsW.nGlyphs;
3163 lpResults->nMaxFit = resultsW.nMaxFit;
3165 if(lpResults->lpOutString) {
3166 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3167 lpResults->lpOutString, uCount, NULL, NULL );
3170 HeapFree(GetProcessHeap(), 0, lpStringW);
3171 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3173 return ret;
3176 /*************************************************************************
3177 * GetCharacterPlacementW [GDI32.@]
3179 * Retrieve information about a string. This includes the width, reordering,
3180 * Glyphing and so on.
3182 * RETURNS
3184 * The width and height of the string if successful, 0 if failed.
3186 * BUGS
3188 * All flags except GCP_REORDER are not yet implemented.
3189 * Reordering is not 100% compliant to the Windows BiDi method.
3190 * Caret positioning is not yet implemented for BiDi.
3191 * Classes are not yet implemented.
3194 DWORD WINAPI
3195 GetCharacterPlacementW(
3196 HDC hdc, /* [in] Device context for which the rendering is to be done */
3197 LPCWSTR lpString, /* [in] The string for which information is to be returned */
3198 INT uCount, /* [in] Number of WORDS in string. */
3199 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
3200 GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */
3201 DWORD dwFlags /* [in] Flags specifying how to process the string */
3204 DWORD ret=0;
3205 SIZE size;
3206 UINT i, nSet;
3208 TRACE("%s, %d, %d, 0x%08x\n",
3209 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3211 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3212 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3213 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
3214 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
3215 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3217 if(dwFlags&(~GCP_REORDER)) FIXME("flags 0x%08x ignored\n", dwFlags);
3218 if(lpResults->lpClass) FIXME("classes not implemented\n");
3219 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
3220 FIXME("Caret positions for complex scripts not implemented\n");
3222 nSet = (UINT)uCount;
3223 if(nSet > lpResults->nGlyphs)
3224 nSet = lpResults->nGlyphs;
3226 /* return number of initialized fields */
3227 lpResults->nGlyphs = nSet;
3229 if((dwFlags&GCP_REORDER)==0 )
3231 /* Treat the case where no special handling was requested in a fastpath way */
3232 /* copy will do if the GCP_REORDER flag is not set */
3233 if(lpResults->lpOutString)
3234 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3236 if(lpResults->lpOrder)
3238 for(i = 0; i < nSet; i++)
3239 lpResults->lpOrder[i] = i;
3241 } else
3243 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3244 nSet, lpResults->lpOrder, NULL, NULL );
3247 /* FIXME: Will use the placement chars */
3248 if (lpResults->lpDx)
3250 int c;
3251 for (i = 0; i < nSet; i++)
3253 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
3254 lpResults->lpDx[i]= c;
3258 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
3260 int pos = 0;
3262 lpResults->lpCaretPos[0] = 0;
3263 for (i = 1; i < nSet; i++)
3264 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
3265 lpResults->lpCaretPos[i] = (pos += size.cx);
3268 if(lpResults->lpGlyphs)
3269 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
3271 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
3272 ret = MAKELONG(size.cx, size.cy);
3274 return ret;
3277 /*************************************************************************
3278 * GetCharABCWidthsFloatA [GDI32.@]
3280 * See GetCharABCWidthsFloatW.
3282 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3284 INT i, wlen;
3285 LPSTR str;
3286 LPWSTR wstr;
3287 BOOL ret = TRUE;
3289 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3290 if (str == NULL)
3291 return FALSE;
3293 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3295 for (i = 0; i < wlen; i++)
3297 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
3299 ret = FALSE;
3300 break;
3302 abcf++;
3305 HeapFree( GetProcessHeap(), 0, str );
3306 HeapFree( GetProcessHeap(), 0, wstr );
3308 return ret;
3311 /*************************************************************************
3312 * GetCharABCWidthsFloatW [GDI32.@]
3314 * Retrieves widths of a range of characters.
3316 * PARAMS
3317 * hdc [I] Handle to device context.
3318 * first [I] First character in range to query.
3319 * last [I] Last character in range to query.
3320 * abcf [O] Array of LPABCFLOAT structures.
3322 * RETURNS
3323 * Success: TRUE
3324 * Failure: FALSE
3326 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3328 UINT i;
3329 ABC *abc;
3330 PHYSDEV dev;
3331 BOOL ret = FALSE;
3332 DC *dc = get_dc_ptr( hdc );
3334 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
3336 if (!dc) return FALSE;
3338 if (!abcf) goto done;
3339 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3341 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3342 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3343 if (ret)
3345 /* convert device units to logical */
3346 for (i = first; i <= last; i++, abcf++)
3348 abcf->abcfA = abc->abcA * dc->xformVport2World.eM11;
3349 abcf->abcfB = abc->abcB * dc->xformVport2World.eM11;
3350 abcf->abcfC = abc->abcC * dc->xformVport2World.eM11;
3353 HeapFree( GetProcessHeap(), 0, abc );
3355 done:
3356 release_dc_ptr( dc );
3357 return ret;
3360 /*************************************************************************
3361 * GetCharWidthFloatA [GDI32.@]
3363 BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
3364 UINT iLastChar, PFLOAT pxBuffer)
3366 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3367 return 0;
3370 /*************************************************************************
3371 * GetCharWidthFloatW [GDI32.@]
3373 BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
3374 UINT iLastChar, PFLOAT pxBuffer)
3376 FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
3377 return 0;
3381 /***********************************************************************
3383 * Font Resource API *
3385 ***********************************************************************/
3387 /***********************************************************************
3388 * AddFontResourceA (GDI32.@)
3390 INT WINAPI AddFontResourceA( LPCSTR str )
3392 return AddFontResourceExA( str, 0, NULL);
3395 /***********************************************************************
3396 * AddFontResourceW (GDI32.@)
3398 INT WINAPI AddFontResourceW( LPCWSTR str )
3400 return AddFontResourceExW(str, 0, NULL);
3404 /***********************************************************************
3405 * AddFontResourceExA (GDI32.@)
3407 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3409 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3410 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3411 INT ret;
3413 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3414 ret = AddFontResourceExW(strW, fl, pdv);
3415 HeapFree(GetProcessHeap(), 0, strW);
3416 return ret;
3419 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
3421 HRSRC rsrc = FindResourceW(hModule, name, type);
3422 HGLOBAL hMem = LoadResource(hModule, rsrc);
3423 LPVOID *pMem = LockResource(hMem);
3424 int *num_total = (int *)lParam;
3425 DWORD num_in_res;
3427 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
3428 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
3430 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
3431 return FALSE;
3434 *num_total += num_in_res;
3435 return TRUE;
3438 /***********************************************************************
3439 * AddFontResourceExW (GDI32.@)
3441 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3443 int ret = WineEngAddFontResourceEx(str, fl, pdv);
3444 if (ret == 0)
3446 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3447 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3448 if (hModule != NULL)
3450 int num_resources = 0;
3451 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
3453 TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3454 wine_dbgstr_w(str));
3455 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
3456 ret = num_resources;
3457 FreeLibrary(hModule);
3460 return ret;
3463 /***********************************************************************
3464 * RemoveFontResourceA (GDI32.@)
3466 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3468 return RemoveFontResourceExA(str, 0, 0);
3471 /***********************************************************************
3472 * RemoveFontResourceW (GDI32.@)
3474 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3476 return RemoveFontResourceExW(str, 0, 0);
3479 /***********************************************************************
3480 * AddFontMemResourceEx (GDI32.@)
3482 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3484 HANDLE ret;
3485 DWORD num_fonts;
3487 if (!pbFont || !cbFont || !pcFonts)
3489 SetLastError(ERROR_INVALID_PARAMETER);
3490 return NULL;
3493 ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
3494 if (ret)
3496 __TRY
3498 *pcFonts = num_fonts;
3500 __EXCEPT_PAGE_FAULT
3502 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
3503 RemoveFontMemResourceEx(ret);
3504 ret = 0;
3506 __ENDTRY
3508 return ret;
3511 /***********************************************************************
3512 * RemoveFontMemResourceEx (GDI32.@)
3514 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
3516 FIXME("(%p) stub\n", fh);
3517 return TRUE;
3520 /***********************************************************************
3521 * RemoveFontResourceExA (GDI32.@)
3523 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
3525 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
3526 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3527 INT ret;
3529 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
3530 ret = RemoveFontResourceExW(strW, fl, pdv);
3531 HeapFree(GetProcessHeap(), 0, strW);
3532 return ret;
3535 /***********************************************************************
3536 * RemoveFontResourceExW (GDI32.@)
3538 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
3540 return WineEngRemoveFontResourceEx(str, fl, pdv);
3543 /***********************************************************************
3544 * GetTextCharset (GDI32.@)
3546 UINT WINAPI GetTextCharset(HDC hdc)
3548 /* MSDN docs say this is equivalent */
3549 return GetTextCharsetInfo(hdc, NULL, 0);
3552 /***********************************************************************
3553 * GetTextCharsetInfo (GDI32.@)
3555 UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags)
3557 UINT ret = DEFAULT_CHARSET;
3558 DC *dc = get_dc_ptr(hdc);
3559 PHYSDEV dev;
3561 if (dc)
3563 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
3564 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3565 release_dc_ptr( dc );
3568 if (ret == DEFAULT_CHARSET && fs)
3569 memset(fs, 0, sizeof(FONTSIGNATURE));
3570 return ret;
3573 /***********************************************************************
3574 * GdiGetCharDimensions (GDI32.@)
3576 * Gets the average width of the characters in the English alphabet.
3578 * PARAMS
3579 * hdc [I] Handle to the device context to measure on.
3580 * lptm [O] Pointer to memory to store the text metrics into.
3581 * height [O] On exit, the maximum height of characters in the English alphabet.
3583 * RETURNS
3584 * The average width of characters in the English alphabet.
3586 * NOTES
3587 * This function is used by the dialog manager to get the size of a dialog
3588 * unit. It should also be used by other pieces of code that need to know
3589 * the size of a dialog unit in logical units without having access to the
3590 * window handle of the dialog.
3591 * Windows caches the font metrics from this function, but we don't and
3592 * there doesn't appear to be an immediate advantage to do so.
3594 * SEE ALSO
3595 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3597 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
3599 SIZE sz;
3600 static const WCHAR alphabet[] = {
3601 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3602 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3603 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3605 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
3607 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
3609 if (height) *height = sz.cy;
3610 return (sz.cx / 26 + 1) / 2;
3613 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
3615 FIXME("(%d): stub\n", fEnableEUDC);
3616 return FALSE;
3619 /***********************************************************************
3620 * GetCharWidthI (GDI32.@)
3622 * Retrieve widths of characters.
3624 * PARAMS
3625 * hdc [I] Handle to a device context.
3626 * first [I] First glyph in range to query.
3627 * count [I] Number of glyph indices to query.
3628 * glyphs [I] Array of glyphs to query.
3629 * buffer [O] Buffer to receive character widths.
3631 * NOTES
3632 * Only works with TrueType fonts.
3634 * RETURNS
3635 * Success: TRUE
3636 * Failure: FALSE
3638 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3640 ABC *abc;
3641 unsigned int i;
3643 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
3645 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
3646 return FALSE;
3648 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
3650 HeapFree(GetProcessHeap(), 0, abc);
3651 return FALSE;
3654 for (i = 0; i < count; i++)
3655 buffer[i] = abc->abcA + abc->abcB + abc->abcC;
3657 HeapFree(GetProcessHeap(), 0, abc);
3658 return TRUE;
3661 /***********************************************************************
3662 * GetFontUnicodeRanges (GDI32.@)
3664 * Retrieve a list of supported Unicode characters in a font.
3666 * PARAMS
3667 * hdc [I] Handle to a device context.
3668 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3670 * RETURNS
3671 * Success: Number of bytes written to the buffer pointed to by lpgs.
3672 * Failure: 0
3675 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
3677 DWORD ret;
3678 PHYSDEV dev;
3679 DC *dc = get_dc_ptr(hdc);
3681 TRACE("(%p, %p)\n", hdc, lpgs);
3683 if (!dc) return 0;
3685 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
3686 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3687 release_dc_ptr(dc);
3688 return ret;
3692 /*************************************************************
3693 * FontIsLinked (GDI32.@)
3695 BOOL WINAPI FontIsLinked(HDC hdc)
3697 DC *dc = get_dc_ptr(hdc);
3698 PHYSDEV dev;
3699 BOOL ret;
3701 if (!dc) return FALSE;
3702 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
3703 ret = dev->funcs->pFontIsLinked( dev );
3704 release_dc_ptr(dc);
3705 TRACE("returning %d\n", ret);
3706 return ret;
3709 /*************************************************************
3710 * GdiRealizationInfo (GDI32.@)
3712 * Returns a structure that contains some font information.
3714 BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
3716 DC *dc = get_dc_ptr(hdc);
3717 PHYSDEV dev;
3718 BOOL ret;
3720 if (!dc) return FALSE;
3721 dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
3722 ret = dev->funcs->pGdiRealizationInfo( dev, info );
3723 release_dc_ptr(dc);
3724 return ret;