ole32: Use wide-char string literals.
[wine.git] / dlls / gdi32 / font.c
blobdb87a283b13e554d375f77034eab1f31a53fe078
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 <limits.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include "winerror.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32 #include "winternl.h"
33 #include "winreg.h"
34 #include "gdi_private.h"
35 #include "resource.h"
36 #include "wine/exception.h"
37 #include "wine/heap.h"
38 #include "wine/rbtree.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(font);
43 static HKEY wine_fonts_key;
44 static HKEY wine_fonts_cache_key;
46 struct font_physdev
48 struct gdi_physdev dev;
49 struct gdi_font *font;
52 static inline struct font_physdev *get_font_dev( PHYSDEV dev )
54 return (struct font_physdev *)dev;
57 struct gdi_font_family
59 struct wine_rb_entry name_entry;
60 struct wine_rb_entry second_name_entry;
61 unsigned int refcount;
62 WCHAR family_name[LF_FACESIZE];
63 WCHAR second_name[LF_FACESIZE];
64 struct list faces;
65 struct gdi_font_family *replacement;
68 struct gdi_font_face
70 struct list entry;
71 unsigned int refcount;
72 WCHAR *style_name;
73 WCHAR *full_name;
74 WCHAR *file;
75 void *data_ptr;
76 SIZE_T data_size;
77 UINT face_index;
78 FONTSIGNATURE fs;
79 DWORD ntmFlags;
80 DWORD version;
81 DWORD flags; /* ADDFONT flags */
82 BOOL scalable;
83 struct bitmap_font_size size; /* set if face is a bitmap */
84 struct gdi_font_family *family;
85 struct gdi_font_enum_data *cached_enum_data;
88 static const struct font_backend_funcs *font_funcs;
90 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
92 static UINT font_smoothing = GGO_BITMAP;
93 static UINT subpixel_orientation = GGO_GRAY4_BITMAP;
94 static BOOL antialias_fakes = TRUE;
95 static struct font_gamma_ramp font_gamma_ramp;
97 static void add_face_to_cache( struct gdi_font_face *face );
98 static void remove_face_from_cache( struct gdi_font_face *face );
100 static inline WCHAR facename_tolower( WCHAR c )
102 if (c >= 'A' && c <= 'Z') return c - 'A' + 'a';
103 else if (c > 127) return RtlDowncaseUnicodeChar( c );
104 else return c;
107 static inline int facename_compare( const WCHAR *str1, const WCHAR *str2, SIZE_T len )
109 while (len--)
111 WCHAR c1 = facename_tolower( *str1++ ), c2 = facename_tolower( *str2++ );
112 if (c1 != c2) return c1 - c2;
113 else if (!c1) return 0;
115 return 0;
118 /* Device -> World size conversion */
120 /* Performs a device to world transformation on the specified width (which
121 * is in integer format).
123 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
125 double floatWidth;
127 /* Perform operation with floating point */
128 floatWidth = (double)width * dc->xformVport2World.eM11;
129 /* Round to integers */
130 return GDI_ROUND(floatWidth);
133 /* Performs a device to world transformation on the specified size (which
134 * is in integer format).
136 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
138 double floatHeight;
140 /* Perform operation with floating point */
141 floatHeight = (double)height * dc->xformVport2World.eM22;
142 /* Round to integers */
143 return GDI_ROUND(floatHeight);
146 /* scale width and height but don't mirror them */
148 static inline INT width_to_LP( DC *dc, INT width )
150 return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
153 static inline INT height_to_LP( DC *dc, INT height )
155 return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
158 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
160 POINT pt[2];
161 pt[0].x = pt[0].y = 0;
162 pt[1].x = 0;
163 pt[1].y = height;
164 lp_to_dp(dc, pt, 2);
165 return pt[1].y - pt[0].y;
168 static inline BOOL is_win9x(void)
170 return GetVersion() & 0x80000000;
173 static inline WCHAR *strdupW( const WCHAR *p )
175 WCHAR *ret;
176 DWORD len = (lstrlenW(p) + 1) * sizeof(WCHAR);
177 ret = HeapAlloc(GetProcessHeap(), 0, len);
178 memcpy(ret, p, len);
179 return ret;
182 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
183 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
184 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
185 static BOOL FONT_DeleteObject( HGDIOBJ handle );
187 static const struct gdi_obj_funcs fontobj_funcs =
189 FONT_SelectObject, /* pSelectObject */
190 FONT_GetObjectA, /* pGetObjectA */
191 FONT_GetObjectW, /* pGetObjectW */
192 NULL, /* pUnrealizeObject */
193 FONT_DeleteObject /* pDeleteObject */
196 typedef struct
198 LOGFONTW logfont;
199 } FONTOBJ;
201 struct font_enum
203 LPLOGFONTW lpLogFontParam;
204 FONTENUMPROCW lpEnumFunc;
205 LPARAM lpData;
206 BOOL unicode;
207 HDC hdc;
208 INT retval;
212 * For TranslateCharsetInfo
214 #define MAXTCIINDEX 32
215 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
216 /* ANSI */
217 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
218 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
219 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
220 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
221 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
222 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
223 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
224 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
225 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
226 /* reserved by ANSI */
227 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
228 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
229 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
230 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
231 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
232 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
233 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
234 /* ANSI and OEM */
235 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
236 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
237 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
238 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
239 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
240 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
241 /* reserved for alternate ANSI and OEM */
242 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
243 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
244 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
245 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
246 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
247 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
248 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
249 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
250 /* reserved for system */
251 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
252 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
255 static const WCHAR * const default_serif_list[3] =
257 L"Times New Roman",
258 L"Liberation Serif",
259 L"Bitstream Vera Serif"
261 static const WCHAR * const default_fixed_list[3] =
263 L"Courier New",
264 L"Liberation Mono",
265 L"Bitstream Vera Sans Mono"
267 static const WCHAR * const default_sans_list[3] =
269 L"Arial",
270 L"Liberation Sans",
271 L"Bitstream Vera Sans"
273 static WCHAR ff_roman_default[LF_FACESIZE];
274 static WCHAR ff_modern_default[LF_FACESIZE];
275 static WCHAR ff_swiss_default[LF_FACESIZE];
277 static const struct nls_update_font_list
279 UINT ansi_cp, oem_cp;
280 const char *oem, *fixed, *system;
281 const char *courier, *serif, *small, *sserif_96, *sserif_120;
282 /* these are for font substitutes */
283 const char *shelldlg, *tmsrmn;
284 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0, *helv_0, *tmsrmn_0;
285 struct subst { const char *from, *to; } arial_0, courier_new_0, times_new_roman_0;
286 } nls_update_font_list[] =
288 /* Latin 1 (United States) */
289 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
291 "Tahoma","Times New Roman"
293 /* Latin 1 (Multilingual) */
294 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
295 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
296 "Tahoma","Times New Roman" /* FIXME unverified */
298 /* Eastern Europe */
299 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
300 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
301 "Tahoma","Times New Roman", /* FIXME unverified */
302 "Fixedsys,238", "System,238",
303 "Courier New,238", "MS Serif,238", "Small Fonts,238",
304 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
305 { "Arial CE,0", "Arial,238" },
306 { "Courier New CE,0", "Courier New,238" },
307 { "Times New Roman CE,0", "Times New Roman,238" }
309 /* Cyrillic */
310 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
311 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
312 "Tahoma","Times New Roman", /* FIXME unverified */
313 "Fixedsys,204", "System,204",
314 "Courier New,204", "MS Serif,204", "Small Fonts,204",
315 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
316 { "Arial Cyr,0", "Arial,204" },
317 { "Courier New Cyr,0", "Courier New,204" },
318 { "Times New Roman Cyr,0", "Times New Roman,204" }
320 /* Greek */
321 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
322 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
323 "Tahoma","Times New Roman", /* FIXME unverified */
324 "Fixedsys,161", "System,161",
325 "Courier New,161", "MS Serif,161", "Small Fonts,161",
326 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
327 { "Arial Greek,0", "Arial,161" },
328 { "Courier New Greek,0", "Courier New,161" },
329 { "Times New Roman Greek,0", "Times New Roman,161" }
331 /* Turkish */
332 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
333 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
334 "Tahoma","Times New Roman", /* FIXME unverified */
335 "Fixedsys,162", "System,162",
336 "Courier New,162", "MS Serif,162", "Small Fonts,162",
337 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
338 { "Arial Tur,0", "Arial,162" },
339 { "Courier New Tur,0", "Courier New,162" },
340 { "Times New Roman Tur,0", "Times New Roman,162" }
342 /* Hebrew */
343 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
344 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
345 "Tahoma","Times New Roman", /* FIXME unverified */
346 "Fixedsys,177", "System,177",
347 "Courier New,177", "MS Serif,177", "Small Fonts,177",
348 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
350 /* Arabic */
351 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
352 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
353 "Microsoft Sans Serif","Times New Roman",
354 "Fixedsys,178", "System,178",
355 "Courier New,178", "MS Serif,178", "Small Fonts,178",
356 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
358 /* Baltic */
359 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
360 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
361 "Tahoma","Times New Roman", /* FIXME unverified */
362 "Fixedsys,186", "System,186",
363 "Courier New,186", "MS Serif,186", "Small Fonts,186",
364 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
365 { "Arial Baltic,0", "Arial,186" },
366 { "Courier New Baltic,0", "Courier New,186" },
367 { "Times New Roman Baltic,0", "Times New Roman,186" }
369 /* Vietnamese */
370 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
371 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
372 "Tahoma","Times New Roman" /* FIXME unverified */
374 /* Thai */
375 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
376 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
377 "Tahoma","Times New Roman" /* FIXME unverified */
379 /* Japanese */
380 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
381 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
382 "MS UI Gothic","MS Serif"
384 /* Chinese Simplified */
385 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
386 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
387 "SimSun", "NSimSun"
389 /* Korean */
390 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
391 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
392 "Gulim", "Batang"
394 /* Chinese Traditional */
395 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
396 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
397 "PMingLiU", "MingLiU"
401 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
403 return ( ansi_cp == 932 /* CP932 for Japanese */
404 || ansi_cp == 936 /* CP936 for Chinese Simplified */
405 || ansi_cp == 949 /* CP949 for Korean */
406 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
409 static CRITICAL_SECTION font_cs;
410 static CRITICAL_SECTION_DEBUG critsect_debug =
412 0, 0, &font_cs,
413 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
414 0, 0, { (DWORD_PTR)(__FILE__ ": font_cs") }
416 static CRITICAL_SECTION font_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
418 #ifndef WINE_FONT_DIR
419 #define WINE_FONT_DIR "fonts"
420 #endif
422 #ifdef WORDS_BIGENDIAN
423 #define GET_BE_WORD(x) (x)
424 #define GET_BE_DWORD(x) (x)
425 #else
426 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
427 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
428 #endif
430 static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
432 if (GetEnvironmentVariableW( L"WINEDATADIR", path, MAX_PATH ))
433 lstrcatW( path, L"\\" WINE_FONT_DIR "\\" );
434 else if (GetEnvironmentVariableW( L"WINEBUILDDIR", path, MAX_PATH ))
435 lstrcatW( path, L"\\fonts\\" );
437 lstrcatW( path, file );
438 if (path[5] == ':') memmove( path, path + 4, (lstrlenW(path) - 3) * sizeof(WCHAR) );
439 else path[1] = '\\'; /* change \??\ to \\?\ */
442 static void get_fonts_win_dir_path( const WCHAR *file, WCHAR *path )
444 GetWindowsDirectoryW( path, MAX_PATH );
445 lstrcatW( path, L"\\fonts\\" );
446 lstrcatW( path, file );
449 /* font substitutions */
451 struct gdi_font_subst
453 struct list entry;
454 int from_charset;
455 int to_charset;
456 WCHAR names[1];
459 static struct list font_subst_list = LIST_INIT(font_subst_list);
461 static inline WCHAR *get_subst_to_name( struct gdi_font_subst *subst )
463 return subst->names + lstrlenW( subst->names ) + 1;
466 static void dump_gdi_font_subst(void)
468 struct gdi_font_subst *subst;
470 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
472 if (subst->from_charset != -1 || subst->to_charset != -1)
473 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst->names),
474 subst->from_charset, debugstr_w(get_subst_to_name(subst)), subst->to_charset);
475 else
476 TRACE("%s -> %s\n", debugstr_w(subst->names), debugstr_w(get_subst_to_name(subst)));
480 static const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset )
482 struct gdi_font_subst *subst;
484 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
486 if (!facename_compare( subst->names, from_name, -1 ) &&
487 (subst->from_charset == from_charset || subst->from_charset == -1))
489 if (to_charset) *to_charset = subst->to_charset;
490 return get_subst_to_name( subst );
493 return NULL;
496 static BOOL add_gdi_font_subst( const WCHAR *from_name, int from_charset, const WCHAR *to_name, int to_charset )
498 struct gdi_font_subst *subst;
499 int len = lstrlenW( from_name ) + lstrlenW( to_name ) + 2;
501 if (get_gdi_font_subst( from_name, from_charset, NULL )) return FALSE; /* already exists */
503 if (!(subst = HeapAlloc( GetProcessHeap(), 0,
504 offsetof( struct gdi_font_subst, names[len] ))))
505 return FALSE;
506 lstrcpyW( subst->names, from_name );
507 lstrcpyW( get_subst_to_name(subst), to_name );
508 subst->from_charset = from_charset;
509 subst->to_charset = to_charset;
510 list_add_tail( &font_subst_list, &subst->entry );
511 return TRUE;
514 static void load_gdi_font_subst(void)
516 HKEY hkey;
517 DWORD i = 0, type, dlen, vlen;
518 WCHAR value[64], data[64], *p;
520 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
521 &hkey)) return;
523 dlen = sizeof(data);
524 vlen = ARRAY_SIZE(value);
525 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)data, &dlen ))
527 int from_charset = -1, to_charset = -1;
529 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
530 if ((p = wcsrchr( value, ',' )) && p[1])
532 *p++ = 0;
533 from_charset = wcstol( p, NULL, 10 );
535 if ((p = wcsrchr( data, ',' )) && p[1])
537 *p++ = 0;
538 to_charset = wcstol( p, NULL, 10 );
541 /* Win 2000 doesn't allow mapping between different charsets
542 or mapping of DEFAULT_CHARSET */
543 if ((!from_charset || to_charset == from_charset) && to_charset != DEFAULT_CHARSET)
544 add_gdi_font_subst( value, from_charset, data, to_charset );
546 /* reset dlen and vlen */
547 dlen = sizeof(data);
548 vlen = ARRAY_SIZE(value);
550 RegCloseKey( hkey );
553 /* font families */
555 static int family_namecmp( const WCHAR *str1, const WCHAR *str2 )
557 int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0);
559 if (!facename_compare( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0;
560 else if (!facename_compare( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1;
561 else if (!facename_compare( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2;
562 else prio1 = 3;
564 if (!facename_compare( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0;
565 else if (!facename_compare( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1;
566 else if (!facename_compare( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2;
567 else prio2 = 3;
569 if (prio1 != prio2) return prio1 - prio2;
570 if (vert1 != vert2) return vert1 - vert2;
571 return facename_compare( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 );
574 static int family_name_compare( const void *key, const struct wine_rb_entry *entry )
576 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, name_entry );
577 return family_namecmp( (const WCHAR *)key, family->family_name );
580 static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry )
582 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, second_name_entry );
583 return family_namecmp( (const WCHAR *)key, family->second_name );
586 static struct wine_rb_tree family_name_tree = { family_name_compare };
587 static struct wine_rb_tree family_second_name_tree = { family_second_name_compare };
589 static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name )
591 struct gdi_font_family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
593 family->refcount = 1;
594 lstrcpynW( family->family_name, name, LF_FACESIZE );
595 if (second_name && second_name[0])
597 lstrcpynW( family->second_name, second_name, LF_FACESIZE );
598 add_gdi_font_subst( second_name, -1, name, -1 );
600 else family->second_name[0] = 0;
601 list_init( &family->faces );
602 family->replacement = NULL;
603 wine_rb_put( &family_name_tree, family->family_name, &family->name_entry );
604 if (family->second_name[0]) wine_rb_put( &family_second_name_tree, family->second_name, &family->second_name_entry );
605 return family;
608 static void release_family( struct gdi_font_family *family )
610 if (--family->refcount) return;
611 assert( list_empty( &family->faces ));
612 wine_rb_remove( &family_name_tree, &family->name_entry );
613 if (family->second_name[0]) wine_rb_remove( &family_second_name_tree, &family->second_name_entry );
614 if (family->replacement) release_family( family->replacement );
615 HeapFree( GetProcessHeap(), 0, family );
618 static struct gdi_font_family *find_family_from_name( const WCHAR *name )
620 struct wine_rb_entry *entry;
621 if (!(entry = wine_rb_get( &family_name_tree, name ))) return NULL;
622 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, name_entry );
625 static struct gdi_font_family *find_family_from_any_name( const WCHAR *name )
627 struct wine_rb_entry *entry;
628 struct gdi_font_family *family;
629 if ((family = find_family_from_name( name ))) return family;
630 if (!(entry = wine_rb_get( &family_second_name_tree, name ))) return NULL;
631 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, second_name_entry );
634 static const struct list *get_family_face_list( const struct gdi_font_family *family )
636 return family->replacement ? &family->replacement->faces : &family->faces;
639 static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name )
641 struct gdi_font_face *face;
642 const WCHAR *file;
643 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
645 if (!face->file) continue;
646 file = wcsrchr(face->file, '\\');
647 if (!file) file = face->file;
648 else file++;
649 if (wcsicmp( file, file_name )) continue;
650 face->refcount++;
651 return face;
653 return NULL;
656 static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name )
658 struct gdi_font_family *family;
659 struct gdi_font_face *face;
661 TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
663 if (!family_name)
665 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
666 if ((face = family_find_face_from_filename( family, file_name ))) return face;
667 return NULL;
670 if (!(family = find_family_from_name( family_name ))) return NULL;
671 return family_find_face_from_filename( family, file_name );
674 static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
676 struct gdi_font_family *new_family, *family;
677 struct gdi_font_face *face;
678 WCHAR new_name_vert[LF_FACESIZE], replace_vert[LF_FACESIZE];
680 if (!(family = find_family_from_any_name( replace )))
682 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace) );
683 return FALSE;
686 if (!(new_family = create_family( new_name, NULL ))) return FALSE;
687 new_family->replacement = family;
688 family->refcount++;
689 TRACE( "mapping %s to %s\n", debugstr_w(replace), debugstr_w(new_name) );
691 /* also add replacement for vertical font if necessary */
692 if (replace[0] == '@') return TRUE;
693 if (list_empty( &family->faces )) return TRUE;
694 face = LIST_ENTRY( list_head(&family->faces), struct gdi_font_face, entry );
695 if (!(face->fs.fsCsb[0] & FS_DBCS_MASK)) return TRUE;
697 new_name_vert[0] = '@';
698 lstrcpynW( new_name_vert + 1, new_name, LF_FACESIZE - 1 );
699 if (find_family_from_any_name( new_name_vert )) return TRUE; /* already exists */
701 replace_vert[0] = '@';
702 lstrcpynW( replace_vert + 1, replace, LF_FACESIZE - 1 );
703 add_family_replacement( new_name_vert, replace_vert );
704 return TRUE;
708 * The replacement list is a way to map an entire font
709 * family onto another family. For example adding
711 * [HKCU\Software\Wine\Fonts\Replacements]
712 * "Wingdings"="Winedings"
714 * would enumerate the Winedings font both as Winedings and
715 * Wingdings. However if a real Wingdings font is present the
716 * replacement does not take place.
718 static void load_gdi_font_replacements(void)
720 HKEY hkey;
721 DWORD i = 0, type, dlen, vlen;
722 WCHAR value[LF_FACESIZE], data[1024];
724 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
725 if (RegOpenKeyW( wine_fonts_key, L"Replacements", &hkey )) return;
727 dlen = sizeof(data);
728 vlen = ARRAY_SIZE(value);
729 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)data, &dlen ))
731 /* "NewName"="Oldname" */
732 if (!find_family_from_any_name( value ))
734 if (type == REG_MULTI_SZ)
736 WCHAR *replace = data;
737 while (*replace)
739 if (add_family_replacement( value, replace )) break;
740 replace += lstrlenW(replace) + 1;
743 else if (type == REG_SZ) add_family_replacement( value, data );
745 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
747 /* reset dlen and vlen */
748 dlen = sizeof(data);
749 vlen = ARRAY_SIZE(value);
751 RegCloseKey( hkey );
754 static void dump_gdi_font_list(void)
756 struct gdi_font_family *family;
757 struct gdi_font_face *face;
759 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
761 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
762 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
764 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
765 face->fs.fsCsb[0] );
766 if (!face->scalable) TRACE(" %d", face->size.height );
767 TRACE("\n");
772 static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
774 if (index < 3)
776 const WCHAR * const *defaults;
778 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
779 defaults = default_fixed_list;
780 else if ((pitch_and_family & 0xf0) == FF_ROMAN)
781 defaults = default_serif_list;
782 else
783 defaults = default_sans_list;
784 lstrcpynW( buffer, defaults[index], LF_FACESIZE );
785 return TRUE;
787 return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
790 static void set_default_family( DWORD pitch_and_family, WCHAR *default_name )
792 struct wine_rb_entry *entry;
793 WCHAR name[LF_FACESIZE];
794 int i = 0;
796 while (enum_fallbacks( pitch_and_family, i++, name ))
798 if (!(entry = wine_rb_get( &family_name_tree, name ))) continue;
799 wine_rb_remove( &family_name_tree, entry );
800 lstrcpynW( default_name, name, LF_FACESIZE - 1 );
801 wine_rb_put( &family_name_tree, name, entry );
802 return;
806 static void reorder_font_list(void)
808 set_default_family( FF_ROMAN, ff_roman_default );
809 set_default_family( FF_MODERN, ff_modern_default );
810 set_default_family( FF_SWISS, ff_swiss_default );
813 static void release_face( struct gdi_font_face *face )
815 if (--face->refcount) return;
816 if (face->family)
818 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
819 list_remove( &face->entry );
820 release_family( face->family );
822 HeapFree( GetProcessHeap(), 0, face->file );
823 HeapFree( GetProcessHeap(), 0, face->style_name );
824 HeapFree( GetProcessHeap(), 0, face->full_name );
825 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
826 HeapFree( GetProcessHeap(), 0, face );
829 static int remove_font( const WCHAR *file, DWORD flags )
831 struct gdi_font_family *family, *family_next;
832 struct gdi_font_face *face, *face_next;
833 int count = 0;
835 EnterCriticalSection( &font_cs );
836 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_name_tree, struct gdi_font_family, name_entry )
838 family->refcount++;
839 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry )
841 if (!face->file) continue;
842 if (LOWORD(face->flags) != LOWORD(flags)) continue;
843 if (!wcsicmp( face->file, file ))
845 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
846 release_face( face );
847 count++;
850 release_family( family );
852 LeaveCriticalSection( &font_cs );
853 return count;
856 static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
858 if (facename_compare( f1->full_name, f2->full_name, -1 )) return FALSE;
859 if (f1->scalable) return TRUE;
860 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
861 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
864 static inline int style_order( const struct gdi_font_face *face )
866 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
868 case NTM_REGULAR:
869 return 0;
870 case NTM_BOLD:
871 return 1;
872 case NTM_ITALIC:
873 return 2;
874 case NTM_BOLD | NTM_ITALIC:
875 return 3;
876 default:
877 WARN( "Don't know how to order face %s with flags 0x%08x\n",
878 debugstr_w(face->full_name), face->ntmFlags );
879 return 9999;
883 static BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
885 struct gdi_font_face *cursor;
887 LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
889 if (faces_equal( face, cursor ))
891 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
892 debugstr_w(face->full_name), debugstr_w(family->family_name),
893 cursor->version, face->version );
895 if (face->file && !wcsicmp( face->file, cursor->file ))
897 cursor->refcount++;
898 TRACE("Font %s already in list, refcount now %d\n",
899 debugstr_w(face->file), cursor->refcount);
900 return FALSE;
902 if (face->version <= cursor->version)
904 TRACE("Original font %s is newer so skipping %s\n",
905 debugstr_w(cursor->file), debugstr_w(face->file));
906 return FALSE;
908 else
910 TRACE("Replacing original %s with %s\n",
911 debugstr_w(cursor->file), debugstr_w(face->file));
912 list_add_before( &cursor->entry, &face->entry );
913 face->family = family;
914 family->refcount++;
915 face->refcount++;
916 release_face( cursor );
917 return TRUE;
920 if (style_order( face ) < style_order( cursor )) break;
923 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
924 debugstr_w(family->family_name), debugstr_w(face->file) );
925 list_add_before( &cursor->entry, &face->entry );
926 face->family = family;
927 family->refcount++;
928 face->refcount++;
929 return TRUE;
932 static struct gdi_font_face *create_face( struct gdi_font_family *family, const WCHAR *style,
933 const WCHAR *fullname, const WCHAR *file,
934 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
935 DWORD ntmflags, DWORD version, DWORD flags,
936 const struct bitmap_font_size *size )
938 struct gdi_font_face *face = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*face) );
940 face->refcount = 1;
941 face->style_name = strdupW( style );
942 face->full_name = strdupW( fullname );
943 face->face_index = index;
944 face->fs = fs;
945 face->ntmFlags = ntmflags;
946 face->version = version;
947 face->flags = flags;
948 face->data_ptr = data_ptr;
949 face->data_size = data_size;
950 if (file) face->file = strdupW( file );
951 if (size) face->size = *size;
952 else face->scalable = TRUE;
953 if (insert_face_in_family_list( face, family )) return face;
954 release_face( face );
955 return NULL;
958 static int CDECL add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
959 const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
960 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
961 DWORD ntmflags, DWORD version, DWORD flags,
962 const struct bitmap_font_size *size )
964 struct gdi_font_face *face;
965 struct gdi_font_family *family;
966 int ret = 0;
968 if ((family = find_family_from_name( family_name ))) family->refcount++;
969 else if (!(family = create_family( family_name, second_name ))) return ret;
971 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
972 index, fs, ntmflags, version, flags, size )))
974 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
975 release_face( face );
977 release_family( family );
978 ret++;
980 if (fs.fsCsb[0] & FS_DBCS_MASK)
982 WCHAR vert_family[LF_FACESIZE], vert_second[LF_FACESIZE], vert_full[LF_FULLFACESIZE];
984 vert_family[0] = '@';
985 lstrcpynW( vert_family + 1, family_name, LF_FACESIZE - 1 );
987 if (second_name && second_name[0])
989 vert_second[0] = '@';
990 lstrcpynW( vert_second + 1, second_name, LF_FACESIZE - 1 );
992 else vert_second[0] = 0;
994 if (fullname)
996 vert_full[0] = '@';
997 lstrcpynW( vert_full + 1, fullname, LF_FULLFACESIZE - 1 );
998 fullname = vert_full;
1001 if ((family = find_family_from_name( vert_family ))) family->refcount++;
1002 else if (!(family = create_family( vert_family, vert_second ))) return ret;
1004 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1005 index, fs, ntmflags, version, flags | ADDFONT_VERTICAL_FONT, size )))
1007 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1008 release_face( face );
1010 release_family( family );
1011 ret++;
1013 return ret;
1016 /* font cache */
1018 struct cached_face
1020 DWORD index;
1021 DWORD flags;
1022 DWORD ntmflags;
1023 DWORD version;
1024 struct bitmap_font_size size;
1025 FONTSIGNATURE fs;
1026 WCHAR full_name[1];
1027 /* WCHAR file_name[]; */
1030 static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
1031 void *buffer, DWORD buffer_size, BOOL scalable )
1033 DWORD type, size, needed, index = 0;
1034 struct gdi_font_face *face;
1035 HKEY hkey_strike;
1036 WCHAR name[256];
1037 struct cached_face *cached = (struct cached_face *)buffer;
1039 size = sizeof(name);
1040 needed = buffer_size - sizeof(DWORD);
1041 while (!RegEnumValueW( hkey_family, index++, name, &size, NULL, &type, buffer, &needed ))
1043 if (type == REG_BINARY && needed > sizeof(*cached))
1045 ((DWORD *)buffer)[needed / sizeof(DWORD)] = 0;
1046 if ((face = create_face( family, name, cached->full_name,
1047 cached->full_name + lstrlenW(cached->full_name) + 1,
1048 NULL, 0, cached->index, cached->fs, cached->ntmflags, cached->version,
1049 cached->flags, scalable ? NULL : &cached->size )))
1051 if (!scalable)
1052 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1053 face->size.height, face->size.width, face->size.size >> 6,
1054 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1056 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1057 face->fs.fsCsb[0], face->fs.fsCsb[1],
1058 face->fs.fsUsb[0], face->fs.fsUsb[1],
1059 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1061 release_face( face );
1064 size = sizeof(name);
1065 needed = buffer_size - sizeof(DWORD);
1068 /* load bitmap strikes */
1070 index = 0;
1071 needed = buffer_size;
1072 while (!RegEnumKeyExW( hkey_family, index++, buffer, &needed, NULL, NULL, NULL, NULL ))
1074 if (!RegOpenKeyExW( hkey_family, buffer, 0, KEY_ALL_ACCESS, &hkey_strike ))
1076 load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
1077 RegCloseKey( hkey_strike );
1079 needed = buffer_size;
1083 static void load_font_list_from_cache(void)
1085 DWORD size, family_index = 0;
1086 struct gdi_font_family *family;
1087 HKEY hkey_family;
1088 WCHAR buffer[4096], second_name[LF_FACESIZE];
1090 size = sizeof(buffer);
1091 while (!RegEnumKeyExW( wine_fonts_cache_key, family_index++, buffer, &size, NULL, NULL, NULL, NULL ))
1093 RegOpenKeyExW( wine_fonts_cache_key, buffer, 0, KEY_ALL_ACCESS, &hkey_family );
1094 TRACE("opened family key %s\n", debugstr_w(buffer));
1095 size = sizeof(second_name);
1096 if (RegQueryValueExW( hkey_family, NULL, NULL, NULL, (BYTE *)second_name, &size ))
1097 second_name[0] = 0;
1099 family = create_family( buffer, second_name );
1101 load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
1103 RegCloseKey( hkey_family );
1104 release_family( family );
1105 size = sizeof(buffer);
1109 static void add_face_to_cache( struct gdi_font_face *face )
1111 HKEY hkey_family, hkey_face;
1112 DWORD len, buffer[1024];
1113 struct cached_face *cached = (struct cached_face *)buffer;
1115 if (RegCreateKeyExW( wine_fonts_cache_key, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE,
1116 KEY_ALL_ACCESS, NULL, &hkey_family, NULL ))
1117 return;
1119 if (face->family->second_name[0])
1120 RegSetValueExW( hkey_family, NULL, 0, REG_SZ, (BYTE *)face->family->second_name,
1121 (lstrlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1123 if (!face->scalable)
1125 WCHAR name[10];
1127 swprintf( name, ARRAY_SIZE(name), L"%d", face->size.y_ppem );
1128 RegCreateKeyExW( hkey_family, name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
1129 NULL, &hkey_face, NULL);
1131 else hkey_face = hkey_family;
1133 memset( cached, 0, sizeof(*cached) );
1134 cached->index = face->face_index;
1135 cached->flags = face->flags;
1136 cached->ntmflags = face->ntmFlags;
1137 cached->version = face->version;
1138 cached->fs = face->fs;
1139 if (!face->scalable) cached->size = face->size;
1140 lstrcpyW( cached->full_name, face->full_name );
1141 len = lstrlenW( face->full_name ) + 1;
1142 lstrcpyW( cached->full_name + len, face->file );
1143 len += lstrlenW( face->file ) + 1;
1145 RegSetValueExW( hkey_face, face->style_name, 0, REG_BINARY, (BYTE *)cached,
1146 offsetof( struct cached_face, full_name[len] ));
1148 if (hkey_face != hkey_family) RegCloseKey( hkey_face );
1149 RegCloseKey( hkey_family );
1152 static void remove_face_from_cache( struct gdi_font_face *face )
1154 HKEY hkey_family;
1156 if (RegOpenKeyExW( wine_fonts_cache_key, face->family->family_name, 0, KEY_ALL_ACCESS, &hkey_family ))
1157 return;
1159 if (!face->scalable)
1161 WCHAR name[10];
1162 swprintf( name, ARRAY_SIZE(name), L"%d", face->size.y_ppem );
1163 RegDeleteKeyW( hkey_family, name );
1165 else RegDeleteValueW( hkey_family, face->style_name );
1167 RegCloseKey( hkey_family );
1170 /* font links */
1172 struct gdi_font_link
1174 struct list entry;
1175 struct list links;
1176 WCHAR name[LF_FACESIZE];
1177 FONTSIGNATURE fs;
1180 struct gdi_font_link_entry
1182 struct list entry;
1183 FONTSIGNATURE fs;
1184 WCHAR family_name[LF_FACESIZE];
1187 static struct list font_links = LIST_INIT(font_links);
1189 static struct gdi_font_link *find_gdi_font_link( const WCHAR *name )
1191 struct gdi_font_link *link;
1193 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1194 if (!facename_compare( link->name, name, LF_FACESIZE - 1 )) return link;
1195 return NULL;
1198 static struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
1199 FONTSIGNATURE fs )
1201 struct gdi_font_link *link;
1202 struct gdi_font_link_entry *entry;
1203 struct gdi_font_family *family;
1205 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1207 if (!facename_compare( link->name, name, LF_FACESIZE - 1 ) ||
1208 (subst && !facename_compare( link->name, subst, LF_FACESIZE - 1 )))
1210 TRACE("found entry in system list\n");
1211 LIST_FOR_EACH_ENTRY( entry, &link->links, struct gdi_font_link_entry, entry )
1213 const struct gdi_font_link *links;
1215 family = find_family_from_name( entry->family_name );
1216 if (!fs.fsCsb[0]) return family;
1217 if (fs.fsCsb[0] & entry->fs.fsCsb[0]) return family;
1218 if ((links = find_gdi_font_link( family->family_name )) && fs.fsCsb[0] & links->fs.fsCsb[0])
1219 return family;
1223 return NULL;
1226 static struct gdi_font_link *add_gdi_font_link( const WCHAR *name )
1228 struct gdi_font_link *link = find_gdi_font_link( name );
1230 if (link) return link;
1231 if ((link = HeapAlloc( GetProcessHeap(), 0, sizeof(*link) )))
1233 lstrcpynW( link->name, name, LF_FACESIZE );
1234 memset( &link->fs, 0, sizeof(link->fs) );
1235 list_init( &link->links );
1236 list_add_tail( &font_links, &link->entry );
1238 return link;
1241 static void add_gdi_font_link_entry( struct gdi_font_link *link, const WCHAR *family_name, FONTSIGNATURE fs )
1243 struct gdi_font_link_entry *entry;
1245 entry = HeapAlloc( GetProcessHeap(), 0, sizeof(*entry) );
1246 lstrcpynW( entry->family_name, family_name, LF_FACESIZE );
1247 entry->fs = fs;
1248 link->fs.fsCsb[0] |= fs.fsCsb[0];
1249 link->fs.fsCsb[1] |= fs.fsCsb[1];
1250 list_add_tail( &link->links, &entry->entry );
1253 static const WCHAR * const font_links_list[] =
1255 L"Lucida Sans Unicode",
1256 L"Microsoft Sans Serif",
1257 L"Tahoma"
1260 static const struct font_links_defaults_list
1262 /* Keyed off substitution for "MS Shell Dlg" */
1263 const WCHAR *shelldlg;
1264 /* Maximum of four substitutes, plus terminating NULL pointer */
1265 const WCHAR *substitutes[5];
1266 } font_links_defaults_list[] =
1268 /* Non East-Asian */
1269 { L"Tahoma", /* FIXME unverified ordering */
1270 { L"MS UI Gothic", L"SimSun", L"Gulim", L"PMingLiU", NULL }
1272 /* Below lists are courtesy of
1273 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1275 /* Japanese */
1276 { L"MS UI Gothic",
1277 { L"MS UI Gothic", L"PMingLiU", L"SimSun", L"Gulim", NULL }
1279 /* Chinese Simplified */
1280 { L"SimSun",
1281 { L"SimSun", L"PMingLiU", L"MS UI Gothic", L"Batang", NULL }
1283 /* Korean */
1284 { L"Gulim",
1285 { L"Gulim", L"PMingLiU", L"MS UI Gothic", L"SimSun", NULL }
1287 /* Chinese Traditional */
1288 { L"PMingLiU",
1289 { L"PMingLiU", L"SimSun", L"MS UI Gothic", L"Batang", NULL }
1293 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1295 struct gdi_font_family *family;
1296 struct gdi_font_face *face;
1297 struct gdi_font_link *font_link;
1298 const WCHAR *file, *value;
1300 /* Don't store fonts that are only substitutes for other fonts */
1301 if (get_gdi_font_subst( name, -1, NULL ))
1303 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1304 return;
1306 font_link = add_gdi_font_link( name );
1307 for ( ; *values; values++)
1309 if (!facename_compare( name, *values, -1 )) continue;
1310 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1311 if (!(family = find_family_from_name( value ))) continue;
1312 /* use first extant filename for this Family */
1313 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1315 if (!face->file) continue;
1316 file = wcsrchr(face->file, '\\');
1317 if (!file) file = face->file;
1318 else file++;
1319 if ((face = find_face_from_filename( file, value )))
1321 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1322 TRACE( "added internal SystemLink for %s to %s in %s\n",
1323 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1325 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1326 break;
1331 static void load_system_links(void)
1333 HKEY hkey;
1334 DWORD i, j;
1335 const WCHAR *shelldlg_name;
1336 struct gdi_font_link *font_link, *system_font_link;
1337 struct gdi_font_face *face;
1339 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE,
1340 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey ))
1342 WCHAR value[MAX_PATH], data[1024];
1343 DWORD type, val_len, data_len;
1344 WCHAR *entry, *next;
1346 val_len = ARRAY_SIZE(value);
1347 data_len = sizeof(data);
1348 i = 0;
1349 while (!RegEnumValueW( hkey, i++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len))
1351 /* Don't store fonts that are only substitutes for other fonts */
1352 if (!get_gdi_font_subst( value, -1, NULL ))
1354 font_link = add_gdi_font_link( value );
1355 for (entry = data; (char *)entry < (char *)data + data_len && *entry; entry = next)
1357 const WCHAR *family_name = NULL;
1358 WCHAR *p;
1360 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1362 next = entry + lstrlenW(entry) + 1;
1363 if ((p = wcschr( entry, ',' )))
1365 *p++ = 0;
1366 while (iswspace(*p)) p++;
1367 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
1369 if ((face = find_face_from_filename( entry, family_name )))
1371 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1372 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
1374 else TRACE( "Unable to find file %s family %s\n",
1375 debugstr_w(entry), debugstr_w(family_name) );
1378 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1380 val_len = ARRAY_SIZE(value);
1381 data_len = sizeof(data);
1383 RegCloseKey( hkey );
1386 if ((shelldlg_name = get_gdi_font_subst( L"MS Shell Dlg", -1, NULL )))
1388 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
1390 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
1392 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
1393 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
1395 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
1396 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
1397 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
1398 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
1402 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1404 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1405 that Tahoma has */
1407 system_font_link = add_gdi_font_link( L"System" );
1408 if ((face = find_face_from_filename( L"tahoma.ttf", L"Tahoma" )))
1410 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
1411 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
1413 if ((font_link = find_gdi_font_link( L"Tahoma" )))
1415 struct gdi_font_link_entry *entry;
1416 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
1417 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
1421 /* font matching */
1423 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
1425 struct gdi_font_link *font_link;
1427 if (!face->scalable && !can_use_bitmap) return FALSE;
1428 if (!fs.fsCsb[0]) return TRUE;
1429 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
1430 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
1431 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
1432 return FALSE;
1435 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
1436 const LOGFONTW *lf, FONTSIGNATURE fs,
1437 BOOL can_use_bitmap )
1439 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
1440 unsigned int best_score = 4;
1441 int best_diff = 0;
1442 int it = !!lf->lfItalic;
1443 int bd = lf->lfWeight > 550;
1444 int height = lf->lfHeight;
1446 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1448 int italic = !!(face->ntmFlags & NTM_ITALIC);
1449 int bold = !!(face->ntmFlags & NTM_BOLD);
1450 int score = (italic ^ it) + (bold ^ bd);
1452 if (!can_select_face( face, fs, can_use_bitmap )) continue;
1453 if (score > best_score) continue;
1454 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
1455 best_score = score;
1456 best = face;
1457 if (best->scalable && best_score == 0) break;
1458 if (!best->scalable)
1460 int diff;
1461 if (height > 0)
1462 diff = height - (signed int)best->size.height;
1463 else
1464 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
1465 if (!best_bitmap ||
1466 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
1467 (best_diff < 0 && diff > best_diff))
1469 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
1470 best_diff = diff;
1471 best_bitmap = best;
1472 if (best_score == 0 && best_diff == 0) break;
1476 if (!best) return NULL;
1477 return best->scalable ? best : best_bitmap;
1480 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
1481 const LOGFONTW *lf, FONTSIGNATURE fs,
1482 BOOL can_use_bitmap )
1484 struct gdi_font_family *family;
1485 struct gdi_font_face *face;
1487 family = find_family_from_any_name( name );
1488 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1489 if (subst)
1491 family = find_family_from_any_name( subst );
1492 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1495 /* search by full face name */
1496 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1497 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1498 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
1499 can_select_face( face, fs, can_use_bitmap ))
1500 return face;
1502 if ((family = find_family_from_font_links( name, subst, fs )))
1504 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1506 return NULL;
1509 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
1510 BOOL can_use_bitmap, BOOL want_vertical )
1512 struct gdi_font_family *family;
1513 struct gdi_font_face *face;
1514 WCHAR name[LF_FACESIZE + 1];
1515 int i = 0;
1517 /* first try the family fallbacks */
1518 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
1520 if (want_vertical)
1522 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
1523 name[0] = '@';
1526 if (!(family = find_family_from_any_name(name))) continue;
1527 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1529 /* otherwise try only scalable */
1530 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1532 if ((family->family_name[0] == '@') == !want_vertical) continue;
1533 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1535 if (!can_use_bitmap) return NULL;
1536 /* then also bitmap fonts */
1537 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1539 if ((family->family_name[0] == '@') == !want_vertical) continue;
1540 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1542 return NULL;
1545 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
1546 const WCHAR **orig_name )
1548 BOOL want_vertical = (lf->lfFaceName[0] == '@');
1549 struct gdi_font_face *face;
1551 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
1553 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
1554 csi->fs.fsCsb[0] = 0;
1557 if (lf->lfFaceName[0])
1559 int subst_charset;
1560 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
1562 if (subst)
1564 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
1565 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
1566 if (subst_charset != -1)
1567 TranslateCharsetInfo( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
1568 *orig_name = lf->lfFaceName;
1571 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap )))
1572 return face;
1574 *orig_name = NULL; /* substitution is no longer relevant */
1576 /* If requested charset was DEFAULT_CHARSET then try using charset
1577 corresponding to the current ansi codepage */
1578 if (!csi->fs.fsCsb[0])
1580 INT acp = GetACP();
1581 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)acp, csi, TCI_SRCCODEPAGE ))
1583 FIXME( "TCI failed on codepage %d\n", acp );
1584 csi->fs.fsCsb[0] = 0;
1588 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1589 if (csi->fs.fsCsb[0])
1591 csi->fs.fsCsb[0] = 0;
1592 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1594 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
1595 return NULL;
1598 /* realized font objects */
1600 #define FIRST_FONT_HANDLE 1
1601 #define MAX_FONT_HANDLES 256
1603 struct font_handle_entry
1605 struct gdi_font *font;
1606 WORD generation; /* generation count for reusing handle values */
1609 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
1610 static struct font_handle_entry *next_free;
1611 static struct font_handle_entry *next_unused = font_handles;
1613 static struct font_handle_entry *handle_entry( DWORD handle )
1615 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
1617 if (idx < MAX_FONT_HANDLES)
1619 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
1620 return &font_handles[idx];
1622 if (handle) WARN( "invalid handle 0x%08x\n", handle );
1623 return NULL;
1626 static struct gdi_font *get_font_from_handle( DWORD handle )
1628 struct font_handle_entry *entry = handle_entry( handle );
1630 if (entry) return entry->font;
1631 SetLastError( ERROR_INVALID_PARAMETER );
1632 return NULL;
1635 static DWORD alloc_font_handle( struct gdi_font *font )
1637 struct font_handle_entry *entry;
1639 entry = next_free;
1640 if (entry)
1641 next_free = (struct font_handle_entry *)entry->font;
1642 else if (next_unused < font_handles + MAX_FONT_HANDLES)
1643 entry = next_unused++;
1644 else
1646 ERR( "out of realized font handles\n" );
1647 return 0;
1649 entry->font = font;
1650 if (++entry->generation == 0xffff) entry->generation = 1;
1651 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
1654 static void free_font_handle( DWORD handle )
1656 struct font_handle_entry *entry;
1658 if ((entry = handle_entry( handle )))
1660 entry->font = (struct gdi_font *)next_free;
1661 next_free = entry;
1665 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
1667 UINT len = file ? lstrlenW(file) : 0;
1668 struct gdi_font *font = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1669 offsetof( struct gdi_font, file[len + 1] ));
1671 font->refcount = 1;
1672 font->matrix.eM11 = font->matrix.eM22 = 1.0;
1673 font->scale_y = 1;
1674 font->kern_count = -1;
1675 list_init( &font->child_fonts );
1677 if (file)
1679 WIN32_FILE_ATTRIBUTE_DATA info;
1680 if (GetFileAttributesExW( file, GetFileExInfoStandard, &info ))
1682 font->writetime = info.ftLastWriteTime;
1683 font->data_size = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
1684 memcpy( font->file, file, len * sizeof(WCHAR) );
1687 else
1689 font->data_ptr = data_ptr;
1690 font->data_size = data_size;
1693 if (!(font->handle = alloc_font_handle( font )))
1695 HeapFree( GetProcessHeap(), 0, font );
1696 return NULL;
1698 return font;
1701 static void free_gdi_font( struct gdi_font *font )
1703 DWORD i;
1704 struct gdi_font *child, *child_next;
1706 if (font->private) font_funcs->destroy_font( font );
1707 free_font_handle( font->handle );
1708 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
1710 list_remove( &child->entry );
1711 free_gdi_font( child );
1713 for (i = 0; i < font->gm_size; i++) HeapFree( GetProcessHeap(), 0, font->gm[i] );
1714 HeapFree( GetProcessHeap(), 0, font->otm.otmpFamilyName );
1715 HeapFree( GetProcessHeap(), 0, font->otm.otmpStyleName );
1716 HeapFree( GetProcessHeap(), 0, font->otm.otmpFaceName );
1717 HeapFree( GetProcessHeap(), 0, font->otm.otmpFullName );
1718 HeapFree( GetProcessHeap(), 0, font->gm );
1719 HeapFree( GetProcessHeap(), 0, font->kern_pairs );
1720 HeapFree( GetProcessHeap(), 0, font->gsub_table );
1721 HeapFree( GetProcessHeap(), 0, font );
1724 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
1726 return (WCHAR *)font->otm.otmpFamilyName;
1729 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
1730 const LOGFONTW *lf )
1732 struct gdi_font *font;
1734 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
1735 font->fs = face->fs;
1736 font->lf = *lf;
1737 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
1738 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
1739 font->scalable = face->scalable;
1740 font->face_index = face->face_index;
1741 font->ntmFlags = face->ntmFlags;
1742 font->aa_flags = HIWORD( face->flags );
1743 if (!family_name) family_name = face->family->family_name;
1744 font->otm.otmpFamilyName = (char *)strdupW( family_name );
1745 font->otm.otmpStyleName = (char *)strdupW( face->style_name );
1746 font->otm.otmpFaceName = (char *)strdupW( face->full_name );
1747 return font;
1750 struct glyph_metrics
1752 GLYPHMETRICS gm;
1753 ABC abc; /* metrics of the unrotated char */
1754 BOOL init;
1757 #define GM_BLOCK_SIZE 128
1759 /* TODO: GGO format support */
1760 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
1762 UINT block = index / GM_BLOCK_SIZE;
1763 UINT entry = index % GM_BLOCK_SIZE;
1765 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
1767 *gm = font->gm[block][entry].gm;
1768 *abc = font->gm[block][entry].abc;
1770 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
1771 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
1772 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
1773 return TRUE;
1776 return FALSE;
1779 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
1780 const GLYPHMETRICS *gm, const ABC *abc )
1782 UINT block = index / GM_BLOCK_SIZE;
1783 UINT entry = index % GM_BLOCK_SIZE;
1785 if (block >= font->gm_size)
1787 struct glyph_metrics **ptr;
1789 if (font->gm)
1790 ptr = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm, (block + 1) * sizeof(*ptr) );
1791 else
1792 ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, (block + 1) * sizeof(*ptr) );
1793 if (!ptr) return;
1794 font->gm_size = block + 1;
1795 font->gm = ptr;
1797 if (!font->gm[block])
1799 font->gm[block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**font->gm) * GM_BLOCK_SIZE );
1800 if (!font->gm[block]) return;
1802 font->gm[block][entry].gm = *gm;
1803 font->gm[block][entry].abc = *abc;
1804 font->gm[block][entry].init = TRUE;
1808 /* GSUB table support */
1810 typedef struct
1812 DWORD version;
1813 WORD ScriptList;
1814 WORD FeatureList;
1815 WORD LookupList;
1816 } GSUB_Header;
1818 typedef struct
1820 CHAR ScriptTag[4];
1821 WORD Script;
1822 } GSUB_ScriptRecord;
1824 typedef struct
1826 WORD ScriptCount;
1827 GSUB_ScriptRecord ScriptRecord[1];
1828 } GSUB_ScriptList;
1830 typedef struct
1832 CHAR LangSysTag[4];
1833 WORD LangSys;
1834 } GSUB_LangSysRecord;
1836 typedef struct
1838 WORD DefaultLangSys;
1839 WORD LangSysCount;
1840 GSUB_LangSysRecord LangSysRecord[1];
1841 } GSUB_Script;
1843 typedef struct
1845 WORD LookupOrder; /* Reserved */
1846 WORD ReqFeatureIndex;
1847 WORD FeatureCount;
1848 WORD FeatureIndex[1];
1849 } GSUB_LangSys;
1851 typedef struct
1853 CHAR FeatureTag[4];
1854 WORD Feature;
1855 } GSUB_FeatureRecord;
1857 typedef struct
1859 WORD FeatureCount;
1860 GSUB_FeatureRecord FeatureRecord[1];
1861 } GSUB_FeatureList;
1863 typedef struct
1865 WORD FeatureParams; /* Reserved */
1866 WORD LookupCount;
1867 WORD LookupListIndex[1];
1868 } GSUB_Feature;
1870 typedef struct
1872 WORD LookupCount;
1873 WORD Lookup[1];
1874 } GSUB_LookupList;
1876 typedef struct
1878 WORD LookupType;
1879 WORD LookupFlag;
1880 WORD SubTableCount;
1881 WORD SubTable[1];
1882 } GSUB_LookupTable;
1884 typedef struct
1886 WORD CoverageFormat;
1887 WORD GlyphCount;
1888 WORD GlyphArray[1];
1889 } GSUB_CoverageFormat1;
1891 typedef struct
1893 WORD Start;
1894 WORD End;
1895 WORD StartCoverageIndex;
1896 } GSUB_RangeRecord;
1898 typedef struct
1900 WORD CoverageFormat;
1901 WORD RangeCount;
1902 GSUB_RangeRecord RangeRecord[1];
1903 } GSUB_CoverageFormat2;
1905 typedef struct
1907 WORD SubstFormat; /* = 1 */
1908 WORD Coverage;
1909 WORD DeltaGlyphID;
1910 } GSUB_SingleSubstFormat1;
1912 typedef struct
1914 WORD SubstFormat; /* = 2 */
1915 WORD Coverage;
1916 WORD GlyphCount;
1917 WORD Substitute[1];
1918 } GSUB_SingleSubstFormat2;
1920 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
1922 GSUB_ScriptList *script;
1923 GSUB_Script *deflt = NULL;
1924 int i;
1926 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
1927 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
1928 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
1930 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
1931 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
1932 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
1933 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
1935 return deflt;
1938 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
1940 int i, offset;
1941 GSUB_LangSys *lang;
1943 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
1945 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
1947 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
1948 lang = (GSUB_LangSys *)((BYTE *)script + offset);
1949 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
1951 offset = GET_BE_WORD(script->DefaultLangSys);
1952 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
1953 return NULL;
1956 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
1958 int i;
1959 const GSUB_FeatureList *feature;
1961 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
1962 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
1963 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
1965 int index = GET_BE_WORD(lang->FeatureIndex[i]);
1966 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
1967 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
1969 return NULL;
1972 static const char *get_opentype_script( const struct gdi_font *font )
1975 * I am not sure if this is the correct way to generate our script tag
1977 switch (font->charset)
1979 case ANSI_CHARSET: return "latn";
1980 case BALTIC_CHARSET: return "latn"; /* ?? */
1981 case CHINESEBIG5_CHARSET: return "hani";
1982 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1983 case GB2312_CHARSET: return "hani";
1984 case GREEK_CHARSET: return "grek";
1985 case HANGUL_CHARSET: return "hang";
1986 case RUSSIAN_CHARSET: return "cyrl";
1987 case SHIFTJIS_CHARSET: return "kana";
1988 case TURKISH_CHARSET: return "latn"; /* ?? */
1989 case VIETNAMESE_CHARSET: return "latn";
1990 case JOHAB_CHARSET: return "latn"; /* ?? */
1991 case ARABIC_CHARSET: return "arab";
1992 case HEBREW_CHARSET: return "hebr";
1993 case THAI_CHARSET: return "thai";
1994 default: return "latn";
1998 static void *get_GSUB_vert_feature( struct gdi_font *font )
2000 GSUB_Header *header;
2001 GSUB_Script *script;
2002 GSUB_LangSys *language;
2003 GSUB_Feature *feature;
2004 DWORD length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2006 if (length == GDI_ERROR) return NULL;
2008 header = HeapAlloc( GetProcessHeap(), 0, length );
2009 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2010 TRACE( "Loaded GSUB table of %i bytes\n", length );
2012 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2014 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2016 feature = GSUB_get_feature( header, language, "vrt2" );
2017 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2018 if (feature)
2020 font->gsub_table = header;
2021 return feature;
2023 TRACE("vrt2/vert feature not found\n");
2025 else TRACE("Language not found\n");
2027 else TRACE("Script not found\n");
2029 HeapFree( GetProcessHeap(), 0, header );
2030 return NULL;
2033 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2035 GSUB_CoverageFormat1 *cf1 = table;
2037 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2039 int i, count = GET_BE_WORD(cf1->GlyphCount);
2041 TRACE("Coverage Format 1, %i glyphs\n",count);
2042 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2043 return -1;
2045 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2047 int i, count;
2048 GSUB_CoverageFormat2 *cf2 = table;
2050 count = GET_BE_WORD(cf2->RangeCount);
2051 TRACE("Coverage Format 2, %i ranges\n",count);
2052 for (i = 0; i < count; i++)
2054 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2055 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2056 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2058 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2059 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2062 return -1;
2064 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2066 return -1;
2069 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2071 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2072 int i, j, offset;
2074 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2075 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2077 GSUB_LookupTable *look;
2078 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2079 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2080 TRACE("type %i, flag %x, subtables %i\n",
2081 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2082 if (GET_BE_WORD(look->LookupType) == 1)
2084 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2086 GSUB_SingleSubstFormat1 *ssf1;
2087 offset = GET_BE_WORD(look->SubTable[j]);
2088 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2089 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2091 int offset = GET_BE_WORD(ssf1->Coverage);
2092 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2093 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2095 TRACE(" Glyph 0x%x ->",glyph);
2096 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2097 TRACE(" 0x%x\n",glyph);
2100 else
2102 GSUB_SingleSubstFormat2 *ssf2;
2103 int index, offset;
2105 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2106 offset = GET_BE_WORD(ssf1->Coverage);
2107 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2108 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2109 TRACE(" Coverage index %i\n",index);
2110 if (index != -1)
2112 TRACE(" Glyph is 0x%x ->",glyph);
2113 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2114 TRACE("0x%x\n",glyph);
2119 else FIXME("We only handle SubType 1\n");
2121 return glyph;
2124 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2126 if (!glyph) return glyph;
2127 if (!font->gsub_table) return glyph;
2128 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2131 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2133 FONTSIGNATURE fs = {{0}};
2134 struct gdi_font *child;
2135 struct gdi_font_face *face;
2137 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE ))) return;
2139 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2140 child->matrix = font->matrix;
2141 child->can_use_bitmap = font->can_use_bitmap;
2142 child->scale_y = font->scale_y;
2143 child->aveWidth = font->aveWidth;
2144 child->charset = font->charset;
2145 child->codepage = font->codepage;
2146 child->base_font = font;
2147 list_add_tail( &font->child_fonts, &child->entry );
2148 TRACE( "created child font %p for base %p\n", child, font );
2151 static void create_child_font_list( struct gdi_font *font )
2153 struct gdi_font_link *font_link;
2154 struct gdi_font_link_entry *entry;
2155 const WCHAR* font_name;
2157 if (!(font_name = get_gdi_font_subst( get_gdi_font_name(font), -1, NULL )))
2158 font_name = get_gdi_font_name( font );
2160 if ((font_link = find_gdi_font_link( font_name )))
2162 TRACE("found entry in system list\n");
2163 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2164 add_child_font( font, entry->family_name );
2167 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2168 * Sans Serif. This is how asian windows get default fallbacks for fonts
2170 if (is_dbcs_ansi_cp(GetACP()) && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2171 facename_compare( font_name, L"Microsoft Sans Serif", -1 ) != 0)
2173 if ((font_link = find_gdi_font_link( L"Microsoft Sans Serif" )))
2175 TRACE("found entry in default fallback list\n");
2176 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2177 add_child_font( font, entry->family_name );
2182 /* font cache */
2184 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2185 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2186 static unsigned int unused_font_count;
2187 #define UNUSED_CACHE_SIZE 10
2189 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2190 const FMAT2 *matrix, BOOL can_use_bitmap )
2192 if (font->hash != hash) return TRUE;
2193 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2194 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2195 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2196 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2199 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2201 DWORD hash = 0, *ptr, two_chars;
2202 WORD *pwc;
2203 unsigned int i;
2205 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2206 hash ^= *ptr;
2207 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2208 hash ^= *ptr;
2209 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2211 two_chars = *ptr;
2212 pwc = (WCHAR *)&two_chars;
2213 if(!*pwc) break;
2214 *pwc = towupper(*pwc);
2215 pwc++;
2216 *pwc = towupper(*pwc);
2217 hash ^= two_chars;
2218 if(!*pwc) break;
2220 hash ^= !can_use_bitmap;
2221 return hash;
2224 static void cache_gdi_font( struct gdi_font *font )
2226 static DWORD cache_num = 1;
2228 font->cache_num = cache_num++;
2229 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2230 list_add_head( &gdi_font_list, &font->entry );
2231 TRACE( "font %p\n", font );
2234 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2236 struct gdi_font *font;
2237 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2239 /* try the in-use list */
2240 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2242 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2243 list_remove( &font->entry );
2244 list_add_head( &gdi_font_list, &font->entry );
2245 if (!font->refcount++)
2247 list_remove( &font->unused_entry );
2248 unused_font_count--;
2250 return font;
2252 return NULL;
2255 static void release_gdi_font( struct gdi_font *font )
2257 if (!font) return;
2258 if (--font->refcount) return;
2260 TRACE( "font %p\n", font );
2262 /* add it to the unused list */
2263 EnterCriticalSection( &font_cs );
2264 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2265 if (unused_font_count > UNUSED_CACHE_SIZE)
2267 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2268 TRACE( "freeing %p\n", font );
2269 list_remove( &font->entry );
2270 list_remove( &font->unused_entry );
2271 free_gdi_font( font );
2273 else unused_font_count++;
2274 LeaveCriticalSection( &font_cs );
2277 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2279 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2281 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2282 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2283 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
2284 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2287 static void set_value_key(HKEY hkey, const char *name, const char *value)
2289 if (value)
2290 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2291 else if (name)
2292 RegDeleteValueA(hkey, name);
2295 static void update_font_association_info(UINT current_ansi_codepage)
2297 if (is_dbcs_ansi_cp(current_ansi_codepage))
2299 HKEY hkey;
2300 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\FontAssoc", &hkey) == ERROR_SUCCESS)
2302 HKEY hsubkey;
2303 if (RegCreateKeyW(hkey, L"Associated Charset", &hsubkey) == ERROR_SUCCESS)
2305 switch (current_ansi_codepage)
2307 case 932:
2308 set_value_key(hsubkey, "ANSI(00)", "NO");
2309 set_value_key(hsubkey, "OEM(FF)", "NO");
2310 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2311 break;
2312 case 936:
2313 case 949:
2314 case 950:
2315 set_value_key(hsubkey, "ANSI(00)", "YES");
2316 set_value_key(hsubkey, "OEM(FF)", "YES");
2317 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2318 break;
2320 RegCloseKey(hsubkey);
2323 /* TODO: Associated DefaultFonts */
2325 RegCloseKey(hkey);
2328 else
2329 RegDeleteTreeW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\FontAssoc");
2332 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
2334 if (value)
2335 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
2336 else if (name)
2337 RegDeleteValueW(hkey, name);
2340 static void update_font_system_link_info(UINT current_ansi_codepage)
2342 static const WCHAR system_link_simplified_chinese[] =
2343 L"SIMSUN.TTC,SimSun\0"
2344 L"MINGLIU.TTC,PMingLiu\0"
2345 L"MSGOTHIC.TTC,MS UI Gothic\0"
2346 L"BATANG.TTC,Batang\0";
2347 static const WCHAR system_link_traditional_chinese[] =
2348 L"MINGLIU.TTC,PMingLiu\0"
2349 L"SIMSUN.TTC,SimSun\0"
2350 L"MSGOTHIC.TTC,MS UI Gothic\0"
2351 L"BATANG.TTC,Batang\0";
2352 static const WCHAR system_link_japanese[] =
2353 L"MSGOTHIC.TTC,MS UI Gothic\0"
2354 L"MINGLIU.TTC,PMingLiU\0"
2355 L"SIMSUN.TTC,SimSun\0"
2356 L"GULIM.TTC,Gulim\0";
2357 static const WCHAR system_link_korean[] =
2358 L"GULIM.TTC,Gulim\0"
2359 L"MSGOTHIC.TTC,MS UI Gothic\0"
2360 L"MINGLIU.TTC,PMingLiU\0"
2361 L"SIMSUN.TTC,SimSun\0";
2362 static const WCHAR system_link_non_cjk[] =
2363 L"MSGOTHIC.TTC,MS UI Gothic\0"
2364 L"MINGLIU.TTC,PMingLiU\0"
2365 L"SIMSUN.TTC,SimSun\0"
2366 L"GULIM.TTC,Gulim\0";
2367 HKEY hkey;
2369 if (!RegCreateKeyW(HKEY_LOCAL_MACHINE,
2370 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey))
2372 const WCHAR *link;
2373 DWORD len;
2375 switch (current_ansi_codepage)
2377 case 932:
2378 link = system_link_japanese;
2379 len = sizeof(system_link_japanese);
2380 break;
2381 case 936:
2382 link = system_link_simplified_chinese;
2383 len = sizeof(system_link_simplified_chinese);
2384 break;
2385 case 949:
2386 link = system_link_korean;
2387 len = sizeof(system_link_korean);
2388 break;
2389 case 950:
2390 link = system_link_traditional_chinese;
2391 len = sizeof(system_link_traditional_chinese);
2392 break;
2393 default:
2394 link = system_link_non_cjk;
2395 len = sizeof(system_link_non_cjk);
2397 set_multi_value_key(hkey, L"Lucida Sans Unicode", link, len);
2398 set_multi_value_key(hkey, L"Microsoft Sans Serif", link, len);
2399 set_multi_value_key(hkey, L"Tahoma", link, len);
2400 RegCloseKey(hkey);
2404 static void update_codepage(void)
2406 char buf[40], cpbuf[40];
2407 HKEY hkey;
2408 DWORD len, type, size;
2409 UINT i, ansi_cp, oem_cp;
2410 DWORD screen_dpi, font_dpi = 0;
2411 BOOL done = FALSE;
2413 screen_dpi = get_dpi();
2414 if (!screen_dpi) screen_dpi = 96;
2416 size = sizeof(DWORD);
2417 if (RegQueryValueExW(wine_fonts_key, L"LogPixels", NULL, &type, (BYTE *)&font_dpi, &size) ||
2418 type != REG_DWORD || size != sizeof(DWORD))
2419 font_dpi = 0;
2421 ansi_cp = GetACP();
2422 oem_cp = GetOEMCP();
2423 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2425 buf[0] = 0;
2426 len = sizeof(buf);
2427 if (!RegQueryValueExA(wine_fonts_key, "Codepages", 0, &type, (BYTE *)buf, &len) && type == REG_SZ)
2429 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) return; /* already set correctly */
2430 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2431 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
2433 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2434 ansi_cp, oem_cp, screen_dpi);
2436 RegSetValueExA(wine_fonts_key, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2437 RegSetValueExW(wine_fonts_key, L"LogPixels", 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
2439 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
2441 if (nls_update_font_list[i].ansi_cp == ansi_cp && nls_update_font_list[i].oem_cp == oem_cp)
2443 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &hkey ))
2445 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem,
2446 strlen(nls_update_font_list[i].oem)+1);
2447 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed,
2448 strlen(nls_update_font_list[i].fixed)+1);
2449 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system,
2450 strlen(nls_update_font_list[i].system)+1);
2451 RegCloseKey(hkey);
2453 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE,
2454 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey ))
2456 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2457 RegCloseKey(hkey);
2459 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE,
2460 L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey ))
2462 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2463 RegCloseKey(hkey);
2465 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE,
2466 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2468 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2469 strlen(nls_update_font_list[i].shelldlg)+1);
2470 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2471 strlen(nls_update_font_list[i].tmsrmn)+1);
2473 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2474 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2475 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2476 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2477 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2478 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2479 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2480 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2482 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2483 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2484 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2486 RegCloseKey(hkey);
2488 done = TRUE;
2490 else
2492 /* Delete the FontSubstitutes from other locales */
2493 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2495 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2496 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2497 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2498 RegCloseKey(hkey);
2502 if (!done)
2503 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2505 /* update locale dependent font association info and font system link info in registry.
2506 update only when codepages changed, not logpixels. */
2507 if (strcmp(buf, cpbuf) != 0)
2509 update_font_association_info(ansi_cp);
2510 update_font_system_link_info(ansi_cp);
2515 /*************************************************************
2516 * font_CreateDC
2518 static BOOL CDECL font_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
2519 LPCWSTR output, const DEVMODEW *devmode )
2521 struct font_physdev *physdev;
2523 if (!font_funcs) return TRUE;
2524 if (!(physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) ))) return FALSE;
2525 push_dc_driver( dev, &physdev->dev, &font_driver );
2526 return TRUE;
2530 /*************************************************************
2531 * font_DeleteDC
2533 static BOOL CDECL font_DeleteDC( PHYSDEV dev )
2535 struct font_physdev *physdev = get_font_dev( dev );
2537 release_gdi_font( physdev->font );
2538 HeapFree( GetProcessHeap(), 0, physdev );
2539 return TRUE;
2543 struct gdi_font_enum_data
2545 ENUMLOGFONTEXW elf;
2546 NEWTEXTMETRICEXW ntm;
2549 struct enum_charset
2551 DWORD mask;
2552 DWORD charset;
2553 DWORD script;
2556 static int load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
2558 HRSRC rsrc;
2559 HGLOBAL hMem;
2560 WCHAR *p;
2561 int i;
2563 id += IDS_FIRST_SCRIPT;
2564 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
2565 if (!rsrc) return 0;
2566 hMem = LoadResource( gdi32_module, rsrc );
2567 if (!hMem) return 0;
2569 p = LockResource( hMem );
2570 id &= 0x000f;
2571 while (id--) p += *p + 1;
2573 i = min(LF_FACESIZE - 1, *p);
2574 memcpy(buffer, p + 1, i * sizeof(WCHAR));
2575 buffer[i] = 0;
2576 return i;
2579 static BOOL is_complex_script_ansi_cp( UINT ansi_cp )
2581 return (ansi_cp == 874 /* Thai */
2582 || ansi_cp == 1255 /* Hebrew */
2583 || ansi_cp == 1256 /* Arabic */
2587 /***************************************************
2588 * create_enum_charset_list
2590 * This function creates charset enumeration list because in DEFAULT_CHARSET
2591 * case, the ANSI codepage's charset takes precedence over other charsets.
2592 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2593 * This function works as a filter other than DEFAULT_CHARSET case.
2595 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
2597 struct enum_charset *start = list;
2598 CHARSETINFO csi;
2599 int i;
2601 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && csi.fs.fsCsb[0] != 0)
2603 list->mask = csi.fs.fsCsb[0];
2604 list->charset = csi.ciCharset;
2605 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2606 list++;
2608 else /* charset is DEFAULT_CHARSET or invalid. */
2610 int acp = GetACP();
2611 DWORD mask = 0;
2613 /* Set the current codepage's charset as the first element. */
2614 if (!is_complex_script_ansi_cp(acp) &&
2615 TranslateCharsetInfo( (DWORD *)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE ) &&
2616 csi.fs.fsCsb[0] != 0)
2618 list->mask = csi.fs.fsCsb[0];
2619 list->charset = csi.ciCharset;
2620 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2621 mask |= csi.fs.fsCsb[0];
2622 list++;
2625 /* Fill out left elements. */
2626 for (i = 0; i < 32; i++)
2628 FONTSIGNATURE fs;
2629 fs.fsCsb[0] = 1u << i;
2630 fs.fsCsb[1] = 0;
2631 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
2632 if (!TranslateCharsetInfo( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
2633 continue; /* skip, this is an invalid fsCsb bit. */
2634 list->mask = fs.fsCsb[0];
2635 list->charset = csi.ciCharset;
2636 list->script = i;
2637 mask |= fs.fsCsb[0];
2638 list++;
2640 /* add catch all mask for remaining bits */
2641 if (~mask)
2643 list->mask = ~mask;
2644 list->charset = DEFAULT_CHARSET;
2645 list->script = IDS_OTHER - IDS_FIRST_SCRIPT;
2646 list++;
2649 return list - start;
2652 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
2654 UINT ret = 0;
2656 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
2657 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
2658 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
2659 return ret;
2662 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
2664 struct gdi_font *font;
2665 LOGFONTW lf = { .lfHeight = 100 };
2667 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2669 if (!font_funcs->load_font( font ))
2671 free_gdi_font( font );
2672 return FALSE;
2675 if (font_funcs->set_outline_text_metrics( font ))
2677 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
2678 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
2679 ntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
2680 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
2682 else if (font_funcs->set_bitmap_text_metrics( font ))
2684 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
2685 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
2686 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
2687 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
2689 ntm->ntmTm.ntmFlags = font->ntmFlags;
2690 ntm->ntmFontSig = font->fs;
2692 elf->elfLogFont.lfEscapement = 0;
2693 elf->elfLogFont.lfOrientation = 0;
2694 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
2695 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
2696 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
2697 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
2698 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
2699 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
2700 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
2701 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2702 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2703 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
2704 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
2705 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
2706 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
2707 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
2709 free_gdi_font( font );
2710 return TRUE;
2713 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
2715 struct gdi_font_face *face;
2717 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
2718 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2719 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
2720 return FALSE;
2723 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
2725 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
2726 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
2729 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
2730 struct enum_charset *list, DWORD count, FONTENUMPROCW proc, LPARAM lparam,
2731 const WCHAR *subst )
2733 ENUMLOGFONTEXW elf;
2734 NEWTEXTMETRICEXW ntm;
2735 DWORD type, i;
2737 if (!face->cached_enum_data)
2739 struct gdi_font_enum_data *data;
2741 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )) ||
2742 !get_face_enum_data( face, &data->elf, &data->ntm ))
2744 HeapFree( GetProcessHeap(), 0, data );
2745 return TRUE;
2747 face->cached_enum_data = data;
2750 elf = face->cached_enum_data->elf;
2751 ntm = face->cached_enum_data->ntm;
2752 type = get_font_type( &ntm );
2754 /* font replacement */
2755 if (family != face->family)
2757 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
2758 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
2760 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
2762 for (i = 0; i < count; i++)
2764 if (!face->scalable && face->fs.fsCsb[0] == 0) /* OEM bitmap */
2766 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2767 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
2768 i = count; /* break out of loop after enumeration */
2770 else
2772 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
2773 /* use the DEFAULT_CHARSET case only if no other charset is present */
2774 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
2775 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
2776 load_script_name( list[i].script, elf.elfScript );
2777 if (!elf.elfScript[0]) FIXME("Unknown elfscript for id %u\n", list[i].script);
2779 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2780 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2781 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
2782 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, ntm.ntmTm.ntmFlags );
2783 /* release section before callback (FIXME) */
2784 LeaveCriticalSection( &font_cs );
2785 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
2786 EnterCriticalSection( &font_cs );
2788 return TRUE;
2791 /*************************************************************
2792 * font_EnumFonts
2794 static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
2796 struct gdi_font_family *family;
2797 struct gdi_font_face *face;
2798 struct enum_charset enum_charsets[32];
2799 DWORD count, charset;
2801 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
2803 count = create_enum_charset_list( charset, enum_charsets );
2805 EnterCriticalSection( &font_cs );
2807 if (lf && lf->lfFaceName[0])
2809 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
2810 const WCHAR *orig_name = NULL;
2812 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
2813 if (face_name)
2815 orig_name = lf->lfFaceName;
2816 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
2818 else face_name = lf->lfFaceName;
2820 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2822 if (!family_matches(family, face_name)) continue;
2823 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2825 if (!face_matches( family->family_name, face, face_name )) continue;
2826 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
2827 return FALSE;
2831 else
2833 TRACE( "charset %d\n", charset );
2834 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2836 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
2837 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
2838 return FALSE;
2841 LeaveCriticalSection( &font_cs );
2842 return TRUE;
2846 static BOOL check_unicode_tategaki( WCHAR ch )
2848 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
2849 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
2851 /* We only reach this code if typographical substitution did not occur */
2852 /* Type: U or Type: Tu */
2853 return (orientation == 1 || orientation == 3);
2856 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2858 UINT index;
2860 if (glyph < 0x100) glyph += 0xf000;
2861 /* there are a number of old pre-Unicode "broken" TTFs, which
2862 do have symbols at U+00XX instead of U+f0XX */
2863 index = glyph;
2864 font_funcs->get_glyph_index( font, &index, FALSE );
2865 if (!index)
2867 index = glyph - 0xf000;
2868 font_funcs->get_glyph_index( font, &index, FALSE );
2870 return index;
2873 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
2875 WCHAR wc = glyph;
2876 char ch;
2877 BOOL used;
2879 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
2881 if (font->codepage == CP_SYMBOL)
2883 glyph = get_glyph_index_symbol( font, wc );
2884 if (!glyph)
2886 if (WideCharToMultiByte( CP_ACP, 0, &wc, 1, &ch, 1, NULL, NULL ))
2887 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2890 else if (WideCharToMultiByte( font->codepage, 0, &wc, 1, &ch, 1, NULL, &used ) && !used)
2892 glyph = (unsigned char)ch;
2893 font_funcs->get_glyph_index( font, &glyph, FALSE );
2895 return glyph;
2898 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
2900 struct gdi_font *child;
2901 UINT res;
2903 if ((res = get_glyph_index( *font, glyph ))) return res;
2904 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
2906 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
2908 if (!child->private && !font_funcs->load_font( child )) continue;
2909 if ((res = get_glyph_index( child, glyph )))
2911 *font = child;
2912 return res;
2915 return 0;
2918 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
2919 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
2920 const MAT2 *mat )
2922 GLYPHMETRICS gm;
2923 ABC abc;
2924 DWORD ret = 1;
2925 UINT index = glyph;
2926 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
2928 if (format & GGO_GLYPH_INDEX)
2930 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
2931 as glyph index. "Treasure Adventure Game" depends on this. */
2932 font_funcs->get_glyph_index( font, &index, FALSE );
2933 /* TODO: Window also turns off tategaki for glyphs passed in by index
2934 if their unicode code points fall outside of the range that is
2935 rotated. */
2937 else
2939 index = get_glyph_index_linked( &font, glyph );
2940 if (tategaki)
2942 UINT orig = index;
2943 index = get_GSUB_vert_glyph( font, index );
2944 if (index == orig) tategaki = check_unicode_tategaki( glyph );
2948 format &= ~(GGO_GLYPH_INDEX | GGO_UNHINTED);
2950 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
2952 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
2953 goto done;
2955 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
2956 if (ret == GDI_ERROR) return ret;
2958 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && !mat)
2959 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
2961 done:
2962 if (gm_ret) *gm_ret = gm;
2963 if (abc_ret) *abc_ret = abc;
2964 return ret;
2968 /*************************************************************
2969 * font_FontIsLinked
2971 static BOOL CDECL font_FontIsLinked( PHYSDEV dev )
2973 struct font_physdev *physdev = get_font_dev( dev );
2975 if (!physdev->font)
2977 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
2978 return dev->funcs->pFontIsLinked( dev );
2980 return !list_empty( &physdev->font->child_fonts );
2984 /*************************************************************
2985 * font_GetCharABCWidths
2987 static BOOL CDECL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT last, ABC *buffer )
2989 struct font_physdev *physdev = get_font_dev( dev );
2990 UINT c;
2992 if (!physdev->font)
2994 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
2995 return dev->funcs->pGetCharABCWidths( dev, first, last, buffer );
2998 TRACE( "%p, %u, %u, %p\n", physdev->font, first, last, buffer );
3000 EnterCriticalSection( &font_cs );
3001 for (c = first; c <= last; c++, buffer++)
3002 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, buffer, 0, NULL, NULL );
3003 LeaveCriticalSection( &font_cs );
3004 return TRUE;
3008 /*************************************************************
3009 * font_GetCharABCWidthsI
3011 static BOOL CDECL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3013 struct font_physdev *physdev = get_font_dev( dev );
3014 UINT c;
3016 if (!physdev->font)
3018 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3019 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3022 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3024 EnterCriticalSection( &font_cs );
3025 for (c = 0; c < count; c++, buffer++)
3026 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3027 NULL, buffer, 0, NULL, NULL );
3028 LeaveCriticalSection( &font_cs );
3029 return TRUE;
3033 /*************************************************************
3034 * font_GetCharWidth
3036 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT last, INT *buffer )
3038 struct font_physdev *physdev = get_font_dev( dev );
3039 ABC abc;
3040 UINT c;
3042 if (!physdev->font)
3044 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3045 return dev->funcs->pGetCharWidth( dev, first, last, buffer );
3048 TRACE( "%p, %d, %d, %p\n", physdev->font, first, last, buffer );
3050 EnterCriticalSection( &font_cs );
3051 for (c = first; c <= last; c++)
3053 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3054 buffer[c - first] = 0;
3055 else
3056 buffer[c - first] = abc.abcA + abc.abcB + abc.abcC;
3058 LeaveCriticalSection( &font_cs );
3059 return TRUE;
3063 /*************************************************************
3064 * font_GetCharWidthInfo
3066 static BOOL CDECL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3068 struct font_physdev *physdev = get_font_dev( dev );
3069 struct char_width_info *info = ptr;
3071 if (!physdev->font)
3073 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3074 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3077 info->unk = 0;
3078 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3079 info->lsb = info->rsb = 0;
3081 return TRUE;
3085 /*************************************************************
3086 * font_GetFontData
3088 static DWORD CDECL font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
3090 struct font_physdev *physdev = get_font_dev( dev );
3092 if (!physdev->font)
3094 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
3095 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
3097 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
3101 /*************************************************************
3102 * font_GetFontRealizationInfo
3104 static BOOL CDECL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
3106 struct font_physdev *physdev = get_font_dev( dev );
3107 struct font_realization_info *info = ptr;
3109 if (!physdev->font)
3111 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
3112 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
3115 TRACE( "(%p, %p)\n", physdev->font, info);
3117 info->flags = 1;
3118 if (physdev->font->scalable) info->flags |= 2;
3120 info->cache_num = physdev->font->cache_num;
3121 info->instance_id = physdev->font->handle;
3122 if (info->size == sizeof(*info))
3124 info->unk = 0;
3125 info->face_index = physdev->font->face_index;
3126 info->simulations = 0;
3127 if (physdev->font->fake_bold) info->simulations |= 0x1;
3128 if (physdev->font->fake_italic) info->simulations |= 0x2;
3130 return TRUE;
3134 /*************************************************************
3135 * font_GetFontUnicodeRanges
3137 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
3139 struct font_physdev *physdev = get_font_dev( dev );
3140 DWORD size, num_ranges;
3142 if (!physdev->font)
3144 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
3145 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
3148 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
3149 size = offsetof( GLYPHSET, ranges[num_ranges] );
3150 if (glyphset)
3152 glyphset->cbThis = size;
3153 glyphset->cRanges = num_ranges;
3154 glyphset->flAccel = 0;
3156 return size;
3160 /*************************************************************
3161 * font_GetGlyphIndices
3163 static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
3165 struct font_physdev *physdev = get_font_dev( dev );
3166 UINT default_char;
3167 char ch;
3168 BOOL used, got_default = FALSE;
3169 int i;
3171 if (!physdev->font)
3173 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
3174 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
3177 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3179 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
3180 got_default = TRUE;
3183 EnterCriticalSection( &font_cs );
3185 for (i = 0; i < count; i++)
3187 UINT glyph = str[i];
3189 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
3191 glyph = 0;
3192 if (physdev->font->codepage == CP_SYMBOL)
3194 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
3195 else if (str[i] < 0x100) glyph = str[i];
3197 else if (WideCharToMultiByte( physdev->font->codepage, 0, &str[i], 1,
3198 &ch, 1, NULL, &used ) && !used)
3199 glyph = (unsigned char)ch;
3201 if (!glyph)
3203 if (!got_default)
3205 default_char = font_funcs->get_default_glyph( physdev->font );
3206 got_default = TRUE;
3208 gi[i] = default_char;
3210 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
3213 LeaveCriticalSection( &font_cs );
3214 return count;
3218 /*************************************************************
3219 * font_GetGlyphOutline
3221 static DWORD CDECL font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
3222 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
3224 struct font_physdev *physdev = get_font_dev( dev );
3225 DWORD ret;
3227 if (!physdev->font)
3229 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
3230 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
3232 EnterCriticalSection( &font_cs );
3233 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
3234 LeaveCriticalSection( &font_cs );
3235 return ret;
3239 /*************************************************************
3240 * font_GetKerningPairs
3242 static DWORD CDECL font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
3244 struct font_physdev *physdev = get_font_dev( dev );
3246 if (!physdev->font)
3248 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
3249 return dev->funcs->pGetKerningPairs( dev, count, pairs );
3252 EnterCriticalSection( &font_cs );
3253 if (physdev->font->kern_count == -1)
3254 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
3255 &physdev->font->kern_pairs );
3256 LeaveCriticalSection( &font_cs );
3258 if (count && pairs)
3260 count = min( count, physdev->font->kern_count );
3261 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
3263 else count = physdev->font->kern_count;
3265 return count;
3269 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
3271 double scale_x, scale_y;
3273 if (font->aveWidth)
3275 scale_x = (double)font->aveWidth;
3276 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3278 else
3279 scale_x = font->scale_y;
3281 scale_x *= fabs(font->matrix.eM11);
3282 scale_y = font->scale_y * fabs(font->matrix.eM22);
3284 /* Windows scales these values as signed integers even if they are unsigned */
3285 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3286 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3288 SCALE_Y(otm->otmTextMetrics.tmHeight);
3289 SCALE_Y(otm->otmTextMetrics.tmAscent);
3290 SCALE_Y(otm->otmTextMetrics.tmDescent);
3291 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
3292 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
3294 SCALE_X(otm->otmTextMetrics.tmOverhang);
3295 if (font->fake_bold)
3297 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
3298 otm->otmTextMetrics.tmAveCharWidth++;
3299 otm->otmTextMetrics.tmMaxCharWidth++;
3301 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
3302 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
3304 SCALE_Y(otm->otmAscent);
3305 SCALE_Y(otm->otmDescent);
3306 SCALE_Y(otm->otmLineGap);
3307 SCALE_Y(otm->otmsCapEmHeight);
3308 SCALE_Y(otm->otmsXHeight);
3309 SCALE_Y(otm->otmrcFontBox.top);
3310 SCALE_Y(otm->otmrcFontBox.bottom);
3311 SCALE_X(otm->otmrcFontBox.left);
3312 SCALE_X(otm->otmrcFontBox.right);
3313 SCALE_Y(otm->otmMacAscent);
3314 SCALE_Y(otm->otmMacDescent);
3315 SCALE_Y(otm->otmMacLineGap);
3316 SCALE_X(otm->otmptSubscriptSize.x);
3317 SCALE_Y(otm->otmptSubscriptSize.y);
3318 SCALE_X(otm->otmptSubscriptOffset.x);
3319 SCALE_Y(otm->otmptSubscriptOffset.y);
3320 SCALE_X(otm->otmptSuperscriptSize.x);
3321 SCALE_Y(otm->otmptSuperscriptSize.y);
3322 SCALE_X(otm->otmptSuperscriptOffset.x);
3323 SCALE_Y(otm->otmptSuperscriptOffset.y);
3324 SCALE_Y(otm->otmsStrikeoutSize);
3325 SCALE_Y(otm->otmsStrikeoutPosition);
3326 SCALE_Y(otm->otmsUnderscoreSize);
3327 SCALE_Y(otm->otmsUnderscorePosition);
3329 #undef SCALE_X
3330 #undef SCALE_Y
3333 /*************************************************************
3334 * font_GetOutlineTextMetrics
3336 static UINT CDECL font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
3338 struct font_physdev *physdev = get_font_dev( dev );
3339 UINT ret = 0;
3341 if (!physdev->font)
3343 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
3344 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
3347 if (!physdev->font->scalable) return 0;
3349 EnterCriticalSection( &font_cs );
3350 if (font_funcs->set_outline_text_metrics( physdev->font ))
3352 ret = physdev->font->otm.otmSize;
3353 if (metrics && size >= physdev->font->otm.otmSize)
3355 WCHAR *ptr = (WCHAR *)(metrics + 1);
3356 *metrics = physdev->font->otm;
3357 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
3358 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
3359 ptr += lstrlenW(ptr) + 1;
3360 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
3361 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
3362 ptr += lstrlenW(ptr) + 1;
3363 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
3364 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
3365 ptr += lstrlenW(ptr) + 1;
3366 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
3367 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
3368 scale_outline_font_metrics( physdev->font, metrics );
3371 LeaveCriticalSection( &font_cs );
3372 return ret;
3376 /*************************************************************
3377 * font_GetTextCharsetInfo
3379 static UINT CDECL font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
3381 struct font_physdev *physdev = get_font_dev( dev );
3383 if (!physdev->font)
3385 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
3386 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3388 if (fs) *fs = physdev->font->fs;
3389 return physdev->font->charset;
3393 /*************************************************************
3394 * font_GetTextExtentExPoint
3396 static BOOL CDECL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
3398 struct font_physdev *physdev = get_font_dev( dev );
3399 INT i, pos;
3400 ABC abc;
3402 if (!physdev->font)
3404 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
3405 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
3408 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
3410 EnterCriticalSection( &font_cs );
3411 for (i = pos = 0; i < count; i++)
3413 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
3414 pos += abc.abcA + abc.abcB + abc.abcC;
3415 dxs[i] = pos;
3417 LeaveCriticalSection( &font_cs );
3418 return TRUE;
3422 /*************************************************************
3423 * font_GetTextExtentExPointI
3425 static BOOL CDECL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
3427 struct font_physdev *physdev = get_font_dev( dev );
3428 INT i, pos;
3429 ABC abc;
3431 if (!physdev->font)
3433 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
3434 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
3437 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
3439 EnterCriticalSection( &font_cs );
3440 for (i = pos = 0; i < count; i++)
3442 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
3443 NULL, &abc, 0, NULL, NULL );
3444 pos += abc.abcA + abc.abcB + abc.abcC;
3445 dxs[i] = pos;
3447 LeaveCriticalSection( &font_cs );
3448 return TRUE;
3452 /*************************************************************
3453 * font_GetTextFace
3455 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
3457 struct font_physdev *physdev = get_font_dev( dev );
3458 INT len;
3460 if (!physdev->font)
3462 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
3463 return dev->funcs->pGetTextFace( dev, count, str );
3465 len = lstrlenW( get_gdi_font_name(physdev->font) ) + 1;
3466 if (str)
3468 lstrcpynW( str, get_gdi_font_name(physdev->font), count );
3469 len = min( count, len );
3471 return len;
3475 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
3477 double scale_x, scale_y;
3479 /* Make sure that the font has sane width/height ratio */
3480 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
3482 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
3483 font->aveWidth = 0;
3486 if (font->aveWidth)
3488 scale_x = (double)font->aveWidth;
3489 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3491 else
3492 scale_x = font->scale_y;
3494 scale_x *= fabs(font->matrix.eM11);
3495 scale_y = font->scale_y * fabs(font->matrix.eM22);
3497 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3498 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3500 SCALE_Y(tm->tmHeight);
3501 SCALE_Y(tm->tmAscent);
3502 SCALE_Y(tm->tmDescent);
3503 SCALE_Y(tm->tmInternalLeading);
3504 SCALE_Y(tm->tmExternalLeading);
3506 SCALE_X(tm->tmOverhang);
3507 if (font->fake_bold)
3509 if (!font->scalable) tm->tmOverhang++;
3510 tm->tmAveCharWidth++;
3511 tm->tmMaxCharWidth++;
3513 SCALE_X(tm->tmAveCharWidth);
3514 SCALE_X(tm->tmMaxCharWidth);
3516 #undef SCALE_X
3517 #undef SCALE_Y
3520 /*************************************************************
3521 * font_GetTextMetrics
3523 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
3525 struct font_physdev *physdev = get_font_dev( dev );
3526 BOOL ret = FALSE;
3528 if (!physdev->font)
3530 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
3531 return dev->funcs->pGetTextMetrics( dev, metrics );
3534 EnterCriticalSection( &font_cs );
3535 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
3536 font_funcs->set_bitmap_text_metrics( physdev->font ))
3538 *metrics = physdev->font->otm.otmTextMetrics;
3539 scale_font_metrics( physdev->font, metrics );
3540 ret = TRUE;
3542 LeaveCriticalSection( &font_cs );
3543 return ret;
3547 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
3549 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3550 a single face with the requested charset. The idea is to check if
3551 the selected font supports the current ANSI codepage, if it does
3552 return the corresponding charset, else return the first charset */
3554 int i;
3556 if (TranslateCharsetInfo( (DWORD*)(INT_PTR)GetACP(), csi, TCI_SRCCODEPAGE ))
3558 const struct gdi_font_link *font_link;
3560 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
3561 font_link = find_gdi_font_link(family_name);
3562 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
3564 for (i = 0; i < 32; i++)
3566 DWORD fs0 = 1u << i;
3567 if (face->fs.fsCsb[0] & fs0)
3569 if (TranslateCharsetInfo(&fs0, csi, TCI_SRCFONTSIG)) return;
3570 FIXME("TCI failing on %x\n", fs0);
3574 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3575 face->fs.fsCsb[0], debugstr_w(face->file));
3576 csi->ciACP = GetACP();
3577 csi->ciCharset = DEFAULT_CHARSET;
3580 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
3582 struct gdi_font *font;
3583 struct gdi_font_face *face;
3584 INT height;
3585 CHARSETINFO csi;
3586 const WCHAR *orig_name = NULL;
3588 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3589 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3590 original value lfCharSet. Note this is a special case for
3591 Symbol and doesn't happen at least for "Wingdings*" */
3592 if (!facename_compare( lf->lfFaceName, L"Symbol", -1 )) lf->lfCharSet = SYMBOL_CHARSET;
3594 /* check the cache first */
3595 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
3597 TRACE( "returning cached gdiFont(%p)\n", font );
3598 return font;
3600 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &orig_name )))
3602 FIXME( "can't find a single appropriate font - bailing\n" );
3603 return NULL;
3605 height = lf->lfHeight;
3607 font = create_gdi_font( face, orig_name, lf );
3608 font->matrix = dcmat;
3609 font->can_use_bitmap = can_use_bitmap;
3610 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
3611 font->charset = csi.ciCharset;
3612 font->codepage = csi.ciACP;
3614 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
3615 face->data_ptr, face->face_index );
3617 font->aveWidth = height ? lf->lfWidth : 0;
3618 if (!face->scalable)
3620 /* Windows uses integer scaling factors for bitmap fonts */
3621 INT scale, scaled_height, diff;
3622 struct gdi_font *cachedfont;
3624 if (height > 0)
3625 diff = height - (signed int)face->size.height;
3626 else
3627 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
3629 /* FIXME: rotation of bitmap fonts is ignored */
3630 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
3631 if (font->aveWidth)
3632 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
3633 font->matrix.eM11 = font->matrix.eM22 = 1.0;
3634 dcmat.eM11 = dcmat.eM22 = 1.0;
3635 /* As we changed the matrix, we need to search the cache for the font again,
3636 * otherwise we might explode the cache. */
3637 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
3639 TRACE("Found cached font after non-scalable matrix rescale!\n");
3640 free_gdi_font( font );
3641 return cachedfont;
3644 if (height != 0) height = diff;
3645 height += face->size.height;
3647 scale = (height + face->size.height - 1) / face->size.height;
3648 scaled_height = scale * face->size.height;
3649 /* Only jump to the next height if the difference <= 25% original height */
3650 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3651 /* The jump between unscaled and doubled is delayed by 1 */
3652 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3653 font->scale_y = scale;
3654 TRACE("font scale y: %d\n", font->scale_y);
3657 if (!font_funcs->load_font( font ))
3659 free_gdi_font( font );
3660 return NULL;
3663 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
3664 font->vert_feature = get_GSUB_vert_feature( font );
3666 create_child_font_list( font );
3668 TRACE( "caching: gdiFont=%p\n", font );
3669 cache_gdi_font( font );
3670 return font;
3673 /*************************************************************
3674 * font_SelectFont
3676 static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
3678 struct font_physdev *physdev = get_font_dev( dev );
3679 struct gdi_font *font = NULL, *prev = physdev->font;
3680 DC *dc = get_physdev_dc( dev );
3682 if (hfont)
3684 LOGFONTW lf;
3685 FMAT2 dcmat;
3686 BOOL can_use_bitmap = !!(GetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
3688 GetObjectW( hfont, sizeof(lf), &lf );
3689 switch (lf.lfQuality)
3691 case NONANTIALIASED_QUALITY:
3692 if (!*aa_flags) *aa_flags = GGO_BITMAP;
3693 break;
3694 case ANTIALIASED_QUALITY:
3695 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
3696 break;
3699 lf.lfWidth = abs(lf.lfWidth);
3701 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3702 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3703 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3704 lf.lfEscapement );
3706 if (dc->GraphicsMode == GM_ADVANCED)
3708 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
3709 /* try to avoid not necessary glyph transformations */
3710 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3712 lf.lfHeight *= fabs(dcmat.eM11);
3713 lf.lfWidth *= fabs(dcmat.eM11);
3714 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
3717 else
3719 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
3720 dcmat.eM11 = dcmat.eM22 = 1.0;
3721 dcmat.eM21 = dcmat.eM12 = 0;
3722 lf.lfOrientation = lf.lfEscapement;
3723 if (dc->vport2WorldValid)
3725 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3726 lf.lfOrientation = -lf.lfOrientation;
3727 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3728 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3731 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
3733 EnterCriticalSection( &font_cs );
3735 font = select_font( &lf, dcmat, can_use_bitmap );
3737 if (font && !*aa_flags)
3739 *aa_flags = font->aa_flags;
3740 if (!*aa_flags)
3742 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
3743 *aa_flags = subpixel_orientation;
3744 else
3745 *aa_flags = font_smoothing;
3747 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
3749 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
3750 LeaveCriticalSection( &font_cs );
3752 physdev->font = font;
3753 if (prev) release_gdi_font( prev );
3754 return font ? hfont : 0;
3758 const struct gdi_dc_funcs font_driver =
3760 NULL, /* pAbortDoc */
3761 NULL, /* pAbortPath */
3762 NULL, /* pAlphaBlend */
3763 NULL, /* pAngleArc */
3764 NULL, /* pArc */
3765 NULL, /* pArcTo */
3766 NULL, /* pBeginPath */
3767 NULL, /* pBlendImage */
3768 NULL, /* pChord */
3769 NULL, /* pCloseFigure */
3770 NULL, /* pCreateCompatibleDC */
3771 font_CreateDC, /* pCreateDC */
3772 font_DeleteDC, /* pDeleteDC */
3773 NULL, /* pDeleteObject */
3774 NULL, /* pDeviceCapabilities */
3775 NULL, /* pEllipse */
3776 NULL, /* pEndDoc */
3777 NULL, /* pEndPage */
3778 NULL, /* pEndPath */
3779 font_EnumFonts, /* pEnumFonts */
3780 NULL, /* pEnumICMProfiles */
3781 NULL, /* pExcludeClipRect */
3782 NULL, /* pExtDeviceMode */
3783 NULL, /* pExtEscape */
3784 NULL, /* pExtFloodFill */
3785 NULL, /* pExtSelectClipRgn */
3786 NULL, /* pExtTextOut */
3787 NULL, /* pFillPath */
3788 NULL, /* pFillRgn */
3789 NULL, /* pFlattenPath */
3790 font_FontIsLinked, /* pFontIsLinked */
3791 NULL, /* pFrameRgn */
3792 NULL, /* pGdiComment */
3793 NULL, /* pGetBoundsRect */
3794 font_GetCharABCWidths, /* pGetCharABCWidths */
3795 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
3796 font_GetCharWidth, /* pGetCharWidth */
3797 font_GetCharWidthInfo, /* pGetCharWidthInfo */
3798 NULL, /* pGetDeviceCaps */
3799 NULL, /* pGetDeviceGammaRamp */
3800 font_GetFontData, /* pGetFontData */
3801 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
3802 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
3803 font_GetGlyphIndices, /* pGetGlyphIndices */
3804 font_GetGlyphOutline, /* pGetGlyphOutline */
3805 NULL, /* pGetICMProfile */
3806 NULL, /* pGetImage */
3807 font_GetKerningPairs, /* pGetKerningPairs */
3808 NULL, /* pGetNearestColor */
3809 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
3810 NULL, /* pGetPixel */
3811 NULL, /* pGetSystemPaletteEntries */
3812 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
3813 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
3814 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
3815 font_GetTextFace, /* pGetTextFace */
3816 font_GetTextMetrics, /* pGetTextMetrics */
3817 NULL, /* pGradientFill */
3818 NULL, /* pIntersectClipRect */
3819 NULL, /* pInvertRgn */
3820 NULL, /* pLineTo */
3821 NULL, /* pModifyWorldTransform */
3822 NULL, /* pMoveTo */
3823 NULL, /* pOffsetClipRgn */
3824 NULL, /* pOffsetViewportOrg */
3825 NULL, /* pOffsetWindowOrg */
3826 NULL, /* pPaintRgn */
3827 NULL, /* pPatBlt */
3828 NULL, /* pPie */
3829 NULL, /* pPolyBezier */
3830 NULL, /* pPolyBezierTo */
3831 NULL, /* pPolyDraw */
3832 NULL, /* pPolyPolygon */
3833 NULL, /* pPolyPolyline */
3834 NULL, /* pPolygon */
3835 NULL, /* pPolyline */
3836 NULL, /* pPolylineTo */
3837 NULL, /* pPutImage */
3838 NULL, /* pRealizeDefaultPalette */
3839 NULL, /* pRealizePalette */
3840 NULL, /* pRectangle */
3841 NULL, /* pResetDC */
3842 NULL, /* pRestoreDC */
3843 NULL, /* pRoundRect */
3844 NULL, /* pSaveDC */
3845 NULL, /* pScaleViewportExt */
3846 NULL, /* pScaleWindowExt */
3847 NULL, /* pSelectBitmap */
3848 NULL, /* pSelectBrush */
3849 NULL, /* pSelectClipPath */
3850 font_SelectFont, /* pSelectFont */
3851 NULL, /* pSelectPalette */
3852 NULL, /* pSelectPen */
3853 NULL, /* pSetArcDirection */
3854 NULL, /* pSetBkColor */
3855 NULL, /* pSetBkMode */
3856 NULL, /* pSetBoundsRect */
3857 NULL, /* pSetDCBrushColor */
3858 NULL, /* pSetDCPenColor */
3859 NULL, /* pSetDIBitsToDevice */
3860 NULL, /* pSetDeviceClipping */
3861 NULL, /* pSetDeviceGammaRamp */
3862 NULL, /* pSetLayout */
3863 NULL, /* pSetMapMode */
3864 NULL, /* pSetMapperFlags */
3865 NULL, /* pSetPixel */
3866 NULL, /* pSetPolyFillMode */
3867 NULL, /* pSetROP2 */
3868 NULL, /* pSetRelAbs */
3869 NULL, /* pSetStretchBltMode */
3870 NULL, /* pSetTextAlign */
3871 NULL, /* pSetTextCharacterExtra */
3872 NULL, /* pSetTextColor */
3873 NULL, /* pSetTextJustification */
3874 NULL, /* pSetViewportExt */
3875 NULL, /* pSetViewportOrg */
3876 NULL, /* pSetWindowExt */
3877 NULL, /* pSetWindowOrg */
3878 NULL, /* pSetWorldTransform */
3879 NULL, /* pStartDoc */
3880 NULL, /* pStartPage */
3881 NULL, /* pStretchBlt */
3882 NULL, /* pStretchDIBits */
3883 NULL, /* pStrokeAndFillPath */
3884 NULL, /* pStrokePath */
3885 NULL, /* pUnrealizePalette */
3886 NULL, /* pWidenPath */
3887 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
3888 NULL, /* pD3DKMTSetVidPnSourceOwner */
3889 NULL, /* wine_get_wgl_driver */
3890 NULL, /* wine_get_vulkan_driver */
3891 GDI_PRIORITY_FONT_DRV /* priority */
3894 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
3896 WCHAR buf[12];
3897 DWORD count = sizeof(buf), type, err;
3899 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
3900 if (!err)
3902 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
3903 else *value = wcstol( buf, NULL, 10 );
3905 return err;
3908 static void init_font_options(void)
3910 HKEY key;
3911 DWORD i, type, size, val, gamma = 1400;
3912 WCHAR buffer[20];
3914 size = sizeof(buffer);
3915 if (!RegQueryValueExW( wine_fonts_key, L"AntialiasFakeBoldOrItalic", NULL,
3916 &type, (BYTE *)buffer, &size) && type == REG_SZ && size >= 1)
3918 antialias_fakes = (wcschr(L"yYtT1", buffer[0]) != NULL);
3921 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Control Panel\\Desktop", &key ))
3923 /* FIXME: handle vertical orientations even though Windows doesn't */
3924 if (!get_key_value( key, L"FontSmoothingOrientation", &val ))
3926 switch (val)
3928 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
3929 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
3930 break;
3931 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
3932 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
3933 break;
3936 if (!get_key_value( key, L"FontSmoothing", &val ) && val /* enabled */)
3938 if (!get_key_value( key, L"FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
3939 font_smoothing = subpixel_orientation;
3940 else
3941 font_smoothing = GGO_GRAY4_BITMAP;
3943 if (!get_key_value( key, L"FontSmoothingGamma", &val ) && val)
3945 gamma = min( max( val, 1000 ), 2200 );
3947 RegCloseKey( key );
3950 /* Calibrating the difference between the registry value and the Wine gamma value.
3951 This looks roughly similar to Windows Native with the same registry value.
3952 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
3953 gamma = 1000 * gamma / 1400;
3954 for (i = 0; i < 256; i++)
3956 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
3957 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
3959 font_gamma_ramp.gamma = gamma;
3960 TRACE("gamma %d\n", font_gamma_ramp.gamma);
3964 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
3966 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
3967 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
3968 LF_FACESIZE);
3969 fontW->lfFaceName[LF_FACESIZE-1] = 0;
3972 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
3974 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
3975 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
3976 LF_FACESIZE, NULL, NULL);
3977 fontA->lfFaceName[LF_FACESIZE-1] = 0;
3980 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
3982 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
3984 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
3985 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
3986 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
3987 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
3988 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
3989 fontA->elfStyle[LF_FACESIZE-1] = '\0';
3990 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
3991 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
3992 fontA->elfScript[LF_FACESIZE-1] = '\0';
3995 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
3997 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
3999 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
4000 fontW->elfFullName, LF_FULLFACESIZE );
4001 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
4002 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
4003 fontW->elfStyle, LF_FACESIZE );
4004 fontW->elfStyle[LF_FACESIZE-1] = '\0';
4005 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
4006 fontW->elfScript, LF_FACESIZE );
4007 fontW->elfScript[LF_FACESIZE-1] = '\0';
4010 /***********************************************************************
4011 * TEXTMETRIC conversion functions.
4013 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
4015 ptmA->tmHeight = ptmW->tmHeight;
4016 ptmA->tmAscent = ptmW->tmAscent;
4017 ptmA->tmDescent = ptmW->tmDescent;
4018 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
4019 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
4020 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
4021 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
4022 ptmA->tmWeight = ptmW->tmWeight;
4023 ptmA->tmOverhang = ptmW->tmOverhang;
4024 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
4025 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
4026 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
4027 if (ptmW->tmCharSet == SYMBOL_CHARSET)
4029 ptmA->tmFirstChar = 0x1e;
4030 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
4032 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
4034 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
4035 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
4037 else
4039 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
4040 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
4042 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
4043 ptmA->tmBreakChar = ptmW->tmBreakChar;
4044 ptmA->tmItalic = ptmW->tmItalic;
4045 ptmA->tmUnderlined = ptmW->tmUnderlined;
4046 ptmA->tmStruckOut = ptmW->tmStruckOut;
4047 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
4048 ptmA->tmCharSet = ptmW->tmCharSet;
4052 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
4054 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
4055 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
4056 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
4057 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
4058 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
4059 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
4062 /* compute positions for text rendering, in device coords */
4063 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4065 TEXTMETRICW tm;
4066 PHYSDEV dev;
4068 size->cx = size->cy = 0;
4069 if (!count) return TRUE;
4071 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4072 dev->funcs->pGetTextMetrics( dev, &tm );
4074 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4075 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4077 if (dc->breakExtra || dc->breakRem)
4079 int i, space = 0, rem = dc->breakRem;
4081 for (i = 0; i < count; i++)
4083 if (str[i] == tm.tmBreakChar)
4085 space += dc->breakExtra;
4086 if (rem > 0)
4088 space++;
4089 rem--;
4092 dx[i] += space;
4095 size->cx = dx[count - 1];
4096 size->cy = tm.tmHeight;
4097 return TRUE;
4100 /* compute positions for text rendering, in device coords */
4101 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4103 TEXTMETRICW tm;
4104 PHYSDEV dev;
4106 size->cx = size->cy = 0;
4107 if (!count) return TRUE;
4109 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4110 dev->funcs->pGetTextMetrics( dev, &tm );
4112 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4113 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4115 if (dc->breakExtra || dc->breakRem)
4117 WORD space_index;
4118 int i, space = 0, rem = dc->breakRem;
4120 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4121 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4123 for (i = 0; i < count; i++)
4125 if (indices[i] == space_index)
4127 space += dc->breakExtra;
4128 if (rem > 0)
4130 space++;
4131 rem--;
4134 dx[i] += space;
4137 size->cx = dx[count - 1];
4138 size->cy = tm.tmHeight;
4139 return TRUE;
4142 /***********************************************************************
4143 * GdiGetCodePage (GDI32.@)
4145 DWORD WINAPI GdiGetCodePage( HDC hdc )
4147 UINT cp = CP_ACP;
4148 DC *dc = get_dc_ptr( hdc );
4150 if (dc)
4152 cp = dc->font_code_page;
4153 release_dc_ptr( dc );
4155 return cp;
4158 /***********************************************************************
4159 * get_text_charset_info
4161 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4163 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4165 UINT ret = DEFAULT_CHARSET;
4166 PHYSDEV dev;
4168 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4169 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4171 if (ret == DEFAULT_CHARSET && fs)
4172 memset(fs, 0, sizeof(FONTSIGNATURE));
4173 return ret;
4176 /***********************************************************************
4177 * GetTextCharsetInfo (GDI32.@)
4179 UINT WINAPI GetTextCharsetInfo(HDC hdc, FONTSIGNATURE *fs, DWORD flags)
4181 UINT ret = DEFAULT_CHARSET;
4182 DC *dc = get_dc_ptr(hdc);
4184 if (dc)
4186 ret = get_text_charset_info( dc, fs, flags );
4187 release_dc_ptr( dc );
4189 return ret;
4192 /***********************************************************************
4193 * FONT_mbtowc
4195 * Returns a Unicode translation of str using the charset of the
4196 * currently selected font in hdc. If count is -1 then str is assumed
4197 * to be '\0' terminated, otherwise it contains the number of bytes to
4198 * convert. If plenW is non-NULL, on return it will point to the
4199 * number of WCHARs that have been written. If pCP is non-NULL, on
4200 * return it will point to the codepage used in the conversion. The
4201 * caller should free the returned LPWSTR from the process heap
4202 * itself.
4204 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
4206 UINT cp;
4207 INT lenW;
4208 LPWSTR strW;
4210 cp = GdiGetCodePage( hdc );
4212 if(count == -1) count = strlen(str);
4213 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
4214 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
4215 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
4216 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
4217 if(plenW) *plenW = lenW;
4218 if(pCP) *pCP = cp;
4219 return strW;
4222 /***********************************************************************
4223 * CreateFontIndirectExA (GDI32.@)
4225 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
4227 ENUMLOGFONTEXDVW enumexW;
4229 if (!penumexA) return 0;
4231 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
4232 enumexW.elfDesignVector = penumexA->elfDesignVector;
4233 return CreateFontIndirectExW( &enumexW );
4236 /***********************************************************************
4237 * CreateFontIndirectExW (GDI32.@)
4239 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
4241 HFONT hFont;
4242 FONTOBJ *fontPtr;
4243 const LOGFONTW *plf;
4245 if (!penumex) return 0;
4247 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
4248 penumex->elfEnumLogfontEx.elfStyle[0] ||
4249 penumex->elfEnumLogfontEx.elfScript[0])
4251 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4252 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
4253 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
4254 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
4257 plf = &penumex->elfEnumLogfontEx.elfLogFont;
4258 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
4260 fontPtr->logfont = *plf;
4262 if (!(hFont = alloc_gdi_handle( fontPtr, OBJ_FONT, &fontobj_funcs )))
4264 HeapFree( GetProcessHeap(), 0, fontPtr );
4265 return 0;
4268 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4269 plf->lfHeight, plf->lfWidth,
4270 plf->lfEscapement, plf->lfOrientation,
4271 plf->lfPitchAndFamily,
4272 plf->lfOutPrecision, plf->lfClipPrecision,
4273 plf->lfQuality, plf->lfCharSet,
4274 debugstr_w(plf->lfFaceName),
4275 plf->lfWeight > 400 ? "Bold" : "",
4276 plf->lfItalic ? "Italic" : "",
4277 plf->lfUnderline ? "Underline" : "", hFont);
4279 return hFont;
4282 /***********************************************************************
4283 * CreateFontIndirectA (GDI32.@)
4285 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
4287 LOGFONTW lfW;
4289 if (!plfA) return 0;
4291 FONT_LogFontAToW( plfA, &lfW );
4292 return CreateFontIndirectW( &lfW );
4295 /***********************************************************************
4296 * CreateFontIndirectW (GDI32.@)
4298 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
4300 ENUMLOGFONTEXDVW exdv;
4302 if (!plf) return 0;
4304 exdv.elfEnumLogfontEx.elfLogFont = *plf;
4305 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
4306 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
4307 exdv.elfEnumLogfontEx.elfScript[0] = 0;
4308 return CreateFontIndirectExW( &exdv );
4311 /*************************************************************************
4312 * CreateFontA (GDI32.@)
4314 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
4315 INT orient, INT weight, DWORD italic,
4316 DWORD underline, DWORD strikeout, DWORD charset,
4317 DWORD outpres, DWORD clippres, DWORD quality,
4318 DWORD pitch, LPCSTR name )
4320 LOGFONTA logfont;
4322 logfont.lfHeight = height;
4323 logfont.lfWidth = width;
4324 logfont.lfEscapement = esc;
4325 logfont.lfOrientation = orient;
4326 logfont.lfWeight = weight;
4327 logfont.lfItalic = italic;
4328 logfont.lfUnderline = underline;
4329 logfont.lfStrikeOut = strikeout;
4330 logfont.lfCharSet = charset;
4331 logfont.lfOutPrecision = outpres;
4332 logfont.lfClipPrecision = clippres;
4333 logfont.lfQuality = quality;
4334 logfont.lfPitchAndFamily = pitch;
4336 if (name)
4337 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
4338 else
4339 logfont.lfFaceName[0] = '\0';
4341 return CreateFontIndirectA( &logfont );
4344 /*************************************************************************
4345 * CreateFontW (GDI32.@)
4347 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
4348 INT orient, INT weight, DWORD italic,
4349 DWORD underline, DWORD strikeout, DWORD charset,
4350 DWORD outpres, DWORD clippres, DWORD quality,
4351 DWORD pitch, LPCWSTR name )
4353 LOGFONTW logfont;
4355 logfont.lfHeight = height;
4356 logfont.lfWidth = width;
4357 logfont.lfEscapement = esc;
4358 logfont.lfOrientation = orient;
4359 logfont.lfWeight = weight;
4360 logfont.lfItalic = italic;
4361 logfont.lfUnderline = underline;
4362 logfont.lfStrikeOut = strikeout;
4363 logfont.lfCharSet = charset;
4364 logfont.lfOutPrecision = outpres;
4365 logfont.lfClipPrecision = clippres;
4366 logfont.lfQuality = quality;
4367 logfont.lfPitchAndFamily = pitch;
4369 if (name)
4370 lstrcpynW(logfont.lfFaceName, name, ARRAY_SIZE(logfont.lfFaceName));
4371 else
4372 logfont.lfFaceName[0] = '\0';
4374 return CreateFontIndirectW( &logfont );
4377 #define ASSOC_CHARSET_OEM 1
4378 #define ASSOC_CHARSET_ANSI 2
4379 #define ASSOC_CHARSET_SYMBOL 4
4381 static DWORD get_associated_charset_info(void)
4383 static DWORD associated_charset = -1;
4385 if (associated_charset == -1)
4387 HKEY hkey;
4388 WCHAR dataW[32];
4389 DWORD type, data_len;
4391 associated_charset = 0;
4393 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
4394 L"System\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset", &hkey))
4395 return 0;
4397 data_len = sizeof(dataW);
4398 if (!RegQueryValueExW(hkey, L"ANSI(00)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4399 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4400 associated_charset |= ASSOC_CHARSET_ANSI;
4402 data_len = sizeof(dataW);
4403 if (!RegQueryValueExW(hkey, L"OEM(FF)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4404 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4405 associated_charset |= ASSOC_CHARSET_OEM;
4407 data_len = sizeof(dataW);
4408 if (!RegQueryValueExW(hkey, L"SYMBOL(02)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4409 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4410 associated_charset |= ASSOC_CHARSET_SYMBOL;
4412 RegCloseKey(hkey);
4414 TRACE("associated_charset = %d\n", associated_charset);
4417 return associated_charset;
4420 static void update_font_code_page( DC *dc, HANDLE font )
4422 CHARSETINFO csi;
4423 int charset = get_text_charset_info( dc, NULL, 0 );
4425 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
4427 LOGFONTW lf;
4429 GetObjectW( font, sizeof(lf), &lf );
4430 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
4431 charset = DEFAULT_CHARSET;
4434 /* Hmm, nicely designed api this one! */
4435 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
4436 dc->font_code_page = csi.ciACP;
4437 else {
4438 switch(charset) {
4439 case OEM_CHARSET:
4440 dc->font_code_page = GetOEMCP();
4441 break;
4442 case DEFAULT_CHARSET:
4443 dc->font_code_page = GetACP();
4444 break;
4446 case VISCII_CHARSET:
4447 case TCVN_CHARSET:
4448 case KOI8_CHARSET:
4449 case ISO3_CHARSET:
4450 case ISO4_CHARSET:
4451 case ISO10_CHARSET:
4452 case CELTIC_CHARSET:
4453 /* FIXME: These have no place here, but because x11drv
4454 enumerates fonts with these (made up) charsets some apps
4455 might use them and then the FIXME below would become
4456 annoying. Now we could pick the intended codepage for
4457 each of these, but since it's broken anyway we'll just
4458 use CP_ACP and hope it'll go away...
4460 dc->font_code_page = CP_ACP;
4461 break;
4463 default:
4464 FIXME("Can't find codepage for charset %d\n", charset);
4465 dc->font_code_page = CP_ACP;
4466 break;
4470 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
4473 /***********************************************************************
4474 * FONT_SelectObject
4476 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
4478 HGDIOBJ ret = 0;
4479 DC *dc = get_dc_ptr( hdc );
4480 PHYSDEV physdev;
4481 UINT aa_flags = 0;
4483 if (!dc) return 0;
4485 if (!GDI_inc_ref_count( handle ))
4487 release_dc_ptr( dc );
4488 return 0;
4491 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
4492 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
4494 ret = dc->hFont;
4495 dc->hFont = handle;
4496 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
4497 update_font_code_page( dc, handle );
4498 if (dc->font_gamma_ramp == NULL)
4499 dc->font_gamma_ramp = &font_gamma_ramp;
4500 GDI_dec_ref_count( ret );
4502 else GDI_dec_ref_count( handle );
4504 release_dc_ptr( dc );
4505 return ret;
4509 /***********************************************************************
4510 * FONT_GetObjectA
4512 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
4514 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
4515 LOGFONTA lfA;
4517 if (!font) return 0;
4518 if (buffer)
4520 FONT_LogFontWToA( &font->logfont, &lfA );
4521 if (count > sizeof(lfA)) count = sizeof(lfA);
4522 memcpy( buffer, &lfA, count );
4524 else count = sizeof(lfA);
4525 GDI_ReleaseObj( handle );
4526 return count;
4529 /***********************************************************************
4530 * FONT_GetObjectW
4532 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
4534 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
4536 if (!font) return 0;
4537 if (buffer)
4539 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
4540 memcpy( buffer, &font->logfont, count );
4542 else count = sizeof(LOGFONTW);
4543 GDI_ReleaseObj( handle );
4544 return count;
4548 /***********************************************************************
4549 * FONT_DeleteObject
4551 static BOOL FONT_DeleteObject( HGDIOBJ handle )
4553 FONTOBJ *obj;
4555 if (!(obj = free_gdi_handle( handle ))) return FALSE;
4556 HeapFree( GetProcessHeap(), 0, obj );
4557 return TRUE;
4561 /***********************************************************************
4562 * FONT_EnumInstance
4564 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
4565 * We have to use other types because of the FONTENUMPROCW definition.
4567 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
4568 DWORD fType, LPARAM lp )
4570 struct font_enum *pfe = (struct font_enum *)lp;
4571 INT ret = 1;
4573 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
4574 if ((!pfe->lpLogFontParam ||
4575 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
4576 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
4577 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
4579 /* convert font metrics */
4580 ENUMLOGFONTEXA logfont;
4581 NEWTEXTMETRICEXA tmA;
4583 if (!pfe->unicode)
4585 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
4586 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
4587 plf = (LOGFONTW *)&logfont.elfLogFont;
4588 ptm = (TEXTMETRICW *)&tmA;
4590 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
4591 pfe->retval = ret;
4593 return ret;
4596 /***********************************************************************
4597 * FONT_EnumFontFamiliesEx
4599 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
4600 LPARAM lParam, BOOL unicode )
4602 INT ret = 0;
4603 DC *dc = get_dc_ptr( hDC );
4604 struct font_enum fe;
4606 if (dc)
4608 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
4610 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4611 fe.lpLogFontParam = plf;
4612 fe.lpEnumFunc = efproc;
4613 fe.lpData = lParam;
4614 fe.unicode = unicode;
4615 fe.hdc = hDC;
4616 fe.retval = 1;
4617 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
4618 release_dc_ptr( dc );
4620 return ret ? fe.retval : 0;
4623 /***********************************************************************
4624 * EnumFontFamiliesExW (GDI32.@)
4626 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
4627 FONTENUMPROCW efproc,
4628 LPARAM lParam, DWORD dwFlags )
4630 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
4633 /***********************************************************************
4634 * EnumFontFamiliesExA (GDI32.@)
4636 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
4637 FONTENUMPROCA efproc,
4638 LPARAM lParam, DWORD dwFlags)
4640 LOGFONTW lfW, *plfW;
4642 if (plf)
4644 FONT_LogFontAToW( plf, &lfW );
4645 plfW = &lfW;
4647 else plfW = NULL;
4649 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
4652 /***********************************************************************
4653 * EnumFontFamiliesA (GDI32.@)
4655 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
4656 FONTENUMPROCA efproc, LPARAM lpData )
4658 LOGFONTA lf, *plf;
4660 if (lpFamily)
4662 if (!*lpFamily) return 1;
4663 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
4664 lf.lfCharSet = DEFAULT_CHARSET;
4665 lf.lfPitchAndFamily = 0;
4666 plf = &lf;
4668 else plf = NULL;
4670 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
4673 /***********************************************************************
4674 * EnumFontFamiliesW (GDI32.@)
4676 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
4677 FONTENUMPROCW efproc, LPARAM lpData )
4679 LOGFONTW lf, *plf;
4681 if (lpFamily)
4683 if (!*lpFamily) return 1;
4684 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
4685 lf.lfCharSet = DEFAULT_CHARSET;
4686 lf.lfPitchAndFamily = 0;
4687 plf = &lf;
4689 else plf = NULL;
4691 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
4694 /***********************************************************************
4695 * EnumFontsA (GDI32.@)
4697 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
4698 LPARAM lpData )
4700 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
4703 /***********************************************************************
4704 * EnumFontsW (GDI32.@)
4706 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
4707 LPARAM lpData )
4709 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
4713 /***********************************************************************
4714 * GetTextCharacterExtra (GDI32.@)
4716 INT WINAPI GetTextCharacterExtra( HDC hdc )
4718 INT ret;
4719 DC *dc = get_dc_ptr( hdc );
4720 if (!dc) return 0x80000000;
4721 ret = dc->charExtra;
4722 release_dc_ptr( dc );
4723 return ret;
4727 /***********************************************************************
4728 * SetTextCharacterExtra (GDI32.@)
4730 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
4732 INT ret = 0x80000000;
4733 DC * dc = get_dc_ptr( hdc );
4735 if (dc)
4737 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
4738 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
4739 if (extra != 0x80000000)
4741 ret = dc->charExtra;
4742 dc->charExtra = extra;
4744 release_dc_ptr( dc );
4746 return ret;
4750 /***********************************************************************
4751 * SetTextJustification (GDI32.@)
4753 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
4755 BOOL ret;
4756 PHYSDEV physdev;
4757 DC * dc = get_dc_ptr( hdc );
4759 if (!dc) return FALSE;
4761 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
4762 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
4763 if (ret)
4765 extra = abs((extra * dc->vport_ext.cx + dc->wnd_ext.cx / 2) / dc->wnd_ext.cx);
4766 if (!extra) breaks = 0;
4767 if (breaks)
4769 dc->breakExtra = extra / breaks;
4770 dc->breakRem = extra - (breaks * dc->breakExtra);
4772 else
4774 dc->breakExtra = 0;
4775 dc->breakRem = 0;
4778 release_dc_ptr( dc );
4779 return ret;
4783 /***********************************************************************
4784 * GetTextFaceA (GDI32.@)
4786 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
4788 INT res = GetTextFaceW(hdc, 0, NULL);
4789 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
4790 GetTextFaceW( hdc, res, nameW );
4792 if (name)
4794 if (count)
4796 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
4797 if (res == 0)
4798 res = count;
4799 name[count-1] = 0;
4800 /* GetTextFaceA does NOT include the nul byte in the return count. */
4801 res--;
4803 else
4804 res = 0;
4806 else
4807 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
4808 HeapFree( GetProcessHeap(), 0, nameW );
4809 return res;
4812 /***********************************************************************
4813 * GetTextFaceW (GDI32.@)
4815 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
4817 PHYSDEV dev;
4818 INT ret;
4820 DC * dc = get_dc_ptr( hdc );
4821 if (!dc) return 0;
4823 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
4824 ret = dev->funcs->pGetTextFace( dev, count, name );
4825 release_dc_ptr( dc );
4826 return ret;
4830 /***********************************************************************
4831 * GetTextExtentPoint32A (GDI32.@)
4833 * See GetTextExtentPoint32W.
4835 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
4836 LPSIZE size )
4838 BOOL ret = FALSE;
4839 INT wlen;
4840 LPWSTR p;
4842 if (count < 0) return FALSE;
4844 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
4846 if (p)
4848 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
4849 HeapFree( GetProcessHeap(), 0, p );
4852 TRACE("(%p %s %d %p): returning %d x %d\n",
4853 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
4854 return ret;
4858 /***********************************************************************
4859 * GetTextExtentPoint32W [GDI32.@]
4861 * Computes width/height for a string.
4863 * Computes width and height of the specified string.
4865 * RETURNS
4866 * Success: TRUE
4867 * Failure: FALSE
4869 BOOL WINAPI GetTextExtentPoint32W(
4870 HDC hdc, /* [in] Handle of device context */
4871 LPCWSTR str, /* [in] Address of text string */
4872 INT count, /* [in] Number of characters in string */
4873 LPSIZE size) /* [out] Address of structure for string size */
4875 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
4878 /***********************************************************************
4879 * GetTextExtentExPointI [GDI32.@]
4881 * Computes width and height of the array of glyph indices.
4883 * PARAMS
4884 * hdc [I] Handle of device context.
4885 * indices [I] Glyph index array.
4886 * count [I] Number of glyphs in array.
4887 * max_ext [I] Maximum width in glyphs.
4888 * nfit [O] Maximum number of characters.
4889 * dxs [O] Partial string widths.
4890 * size [O] Returned string size.
4892 * RETURNS
4893 * Success: TRUE
4894 * Failure: FALSE
4896 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
4897 LPINT nfit, LPINT dxs, LPSIZE size )
4899 DC *dc;
4900 int i;
4901 BOOL ret;
4902 INT buffer[256], *pos = dxs;
4904 if (count < 0) return FALSE;
4906 dc = get_dc_ptr( hdc );
4907 if (!dc) return FALSE;
4909 if (!dxs)
4911 pos = buffer;
4912 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
4914 release_dc_ptr( dc );
4915 return FALSE;
4919 ret = get_char_positions_indices( dc, indices, count, pos, size );
4920 if (ret)
4922 if (dxs || nfit)
4924 for (i = 0; i < count; i++)
4926 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
4927 if (nfit && dx > (unsigned int)max_ext) break;
4928 if (dxs) dxs[i] = dx;
4930 if (nfit) *nfit = i;
4933 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
4934 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
4937 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
4938 release_dc_ptr( dc );
4940 TRACE("(%p %p %d %p): returning %d x %d\n",
4941 hdc, indices, count, size, size->cx, size->cy );
4942 return ret;
4945 /***********************************************************************
4946 * GetTextExtentPointI [GDI32.@]
4948 * Computes width and height of the array of glyph indices.
4950 * PARAMS
4951 * hdc [I] Handle of device context.
4952 * indices [I] Glyph index array.
4953 * count [I] Number of glyphs in array.
4954 * size [O] Returned string size.
4956 * RETURNS
4957 * Success: TRUE
4958 * Failure: FALSE
4960 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
4962 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
4966 /***********************************************************************
4967 * GetTextExtentPointA (GDI32.@)
4969 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
4970 LPSIZE size )
4972 TRACE("not bug compatible.\n");
4973 return GetTextExtentPoint32A( hdc, str, count, size );
4976 /***********************************************************************
4977 * GetTextExtentPointW (GDI32.@)
4979 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
4980 LPSIZE size )
4982 TRACE("not bug compatible.\n");
4983 return GetTextExtentPoint32W( hdc, str, count, size );
4987 /***********************************************************************
4988 * GetTextExtentExPointA (GDI32.@)
4990 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
4991 INT maxExt, LPINT lpnFit,
4992 LPINT alpDx, LPSIZE size )
4994 BOOL ret;
4995 INT wlen;
4996 INT *walpDx = NULL;
4997 LPWSTR p = NULL;
4999 if (count < 0) return FALSE;
5000 if (maxExt < -1) return FALSE;
5002 if (alpDx)
5004 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
5005 if (!walpDx) return FALSE;
5008 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
5009 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
5010 if (walpDx)
5012 INT n = lpnFit ? *lpnFit : wlen;
5013 INT i, j;
5014 for(i = 0, j = 0; i < n; i++, j++)
5016 alpDx[j] = walpDx[i];
5017 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
5020 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
5021 HeapFree( GetProcessHeap(), 0, p );
5022 HeapFree( GetProcessHeap(), 0, walpDx );
5023 return ret;
5027 /***********************************************************************
5028 * GetTextExtentExPointW (GDI32.@)
5030 * Return the size of the string as it would be if it was output properly by
5031 * e.g. TextOut.
5033 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
5034 LPINT nfit, LPINT dxs, LPSIZE size )
5036 DC *dc;
5037 int i;
5038 BOOL ret;
5039 INT buffer[256], *pos = dxs;
5041 if (count < 0) return FALSE;
5043 dc = get_dc_ptr(hdc);
5044 if (!dc) return FALSE;
5046 if (!dxs)
5048 pos = buffer;
5049 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
5051 release_dc_ptr( dc );
5052 return FALSE;
5056 ret = get_char_positions( dc, str, count, pos, size );
5057 if (ret)
5059 if (dxs || nfit)
5061 for (i = 0; i < count; i++)
5063 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
5064 if (nfit && dx > (unsigned int)max_ext) break;
5065 if (dxs) dxs[i] = dx;
5067 if (nfit) *nfit = i;
5070 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
5071 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5074 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
5075 release_dc_ptr( dc );
5077 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
5078 return ret;
5081 /***********************************************************************
5082 * GetTextMetricsA (GDI32.@)
5084 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
5086 TEXTMETRICW tm32;
5088 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
5089 FONT_TextMetricWToA( &tm32, metrics );
5090 return TRUE;
5093 /***********************************************************************
5094 * GetTextMetricsW (GDI32.@)
5096 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
5098 PHYSDEV physdev;
5099 BOOL ret = FALSE;
5100 DC * dc = get_dc_ptr( hdc );
5101 if (!dc) return FALSE;
5103 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5104 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5106 if (ret)
5108 /* device layer returns values in device units
5109 * therefore we have to convert them to logical */
5111 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
5112 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
5113 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5114 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5115 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5116 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5117 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5118 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5119 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5120 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5121 ret = TRUE;
5123 TRACE("text metrics:\n"
5124 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5125 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5126 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5127 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5128 " PitchAndFamily = %02x\n"
5129 " --------------------\n"
5130 " InternalLeading = %i\n"
5131 " Ascent = %i\n"
5132 " Descent = %i\n"
5133 " Height = %i\n",
5134 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
5135 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
5136 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
5137 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5138 metrics->tmPitchAndFamily,
5139 metrics->tmInternalLeading,
5140 metrics->tmAscent,
5141 metrics->tmDescent,
5142 metrics->tmHeight );
5144 release_dc_ptr( dc );
5145 return ret;
5149 /***********************************************************************
5150 * GetOutlineTextMetricsA (GDI32.@)
5151 * Gets metrics for TrueType fonts.
5153 * NOTES
5154 * If the supplied buffer isn't big enough Windows partially fills it up to
5155 * its given length and returns that length.
5157 * RETURNS
5158 * Success: Non-zero or size of required buffer
5159 * Failure: 0
5161 UINT WINAPI GetOutlineTextMetricsA(
5162 HDC hdc, /* [in] Handle of device context */
5163 UINT cbData, /* [in] Size of metric data array */
5164 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
5166 char buf[512], *ptr;
5167 UINT ret, needed;
5168 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
5169 OUTLINETEXTMETRICA *output = lpOTM;
5170 INT left, len;
5172 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
5173 return 0;
5174 if(ret > sizeof(buf))
5175 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
5176 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
5178 needed = sizeof(OUTLINETEXTMETRICA);
5179 if(lpOTMW->otmpFamilyName)
5180 needed += WideCharToMultiByte(CP_ACP, 0,
5181 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
5182 NULL, 0, NULL, NULL);
5183 if(lpOTMW->otmpFaceName)
5184 needed += WideCharToMultiByte(CP_ACP, 0,
5185 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
5186 NULL, 0, NULL, NULL);
5187 if(lpOTMW->otmpStyleName)
5188 needed += WideCharToMultiByte(CP_ACP, 0,
5189 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
5190 NULL, 0, NULL, NULL);
5191 if(lpOTMW->otmpFullName)
5192 needed += WideCharToMultiByte(CP_ACP, 0,
5193 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
5194 NULL, 0, NULL, NULL);
5196 if(!lpOTM) {
5197 ret = needed;
5198 goto end;
5201 TRACE("needed = %d\n", needed);
5202 if(needed > cbData)
5203 /* Since the supplied buffer isn't big enough, we'll alloc one
5204 that is and memcpy the first cbData bytes into the lpOTM at
5205 the end. */
5206 output = HeapAlloc(GetProcessHeap(), 0, needed);
5208 ret = output->otmSize = min(needed, cbData);
5209 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
5210 output->otmFiller = 0;
5211 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
5212 output->otmfsSelection = lpOTMW->otmfsSelection;
5213 output->otmfsType = lpOTMW->otmfsType;
5214 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
5215 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
5216 output->otmItalicAngle = lpOTMW->otmItalicAngle;
5217 output->otmEMSquare = lpOTMW->otmEMSquare;
5218 output->otmAscent = lpOTMW->otmAscent;
5219 output->otmDescent = lpOTMW->otmDescent;
5220 output->otmLineGap = lpOTMW->otmLineGap;
5221 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
5222 output->otmsXHeight = lpOTMW->otmsXHeight;
5223 output->otmrcFontBox = lpOTMW->otmrcFontBox;
5224 output->otmMacAscent = lpOTMW->otmMacAscent;
5225 output->otmMacDescent = lpOTMW->otmMacDescent;
5226 output->otmMacLineGap = lpOTMW->otmMacLineGap;
5227 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
5228 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
5229 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
5230 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
5231 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
5232 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
5233 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
5234 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
5235 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
5238 ptr = (char*)(output + 1);
5239 left = needed - sizeof(*output);
5241 if(lpOTMW->otmpFamilyName) {
5242 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
5243 len = WideCharToMultiByte(CP_ACP, 0,
5244 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
5245 ptr, left, NULL, NULL);
5246 left -= len;
5247 ptr += len;
5248 } else
5249 output->otmpFamilyName = 0;
5251 if(lpOTMW->otmpFaceName) {
5252 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
5253 len = WideCharToMultiByte(CP_ACP, 0,
5254 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
5255 ptr, left, NULL, NULL);
5256 left -= len;
5257 ptr += len;
5258 } else
5259 output->otmpFaceName = 0;
5261 if(lpOTMW->otmpStyleName) {
5262 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
5263 len = WideCharToMultiByte(CP_ACP, 0,
5264 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
5265 ptr, left, NULL, NULL);
5266 left -= len;
5267 ptr += len;
5268 } else
5269 output->otmpStyleName = 0;
5271 if(lpOTMW->otmpFullName) {
5272 output->otmpFullName = (LPSTR)(ptr - (char*)output);
5273 len = WideCharToMultiByte(CP_ACP, 0,
5274 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
5275 ptr, left, NULL, NULL);
5276 left -= len;
5277 } else
5278 output->otmpFullName = 0;
5280 assert(left == 0);
5282 if(output != lpOTM) {
5283 memcpy(lpOTM, output, cbData);
5284 HeapFree(GetProcessHeap(), 0, output);
5286 /* check if the string offsets really fit into the provided size */
5287 /* FIXME: should we check string length as well? */
5288 /* make sure that we don't read/write beyond the provided buffer */
5289 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
5291 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
5292 lpOTM->otmpFamilyName = 0; /* doesn't fit */
5295 /* make sure that we don't read/write beyond the provided buffer */
5296 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
5298 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
5299 lpOTM->otmpFaceName = 0; /* doesn't fit */
5302 /* make sure that we don't read/write beyond the provided buffer */
5303 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
5305 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
5306 lpOTM->otmpStyleName = 0; /* doesn't fit */
5309 /* make sure that we don't read/write beyond the provided buffer */
5310 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
5312 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
5313 lpOTM->otmpFullName = 0; /* doesn't fit */
5317 end:
5318 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
5319 HeapFree(GetProcessHeap(), 0, lpOTMW);
5321 return ret;
5325 /***********************************************************************
5326 * GetOutlineTextMetricsW [GDI32.@]
5328 UINT WINAPI GetOutlineTextMetricsW(
5329 HDC hdc, /* [in] Handle of device context */
5330 UINT cbData, /* [in] Size of metric data array */
5331 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
5333 DC *dc = get_dc_ptr( hdc );
5334 OUTLINETEXTMETRICW *output = lpOTM;
5335 PHYSDEV dev;
5336 UINT ret;
5338 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5339 if(!dc) return 0;
5341 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5342 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5344 if (lpOTM && ret > cbData)
5346 output = HeapAlloc(GetProcessHeap(), 0, ret);
5347 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5350 if (lpOTM && ret)
5352 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
5353 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
5354 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5355 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5356 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5357 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5358 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5359 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5360 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5361 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5362 output->otmAscent = height_to_LP( dc, output->otmAscent);
5363 output->otmDescent = height_to_LP( dc, output->otmDescent);
5364 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5365 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5366 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5367 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5368 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5369 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5370 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5371 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5372 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5373 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5374 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5375 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5376 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5377 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5378 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5379 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5380 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5381 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5382 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5383 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5384 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5385 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5387 if(output != lpOTM)
5389 memcpy(lpOTM, output, cbData);
5390 HeapFree(GetProcessHeap(), 0, output);
5391 ret = cbData;
5394 release_dc_ptr(dc);
5395 return ret;
5398 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
5400 INT i, count = lastChar - firstChar + 1;
5401 UINT mbcp;
5402 UINT c;
5403 LPSTR str;
5405 if (count <= 0)
5406 return NULL;
5408 mbcp = GdiGetCodePage(hdc);
5409 switch (mbcp)
5411 case 932:
5412 case 936:
5413 case 949:
5414 case 950:
5415 case 1361:
5416 if (lastChar > 0xffff)
5417 return NULL;
5418 if ((firstChar ^ lastChar) > 0xff)
5419 return NULL;
5420 break;
5421 default:
5422 if (lastChar > 0xff)
5423 return NULL;
5424 mbcp = 0;
5425 break;
5428 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
5429 if (str == NULL)
5430 return NULL;
5432 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
5434 if (mbcp) {
5435 if (c > 0xff)
5436 str[i++] = (BYTE)(c >> 8);
5437 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
5438 str[i] = 0x1f; /* FIXME: use default character */
5439 else
5440 str[i] = (BYTE)c;
5442 else
5443 str[i] = (BYTE)c;
5445 str[i] = '\0';
5447 *pByteLen = i;
5449 return str;
5452 /***********************************************************************
5453 * GetCharWidthW (GDI32.@)
5454 * GetCharWidth32W (GDI32.@)
5456 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
5457 LPINT buffer )
5459 UINT i;
5460 BOOL ret;
5461 PHYSDEV dev;
5462 DC * dc = get_dc_ptr( hdc );
5464 if (!dc) return FALSE;
5466 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5467 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
5469 if (ret)
5471 /* convert device units to logical */
5472 for( i = firstChar; i <= lastChar; i++, buffer++ )
5473 *buffer = width_to_LP( dc, *buffer );
5475 release_dc_ptr( dc );
5476 return ret;
5480 /***********************************************************************
5481 * GetCharWidthA (GDI32.@)
5482 * GetCharWidth32A (GDI32.@)
5484 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
5485 LPINT buffer )
5487 INT i, wlen;
5488 LPSTR str;
5489 LPWSTR wstr;
5490 BOOL ret = TRUE;
5492 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
5493 if(str == NULL)
5494 return FALSE;
5496 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
5498 for(i = 0; i < wlen; i++)
5500 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
5502 ret = FALSE;
5503 break;
5505 buffer++;
5508 HeapFree(GetProcessHeap(), 0, str);
5509 HeapFree(GetProcessHeap(), 0, wstr);
5511 return ret;
5515 /* helper for nulldrv_ExtTextOut */
5516 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5517 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5519 UINT indices[3] = {0, 0, 0x20};
5520 unsigned int i;
5521 DWORD ret, size;
5522 int stride;
5524 indices[0] = index;
5525 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5527 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5529 index = indices[i];
5530 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
5531 if (ret != GDI_ERROR) break;
5534 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5535 if (!image) return ERROR_SUCCESS;
5537 image->ptr = NULL;
5538 image->free = NULL;
5539 if (!ret) /* empty glyph */
5541 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5542 return ERROR_SUCCESS;
5545 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5546 size = metrics->gmBlackBoxY * stride;
5548 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
5549 image->is_copy = TRUE;
5550 image->free = free_heap_bits;
5552 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
5553 if (ret == GDI_ERROR)
5555 HeapFree( GetProcessHeap(), 0, image->ptr );
5556 return ERROR_NOT_FOUND;
5558 return ERROR_SUCCESS;
5561 /* helper for nulldrv_ExtTextOut */
5562 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5563 LPCWSTR str, UINT count, const INT *dx )
5565 UINT i;
5566 RECT rect, bounds;
5568 reset_bounds( &bounds );
5569 for (i = 0; i < count; i++)
5571 GLYPHMETRICS metrics;
5573 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5575 rect.left = x + metrics.gmptGlyphOrigin.x;
5576 rect.top = y - metrics.gmptGlyphOrigin.y;
5577 rect.right = rect.left + metrics.gmBlackBoxX;
5578 rect.bottom = rect.top + metrics.gmBlackBoxY;
5579 add_bounds_rect( &bounds, &rect );
5581 if (dx)
5583 if (flags & ETO_PDY)
5585 x += dx[ i * 2 ];
5586 y += dx[ i * 2 + 1];
5588 else x += dx[ i ];
5590 else
5592 x += metrics.gmCellIncX;
5593 y += metrics.gmCellIncY;
5596 return bounds;
5599 /* helper for nulldrv_ExtTextOut */
5600 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5601 const struct gdi_image_bits *image, const RECT *clip )
5603 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5604 UINT i, count, max_count;
5605 LONG x, y;
5606 BYTE *ptr = image->ptr;
5607 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5608 POINT *pts;
5609 RECT rect, clipped_rect;
5611 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5612 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5613 rect.right = rect.left + metrics->gmBlackBoxX;
5614 rect.bottom = rect.top + metrics->gmBlackBoxY;
5615 if (!clip) clipped_rect = rect;
5616 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5618 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5619 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
5620 if (!pts) return;
5622 count = 0;
5623 ptr += (clipped_rect.top - rect.top) * stride;
5624 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5626 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5628 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5629 pts[count].x = rect.left + x;
5630 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5631 pts[count + 1].x = rect.left + x;
5632 if (pts[count + 1].x > pts[count].x)
5634 pts[count].y = pts[count + 1].y = y;
5635 count += 2;
5639 assert( count <= max_count );
5640 dp_to_lp( dc, pts, count );
5641 for (i = 0; i < count; i += 2) Polyline( dc->hSelf, pts + i, 2 );
5642 HeapFree( GetProcessHeap(), 0, pts );
5645 /***********************************************************************
5646 * nulldrv_ExtTextOut
5648 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5649 LPCWSTR str, UINT count, const INT *dx )
5651 DC *dc = get_nulldrv_dc( dev );
5652 UINT i;
5653 DWORD err;
5654 HGDIOBJ orig;
5655 HPEN pen;
5657 if (flags & ETO_OPAQUE)
5659 RECT rc = *rect;
5660 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, dc->backgroundColor ) );
5662 if (brush)
5664 orig = SelectObject( dev->hdc, brush );
5665 dp_to_lp( dc, (POINT *)&rc, 2 );
5666 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5667 SelectObject( dev->hdc, orig );
5668 DeleteObject( brush );
5672 if (!count) return TRUE;
5674 if (dc->aa_flags != GGO_BITMAP)
5676 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5677 BITMAPINFO *info = (BITMAPINFO *)buffer;
5678 struct gdi_image_bits bits;
5679 struct bitblt_coords src, dst;
5680 PHYSDEV dst_dev;
5681 /* FIXME Subpixel modes */
5682 UINT aa_flags = GGO_GRAY4_BITMAP;
5684 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5685 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5686 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5687 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5689 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5690 src.x = src.visrect.left;
5691 src.y = src.visrect.top;
5692 src.width = src.visrect.right - src.visrect.left;
5693 src.height = src.visrect.bottom - src.visrect.top;
5694 dst = src;
5695 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5696 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5698 /* we can avoid the GetImage, just query the needed format */
5699 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5700 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5701 info->bmiHeader.biWidth = src.width;
5702 info->bmiHeader.biHeight = -src.height;
5703 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5704 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5705 if (!err || err == ERROR_BAD_FORMAT)
5707 /* make the source rectangle relative to the source bits */
5708 src.x = src.y = 0;
5709 src.visrect.left = src.visrect.top = 0;
5710 src.visrect.right = src.width;
5711 src.visrect.bottom = src.height;
5713 bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
5714 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5715 bits.is_copy = TRUE;
5716 bits.free = free_heap_bits;
5717 err = ERROR_SUCCESS;
5720 else
5722 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5723 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5724 if (!err && !bits.is_copy)
5726 void *ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
5727 if (!ptr)
5729 if (bits.free) bits.free( &bits );
5730 return ERROR_OUTOFMEMORY;
5732 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5733 if (bits.free) bits.free( &bits );
5734 bits.ptr = ptr;
5735 bits.is_copy = TRUE;
5736 bits.free = free_heap_bits;
5739 if (!err)
5741 /* make x,y relative to the image bits */
5742 x += src.visrect.left - dst.visrect.left;
5743 y += src.visrect.top - dst.visrect.top;
5744 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5745 aa_flags, str, count, dx );
5746 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5747 if (bits.free) bits.free( &bits );
5748 return !err;
5752 pen = CreatePen( PS_SOLID, 1, dc->textColor );
5753 orig = SelectObject( dev->hdc, pen );
5755 for (i = 0; i < count; i++)
5757 GLYPHMETRICS metrics;
5758 struct gdi_image_bits image;
5760 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5761 if (err) continue;
5763 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5764 if (image.free) image.free( &image );
5766 if (dx)
5768 if (flags & ETO_PDY)
5770 x += dx[ i * 2 ];
5771 y += dx[ i * 2 + 1];
5773 else x += dx[ i ];
5775 else
5777 x += metrics.gmCellIncX;
5778 y += metrics.gmCellIncY;
5782 SelectObject( dev->hdc, orig );
5783 DeleteObject( pen );
5784 return TRUE;
5788 /***********************************************************************
5789 * ExtTextOutA (GDI32.@)
5791 * See ExtTextOutW.
5793 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
5794 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
5796 INT wlen;
5797 UINT codepage;
5798 LPWSTR p;
5799 BOOL ret;
5800 LPINT lpDxW = NULL;
5802 if (flags & ETO_GLYPH_INDEX)
5803 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
5805 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
5807 if (lpDx) {
5808 unsigned int i = 0, j = 0;
5810 /* allocate enough for a ETO_PDY */
5811 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
5812 while(i < count) {
5813 if(IsDBCSLeadByteEx(codepage, str[i]))
5815 if(flags & ETO_PDY)
5817 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
5818 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
5820 else
5821 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
5822 i = i + 2;
5824 else
5826 if(flags & ETO_PDY)
5828 lpDxW[j++] = lpDx[i * 2];
5829 lpDxW[j++] = lpDx[i * 2 + 1];
5831 else
5832 lpDxW[j++] = lpDx[i];
5833 i = i + 1;
5838 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
5840 HeapFree( GetProcessHeap(), 0, p );
5841 HeapFree( GetProcessHeap(), 0, lpDxW );
5842 return ret;
5845 /***********************************************************************
5846 * get_line_width
5848 * Scale the underline / strikeout line width.
5850 static inline int get_line_width( DC *dc, int metric_size )
5852 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5853 if (width == 0) width = 1;
5854 if (metric_size < 0) width = -width;
5855 return width;
5858 /***********************************************************************
5859 * ExtTextOutW (GDI32.@)
5861 * Draws text using the currently selected font, background color, and text color.
5864 * PARAMS
5865 * x,y [I] coordinates of string
5866 * flags [I]
5867 * ETO_GRAYED - undocumented on MSDN
5868 * ETO_OPAQUE - use background color for fill the rectangle
5869 * ETO_CLIPPED - clipping text to the rectangle
5870 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5871 * than encoded characters. Implies ETO_IGNORELANGUAGE
5872 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5873 * Affects BiDi ordering
5874 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5875 * ETO_PDY - unimplemented
5876 * ETO_NUMERICSLATIN - unimplemented always assumed -
5877 * do not translate numbers into locale representations
5878 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5879 * lprect [I] dimensions for clipping or/and opaquing
5880 * str [I] text string
5881 * count [I] number of symbols in string
5882 * lpDx [I] optional parameter with distance between drawing characters
5884 * RETURNS
5885 * Success: TRUE
5886 * Failure: FALSE
5888 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
5889 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
5891 BOOL ret = FALSE;
5892 LPWSTR reordered_str = (LPWSTR)str;
5893 WORD *glyphs = NULL;
5894 UINT align;
5895 DWORD layout;
5896 POINT pt;
5897 TEXTMETRICW tm;
5898 LOGFONTW lf;
5899 double cosEsc, sinEsc;
5900 INT char_extra;
5901 SIZE sz;
5902 RECT rc;
5903 POINT *deltas = NULL, width = {0, 0};
5904 DWORD type;
5905 DC * dc = get_dc_ptr( hdc );
5906 PHYSDEV physdev;
5907 INT breakRem;
5908 static int quietfixme = 0;
5910 if (!dc) return FALSE;
5912 align = dc->textAlign;
5913 breakRem = dc->breakRem;
5914 layout = dc->layout;
5916 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5918 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5919 quietfixme = 1;
5922 update_dc( dc );
5923 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5924 type = GetObjectType(hdc);
5925 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
5927 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
5928 release_dc_ptr( dc );
5929 return ret;
5932 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5933 if (layout & LAYOUT_RTL)
5935 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5936 align ^= TA_RTLREADING;
5939 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
5941 INT cGlyphs;
5942 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
5944 BIDI_Reorder( hdc, str, count, GCP_REORDER,
5945 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
5946 reordered_str, count, NULL, &glyphs, &cGlyphs);
5948 flags |= ETO_IGNORELANGUAGE;
5949 if (glyphs)
5951 flags |= ETO_GLYPH_INDEX;
5952 if (cGlyphs != count)
5953 count = cGlyphs;
5956 else if(flags & ETO_GLYPH_INDEX)
5957 glyphs = reordered_str;
5959 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5960 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5961 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->backgroundMode, dc->MapMode);
5963 if(align & TA_UPDATECP)
5965 pt = dc->cur_pos;
5966 x = pt.x;
5967 y = pt.y;
5970 GetTextMetricsW(hdc, &tm);
5971 GetObjectW(dc->hFont, sizeof(lf), &lf);
5973 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5974 lf.lfEscapement = 0;
5976 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
5977 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5979 lf.lfEscapement = -lf.lfEscapement;
5982 if(lf.lfEscapement != 0)
5984 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5985 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5987 else
5989 cosEsc = 1;
5990 sinEsc = 0;
5993 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5995 rc = *lprect;
5996 lp_to_dp(dc, (POINT*)&rc, 2);
5997 order_rect( &rc );
5998 if (flags & ETO_OPAQUE)
5999 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
6001 else flags &= ~ETO_CLIPPED;
6003 if(count == 0)
6005 ret = TRUE;
6006 goto done;
6009 pt.x = x;
6010 pt.y = y;
6011 lp_to_dp(dc, &pt, 1);
6012 x = pt.x;
6013 y = pt.y;
6015 char_extra = GetTextCharacterExtra(hdc);
6016 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
6017 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
6019 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
6021 UINT i;
6022 POINT total = {0, 0}, desired[2];
6024 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
6025 if (lpDx)
6027 if (flags & ETO_PDY)
6029 for (i = 0; i < count; i++)
6031 deltas[i].x = lpDx[i * 2] + char_extra;
6032 deltas[i].y = -lpDx[i * 2 + 1];
6035 else
6037 for (i = 0; i < count; i++)
6039 deltas[i].x = lpDx[i] + char_extra;
6040 deltas[i].y = 0;
6044 else
6046 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
6048 if (flags & ETO_GLYPH_INDEX)
6049 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
6050 else
6051 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
6053 deltas[0].x = dx[0];
6054 deltas[0].y = 0;
6055 for (i = 1; i < count; i++)
6057 deltas[i].x = dx[i] - dx[i - 1];
6058 deltas[i].y = 0;
6060 HeapFree( GetProcessHeap(), 0, dx );
6063 for(i = 0; i < count; i++)
6065 total.x += deltas[i].x;
6066 total.y += deltas[i].y;
6068 desired[0].x = desired[0].y = 0;
6070 desired[1].x = cosEsc * total.x + sinEsc * total.y;
6071 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
6073 lp_to_dp(dc, desired, 2);
6074 desired[1].x -= desired[0].x;
6075 desired[1].y -= desired[0].y;
6077 if (dc->GraphicsMode == GM_COMPATIBLE)
6079 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6080 desired[1].x = -desired[1].x;
6081 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6082 desired[1].y = -desired[1].y;
6085 deltas[i].x = desired[1].x - width.x;
6086 deltas[i].y = desired[1].y - width.y;
6088 width = desired[1];
6090 flags |= ETO_PDY;
6092 else
6094 POINT desired[2];
6096 if(flags & ETO_GLYPH_INDEX)
6097 GetTextExtentPointI(hdc, glyphs, count, &sz);
6098 else
6099 GetTextExtentPointW(hdc, reordered_str, count, &sz);
6100 desired[0].x = desired[0].y = 0;
6101 desired[1].x = sz.cx;
6102 desired[1].y = 0;
6103 lp_to_dp(dc, desired, 2);
6104 desired[1].x -= desired[0].x;
6105 desired[1].y -= desired[0].y;
6107 if (dc->GraphicsMode == GM_COMPATIBLE)
6109 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6110 desired[1].x = -desired[1].x;
6111 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6112 desired[1].y = -desired[1].y;
6114 width = desired[1];
6117 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
6118 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
6119 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
6121 case TA_LEFT:
6122 if (align & TA_UPDATECP)
6124 pt.x = x + width.x;
6125 pt.y = y + width.y;
6126 dp_to_lp(dc, &pt, 1);
6127 MoveToEx(hdc, pt.x, pt.y, NULL);
6129 break;
6131 case TA_CENTER:
6132 x -= width.x / 2;
6133 y -= width.y / 2;
6134 break;
6136 case TA_RIGHT:
6137 x -= width.x;
6138 y -= width.y;
6139 if (align & TA_UPDATECP)
6141 pt.x = x;
6142 pt.y = y;
6143 dp_to_lp(dc, &pt, 1);
6144 MoveToEx(hdc, pt.x, pt.y, NULL);
6146 break;
6149 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
6151 case TA_TOP:
6152 y += tm.tmAscent * cosEsc;
6153 x += tm.tmAscent * sinEsc;
6154 break;
6156 case TA_BOTTOM:
6157 y -= tm.tmDescent * cosEsc;
6158 x -= tm.tmDescent * sinEsc;
6159 break;
6161 case TA_BASELINE:
6162 break;
6165 if (dc->backgroundMode != TRANSPARENT)
6167 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
6169 if(!(flags & ETO_OPAQUE) || !lprect ||
6170 x < rc.left || x + width.x >= rc.right ||
6171 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
6173 RECT text_box;
6174 text_box.left = x;
6175 text_box.right = x + width.x;
6176 text_box.top = y - tm.tmAscent;
6177 text_box.bottom = y + tm.tmDescent;
6179 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
6180 if (!is_rect_empty( &text_box ))
6181 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
6186 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
6187 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
6189 done:
6190 HeapFree(GetProcessHeap(), 0, deltas);
6191 if(glyphs != reordered_str)
6192 HeapFree(GetProcessHeap(), 0, glyphs);
6193 if(reordered_str != str)
6194 HeapFree(GetProcessHeap(), 0, reordered_str);
6196 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
6198 int underlinePos, strikeoutPos;
6199 int underlineWidth, strikeoutWidth;
6200 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
6201 OUTLINETEXTMETRICW* otm = NULL;
6202 POINT pts[5];
6203 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
6204 HBRUSH hbrush = CreateSolidBrush(dc->textColor);
6206 hbrush = SelectObject(hdc, hbrush);
6208 if(!size)
6210 underlinePos = 0;
6211 underlineWidth = tm.tmAscent / 20 + 1;
6212 strikeoutPos = tm.tmAscent / 2;
6213 strikeoutWidth = underlineWidth;
6215 else
6217 otm = HeapAlloc(GetProcessHeap(), 0, size);
6218 GetOutlineTextMetricsW(hdc, size, otm);
6219 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
6220 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
6221 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
6222 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
6223 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
6224 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
6225 HeapFree(GetProcessHeap(), 0, otm);
6229 if (lf.lfUnderline)
6231 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
6232 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
6233 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
6234 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
6235 pts[2].x = pts[1].x + underlineWidth * sinEsc;
6236 pts[2].y = pts[1].y + underlineWidth * cosEsc;
6237 pts[3].x = pts[0].x + underlineWidth * sinEsc;
6238 pts[3].y = pts[0].y + underlineWidth * cosEsc;
6239 pts[4].x = pts[0].x;
6240 pts[4].y = pts[0].y;
6241 dp_to_lp(dc, pts, 5);
6242 Polygon(hdc, pts, 5);
6245 if (lf.lfStrikeOut)
6247 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6248 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6249 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6250 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6251 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
6252 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
6253 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
6254 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
6255 pts[4].x = pts[0].x;
6256 pts[4].y = pts[0].y;
6257 dp_to_lp(dc, pts, 5);
6258 Polygon(hdc, pts, 5);
6261 SelectObject(hdc, hpen);
6262 hbrush = SelectObject(hdc, hbrush);
6263 DeleteObject(hbrush);
6266 release_dc_ptr( dc );
6268 return ret;
6272 /***********************************************************************
6273 * TextOutA (GDI32.@)
6275 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
6277 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
6281 /***********************************************************************
6282 * TextOutW (GDI32.@)
6284 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
6286 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
6290 /***********************************************************************
6291 * PolyTextOutA (GDI32.@)
6293 * See PolyTextOutW.
6295 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
6297 for (; cStrings>0; cStrings--, pptxt++)
6298 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
6299 return FALSE;
6300 return TRUE;
6305 /***********************************************************************
6306 * PolyTextOutW (GDI32.@)
6308 * Draw several Strings
6310 * RETURNS
6311 * TRUE: Success.
6312 * FALSE: Failure.
6314 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
6316 for (; cStrings>0; cStrings--, pptxt++)
6317 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
6318 return FALSE;
6319 return TRUE;
6323 /***********************************************************************
6324 * SetMapperFlags (GDI32.@)
6326 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
6328 DC *dc = get_dc_ptr( hdc );
6329 DWORD ret = GDI_ERROR;
6331 if (dc)
6333 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
6334 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
6335 if (flags != GDI_ERROR)
6337 ret = dc->mapperFlags;
6338 dc->mapperFlags = flags;
6340 release_dc_ptr( dc );
6342 return ret;
6345 /***********************************************************************
6346 * GetAspectRatioFilterEx (GDI32.@)
6348 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
6350 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
6351 return FALSE;
6355 /***********************************************************************
6356 * GetCharABCWidthsA (GDI32.@)
6358 * See GetCharABCWidthsW.
6360 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
6361 LPABC abc )
6363 INT i, wlen;
6364 LPSTR str;
6365 LPWSTR wstr;
6366 BOOL ret = TRUE;
6368 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
6369 if (str == NULL)
6370 return FALSE;
6372 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
6373 if (wstr == NULL)
6375 HeapFree(GetProcessHeap(), 0, str);
6376 return FALSE;
6379 for(i = 0; i < wlen; i++)
6381 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
6383 ret = FALSE;
6384 break;
6386 abc++;
6389 HeapFree(GetProcessHeap(), 0, str);
6390 HeapFree(GetProcessHeap(), 0, wstr);
6392 return ret;
6396 /******************************************************************************
6397 * GetCharABCWidthsW [GDI32.@]
6399 * Retrieves widths of characters in range.
6401 * PARAMS
6402 * hdc [I] Handle of device context
6403 * firstChar [I] First character in range to query
6404 * lastChar [I] Last character in range to query
6405 * abc [O] Address of character-width structure
6407 * NOTES
6408 * Only works with TrueType fonts
6410 * RETURNS
6411 * Success: TRUE
6412 * Failure: FALSE
6414 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
6415 LPABC abc )
6417 DC *dc = get_dc_ptr(hdc);
6418 PHYSDEV dev;
6419 unsigned int i;
6420 BOOL ret;
6421 TEXTMETRICW tm;
6423 if (!dc) return FALSE;
6425 if (!abc)
6427 release_dc_ptr( dc );
6428 return FALSE;
6431 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
6432 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
6433 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
6435 release_dc_ptr( dc );
6436 return FALSE;
6439 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6440 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
6441 if (ret)
6443 /* convert device units to logical */
6444 for( i = firstChar; i <= lastChar; i++, abc++ ) {
6445 abc->abcA = width_to_LP(dc, abc->abcA);
6446 abc->abcB = width_to_LP(dc, abc->abcB);
6447 abc->abcC = width_to_LP(dc, abc->abcC);
6451 release_dc_ptr( dc );
6452 return ret;
6456 /******************************************************************************
6457 * GetCharABCWidthsI [GDI32.@]
6459 * Retrieves widths of characters in range.
6461 * PARAMS
6462 * hdc [I] Handle of device context
6463 * firstChar [I] First glyphs in range to query
6464 * count [I] Last glyphs in range to query
6465 * pgi [i] Array of glyphs to query
6466 * abc [O] Address of character-width structure
6468 * NOTES
6469 * Only works with TrueType fonts
6471 * RETURNS
6472 * Success: TRUE
6473 * Failure: FALSE
6475 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
6476 LPWORD pgi, LPABC abc)
6478 DC *dc = get_dc_ptr(hdc);
6479 PHYSDEV dev;
6480 unsigned int i;
6481 BOOL ret;
6483 if (!dc) return FALSE;
6485 if (!abc)
6487 release_dc_ptr( dc );
6488 return FALSE;
6491 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6492 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
6493 if (ret)
6495 /* convert device units to logical */
6496 for( i = 0; i < count; i++, abc++ ) {
6497 abc->abcA = width_to_LP(dc, abc->abcA);
6498 abc->abcB = width_to_LP(dc, abc->abcB);
6499 abc->abcC = width_to_LP(dc, abc->abcC);
6503 release_dc_ptr( dc );
6504 return ret;
6508 /***********************************************************************
6509 * GetGlyphOutlineA (GDI32.@)
6511 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
6512 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
6513 LPVOID lpBuffer, const MAT2 *lpmat2 )
6515 if (!lpmat2) return GDI_ERROR;
6517 if(!(fuFormat & GGO_GLYPH_INDEX)) {
6518 UINT cp;
6519 int len;
6520 char mbchs[2];
6521 WCHAR wChar;
6523 cp = GdiGetCodePage(hdc);
6524 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
6525 len = 2;
6526 mbchs[0] = (uChar & 0xff00) >> 8;
6527 mbchs[1] = (uChar & 0xff);
6528 } else {
6529 len = 1;
6530 mbchs[0] = (uChar & 0xff);
6532 wChar = 0;
6533 MultiByteToWideChar(cp, 0, mbchs, len, &wChar, 1);
6534 uChar = wChar;
6537 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
6538 lpmat2);
6541 /***********************************************************************
6542 * GetGlyphOutlineW (GDI32.@)
6544 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
6545 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
6546 LPVOID lpBuffer, const MAT2 *lpmat2 )
6548 DC *dc;
6549 DWORD ret;
6550 PHYSDEV dev;
6552 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
6553 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
6555 if (!lpmat2) return GDI_ERROR;
6557 dc = get_dc_ptr(hdc);
6558 if(!dc) return GDI_ERROR;
6560 uChar &= 0xffff;
6562 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6563 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
6564 release_dc_ptr( dc );
6565 return ret;
6569 /***********************************************************************
6570 * CreateScalableFontResourceA (GDI32.@)
6572 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
6573 LPCSTR lpszResourceFile,
6574 LPCSTR lpszFontFile,
6575 LPCSTR lpszCurrentPath )
6577 LPWSTR lpszResourceFileW = NULL;
6578 LPWSTR lpszFontFileW = NULL;
6579 LPWSTR lpszCurrentPathW = NULL;
6580 int len;
6581 BOOL ret;
6583 if (lpszResourceFile)
6585 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
6586 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6587 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
6590 if (lpszFontFile)
6592 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
6593 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6594 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
6597 if (lpszCurrentPath)
6599 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
6600 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6601 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
6604 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
6605 lpszFontFileW, lpszCurrentPathW);
6607 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
6608 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
6609 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
6611 return ret;
6614 #define NE_FFLAGS_LIBMODULE 0x8000
6615 #define NE_OSFLAGS_WINDOWS 0x02
6617 static const char dos_string[0x40] = "This is a TrueType resource file";
6618 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
6620 #include <pshpack1.h>
6621 struct fontdir
6623 WORD num_of_resources;
6624 WORD res_id;
6625 WORD dfVersion;
6626 DWORD dfSize;
6627 CHAR dfCopyright[60];
6628 WORD dfType;
6629 WORD dfPoints;
6630 WORD dfVertRes;
6631 WORD dfHorizRes;
6632 WORD dfAscent;
6633 WORD dfInternalLeading;
6634 WORD dfExternalLeading;
6635 BYTE dfItalic;
6636 BYTE dfUnderline;
6637 BYTE dfStrikeOut;
6638 WORD dfWeight;
6639 BYTE dfCharSet;
6640 WORD dfPixWidth;
6641 WORD dfPixHeight;
6642 BYTE dfPitchAndFamily;
6643 WORD dfAvgWidth;
6644 WORD dfMaxWidth;
6645 BYTE dfFirstChar;
6646 BYTE dfLastChar;
6647 BYTE dfDefaultChar;
6648 BYTE dfBreakChar;
6649 WORD dfWidthBytes;
6650 DWORD dfDevice;
6651 DWORD dfFace;
6652 DWORD dfReserved;
6653 CHAR szFaceName[LF_FACESIZE];
6655 #include <poppack.h>
6657 #include <pshpack2.h>
6659 struct ne_typeinfo
6661 WORD type_id;
6662 WORD count;
6663 DWORD res;
6666 struct ne_nameinfo
6668 WORD off;
6669 WORD len;
6670 WORD flags;
6671 WORD id;
6672 DWORD res;
6675 struct rsrc_tab
6677 WORD align;
6678 struct ne_typeinfo fontdir_type;
6679 struct ne_nameinfo fontdir_name;
6680 struct ne_typeinfo scalable_type;
6681 struct ne_nameinfo scalable_name;
6682 WORD end_of_rsrc;
6683 BYTE fontdir_res_name[8];
6686 #include <poppack.h>
6688 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
6690 BOOL ret = FALSE;
6691 HANDLE file;
6692 DWORD size, written;
6693 BYTE *ptr, *start;
6694 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
6695 char *font_fileA, *last_part, *ext;
6696 IMAGE_DOS_HEADER dos;
6697 IMAGE_OS2_HEADER ne =
6699 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
6700 0, 0, 0, 0, 0, 0,
6701 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
6702 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
6704 struct rsrc_tab rsrc_tab =
6707 { 0x8007, 1, 0 },
6708 { 0, 0, 0x0c50, 0x2c, 0 },
6709 { 0x80cc, 1, 0 },
6710 { 0, 0, 0x0c50, 0x8001, 0 },
6712 { 7,'F','O','N','T','D','I','R'}
6715 memset( &dos, 0, sizeof(dos) );
6716 dos.e_magic = IMAGE_DOS_SIGNATURE;
6717 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
6719 /* import name is last part\0, resident name is last part without extension
6720 non-resident name is "FONTRES:" + lfFaceName */
6722 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
6723 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
6724 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
6726 last_part = strrchr( font_fileA, '\\' );
6727 if (last_part) last_part++;
6728 else last_part = font_fileA;
6729 import_name_len = strlen( last_part ) + 1;
6731 ext = strchr( last_part, '.' );
6732 if (ext) res_name_len = ext - last_part;
6733 else res_name_len = import_name_len - 1;
6735 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
6737 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
6738 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
6739 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
6740 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
6741 ne.ne_cbenttab = 2;
6742 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
6744 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
6745 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
6746 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
6747 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
6749 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
6750 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
6752 if (!ptr)
6754 HeapFree( GetProcessHeap(), 0, font_fileA );
6755 return FALSE;
6758 memcpy( ptr, &dos, sizeof(dos) );
6759 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
6760 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
6762 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
6763 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
6765 ptr = start + dos.e_lfanew + ne.ne_restab;
6766 *ptr++ = res_name_len;
6767 memcpy( ptr, last_part, res_name_len );
6769 ptr = start + dos.e_lfanew + ne.ne_imptab;
6770 *ptr++ = import_name_len;
6771 memcpy( ptr, last_part, import_name_len );
6773 ptr = start + ne.ne_nrestab;
6774 *ptr++ = non_res_name_len;
6775 memcpy( ptr, FONTRES, sizeof(FONTRES) );
6776 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
6778 ptr = start + (rsrc_tab.scalable_name.off << 4);
6779 memcpy( ptr, font_fileA, font_file_len );
6781 ptr = start + (rsrc_tab.fontdir_name.off << 4);
6782 memcpy( ptr, fontdir, fontdir->dfSize );
6784 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
6785 if (file != INVALID_HANDLE_VALUE)
6787 if (WriteFile( file, start, size, &written, NULL ) && written == size)
6788 ret = TRUE;
6789 CloseHandle( file );
6792 HeapFree( GetProcessHeap(), 0, start );
6793 HeapFree( GetProcessHeap(), 0, font_fileA );
6795 return ret;
6798 /***********************************************************************
6799 * CreateScalableFontResourceW (GDI32.@)
6801 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
6802 LPCWSTR font_file, LPCWSTR font_path )
6804 struct fontdir fontdir = { 0 };
6805 struct gdi_font *font = NULL;
6806 WCHAR path[MAX_PATH];
6808 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
6809 debugstr_w(font_file), debugstr_w(font_path) );
6811 if (!font_funcs) return FALSE;
6813 if (!font_file) goto done;
6814 if (font_path && font_path[0])
6816 int len = lstrlenW( font_path ) + lstrlenW( font_file ) + 2;
6817 if (len > MAX_PATH) goto done;
6818 lstrcpynW( path, font_path, MAX_PATH );
6819 lstrcatW( path, L"\\" );
6820 lstrcatW( path, font_file );
6822 else if (!GetFullPathNameW( font_file, MAX_PATH, path, NULL )) goto done;
6824 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6825 font->lf.lfHeight = 100;
6826 if (!font_funcs->load_font( font )) goto done;
6827 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6829 if (!(font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) goto done;
6831 fontdir.num_of_resources = 1;
6832 fontdir.res_id = 0;
6833 fontdir.dfVersion = 0x200;
6834 fontdir.dfSize = sizeof(fontdir);
6835 strcpy( fontdir.dfCopyright, "Wine fontdir" );
6836 fontdir.dfType = 0x4003; /* 0x0080 set if private */
6837 fontdir.dfPoints = font->otm.otmEMSquare;
6838 fontdir.dfVertRes = 72;
6839 fontdir.dfHorizRes = 72;
6840 fontdir.dfAscent = font->otm.otmTextMetrics.tmAscent;
6841 fontdir.dfInternalLeading = font->otm.otmTextMetrics.tmInternalLeading;
6842 fontdir.dfExternalLeading = font->otm.otmTextMetrics.tmExternalLeading;
6843 fontdir.dfItalic = font->otm.otmTextMetrics.tmItalic;
6844 fontdir.dfUnderline = font->otm.otmTextMetrics.tmUnderlined;
6845 fontdir.dfStrikeOut = font->otm.otmTextMetrics.tmStruckOut;
6846 fontdir.dfWeight = font->otm.otmTextMetrics.tmWeight;
6847 fontdir.dfCharSet = font->otm.otmTextMetrics.tmCharSet;
6848 fontdir.dfPixWidth = 0;
6849 fontdir.dfPixHeight = font->otm.otmTextMetrics.tmHeight;
6850 fontdir.dfPitchAndFamily = font->otm.otmTextMetrics.tmPitchAndFamily;
6851 fontdir.dfAvgWidth = font->otm.otmTextMetrics.tmAveCharWidth;
6852 fontdir.dfMaxWidth = font->otm.otmTextMetrics.tmMaxCharWidth;
6853 fontdir.dfFirstChar = font->otm.otmTextMetrics.tmFirstChar;
6854 fontdir.dfLastChar = font->otm.otmTextMetrics.tmLastChar;
6855 fontdir.dfDefaultChar = font->otm.otmTextMetrics.tmDefaultChar;
6856 fontdir.dfBreakChar = font->otm.otmTextMetrics.tmBreakChar;
6857 fontdir.dfWidthBytes = 0;
6858 fontdir.dfDevice = 0;
6859 fontdir.dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
6860 fontdir.dfReserved = 0;
6861 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)font->otm.otmpFamilyName, -1,
6862 fontdir.szFaceName, LF_FACESIZE, NULL, NULL );
6864 if (hidden) fontdir.dfType |= 0x80;
6865 return create_fot( resource_file, font_file, &fontdir );
6867 done:
6868 if (font) free_gdi_font( font );
6869 SetLastError( ERROR_INVALID_PARAMETER );
6870 return FALSE;
6873 /*************************************************************************
6874 * GetKerningPairsA (GDI32.@)
6876 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
6877 LPKERNINGPAIR kern_pairA )
6879 UINT cp;
6880 CPINFO cpi;
6881 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
6882 KERNINGPAIR *kern_pairW;
6884 if (!cPairs && kern_pairA)
6886 SetLastError(ERROR_INVALID_PARAMETER);
6887 return 0;
6890 cp = GdiGetCodePage(hDC);
6892 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
6893 * to fail on an invalid character for CP_SYMBOL.
6895 cpi.DefaultChar[0] = 0;
6896 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
6898 FIXME("Can't find codepage %u info\n", cp);
6899 return 0;
6902 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
6903 if (!total_kern_pairs) return 0;
6905 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
6906 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
6908 for (i = 0; i < total_kern_pairs; i++)
6910 char first, second;
6912 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
6913 continue;
6915 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
6916 continue;
6918 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
6919 continue;
6921 if (kern_pairA)
6923 if (kern_pairs_copied >= cPairs) break;
6925 kern_pairA->wFirst = (BYTE)first;
6926 kern_pairA->wSecond = (BYTE)second;
6927 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
6928 kern_pairA++;
6930 kern_pairs_copied++;
6933 HeapFree(GetProcessHeap(), 0, kern_pairW);
6935 return kern_pairs_copied;
6938 /*************************************************************************
6939 * GetKerningPairsW (GDI32.@)
6941 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
6942 LPKERNINGPAIR lpKerningPairs )
6944 DC *dc;
6945 DWORD ret;
6946 PHYSDEV dev;
6948 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
6950 if (!cPairs && lpKerningPairs)
6952 SetLastError(ERROR_INVALID_PARAMETER);
6953 return 0;
6956 dc = get_dc_ptr(hDC);
6957 if (!dc) return 0;
6959 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
6960 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
6961 release_dc_ptr( dc );
6962 return ret;
6965 /*************************************************************************
6966 * TranslateCharsetInfo [GDI32.@]
6968 * Fills a CHARSETINFO structure for a character set, code page, or
6969 * font. This allows making the correspondence between different labels
6970 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
6971 * of the same encoding.
6973 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
6974 * only one codepage should be set in *lpSrc.
6976 * RETURNS
6977 * TRUE on success, FALSE on failure.
6980 BOOL WINAPI TranslateCharsetInfo(
6981 LPDWORD lpSrc, /* [in]
6982 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
6983 if flags == TCI_SRCCHARSET: a character set value
6984 if flags == TCI_SRCCODEPAGE: a code page value
6986 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
6987 DWORD flags /* [in] determines interpretation of lpSrc */)
6989 int index = 0;
6990 switch (flags) {
6991 case TCI_SRCFONTSIG:
6992 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
6993 break;
6994 case TCI_SRCCODEPAGE:
6995 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
6996 break;
6997 case TCI_SRCCHARSET:
6998 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
6999 break;
7000 default:
7001 return FALSE;
7003 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
7004 *lpCs = FONT_tci[index];
7005 return TRUE;
7008 /*************************************************************************
7009 * GetFontLanguageInfo (GDI32.@)
7011 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
7013 FONTSIGNATURE fontsig;
7014 static const DWORD GCP_DBCS_MASK=FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB,
7015 GCP_DIACRITIC_MASK=0x00000000,
7016 FLI_GLYPHS_MASK=0x00000000,
7017 GCP_GLYPHSHAPE_MASK=FS_ARABIC,
7018 GCP_KASHIDA_MASK=0x00000000,
7019 GCP_LIGATE_MASK=0x00000000,
7020 GCP_REORDER_MASK=FS_HEBREW|FS_ARABIC;
7022 DWORD result=0;
7024 GetTextCharsetInfo( hdc, &fontsig, 0 );
7025 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
7027 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
7028 result|=GCP_DBCS;
7030 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
7031 result|=GCP_DIACRITIC;
7033 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
7034 result|=FLI_GLYPHS;
7036 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
7037 result|=GCP_GLYPHSHAPE;
7039 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
7040 result|=GCP_KASHIDA;
7042 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
7043 result|=GCP_LIGATE;
7045 if( GetKerningPairsW( hdc, 0, NULL ) )
7046 result|=GCP_USEKERNING;
7048 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
7049 if( GetTextAlign( hdc) & TA_RTLREADING )
7050 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
7051 result|=GCP_REORDER;
7053 return result;
7057 /*************************************************************************
7058 * GetFontData [GDI32.@]
7060 * Retrieve data for TrueType font.
7062 * RETURNS
7064 * success: Number of bytes returned
7065 * failure: GDI_ERROR
7067 * NOTES
7069 * Calls SetLastError()
7072 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
7073 LPVOID buffer, DWORD length)
7075 DC *dc = get_dc_ptr(hdc);
7076 PHYSDEV dev;
7077 DWORD ret;
7079 if(!dc) return GDI_ERROR;
7081 dev = GET_DC_PHYSDEV( dc, pGetFontData );
7082 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
7083 release_dc_ptr( dc );
7084 return ret;
7087 /*************************************************************************
7088 * GetGlyphIndicesA [GDI32.@]
7090 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
7091 LPWORD pgi, DWORD flags)
7093 DWORD ret;
7094 WCHAR *lpstrW;
7095 INT countW;
7097 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7098 hdc, debugstr_an(lpstr, count), count, pgi, flags);
7100 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
7101 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
7102 HeapFree(GetProcessHeap(), 0, lpstrW);
7104 return ret;
7107 /*************************************************************************
7108 * GetGlyphIndicesW [GDI32.@]
7110 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
7111 LPWORD pgi, DWORD flags)
7113 DC *dc = get_dc_ptr(hdc);
7114 PHYSDEV dev;
7115 DWORD ret;
7117 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7118 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
7120 if(!dc) return GDI_ERROR;
7122 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
7123 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
7124 release_dc_ptr( dc );
7125 return ret;
7128 /*************************************************************************
7129 * GetCharacterPlacementA [GDI32.@]
7131 * See GetCharacterPlacementW.
7133 * NOTES:
7134 * the web browser control of ie4 calls this with dwFlags=0
7136 DWORD WINAPI
7137 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
7138 INT nMaxExtent, GCP_RESULTSA *lpResults,
7139 DWORD dwFlags)
7141 WCHAR *lpStringW;
7142 INT uCountW;
7143 GCP_RESULTSW resultsW;
7144 DWORD ret;
7145 UINT font_cp;
7147 TRACE("%s, %d, %d, 0x%08x\n",
7148 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
7150 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
7152 if (!lpResults)
7154 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, NULL, dwFlags);
7155 HeapFree(GetProcessHeap(), 0, lpStringW);
7156 return ret;
7159 /* both structs are equal in size */
7160 memcpy(&resultsW, lpResults, sizeof(resultsW));
7162 if(lpResults->lpOutString)
7163 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
7165 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
7167 lpResults->nGlyphs = resultsW.nGlyphs;
7168 lpResults->nMaxFit = resultsW.nMaxFit;
7170 if(lpResults->lpOutString) {
7171 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
7172 lpResults->lpOutString, uCount, NULL, NULL );
7175 HeapFree(GetProcessHeap(), 0, lpStringW);
7176 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
7178 return ret;
7181 static int kern_pair(const KERNINGPAIR *kern, int count, WCHAR c1, WCHAR c2)
7183 int i;
7185 for (i = 0; i < count; i++)
7187 if (kern[i].wFirst == c1 && kern[i].wSecond == c2)
7188 return kern[i].iKernAmount;
7191 return 0;
7194 static int *kern_string(HDC hdc, const WCHAR *str, int len, int *kern_total)
7196 int i, count;
7197 KERNINGPAIR *kern = NULL;
7198 int *ret;
7200 *kern_total = 0;
7202 ret = heap_alloc(len * sizeof(*ret));
7203 if (!ret) return NULL;
7205 count = GetKerningPairsW(hdc, 0, NULL);
7206 if (count)
7208 kern = heap_alloc(count * sizeof(*kern));
7209 if (!kern)
7211 heap_free(ret);
7212 return NULL;
7215 GetKerningPairsW(hdc, count, kern);
7218 for (i = 0; i < len - 1; i++)
7220 ret[i] = kern_pair(kern, count, str[i], str[i + 1]);
7221 *kern_total += ret[i];
7224 ret[len - 1] = 0; /* no kerning for last element */
7226 heap_free(kern);
7227 return ret;
7230 /*************************************************************************
7231 * GetCharacterPlacementW [GDI32.@]
7233 * Retrieve information about a string. This includes the width, reordering,
7234 * Glyphing and so on.
7236 * RETURNS
7238 * The width and height of the string if successful, 0 if failed.
7240 * BUGS
7242 * All flags except GCP_REORDER are not yet implemented.
7243 * Reordering is not 100% compliant to the Windows BiDi method.
7244 * Caret positioning is not yet implemented for BiDi.
7245 * Classes are not yet implemented.
7248 DWORD WINAPI
7249 GetCharacterPlacementW(
7250 HDC hdc, /* [in] Device context for which the rendering is to be done */
7251 LPCWSTR lpString, /* [in] The string for which information is to be returned */
7252 INT uCount, /* [in] Number of WORDS in string. */
7253 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
7254 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
7255 DWORD dwFlags /* [in] Flags specifying how to process the string */
7258 DWORD ret=0;
7259 SIZE size;
7260 UINT i, nSet;
7261 int *kern = NULL, kern_total = 0;
7263 TRACE("%s, %d, %d, 0x%08x\n",
7264 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
7266 if (!uCount)
7267 return 0;
7269 if (!lpResults)
7270 return GetTextExtentPoint32W(hdc, lpString, uCount, &size) ? MAKELONG(size.cx, size.cy) : 0;
7272 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
7273 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
7274 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
7275 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
7276 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
7278 if (dwFlags & ~(GCP_REORDER | GCP_USEKERNING))
7279 FIXME("flags 0x%08x ignored\n", dwFlags);
7280 if (lpResults->lpClass)
7281 FIXME("classes not implemented\n");
7282 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
7283 FIXME("Caret positions for complex scripts not implemented\n");
7285 nSet = (UINT)uCount;
7286 if (nSet > lpResults->nGlyphs)
7287 nSet = lpResults->nGlyphs;
7289 /* return number of initialized fields */
7290 lpResults->nGlyphs = nSet;
7292 if (!(dwFlags & GCP_REORDER))
7294 /* Treat the case where no special handling was requested in a fastpath way */
7295 /* copy will do if the GCP_REORDER flag is not set */
7296 if (lpResults->lpOutString)
7297 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
7299 if (lpResults->lpOrder)
7301 for (i = 0; i < nSet; i++)
7302 lpResults->lpOrder[i] = i;
7305 else
7307 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
7308 nSet, lpResults->lpOrder, NULL, NULL );
7311 if (dwFlags & GCP_USEKERNING)
7313 kern = kern_string(hdc, lpString, nSet, &kern_total);
7314 if (!kern)
7316 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
7317 return 0;
7321 /* FIXME: Will use the placement chars */
7322 if (lpResults->lpDx)
7324 int c;
7325 for (i = 0; i < nSet; i++)
7327 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
7329 lpResults->lpDx[i] = c;
7330 if (dwFlags & GCP_USEKERNING)
7331 lpResults->lpDx[i] += kern[i];
7336 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
7338 int pos = 0;
7340 lpResults->lpCaretPos[0] = 0;
7341 for (i = 0; i < nSet - 1; i++)
7343 if (dwFlags & GCP_USEKERNING)
7344 pos += kern[i];
7346 if (GetTextExtentPoint32W(hdc, &lpString[i], 1, &size))
7347 lpResults->lpCaretPos[i + 1] = (pos += size.cx);
7351 if (lpResults->lpGlyphs)
7352 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
7354 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
7355 ret = MAKELONG(size.cx + kern_total, size.cy);
7357 heap_free(kern);
7359 return ret;
7362 /*************************************************************************
7363 * GetCharABCWidthsFloatA [GDI32.@]
7365 * See GetCharABCWidthsFloatW.
7367 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
7369 INT i, wlen;
7370 LPSTR str;
7371 LPWSTR wstr;
7372 BOOL ret = TRUE;
7374 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
7375 if (str == NULL)
7376 return FALSE;
7378 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
7380 for (i = 0; i < wlen; i++)
7382 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
7384 ret = FALSE;
7385 break;
7387 abcf++;
7390 HeapFree( GetProcessHeap(), 0, str );
7391 HeapFree( GetProcessHeap(), 0, wstr );
7393 return ret;
7396 /*************************************************************************
7397 * GetCharABCWidthsFloatW [GDI32.@]
7399 * Retrieves widths of a range of characters.
7401 * PARAMS
7402 * hdc [I] Handle to device context.
7403 * first [I] First character in range to query.
7404 * last [I] Last character in range to query.
7405 * abcf [O] Array of LPABCFLOAT structures.
7407 * RETURNS
7408 * Success: TRUE
7409 * Failure: FALSE
7411 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
7413 UINT i;
7414 ABC *abc;
7415 PHYSDEV dev;
7416 BOOL ret = FALSE;
7417 DC *dc = get_dc_ptr( hdc );
7419 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
7421 if (!dc) return FALSE;
7423 if (!abcf) goto done;
7424 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
7426 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
7427 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
7428 if (ret)
7430 /* convert device units to logical */
7431 FLOAT scale = fabs( dc->xformVport2World.eM11 );
7432 for (i = first; i <= last; i++, abcf++)
7434 abcf->abcfA = abc[i - first].abcA * scale;
7435 abcf->abcfB = abc[i - first].abcB * scale;
7436 abcf->abcfC = abc[i - first].abcC * scale;
7439 HeapFree( GetProcessHeap(), 0, abc );
7441 done:
7442 release_dc_ptr( dc );
7443 return ret;
7446 /*************************************************************************
7447 * GetCharWidthFloatA [GDI32.@]
7449 BOOL WINAPI GetCharWidthFloatA( HDC hdc, UINT first, UINT last, float *buffer )
7451 WCHAR *wstr;
7452 int i, wlen;
7453 char *str;
7455 if (!(str = FONT_GetCharsByRangeA( hdc, first, last, &i )))
7456 return FALSE;
7457 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
7458 heap_free(str);
7460 for (i = 0; i < wlen; ++i)
7462 if (!GetCharWidthFloatW( hdc, wstr[i], wstr[i], &buffer[i] ))
7464 heap_free(wstr);
7465 return FALSE;
7468 heap_free(wstr);
7469 return TRUE;
7472 /*************************************************************************
7473 * GetCharWidthFloatW [GDI32.@]
7475 BOOL WINAPI GetCharWidthFloatW( HDC hdc, UINT first, UINT last, float *buffer )
7477 DC *dc = get_dc_ptr( hdc );
7478 int *ibuffer;
7479 PHYSDEV dev;
7480 BOOL ret;
7481 UINT i;
7483 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc, first, last, buffer);
7485 if (!dc) return FALSE;
7487 if (!(ibuffer = heap_alloc( (last - first + 1) * sizeof(int) )))
7489 release_dc_ptr( dc );
7490 return FALSE;
7493 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
7494 if ((ret = dev->funcs->pGetCharWidth( dev, first, last, ibuffer )))
7496 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
7497 for (i = first; i <= last; ++i)
7498 buffer[i - first] = ibuffer[i - first] * scale;
7501 heap_free(ibuffer);
7502 return ret;
7505 /***********************************************************************
7507 * Font Resource API *
7509 ***********************************************************************/
7511 /***********************************************************************
7512 * AddFontResourceA (GDI32.@)
7514 INT WINAPI AddFontResourceA( LPCSTR str )
7516 return AddFontResourceExA( str, 0, NULL);
7519 /***********************************************************************
7520 * AddFontResourceW (GDI32.@)
7522 INT WINAPI AddFontResourceW( LPCWSTR str )
7524 return AddFontResourceExW(str, 0, NULL);
7528 /***********************************************************************
7529 * AddFontResourceExA (GDI32.@)
7531 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
7533 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
7534 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7535 INT ret;
7537 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
7538 ret = AddFontResourceExW(strW, fl, pdv);
7539 HeapFree(GetProcessHeap(), 0, strW);
7540 return ret;
7543 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
7545 HRSRC rsrc = FindResourceW(hModule, name, type);
7546 HGLOBAL hMem = LoadResource(hModule, rsrc);
7547 LPVOID *pMem = LockResource(hMem);
7548 int *num_total = (int *)lParam;
7549 DWORD num_in_res;
7551 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
7552 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
7554 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
7555 return FALSE;
7558 *num_total += num_in_res;
7559 return TRUE;
7562 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
7564 HANDLE file, mapping;
7565 void *ptr;
7567 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
7568 if (file == INVALID_HANDLE_VALUE) return NULL;
7570 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
7572 CloseHandle( file );
7573 return NULL;
7576 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
7577 CloseHandle( file );
7578 if (!mapping) return NULL;
7580 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
7581 CloseHandle( mapping );
7583 return ptr;
7586 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
7588 WORD align, type_id, count;
7589 DWORD res_off;
7591 if (size < rsrc_off + 10) return NULL;
7592 align = *(WORD *)(ptr + rsrc_off);
7593 rsrc_off += 2;
7594 type_id = *(WORD *)(ptr + rsrc_off);
7595 while (type_id && type_id != type)
7597 count = *(WORD *)(ptr + rsrc_off + 2);
7598 rsrc_off += 8 + count * 12;
7599 if (size < rsrc_off + 8) return NULL;
7600 type_id = *(WORD *)(ptr + rsrc_off);
7602 if (!type_id) return NULL;
7603 count = *(WORD *)(ptr + rsrc_off + 2);
7604 if (size < rsrc_off + 8 + count * 12) return NULL;
7605 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
7606 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
7607 if (size < res_off + *len) return NULL;
7608 return ptr + res_off;
7611 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
7613 LARGE_INTEGER size;
7614 BYTE *ptr = map_file( res, &size );
7615 const IMAGE_DOS_HEADER *dos;
7616 const IMAGE_OS2_HEADER *ne;
7617 WORD *fontdir;
7618 char *data;
7619 WCHAR *name = NULL;
7620 DWORD len;
7622 if (!ptr) return NULL;
7624 if (size.u.LowPart < sizeof( *dos )) goto fail;
7625 dos = (const IMAGE_DOS_HEADER *)ptr;
7626 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
7627 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
7628 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
7630 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
7631 if (!fontdir) goto fail;
7632 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
7634 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
7635 if (!data) goto fail;
7636 if (!memchr( data, 0, len )) goto fail;
7638 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
7639 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
7640 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
7642 fail:
7643 UnmapViewOfFile( ptr );
7644 return name;
7647 static int add_system_font_resource( const WCHAR *file, DWORD flags )
7649 WCHAR path[MAX_PATH];
7650 int ret;
7652 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
7653 get_fonts_win_dir_path( file, path );
7654 EnterCriticalSection( &font_cs );
7655 ret = font_funcs->add_font( path, flags );
7656 LeaveCriticalSection( &font_cs );
7657 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
7658 if (!ret)
7660 get_fonts_data_dir_path( file, path );
7661 EnterCriticalSection( &font_cs );
7662 ret = font_funcs->add_font( path, flags );
7663 LeaveCriticalSection( &font_cs );
7665 return ret;
7668 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
7670 WCHAR path[MAX_PATH];
7671 int ret;
7673 get_fonts_win_dir_path( file, path );
7674 if (!(ret = remove_font( path, flags )))
7676 get_fonts_data_dir_path( file, path );
7677 ret = remove_font( path, flags );
7679 return ret;
7682 static int add_font_resource( LPCWSTR file, DWORD flags )
7684 WCHAR path[MAX_PATH];
7685 int ret = 0;
7687 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
7689 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
7691 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
7692 EnterCriticalSection( &font_cs );
7693 ret = font_funcs->add_font( path, addfont_flags );
7694 LeaveCriticalSection( &font_cs );
7697 if (!ret && !wcschr( file, '\\' ))
7698 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
7700 return ret;
7703 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
7705 WCHAR path[MAX_PATH];
7706 BOOL ret = FALSE;
7708 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
7710 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
7712 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
7713 ret = remove_font( path, addfont_flags );
7716 if (!ret && !wcschr( file, '\\' ))
7717 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
7719 return ret;
7722 static void load_system_bitmap_fonts(void)
7724 static const WCHAR * const fonts[] = { L"FONTS.FON", L"OEMFONT.FON", L"FIXEDFON.FON" };
7725 HKEY hkey;
7726 WCHAR data[MAX_PATH];
7727 DWORD i, dlen, type;
7729 if (RegOpenKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &hkey )) return;
7730 for (i = 0; i < ARRAY_SIZE(fonts); i++)
7732 dlen = sizeof(data);
7733 if (!RegQueryValueExW( hkey, fonts[i], 0, &type, (BYTE *)data, &dlen ) && type == REG_SZ)
7734 add_system_font_resource( data, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE );
7736 RegCloseKey( hkey );
7739 static void load_directory_fonts( WCHAR *path, UINT flags )
7741 HANDLE handle;
7742 WIN32_FIND_DATAW data;
7743 WCHAR *p;
7745 p = path + lstrlenW(path) - 1;
7746 TRACE( "loading fonts from %s\n", debugstr_w(path) );
7747 handle = FindFirstFileW( path, &data );
7748 if (handle == INVALID_HANDLE_VALUE) return;
7751 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
7752 lstrcpyW( p, data.cFileName );
7753 font_funcs->add_font( path, flags );
7754 } while (FindNextFileW( handle, &data ));
7755 FindClose( handle );
7758 static void load_file_system_fonts(void)
7760 WCHAR *ptr, *next, path[MAX_PATH], value[1024];
7761 DWORD len = ARRAY_SIZE(value);
7763 /* Windows directory */
7764 get_fonts_win_dir_path( L"*", path );
7765 load_directory_fonts( path, ADDFONT_ADD_TO_CACHE );
7767 /* Wine data directory */
7768 get_fonts_data_dir_path( L"*", path );
7769 load_directory_fonts( path, ADDFONT_ADD_TO_CACHE | ADDFONT_EXTERNAL_FONT );
7771 /* custom paths */
7772 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
7773 if (!RegQueryValueExW( wine_fonts_key, L"Path", NULL, NULL, (BYTE *)value, &len ))
7775 for (ptr = value; ptr; ptr = next)
7777 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
7778 if (next && next - ptr < 2) continue;
7779 lstrcpynW( path, ptr, MAX_PATH - 2 );
7780 lstrcatW( path, L"\\*" );
7781 load_directory_fonts( path, ADDFONT_ADD_TO_CACHE | ADDFONT_EXTERNAL_FONT );
7786 struct external_key
7788 struct wine_rb_entry entry;
7789 BOOL found;
7790 WCHAR value[LF_FULLFACESIZE + 12];
7791 WCHAR path[1];
7794 static int compare_external_key( const void *key, const struct wine_rb_entry *entry )
7796 return facename_compare( key, WINE_RB_ENTRY_VALUE( entry, struct external_key, entry )->value, -1 );
7799 static struct wine_rb_tree external_keys = { compare_external_key };
7801 static HKEY load_external_font_keys(void)
7803 WCHAR value[LF_FULLFACESIZE + 12], path[MAX_PATH];
7804 DWORD i = 0, type, dlen, vlen;
7805 struct external_key *key;
7806 HKEY hkey;
7808 if (RegCreateKeyW( wine_fonts_key, L"External Fonts", &hkey )) return 0;
7810 vlen = ARRAY_SIZE(value);
7811 dlen = sizeof(path);
7812 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)path, &dlen ))
7814 if (type != REG_SZ) goto next;
7815 dlen /= sizeof(WCHAR);
7816 if (!(key = HeapAlloc( GetProcessHeap(), 0, offsetof(struct external_key, path[dlen]) ))) break;
7817 key->found = FALSE;
7818 lstrcpyW( key->value, value );
7819 lstrcpyW( key->path, path );
7820 wine_rb_put( &external_keys, value, &key->entry );
7821 next:
7822 vlen = ARRAY_SIZE(value);
7823 dlen = sizeof(path);
7825 return hkey;
7828 static void update_external_font_keys( HKEY hkey )
7830 HKEY winnt_key = 0, win9x_key = 0;
7831 struct gdi_font_family *family;
7832 struct gdi_font_face *face;
7833 struct wine_rb_entry *entry;
7834 struct external_key *key, *next;
7835 DWORD len;
7836 BOOL skip;
7837 WCHAR value[LF_FULLFACESIZE + 12], path[MAX_PATH];
7838 WCHAR *file;
7840 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
7841 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL );
7842 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
7843 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL );
7845 /* enumerate the fonts and add external ones to the two keys */
7847 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
7849 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
7851 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
7853 lstrcpyW( value, face->full_name );
7854 if (face->scalable) lstrcatW( value, L" (TrueType)" );
7856 if (GetFullPathNameW( face->file, MAX_PATH, path, NULL ))
7857 file = path;
7858 else if ((file = wcsrchr( face->file, '\\' )))
7859 file++;
7860 else
7861 file = face->file;
7863 skip = FALSE;
7864 if ((entry = wine_rb_get( &external_keys, value )))
7866 struct external_key *key = WINE_RB_ENTRY_VALUE( entry, struct external_key, entry );
7867 skip = key->found && !wcsicmp( key->path, file );
7868 wine_rb_remove_key( &external_keys, value );
7869 HeapFree( GetProcessHeap(), 0, key );
7871 if (skip) continue;
7872 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
7873 RegSetValueExW( winnt_key, value, 0, REG_SZ, (BYTE *)file, len );
7874 RegSetValueExW( win9x_key, value, 0, REG_SZ, (BYTE *)file, len );
7875 RegSetValueExW( hkey, value, 0, REG_SZ, (BYTE *)file, len );
7878 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( key, next, &external_keys, struct external_key, entry )
7880 RegDeleteValueW( win9x_key, key->value );
7881 RegDeleteValueW( winnt_key, key->value );
7882 RegDeleteValueW( hkey, key->value );
7883 wine_rb_remove_key( &external_keys, key->value );
7884 HeapFree( GetProcessHeap(), 0, key );
7886 RegCloseKey( win9x_key );
7887 RegCloseKey( winnt_key );
7890 static void load_registry_fonts(void)
7892 WCHAR value[LF_FULLFACESIZE + 12], data[MAX_PATH];
7893 DWORD i = 0, type, dlen, vlen;
7894 struct wine_rb_entry *entry;
7895 HKEY hkey;
7897 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
7898 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
7899 full path as the entry. Also look for any .fon fonts, since ReadFontDir
7900 will skip these. */
7901 if (RegOpenKeyW( HKEY_LOCAL_MACHINE,
7902 is_win9x() ? L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts" :
7903 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey ))
7904 return;
7906 vlen = ARRAY_SIZE(value);
7907 dlen = sizeof(data);
7908 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (LPBYTE)data, &dlen ))
7910 if (type != REG_SZ) goto next;
7911 dlen /= sizeof(WCHAR);
7912 if ((entry = wine_rb_get( &external_keys, value )))
7914 struct external_key *key = WINE_RB_ENTRY_VALUE( entry, struct external_key, entry );
7915 if (!wcsicmp( key->path, data ))
7917 key->found = TRUE;
7918 goto next;
7921 if (data[0] && data[1] == ':')
7922 add_font_resource( data, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE );
7923 else if (dlen >= 6 && !wcsicmp( data + dlen - 5, L".fon" ))
7924 add_system_font_resource( data, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE );
7925 next:
7926 vlen = ARRAY_SIZE(value);
7927 dlen = sizeof(data);
7929 RegCloseKey( hkey );
7932 static const struct font_callback_funcs callback_funcs = { add_gdi_face };
7934 /***********************************************************************
7935 * font_init
7937 void font_init(void)
7939 HANDLE mutex;
7940 DWORD disposition;
7942 if (RegCreateKeyExW( HKEY_CURRENT_USER, L"Software\\Wine\\Fonts", 0, NULL, 0,
7943 KEY_ALL_ACCESS, NULL, &wine_fonts_key, NULL ))
7944 return;
7946 init_font_options();
7947 update_codepage();
7948 if (__wine_init_unix_lib( gdi32_module, DLL_PROCESS_ATTACH, &callback_funcs, &font_funcs )) return;
7950 if (!(mutex = CreateMutexW( NULL, FALSE, L"__WINE_FONT_MUTEX__" ))) return;
7951 WaitForSingleObject( mutex, INFINITE );
7953 RegCreateKeyExW( wine_fonts_key, L"Cache", 0, NULL, REG_OPTION_VOLATILE,
7954 KEY_ALL_ACCESS, NULL, &wine_fonts_cache_key, &disposition );
7956 if (disposition == REG_CREATED_NEW_KEY)
7958 HKEY key = load_external_font_keys();
7959 load_system_bitmap_fonts();
7960 load_file_system_fonts();
7961 load_registry_fonts();
7962 font_funcs->load_fonts();
7963 update_external_font_keys( key );
7964 RegCloseKey( key );
7966 else load_font_list_from_cache();
7968 ReleaseMutex( mutex );
7970 reorder_font_list();
7971 load_gdi_font_subst();
7972 load_gdi_font_replacements();
7973 load_system_links();
7974 dump_gdi_font_list();
7975 dump_gdi_font_subst();
7978 /***********************************************************************
7979 * AddFontResourceExW (GDI32.@)
7981 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD flags, PVOID pdv )
7983 int ret;
7984 WCHAR *filename;
7985 BOOL hidden;
7987 if (!font_funcs) return 1;
7988 if (!(ret = add_font_resource( str, flags )))
7990 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
7991 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
7992 if (hModule != NULL)
7994 int num_resources = 0;
7995 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
7997 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
7998 wine_dbgstr_w(str));
7999 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
8000 ret = num_resources;
8001 FreeLibrary(hModule);
8003 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
8005 if (hidden) flags |= FR_PRIVATE | FR_NOT_ENUM;
8006 ret = add_font_resource( filename, flags );
8007 HeapFree( GetProcessHeap(), 0, filename );
8010 return ret;
8013 /***********************************************************************
8014 * RemoveFontResourceA (GDI32.@)
8016 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
8018 return RemoveFontResourceExA(str, 0, 0);
8021 /***********************************************************************
8022 * RemoveFontResourceW (GDI32.@)
8024 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
8026 return RemoveFontResourceExW(str, 0, 0);
8029 /***********************************************************************
8030 * AddFontMemResourceEx (GDI32.@)
8032 HANDLE WINAPI AddFontMemResourceEx( PVOID ptr, DWORD size, PVOID pdv, DWORD *pcFonts )
8034 HANDLE ret;
8035 DWORD num_fonts;
8036 void *copy;
8038 if (!ptr || !size || !pcFonts)
8040 SetLastError(ERROR_INVALID_PARAMETER);
8041 return NULL;
8043 if (!font_funcs) return NULL;
8044 if (!(copy = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
8045 memcpy( copy, ptr, size );
8047 EnterCriticalSection( &font_cs );
8048 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
8049 LeaveCriticalSection( &font_cs );
8051 if (!num_fonts)
8053 HeapFree( GetProcessHeap(), 0, copy );
8054 return NULL;
8057 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
8058 * For now return something unique but quite random
8060 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
8062 __TRY
8064 *pcFonts = num_fonts;
8066 __EXCEPT_PAGE_FAULT
8068 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
8069 RemoveFontMemResourceEx( ret );
8070 ret = 0;
8072 __ENDTRY
8073 TRACE( "Returning handle %p\n", ret );
8074 return ret;
8077 /***********************************************************************
8078 * RemoveFontMemResourceEx (GDI32.@)
8080 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
8082 FIXME("(%p) stub\n", fh);
8083 return TRUE;
8086 /***********************************************************************
8087 * RemoveFontResourceExA (GDI32.@)
8089 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
8091 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
8092 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8093 INT ret;
8095 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
8096 ret = RemoveFontResourceExW(strW, fl, pdv);
8097 HeapFree(GetProcessHeap(), 0, strW);
8098 return ret;
8101 /***********************************************************************
8102 * RemoveFontResourceExW (GDI32.@)
8104 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD flags, PVOID pdv )
8106 int ret;
8107 WCHAR *filename;
8108 BOOL hidden;
8110 if (!font_funcs) return TRUE;
8112 if (!(ret = remove_font_resource( str, flags )))
8114 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8115 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
8116 if (hModule != NULL)
8118 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
8119 FreeLibrary(hModule);
8121 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
8123 if (hidden) flags |= FR_PRIVATE | FR_NOT_ENUM;
8124 ret = remove_font_resource( filename, flags );
8125 HeapFree( GetProcessHeap(), 0, filename );
8128 return ret;
8131 /***********************************************************************
8132 * GetFontResourceInfoW (GDI32.@)
8134 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
8136 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
8137 return FALSE;
8140 /***********************************************************************
8141 * GetTextCharset (GDI32.@)
8143 UINT WINAPI GetTextCharset(HDC hdc)
8145 /* MSDN docs say this is equivalent */
8146 return GetTextCharsetInfo(hdc, NULL, 0);
8149 /***********************************************************************
8150 * GdiGetCharDimensions (GDI32.@)
8152 * Gets the average width of the characters in the English alphabet.
8154 * PARAMS
8155 * hdc [I] Handle to the device context to measure on.
8156 * lptm [O] Pointer to memory to store the text metrics into.
8157 * height [O] On exit, the maximum height of characters in the English alphabet.
8159 * RETURNS
8160 * The average width of characters in the English alphabet.
8162 * NOTES
8163 * This function is used by the dialog manager to get the size of a dialog
8164 * unit. It should also be used by other pieces of code that need to know
8165 * the size of a dialog unit in logical units without having access to the
8166 * window handle of the dialog.
8167 * Windows caches the font metrics from this function, but we don't and
8168 * there doesn't appear to be an immediate advantage to do so.
8170 * SEE ALSO
8171 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
8173 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
8175 SIZE sz;
8177 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
8179 if(!GetTextExtentPointW(hdc, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52, &sz))
8180 return 0;
8182 if (height) *height = sz.cy;
8183 return (sz.cx / 26 + 1) / 2;
8186 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
8188 FIXME("(%d): stub\n", fEnableEUDC);
8189 return FALSE;
8192 /***********************************************************************
8193 * GetCharWidthI (GDI32.@)
8195 * Retrieve widths of characters.
8197 * PARAMS
8198 * hdc [I] Handle to a device context.
8199 * first [I] First glyph in range to query.
8200 * count [I] Number of glyph indices to query.
8201 * glyphs [I] Array of glyphs to query.
8202 * buffer [O] Buffer to receive character widths.
8204 * NOTES
8205 * Only works with TrueType fonts.
8207 * RETURNS
8208 * Success: TRUE
8209 * Failure: FALSE
8211 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
8213 ABC *abc;
8214 unsigned int i;
8216 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
8218 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
8219 return FALSE;
8221 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
8223 HeapFree(GetProcessHeap(), 0, abc);
8224 return FALSE;
8227 for (i = 0; i < count; i++)
8228 buffer[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
8230 HeapFree(GetProcessHeap(), 0, abc);
8231 return TRUE;
8234 /***********************************************************************
8235 * GetFontUnicodeRanges (GDI32.@)
8237 * Retrieve a list of supported Unicode characters in a font.
8239 * PARAMS
8240 * hdc [I] Handle to a device context.
8241 * lpgs [O] GLYPHSET structure specifying supported character ranges.
8243 * RETURNS
8244 * Success: Number of bytes written to the buffer pointed to by lpgs.
8245 * Failure: 0
8248 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
8250 DWORD ret;
8251 PHYSDEV dev;
8252 DC *dc = get_dc_ptr(hdc);
8254 TRACE("(%p, %p)\n", hdc, lpgs);
8256 if (!dc) return 0;
8258 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
8259 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
8260 release_dc_ptr(dc);
8261 return ret;
8265 /*************************************************************
8266 * FontIsLinked (GDI32.@)
8268 BOOL WINAPI FontIsLinked(HDC hdc)
8270 DC *dc = get_dc_ptr(hdc);
8271 PHYSDEV dev;
8272 BOOL ret;
8274 if (!dc) return FALSE;
8275 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
8276 ret = dev->funcs->pFontIsLinked( dev );
8277 release_dc_ptr(dc);
8278 TRACE("returning %d\n", ret);
8279 return ret;
8282 /*************************************************************
8283 * GetFontRealizationInfo (GDI32.@)
8285 BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info)
8287 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, unk);
8288 PHYSDEV dev;
8289 BOOL ret;
8290 DC *dc;
8292 if (info->size != sizeof(*info) && !is_v0)
8293 return FALSE;
8295 dc = get_dc_ptr(hdc);
8296 if (!dc) return FALSE;
8297 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
8298 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
8299 release_dc_ptr(dc);
8300 return ret;
8303 /*************************************************************************
8304 * GetRasterizerCaps (GDI32.@)
8306 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8308 lprs->nSize = sizeof(RASTERIZER_STATUS);
8309 lprs->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
8310 lprs->nLanguageID = 0;
8311 return TRUE;
8314 /*************************************************************************
8315 * GetFontFileData (GDI32.@)
8317 BOOL WINAPI GetFontFileData( DWORD instance_id, DWORD unknown, UINT64 offset, void *buff, DWORD buff_size )
8319 struct gdi_font *font;
8320 DWORD tag = 0, size;
8321 BOOL ret = FALSE;
8323 if (!font_funcs) return FALSE;
8324 EnterCriticalSection( &font_cs );
8325 if ((font = get_font_from_handle( instance_id )))
8327 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
8328 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
8329 if (size != GDI_ERROR && size >= buff_size && offset <= size - buff_size)
8330 ret = font_funcs->get_font_data( font, tag, offset, buff, buff_size ) != GDI_ERROR;
8331 else
8332 SetLastError( ERROR_INVALID_PARAMETER );
8334 LeaveCriticalSection( &font_cs );
8335 return ret;
8338 /* Undocumented structure filled in by GetFontFileInfo */
8339 struct font_fileinfo
8341 FILETIME writetime;
8342 LARGE_INTEGER size;
8343 WCHAR path[1];
8346 /*************************************************************************
8347 * GetFontFileInfo (GDI32.@)
8349 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info,
8350 SIZE_T size, SIZE_T *needed )
8352 SIZE_T required_size = 0;
8353 struct gdi_font *font;
8354 BOOL ret = FALSE;
8356 EnterCriticalSection( &font_cs );
8358 if ((font = get_font_from_handle( instance_id )))
8360 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
8361 if (required_size <= size)
8363 info->writetime = font->writetime;
8364 info->size.QuadPart = font->data_size;
8365 lstrcpyW( info->path, font->file );
8366 ret = TRUE;
8368 else SetLastError( ERROR_INSUFFICIENT_BUFFER );
8371 LeaveCriticalSection( &font_cs );
8372 if (needed) *needed = required_size;
8373 return ret;
8376 struct realization_info
8378 DWORD flags; /* 1 for bitmap fonts, 3 for scalable fonts */
8379 DWORD cache_num; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
8380 DWORD instance_id; /* identifies a realized font instance */
8383 /*************************************************************
8384 * GdiRealizationInfo (GDI32.@)
8386 * Returns a structure that contains some font information.
8388 BOOL WINAPI GdiRealizationInfo(HDC hdc, struct realization_info *info)
8390 struct font_realization_info ri;
8391 BOOL ret;
8393 ri.size = sizeof(ri);
8394 ret = GetFontRealizationInfo( hdc, &ri );
8395 if (ret)
8397 info->flags = ri.flags;
8398 info->cache_num = ri.cache_num;
8399 info->instance_id = ri.instance_id;
8402 return ret;
8405 /*************************************************************
8406 * GetCharWidthInfo (GDI32.@)
8409 BOOL WINAPI GetCharWidthInfo(HDC hdc, struct char_width_info *info)
8411 PHYSDEV dev;
8412 BOOL ret;
8413 DC *dc;
8415 dc = get_dc_ptr(hdc);
8416 if (!dc) return FALSE;
8417 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
8418 ret = dev->funcs->pGetCharWidthInfo( dev, info );
8420 if (ret)
8422 info->lsb = width_to_LP( dc, info->lsb );
8423 info->rsb = width_to_LP( dc, info->rsb );
8425 release_dc_ptr(dc);
8426 return ret;