include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / win32u / font.c
blob8fb3128f5e0bb9b0c451fbe9bf5ae7811f1b6e78
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 #if 0
24 #pragma makedep unix
25 #endif
27 #include <limits.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <pthread.h>
34 #include "ntstatus.h"
35 #define WIN32_NO_STATUS
36 #include "winerror.h"
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winternl.h"
41 #include "winreg.h"
42 #include "ntgdi_private.h"
44 #include "wine/unixlib.h"
45 #include "wine/rbtree.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(font);
50 static HKEY wine_fonts_key;
51 static HKEY wine_fonts_cache_key;
52 HKEY hkcu_key;
54 struct font_physdev
56 struct gdi_physdev dev;
57 struct gdi_font *font;
60 static inline struct font_physdev *get_font_dev( PHYSDEV dev )
62 return (struct font_physdev *)dev;
65 struct gdi_font_family
67 struct wine_rb_entry name_entry;
68 struct wine_rb_entry second_name_entry;
69 unsigned int refcount;
70 WCHAR family_name[LF_FACESIZE];
71 WCHAR second_name[LF_FACESIZE];
72 struct list faces;
73 struct gdi_font_family *replacement;
76 struct gdi_font_face
78 struct list entry;
79 unsigned int refcount;
80 WCHAR *style_name;
81 WCHAR *full_name;
82 WCHAR *file;
83 void *data_ptr;
84 SIZE_T data_size;
85 UINT face_index;
86 FONTSIGNATURE fs;
87 UINT ntmFlags;
88 UINT version;
89 UINT flags; /* ADDFONT flags */
90 BOOL scalable;
91 struct bitmap_font_size size; /* set if face is a bitmap */
92 struct gdi_font_family *family;
93 struct gdi_font_enum_data *cached_enum_data;
94 struct wine_rb_entry full_name_entry;
97 static const struct font_backend_funcs *font_funcs;
99 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
101 static const WCHAR nt_prefixW[] = {'\\','?','?','\\'};
103 static const WCHAR true_type_suffixW[] = {' ','(','T','r','u','e','T','y','p','e',')',0};
105 static const WCHAR system_link_keyW[] =
107 '\\','R','e','g','i','s','t','r','y',
108 '\\','M','a','c','h','i','n','e',
109 '\\','S','o','f','t','w','a','r','e',
110 '\\','M','i','c','r','o','s','o','f','t',
111 '\\','W','i','n','d','o','w','s',' ','N','T',
112 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
113 '\\','F','o','n','t','L','i','n','k',
114 '\\','S','y','s','t','e','m','L','i','n','k'
117 static const WCHAR associated_charset_keyW[] =
119 '\\','R','e','g','i','s','t','r','y',
120 '\\','M','a','c','h','i','n','e',
121 '\\','S','y','s','t','e','m',
122 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
123 '\\','C','o','n','t','r','o','l',
124 '\\','F','o','n','t','A','s','s','o','c',
125 '\\','A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t'
128 static const WCHAR software_config_keyW[] =
130 '\\','R','e','g','i','s','t','r','y',
131 '\\','M','a','c','h','i','n','e',
132 '\\','S','y','s','t','e','m',
133 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
134 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
135 '\\','C','u','r','r','e','n','t',
136 '\\','S','o','f','t','w','a','r','e',
139 static const WCHAR fonts_config_keyW[] =
141 '\\','R','e','g','i','s','t','r','y',
142 '\\','M','a','c','h','i','n','e',
143 '\\','S','y','s','t','e','m',
144 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
145 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
146 '\\','C','u','r','r','e','n','t',
147 '\\','S','o','f','t','w','a','r','e',
148 '\\','F','o','n','t','s'
151 static const WCHAR fonts_win9x_config_keyW[] =
153 '\\','R','e','g','i','s','t','r','y',
154 '\\','M','a','c','h','i','n','e',
155 '\\','S','o','f','t','w','a','r','e',
156 '\\','M','i','c','r','o','s','o','f','t',
157 '\\','W','i','n','d','o','w','s',
158 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
159 '\\','F','o','n','t','s'
162 static const WCHAR fonts_winnt_config_keyW[] =
164 '\\','R','e','g','i','s','t','r','y',
165 '\\','M','a','c','h','i','n','e',
166 '\\','S','o','f','t','w','a','r','e',
167 '\\','M','i','c','r','o','s','o','f','t',
168 '\\','W','i','n','d','o','w','s',' ','N','T',
169 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
170 '\\','F','o','n','t','s'
173 static const WCHAR font_substitutes_keyW[] =
175 '\\','R','e','g','i','s','t','r','y',
176 '\\','M','a','c','h','i','n','e',
177 '\\','S','o','f','t','w','a','r','e',
178 '\\','M','i','c','r','o','s','o','f','t',
179 '\\','W','i','n','d','o','w','s',' ','N','T',
180 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
181 '\\','F','o','n','t','S','u','b','s','t','i','t','u','t','e','s'
184 static const WCHAR font_assoc_keyW[] =
186 '\\','R','e','g','i','s','t','r','y',
187 '\\','M','a','c','h','i','n','e',
188 '\\','S','y','s','t','e','m',
189 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
190 '\\','C','o','n','t','r','o','l',
191 '\\','F','o','n','t','A','s','s','o','c'
194 static UINT font_smoothing = GGO_BITMAP;
195 static UINT subpixel_orientation = GGO_GRAY4_BITMAP;
196 static BOOL antialias_fakes = TRUE;
197 static struct font_gamma_ramp font_gamma_ramp;
199 static void add_face_to_cache( struct gdi_font_face *face );
200 static void remove_face_from_cache( struct gdi_font_face *face );
202 static CPTABLEINFO utf8_cp;
203 static CPTABLEINFO oem_cp;
204 CPTABLEINFO ansi_cp = { 0 };
206 static inline WCHAR facename_tolower( WCHAR c )
208 if (c >= 'A' && c <= 'Z') return c - 'A' + 'a';
209 else if (c > 127) return RtlDowncaseUnicodeChar( c );
210 else return c;
213 static inline int facename_compare( const WCHAR *str1, const WCHAR *str2, SIZE_T len )
215 while (len--)
217 WCHAR c1 = facename_tolower( *str1++ ), c2 = facename_tolower( *str2++ );
218 if (c1 != c2) return c1 - c2;
219 else if (!c1) return 0;
221 return 0;
224 /* Device -> World size conversion */
226 /* Performs a device to world transformation on the specified width (which
227 * is in integer format).
229 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
231 double floatWidth;
233 /* Perform operation with floating point */
234 floatWidth = (double)width * dc->xformVport2World.eM11;
235 /* Round to integers */
236 return GDI_ROUND(floatWidth);
239 /* Performs a device to world transformation on the specified size (which
240 * is in integer format).
242 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
244 double floatHeight;
246 /* Perform operation with floating point */
247 floatHeight = (double)height * dc->xformVport2World.eM22;
248 /* Round to integers */
249 return GDI_ROUND(floatHeight);
252 /* scale width and height but don't mirror them */
254 static inline INT width_to_LP( DC *dc, INT width )
256 return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
259 static inline INT height_to_LP( DC *dc, INT height )
261 return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
264 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
266 POINT pt[2];
267 pt[0].x = pt[0].y = 0;
268 pt[1].x = 0;
269 pt[1].y = height;
270 lp_to_dp(dc, pt, 2);
271 return pt[1].y - pt[0].y;
274 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
275 static BOOL FONT_DeleteObject( HGDIOBJ handle );
277 static const struct gdi_obj_funcs fontobj_funcs =
279 FONT_GetObjectW, /* pGetObjectW */
280 NULL, /* pUnrealizeObject */
281 FONT_DeleteObject /* pDeleteObject */
284 typedef struct
286 struct gdi_obj_header obj;
287 LOGFONTW logfont;
288 } FONTOBJ;
290 /* for translate_charset_info */
291 static const CHARSETINFO charset_info[] =
293 { ANSI_CHARSET, 1252, { {0}, { FS_LATIN1 }}},
294 { EASTEUROPE_CHARSET, 1250, { {0}, { FS_LATIN2 }}},
295 { RUSSIAN_CHARSET, 1251, { {0}, { FS_CYRILLIC }}},
296 { GREEK_CHARSET, 1253, { {0}, { FS_GREEK }}},
297 { TURKISH_CHARSET, 1254, { {0}, { FS_TURKISH }}},
298 { HEBREW_CHARSET, 1255, { {0}, { FS_HEBREW }}},
299 { ARABIC_CHARSET, 1256, { {0}, { FS_ARABIC }}},
300 { BALTIC_CHARSET, 1257, { {0}, { FS_BALTIC }}},
301 { VIETNAMESE_CHARSET, 1258, { {0}, { FS_VIETNAMESE }}},
302 { THAI_CHARSET, 874, { {0}, { FS_THAI }}},
303 { SHIFTJIS_CHARSET, 932, { {0}, { FS_JISJAPAN }}},
304 { GB2312_CHARSET, 936, { {0}, { FS_CHINESESIMP }}},
305 { HANGEUL_CHARSET, 949, { {0}, { FS_WANSUNG }}},
306 { CHINESEBIG5_CHARSET, 950, { {0}, { FS_CHINESETRAD }}},
307 { JOHAB_CHARSET, 1361, { {0}, { FS_JOHAB }}},
308 { 254, CP_UTF8, { {0}, { 0x04000000 }}},
309 { SYMBOL_CHARSET, CP_SYMBOL, { {0}, { FS_SYMBOL }}}
312 static const char * const default_serif_list[3] =
314 "Times New Roman",
315 "Liberation Serif",
316 "Bitstream Vera Serif"
318 static const char * const default_fixed_list[3] =
320 "Courier New",
321 "Liberation Mono",
322 "Bitstream Vera Sans Mono"
324 static const char * const default_sans_list[3] =
326 "Arial",
327 "Liberation Sans",
328 "Bitstream Vera Sans"
330 static WCHAR ff_roman_default[LF_FACESIZE];
331 static WCHAR ff_modern_default[LF_FACESIZE];
332 static WCHAR ff_swiss_default[LF_FACESIZE];
334 static const struct nls_update_font_list
336 UINT ansi_cp, oem_cp;
337 const char *oem, *fixed, *system;
338 const char *courier, *serif, *small, *sserif_96, *sserif_120;
339 /* these are for font substitutes */
340 const char *shelldlg, *tmsrmn;
341 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0, *helv_0, *tmsrmn_0;
342 struct subst { const char *from, *to; } arial_0, courier_new_0, times_new_roman_0;
343 } nls_update_font_list[] =
345 /* Latin 1 (United States) */
346 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
347 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
348 "Tahoma","Times New Roman"
350 /* Latin 1 (Multilingual) */
351 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
352 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
353 "Tahoma","Times New Roman" /* FIXME unverified */
355 /* UTF-8 */
356 { CP_UTF8, CP_UTF8, "vga850.fon", "vgafix.fon", "vgasys.fon",
357 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
358 "Tahoma", "Times New Roman" /* FIXME unverified */
360 /* Eastern Europe */
361 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
362 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
363 "Tahoma","Times New Roman", /* FIXME unverified */
364 "Fixedsys,238", "System,238",
365 "Courier New,238", "MS Serif,238", "Small Fonts,238",
366 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
367 { "Arial CE,0", "Arial,238" },
368 { "Courier New CE,0", "Courier New,238" },
369 { "Times New Roman CE,0", "Times New Roman,238" }
371 /* Cyrillic */
372 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
373 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
374 "Tahoma","Times New Roman", /* FIXME unverified */
375 "Fixedsys,204", "System,204",
376 "Courier New,204", "MS Serif,204", "Small Fonts,204",
377 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
378 { "Arial Cyr,0", "Arial,204" },
379 { "Courier New Cyr,0", "Courier New,204" },
380 { "Times New Roman Cyr,0", "Times New Roman,204" }
382 /* Greek */
383 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
384 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
385 "Tahoma","Times New Roman", /* FIXME unverified */
386 "Fixedsys,161", "System,161",
387 "Courier New,161", "MS Serif,161", "Small Fonts,161",
388 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
389 { "Arial Greek,0", "Arial,161" },
390 { "Courier New Greek,0", "Courier New,161" },
391 { "Times New Roman Greek,0", "Times New Roman,161" }
393 /* Turkish */
394 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
395 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
396 "Tahoma","Times New Roman", /* FIXME unverified */
397 "Fixedsys,162", "System,162",
398 "Courier New,162", "MS Serif,162", "Small Fonts,162",
399 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
400 { "Arial Tur,0", "Arial,162" },
401 { "Courier New Tur,0", "Courier New,162" },
402 { "Times New Roman Tur,0", "Times New Roman,162" }
404 /* Hebrew */
405 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
406 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
407 "Tahoma","Times New Roman", /* FIXME unverified */
408 "Fixedsys,177", "System,177",
409 "Courier New,177", "MS Serif,177", "Small Fonts,177",
410 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
412 /* Arabic */
413 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
414 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
415 "Microsoft Sans Serif","Times New Roman",
416 "Fixedsys,178", "System,178",
417 "Courier New,178", "MS Serif,178", "Small Fonts,178",
418 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
420 /* Baltic */
421 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
422 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
423 "Tahoma","Times New Roman", /* FIXME unverified */
424 "Fixedsys,186", "System,186",
425 "Courier New,186", "MS Serif,186", "Small Fonts,186",
426 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
427 { "Arial Baltic,0", "Arial,186" },
428 { "Courier New Baltic,0", "Courier New,186" },
429 { "Times New Roman Baltic,0", "Times New Roman,186" }
431 /* Vietnamese */
432 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
433 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
434 "Tahoma","Times New Roman" /* FIXME unverified */
436 /* Thai */
437 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
438 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
439 "Tahoma","Times New Roman" /* FIXME unverified */
441 /* Japanese */
442 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
443 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
444 "MS UI Gothic","MS Serif"
446 /* Chinese Simplified */
447 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
449 "SimSun", "NSimSun"
451 /* Korean */
452 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
453 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
454 "Gulim", "Batang"
456 /* Chinese Traditional */
457 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
458 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
459 "PMingLiU", "MingLiU"
463 static pthread_mutex_t font_lock = PTHREAD_MUTEX_INITIALIZER;
465 #ifdef WORDS_BIGENDIAN
466 #define GET_BE_WORD(x) (x)
467 #define GET_BE_DWORD(x) (x)
468 #else
469 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
470 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
471 #endif
473 static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
475 const char *dir = ntdll_get_build_dir();
476 ULONG len = MAX_PATH;
478 if (!dir) dir = ntdll_get_data_dir();
479 wine_unix_to_nt_file_name( dir, path, &len );
480 asciiz_to_unicode( path + len - 1, "\\fonts\\" );
481 if (file) lstrcatW( path, file );
484 static void get_fonts_win_dir_path( const WCHAR *file, WCHAR *path )
486 asciiz_to_unicode( path, "\\??\\C:\\windows\\fonts\\" );
487 if (file) lstrcatW( path, file );
490 HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len )
492 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
493 OBJECT_ATTRIBUTES attr;
494 HANDLE ret;
496 attr.Length = sizeof(attr);
497 attr.RootDirectory = root;
498 attr.ObjectName = &nameW;
499 attr.Attributes = 0;
500 attr.SecurityDescriptor = NULL;
501 attr.SecurityQualityOfService = NULL;
503 if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0;
504 return ret;
507 HKEY reg_open_ascii_key( HKEY root, const char *name )
509 WCHAR nameW[MAX_PATH];
510 return reg_open_key( root, nameW, asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) );
513 /* wrapper for NtCreateKey that creates the key recursively if necessary */
514 HKEY reg_create_key( HKEY root, const WCHAR *name, ULONG name_len,
515 DWORD options, DWORD *disposition )
517 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
518 OBJECT_ATTRIBUTES attr;
519 NTSTATUS status;
520 HANDLE ret;
522 attr.Length = sizeof(attr);
523 attr.RootDirectory = root;
524 attr.ObjectName = &nameW;
525 attr.Attributes = 0;
526 attr.SecurityDescriptor = NULL;
527 attr.SecurityQualityOfService = NULL;
529 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, options, disposition );
530 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
532 static const WCHAR registry_rootW[] = { '\\','R','e','g','i','s','t','r','y','\\' };
533 DWORD pos = 0, i = 0, len = name_len / sizeof(WCHAR);
535 /* don't try to create registry root */
536 if (!root && len > ARRAY_SIZE(registry_rootW) &&
537 !memcmp( name, registry_rootW, sizeof(registry_rootW) ))
538 i += ARRAY_SIZE(registry_rootW);
540 while (i < len && name[i] != '\\') i++;
541 if (i == len) return 0;
542 for (;;)
544 unsigned int subkey_options = options;
545 if (i < len) subkey_options &= ~(REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK);
546 nameW.Buffer = (WCHAR *)name + pos;
547 nameW.Length = (i - pos) * sizeof(WCHAR);
548 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, subkey_options, disposition );
550 if (attr.RootDirectory != root) NtClose( attr.RootDirectory );
551 if (!NT_SUCCESS(status)) return 0;
552 if (i == len) break;
553 attr.RootDirectory = ret;
554 while (i < len && name[i] == '\\') i++;
555 pos = i;
556 while (i < len && name[i] != '\\') i++;
559 return ret;
562 HKEY reg_create_ascii_key( HKEY root, const char *name, DWORD options,
563 DWORD *disposition )
565 WCHAR nameW[MAX_PATH];
566 return reg_create_key( root, nameW, asciiz_to_unicode( nameW, name ) - sizeof(WCHAR),
567 options, disposition );
570 HKEY reg_open_hkcu_key( const char *name )
572 return reg_open_ascii_key( hkcu_key, name );
575 BOOL set_reg_value( HKEY hkey, const WCHAR *name, UINT type, const void *value, DWORD count )
577 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
578 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
579 return !NtSetValueKey( hkey, &nameW, 0, type, value, count );
582 void set_reg_ascii_value( HKEY hkey, const char *name, const char *value )
584 WCHAR nameW[64], valueW[128];
585 asciiz_to_unicode( nameW, name );
586 set_reg_value( hkey, nameW, REG_SZ, valueW, asciiz_to_unicode( valueW, value ));
589 ULONG query_reg_value( HKEY hkey, const WCHAR *name,
590 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
592 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
593 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
595 if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
596 info, size, &size ))
597 return 0;
599 return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
602 ULONG query_reg_ascii_value( HKEY hkey, const char *name,
603 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
605 WCHAR nameW[64];
606 asciiz_to_unicode( nameW, name );
607 return query_reg_value( hkey, nameW, info, size );
610 static BOOL reg_enum_value( HKEY hkey, unsigned int index, KEY_VALUE_FULL_INFORMATION *info,
611 ULONG size, WCHAR *name, ULONG name_size )
613 ULONG full_size;
615 if (NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
616 info, size, &full_size ))
617 return FALSE;
619 if (name_size)
621 if (name_size < info->NameLength + sizeof(WCHAR)) return FALSE;
622 memcpy( name, info->Name, info->NameLength );
623 name[info->NameLength / sizeof(WCHAR)] = 0;
625 return TRUE;
628 void reg_delete_value( HKEY hkey, const WCHAR *name )
630 unsigned int name_size = lstrlenW( name ) * sizeof(WCHAR);
631 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
632 NtDeleteValueKey( hkey, &nameW );
635 BOOL reg_delete_tree( HKEY parent, const WCHAR *name, ULONG name_len )
637 char buffer[4096];
638 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
639 DWORD size;
640 HKEY key;
641 BOOL ret = TRUE;
643 if (!(key = reg_open_key( parent, name, name_len ))) return FALSE;
645 while (ret && !NtEnumerateKey( key, 0, KeyNodeInformation, key_info, sizeof(buffer), &size ))
646 ret = reg_delete_tree( key, key_info->Name, key_info->NameLength );
648 if (ret) ret = !NtDeleteKey( key );
649 NtClose( key );
650 return ret;
653 /* font substitutions */
655 struct gdi_font_subst
657 struct list entry;
658 int from_charset;
659 int to_charset;
660 WCHAR names[1];
663 static struct list font_subst_list = LIST_INIT(font_subst_list);
665 static inline WCHAR *get_subst_to_name( struct gdi_font_subst *subst )
667 return subst->names + lstrlenW( subst->names ) + 1;
670 static void dump_gdi_font_subst(void)
672 struct gdi_font_subst *subst;
674 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
676 if (subst->from_charset != -1 || subst->to_charset != -1)
677 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst->names),
678 subst->from_charset, debugstr_w(get_subst_to_name(subst)), subst->to_charset);
679 else
680 TRACE("%s -> %s\n", debugstr_w(subst->names), debugstr_w(get_subst_to_name(subst)));
684 static const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset )
686 struct gdi_font_subst *subst;
688 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
690 if (!facename_compare( subst->names, from_name, -1 ) &&
691 (subst->from_charset == from_charset || subst->from_charset == -1))
693 if (to_charset) *to_charset = subst->to_charset;
694 return get_subst_to_name( subst );
697 return NULL;
700 static BOOL add_gdi_font_subst( const WCHAR *from_name, int from_charset, const WCHAR *to_name, int to_charset )
702 struct gdi_font_subst *subst;
703 int len = lstrlenW( from_name ) + lstrlenW( to_name ) + 2;
705 if (get_gdi_font_subst( from_name, from_charset, NULL )) return FALSE; /* already exists */
707 if (!(subst = malloc( offsetof( struct gdi_font_subst, names[len] ) )))
708 return FALSE;
709 lstrcpyW( subst->names, from_name );
710 lstrcpyW( get_subst_to_name(subst), to_name );
711 subst->from_charset = from_charset;
712 subst->to_charset = to_charset;
713 list_add_tail( &font_subst_list, &subst->entry );
714 return TRUE;
717 static void load_gdi_font_subst(void)
719 char buffer[512];
720 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
721 HKEY hkey;
722 DWORD i = 0;
723 WCHAR *data, *p, value[64];
725 if (!(hkey = reg_open_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW) )))
726 return;
728 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
730 int from_charset = -1, to_charset = -1;
732 if (info->Type != REG_SZ) continue;
733 data = (WCHAR *)((char *)info + info->DataOffset);
735 TRACE( "Got %s=%s\n", debugstr_w(value), debugstr_w(data) );
736 if ((p = wcsrchr( value, ',' )) && p[1])
738 *p++ = 0;
739 from_charset = wcstol( p, NULL, 10 );
741 if ((p = wcsrchr( data, ',' )) && p[1])
743 *p++ = 0;
744 to_charset = wcstol( p, NULL, 10 );
747 /* Win 2000 doesn't allow mapping between different charsets
748 or mapping of DEFAULT_CHARSET */
749 if ((!from_charset || to_charset == from_charset) && to_charset != DEFAULT_CHARSET)
750 add_gdi_font_subst( value, from_charset, data, to_charset );
752 NtClose( hkey );
755 /* font families */
757 static int family_namecmp( const WCHAR *str1, const WCHAR *str2 )
759 int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0);
761 if (!facename_compare( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0;
762 else if (!facename_compare( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1;
763 else if (!facename_compare( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2;
764 else prio1 = 3;
766 if (!facename_compare( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0;
767 else if (!facename_compare( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1;
768 else if (!facename_compare( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2;
769 else prio2 = 3;
771 if (prio1 != prio2) return prio1 - prio2;
772 if (vert1 != vert2) return vert1 - vert2;
773 return facename_compare( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 );
776 static int family_name_compare( const void *key, const struct wine_rb_entry *entry )
778 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, name_entry );
779 return family_namecmp( (const WCHAR *)key, family->family_name );
782 static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry )
784 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, second_name_entry );
785 return family_namecmp( (const WCHAR *)key, family->second_name );
788 static int face_full_name_compare( const void *key, const struct wine_rb_entry *entry )
790 const struct gdi_font_face *face = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_face, full_name_entry );
791 return facename_compare( (const WCHAR *)key, face->full_name, LF_FULLFACESIZE - 1 );
794 static struct wine_rb_tree family_name_tree = { family_name_compare };
795 static struct wine_rb_tree family_second_name_tree = { family_second_name_compare };
796 static struct wine_rb_tree face_full_name_tree = { face_full_name_compare };
798 static int face_is_in_full_name_tree( const struct gdi_font_face *face )
800 return face->full_name_entry.parent || face_full_name_tree.root == &face->full_name_entry;
803 static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name )
805 struct gdi_font_family *family = malloc( sizeof(*family) );
807 family->refcount = 1;
808 lstrcpynW( family->family_name, name, LF_FACESIZE );
809 if (second_name && second_name[0] && wcsicmp( name, second_name ))
811 lstrcpynW( family->second_name, second_name, LF_FACESIZE );
812 add_gdi_font_subst( second_name, -1, name, -1 );
814 else family->second_name[0] = 0;
815 list_init( &family->faces );
816 family->replacement = NULL;
817 wine_rb_put( &family_name_tree, family->family_name, &family->name_entry );
818 if (family->second_name[0]) wine_rb_put( &family_second_name_tree, family->second_name, &family->second_name_entry );
819 return family;
822 static void release_family( struct gdi_font_family *family )
824 if (--family->refcount) return;
825 assert( list_empty( &family->faces ));
826 wine_rb_remove( &family_name_tree, &family->name_entry );
827 if (family->second_name[0]) wine_rb_remove( &family_second_name_tree, &family->second_name_entry );
828 if (family->replacement) release_family( family->replacement );
829 free( family );
832 static struct gdi_font_family *find_family_from_name( const WCHAR *name )
834 struct wine_rb_entry *entry;
835 if (!(entry = wine_rb_get( &family_name_tree, name ))) return NULL;
836 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, name_entry );
839 static struct gdi_font_family *find_family_from_any_name( const WCHAR *name )
841 struct wine_rb_entry *entry;
842 struct gdi_font_family *family;
843 if ((family = find_family_from_name( name ))) return family;
844 if (!(entry = wine_rb_get( &family_second_name_tree, name ))) return NULL;
845 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, second_name_entry );
848 static struct gdi_font_face *find_face_from_full_name( const WCHAR *full_name )
850 struct wine_rb_entry *entry;
851 if (!(entry = wine_rb_get( &face_full_name_tree, full_name ))) return NULL;
852 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_face, full_name_entry );
855 static const struct list *get_family_face_list( const struct gdi_font_family *family )
857 return family->replacement ? &family->replacement->faces : &family->faces;
860 static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name )
862 struct gdi_font_face *face;
863 const WCHAR *file;
864 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
866 if (!face->file) continue;
867 file = wcsrchr(face->file, '\\');
868 if (!file) file = face->file;
869 else file++;
870 if (wcsicmp( file, file_name )) continue;
871 face->refcount++;
872 return face;
874 return NULL;
877 static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name )
879 struct gdi_font_family *family;
880 struct gdi_font_face *face;
882 TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
884 if (!family_name)
886 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
887 if ((face = family_find_face_from_filename( family, file_name ))) return face;
888 return NULL;
891 if (!(family = find_family_from_name( family_name ))) return NULL;
892 return family_find_face_from_filename( family, file_name );
895 static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
897 struct gdi_font_family *new_family, *family;
898 struct gdi_font_face *face;
899 WCHAR new_name_vert[LF_FACESIZE], replace_vert[LF_FACESIZE];
901 if (!(family = find_family_from_any_name( replace )))
903 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace) );
904 return FALSE;
907 if (family->replacement)
909 TRACE( "%s is replaced by another font, skipping.\n", debugstr_w(replace) );
910 return FALSE;
913 if (!(new_family = create_family( new_name, NULL ))) return FALSE;
914 new_family->replacement = family;
915 family->refcount++;
916 TRACE( "mapping %s to %s\n", debugstr_w(replace), debugstr_w(new_name) );
918 /* also add replacement for vertical font if necessary */
919 if (replace[0] == '@') return TRUE;
920 if (list_empty( &family->faces )) return TRUE;
921 face = LIST_ENTRY( list_head(&family->faces), struct gdi_font_face, entry );
922 if (!(face->fs.fsCsb[0] & FS_DBCS_MASK)) return TRUE;
924 new_name_vert[0] = '@';
925 lstrcpynW( new_name_vert + 1, new_name, LF_FACESIZE - 1 );
926 if (find_family_from_any_name( new_name_vert )) return TRUE; /* already exists */
928 replace_vert[0] = '@';
929 lstrcpynW( replace_vert + 1, replace, LF_FACESIZE - 1 );
930 add_family_replacement( new_name_vert, replace_vert );
931 return TRUE;
935 * The replacement list is a way to map an entire font
936 * family onto another family. For example adding
938 * [HKCU\Software\Wine\Fonts\Replacements]
939 * "Wingdings"="Winedings"
941 * would enumerate the Winedings font both as Winedings and
942 * Wingdings. However if a real Wingdings font is present the
943 * replacement does not take place.
945 static void load_gdi_font_replacements(void)
947 char buffer[2048];
948 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
949 HKEY hkey;
950 DWORD i = 0;
951 WCHAR value[LF_FACESIZE];
953 static const WCHAR replacementsW[] = {'R','e','p','l','a','c','e','m','e','n','t','s'};
955 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
956 if (!(hkey = reg_open_key( wine_fonts_key, replacementsW, sizeof(replacementsW) ))) return;
958 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
960 WCHAR *data = (WCHAR *)((char *)info + info->DataOffset);
961 /* "NewName"="Oldname" */
962 if (!find_family_from_any_name( value ))
964 if (info->Type == REG_MULTI_SZ)
966 WCHAR *replace = data;
967 while (*replace)
969 if (add_family_replacement( value, replace )) break;
970 replace += lstrlenW(replace) + 1;
973 else if (info->Type == REG_SZ) add_family_replacement( value, data );
975 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
977 NtClose( hkey );
980 static void dump_gdi_font_list(void)
982 struct gdi_font_family *family;
983 struct gdi_font_face *face;
985 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
987 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
988 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
990 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
991 (int)face->fs.fsCsb[0] );
992 if (!face->scalable) TRACE(" %d", face->size.height );
993 TRACE("\n");
998 static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
1000 if (index < 3)
1002 const char * const *defaults;
1004 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
1005 defaults = default_fixed_list;
1006 else if ((pitch_and_family & 0xf0) == FF_ROMAN)
1007 defaults = default_serif_list;
1008 else
1009 defaults = default_sans_list;
1010 asciiz_to_unicode( buffer, defaults[index] );
1011 return TRUE;
1013 return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
1016 static void set_default_family( DWORD pitch_and_family, WCHAR *default_name )
1018 struct wine_rb_entry *entry;
1019 WCHAR name[LF_FACESIZE];
1020 int i = 0;
1022 while (enum_fallbacks( pitch_and_family, i++, name ))
1024 if (!(entry = wine_rb_get( &family_name_tree, name ))) continue;
1025 wine_rb_remove( &family_name_tree, entry );
1026 lstrcpynW( default_name, name, LF_FACESIZE - 1 );
1027 wine_rb_put( &family_name_tree, name, entry );
1028 return;
1032 static void reorder_font_list(void)
1034 set_default_family( FF_ROMAN, ff_roman_default );
1035 set_default_family( FF_MODERN, ff_modern_default );
1036 set_default_family( FF_SWISS, ff_swiss_default );
1039 static void release_face( struct gdi_font_face *face )
1041 if (--face->refcount) return;
1042 if (face->family)
1044 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1045 list_remove( &face->entry );
1046 release_family( face->family );
1048 if (face_is_in_full_name_tree( face )) wine_rb_remove( &face_full_name_tree, &face->full_name_entry );
1049 free( face->file );
1050 free( face->style_name );
1051 free( face->full_name );
1052 free( face->cached_enum_data );
1053 free( face );
1056 static int remove_font( const WCHAR *file, DWORD flags )
1058 struct gdi_font_family *family, *family_next;
1059 struct gdi_font_face *face, *face_next;
1060 int count = 0;
1062 pthread_mutex_lock( &font_lock );
1063 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_name_tree, struct gdi_font_family, name_entry )
1065 family->refcount++;
1066 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry )
1068 if (!face->file) continue;
1069 if (LOWORD(face->flags) != LOWORD(flags)) continue;
1070 if (!wcsicmp( face->file, file ))
1072 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
1073 release_face( face );
1074 count++;
1077 release_family( family );
1079 pthread_mutex_unlock( &font_lock );
1080 return count;
1083 static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
1085 if (facename_compare( f1->full_name, f2->full_name, -1 )) return FALSE;
1086 if (f1->scalable) return TRUE;
1087 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1088 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1091 static inline int style_order( const struct gdi_font_face *face )
1093 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1095 case NTM_REGULAR:
1096 return 0;
1097 case NTM_BOLD:
1098 return 1;
1099 case NTM_ITALIC:
1100 return 2;
1101 case NTM_BOLD | NTM_ITALIC:
1102 return 3;
1103 default:
1104 WARN( "Don't know how to order face %s with flags 0x%08x\n",
1105 debugstr_w(face->full_name), face->ntmFlags );
1106 return 9999;
1110 static BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
1112 struct gdi_font_face *cursor;
1114 LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
1116 if (faces_equal( face, cursor ))
1118 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
1119 debugstr_w(face->full_name), debugstr_w(family->family_name),
1120 cursor->version, face->version );
1122 if (face->file && cursor->file && !wcsicmp( face->file, cursor->file ))
1124 cursor->refcount++;
1125 TRACE("Font %s already in list, refcount now %d\n",
1126 debugstr_w(face->file), cursor->refcount);
1127 return FALSE;
1129 if (face->version <= cursor->version)
1131 TRACE("Original font %s is newer so skipping %s\n",
1132 debugstr_w(cursor->file), debugstr_w(face->file));
1133 return FALSE;
1135 else
1137 TRACE("Replacing original %s with %s\n",
1138 debugstr_w(cursor->file), debugstr_w(face->file));
1139 list_add_before( &cursor->entry, &face->entry );
1140 face->family = family;
1141 family->refcount++;
1142 face->refcount++;
1143 if (face_is_in_full_name_tree( cursor ))
1145 wine_rb_replace( &face_full_name_tree, &cursor->full_name_entry, &face->full_name_entry );
1146 memset( &cursor->full_name_entry, 0, sizeof(cursor->full_name_entry) );
1148 release_face( cursor );
1149 return TRUE;
1152 if (style_order( face ) < style_order( cursor )) break;
1155 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
1156 debugstr_w(family->family_name), debugstr_w(face->file) );
1157 list_add_before( &cursor->entry, &face->entry );
1158 if (face->scalable) wine_rb_put( &face_full_name_tree, face->full_name, &face->full_name_entry );
1159 face->family = family;
1160 family->refcount++;
1161 face->refcount++;
1162 return TRUE;
1165 static struct gdi_font_face *create_face( struct gdi_font_family *family, const WCHAR *style,
1166 const WCHAR *fullname, const WCHAR *file,
1167 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1168 DWORD ntmflags, DWORD version, DWORD flags,
1169 const struct bitmap_font_size *size )
1171 struct gdi_font_face *face = calloc( 1, sizeof(*face) );
1173 face->refcount = 1;
1174 face->style_name = wcsdup( style );
1175 face->full_name = wcsdup( fullname );
1176 face->face_index = index;
1177 face->fs = fs;
1178 face->ntmFlags = ntmflags;
1179 face->version = version;
1180 face->flags = flags;
1181 face->data_ptr = data_ptr;
1182 face->data_size = data_size;
1183 if (file) face->file = wcsdup( file );
1184 if (size) face->size = *size;
1185 else face->scalable = TRUE;
1186 if (insert_face_in_family_list( face, family )) return face;
1187 release_face( face );
1188 return NULL;
1191 int add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
1192 const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
1193 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1194 DWORD ntmflags, DWORD version, DWORD flags,
1195 const struct bitmap_font_size *size )
1197 struct gdi_font_face *face;
1198 struct gdi_font_family *family;
1199 int ret = 0;
1201 if ((family = find_family_from_name( family_name ))) family->refcount++;
1202 else if (!(family = create_family( family_name, second_name ))) return ret;
1204 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1205 index, fs, ntmflags, version, flags, size )))
1207 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1208 release_face( face );
1210 release_family( family );
1211 ret++;
1213 if (fs.fsCsb[0] & FS_DBCS_MASK)
1215 WCHAR vert_family[LF_FACESIZE], vert_second[LF_FACESIZE], vert_full[LF_FULLFACESIZE];
1217 vert_family[0] = '@';
1218 lstrcpynW( vert_family + 1, family_name, LF_FACESIZE - 1 );
1220 if (second_name && second_name[0])
1222 vert_second[0] = '@';
1223 lstrcpynW( vert_second + 1, second_name, LF_FACESIZE - 1 );
1225 else vert_second[0] = 0;
1227 if (fullname)
1229 vert_full[0] = '@';
1230 lstrcpynW( vert_full + 1, fullname, LF_FULLFACESIZE - 1 );
1231 fullname = vert_full;
1234 if ((family = find_family_from_name( vert_family ))) family->refcount++;
1235 else if (!(family = create_family( vert_family, vert_second ))) return ret;
1237 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1238 index, fs, ntmflags, version, flags | ADDFONT_VERTICAL_FONT, size )))
1240 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1241 release_face( face );
1243 release_family( family );
1244 ret++;
1246 return ret;
1249 /* font cache */
1251 struct cached_face
1253 DWORD index;
1254 DWORD flags;
1255 DWORD ntmflags;
1256 DWORD version;
1257 struct bitmap_font_size size;
1258 FONTSIGNATURE fs;
1259 WCHAR full_name[1];
1260 /* WCHAR file_name[]; */
1263 static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
1264 void *buffer, DWORD buffer_size, BOOL scalable )
1266 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1267 KEY_NODE_INFORMATION *node_info = (KEY_NODE_INFORMATION *)buffer;
1268 DWORD index = 0, total_size;
1269 struct gdi_font_face *face;
1270 HKEY hkey_strike;
1271 WCHAR name[256];
1272 struct cached_face *cached;
1274 while (reg_enum_value( hkey_family, index++, info,
1275 buffer_size - sizeof(DWORD), name, sizeof(name) ))
1277 cached = (struct cached_face *)((char *)info + info->DataOffset);
1278 if (info->Type == REG_BINARY && info->DataLength > sizeof(*cached))
1280 ((DWORD *)cached)[info->DataLength / sizeof(DWORD)] = 0;
1281 if ((face = create_face( family, name, cached->full_name,
1282 cached->full_name + lstrlenW(cached->full_name) + 1,
1283 NULL, 0, cached->index, cached->fs, cached->ntmflags, cached->version,
1284 cached->flags, scalable ? NULL : &cached->size )))
1286 if (!scalable)
1287 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1288 face->size.height, face->size.width, face->size.size >> 6,
1289 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1291 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1292 (int)face->fs.fsCsb[0], (int)face->fs.fsCsb[1],
1293 (int)face->fs.fsUsb[0], (int)face->fs.fsUsb[1],
1294 (int)face->fs.fsUsb[2], (int)face->fs.fsUsb[3]);
1296 release_face( face );
1301 /* load bitmap strikes */
1303 index = 0;
1304 while (!NtEnumerateKey( hkey_family, index++, KeyNodeInformation, node_info,
1305 buffer_size, &total_size ))
1307 if ((hkey_strike = reg_open_key( hkey_family, node_info->Name, node_info->NameLength )))
1309 load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
1310 NtClose( hkey_strike );
1315 static void load_font_list_from_cache(void)
1317 WCHAR buffer[4096];
1318 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer;
1319 KEY_NODE_INFORMATION *enum_info = (KEY_NODE_INFORMATION *)buffer;
1320 DWORD family_index = 0, total_size;
1321 struct gdi_font_family *family;
1322 HKEY hkey_family;
1323 WCHAR *second_name = (WCHAR *)info->Data;
1325 while (!NtEnumerateKey( wine_fonts_cache_key, family_index++, KeyNodeInformation, enum_info,
1326 sizeof(buffer), &total_size ))
1328 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, enum_info->Name,
1329 enum_info->NameLength )))
1330 continue;
1331 TRACE( "opened family key %s\n", debugstr_wn(enum_info->Name, enum_info->NameLength / sizeof(WCHAR)) );
1332 if (!query_reg_value( hkey_family, NULL, info, sizeof(buffer) ))
1333 second_name[0] = 0;
1335 family = create_family( buffer, second_name );
1337 load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
1339 NtClose( hkey_family );
1340 release_family( family );
1344 static void add_face_to_cache( struct gdi_font_face *face )
1346 HKEY hkey_family, hkey_face;
1347 DWORD len, buffer[1024];
1348 struct cached_face *cached = (struct cached_face *)buffer;
1350 if (!(hkey_family = reg_create_key( wine_fonts_cache_key, face->family->family_name,
1351 lstrlenW( face->family->family_name ) * sizeof(WCHAR),
1352 REG_OPTION_VOLATILE, NULL )))
1353 return;
1355 if (face->family->second_name[0])
1356 set_reg_value( hkey_family, NULL, REG_SZ, face->family->second_name,
1357 (lstrlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1359 if (!face->scalable)
1361 WCHAR nameW[10];
1362 char name[10];
1364 snprintf( name, sizeof(name), "%d", face->size.y_ppem );
1365 hkey_face = reg_create_key( hkey_family, nameW,
1366 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR),
1367 REG_OPTION_VOLATILE, NULL );
1369 else hkey_face = hkey_family;
1371 memset( cached, 0, sizeof(*cached) );
1372 cached->index = face->face_index;
1373 cached->flags = face->flags;
1374 cached->ntmflags = face->ntmFlags;
1375 cached->version = face->version;
1376 cached->fs = face->fs;
1377 if (!face->scalable) cached->size = face->size;
1378 lstrcpyW( cached->full_name, face->full_name );
1379 len = lstrlenW( face->full_name ) + 1;
1380 lstrcpyW( cached->full_name + len, face->file );
1381 len += lstrlenW( face->file ) + 1;
1383 set_reg_value( hkey_face, face->style_name, REG_BINARY, cached,
1384 offsetof( struct cached_face, full_name[len] ));
1386 if (hkey_face != hkey_family) NtClose( hkey_face );
1387 NtClose( hkey_family );
1390 static void remove_face_from_cache( struct gdi_font_face *face )
1392 HKEY hkey_family, hkey;
1394 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, face->family->family_name,
1395 lstrlenW( face->family->family_name ) * sizeof(WCHAR) )))
1396 return;
1398 if (!face->scalable)
1400 WCHAR nameW[10];
1401 char name[10];
1402 snprintf( name, sizeof(name), "%d", face->size.y_ppem );
1403 if ((hkey = reg_open_key( hkey_family, nameW,
1404 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) )))
1406 NtDeleteKey( hkey );
1407 NtClose( hkey );
1410 else reg_delete_value( hkey_family, face->style_name );
1412 NtClose( hkey_family );
1415 /* font links */
1417 struct gdi_font_link
1419 struct list entry;
1420 struct list links;
1421 WCHAR name[LF_FACESIZE];
1422 FONTSIGNATURE fs;
1425 struct gdi_font_link_entry
1427 struct list entry;
1428 FONTSIGNATURE fs;
1429 WCHAR family_name[LF_FACESIZE];
1432 static struct list font_links = LIST_INIT(font_links);
1434 static struct gdi_font_link *find_gdi_font_link( const WCHAR *name )
1436 struct gdi_font_link *link;
1438 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1439 if (!facename_compare( link->name, name, LF_FACESIZE - 1 )) return link;
1440 return NULL;
1443 static struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
1444 FONTSIGNATURE fs )
1446 struct gdi_font_link *link;
1447 struct gdi_font_link_entry *entry;
1448 struct gdi_font_family *family;
1450 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1452 if (!facename_compare( link->name, name, LF_FACESIZE - 1 ) ||
1453 (subst && !facename_compare( link->name, subst, LF_FACESIZE - 1 )))
1455 TRACE("found entry in system list\n");
1456 LIST_FOR_EACH_ENTRY( entry, &link->links, struct gdi_font_link_entry, entry )
1458 const struct gdi_font_link *links;
1460 family = find_family_from_name( entry->family_name );
1461 if (!fs.fsCsb[0]) return family;
1462 if (fs.fsCsb[0] & entry->fs.fsCsb[0]) return family;
1463 if ((links = find_gdi_font_link( family->family_name )) && fs.fsCsb[0] & links->fs.fsCsb[0])
1464 return family;
1468 return NULL;
1471 static struct gdi_font_link *add_gdi_font_link( const WCHAR *name )
1473 struct gdi_font_link *link = find_gdi_font_link( name );
1475 if (link) return link;
1476 if ((link = malloc( sizeof(*link) )))
1478 lstrcpynW( link->name, name, LF_FACESIZE );
1479 memset( &link->fs, 0, sizeof(link->fs) );
1480 list_init( &link->links );
1481 list_add_tail( &font_links, &link->entry );
1483 return link;
1486 static void add_gdi_font_link_entry( struct gdi_font_link *link, const WCHAR *family_name, FONTSIGNATURE fs )
1488 struct gdi_font_link_entry *entry;
1490 entry = malloc( sizeof(*entry) );
1491 lstrcpynW( entry->family_name, family_name, LF_FACESIZE );
1492 entry->fs = fs;
1493 link->fs.fsCsb[0] |= fs.fsCsb[0];
1494 link->fs.fsCsb[1] |= fs.fsCsb[1];
1495 list_add_tail( &link->links, &entry->entry );
1498 static const WCHAR lucida_sans_unicodeW[] =
1499 {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
1500 static const WCHAR microsoft_sans_serifW[] =
1501 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1502 static const WCHAR tahomaW[] =
1503 {'T','a','h','o','m','a',0};
1504 static const WCHAR ms_gothicW[] =
1505 {'M','S',' ','G','o','t','h','i','c',0};
1506 static const WCHAR ms_p_gothicW[] =
1507 {'M','S',' ','P','G','o','t','h','i','c',0};
1508 static const WCHAR ms_ui_gothicW[] =
1509 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1510 static const WCHAR sim_sunW[] =
1511 {'S','i','m','S','u','n',0};
1512 static const WCHAR gulimW[] =
1513 {'G','u','l','i','m',0};
1514 static const WCHAR ming_li_uW[] =
1515 {'M','i','n','g','L','i','U',0};
1516 static const WCHAR p_ming_li_uW[] =
1517 {'P','M','i','n','g','L','i','U',0};
1518 static const WCHAR ming_li_u_hkscsW[] =
1519 {'M','i','n','g','L','i','U','_','H','K','S','C','S',0};
1520 static const WCHAR ming_li_u_ext_bW[] =
1521 {'M','i','n','g','L','i','U','-','E','x','t','B',0};
1522 static const WCHAR p_ming_li_u_ext_bW[] =
1523 {'P','M','i','n','g','L','i','U','-','E','x','t','B',0};
1524 static const WCHAR ming_li_u_hkscs_ext_bW[] =
1525 {'M','i','n','g','L','i','U','_','H','K','S','C','S','-','E','x','t','B',0};
1526 static const WCHAR batangW[] =
1527 {'B','a','t','a','n','g',0};
1528 static const WCHAR microsoft_jheng_heiW[] =
1529 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',0};
1530 static const WCHAR microsoft_jheng_hei_boldW[] =
1531 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','B','o','l','d',0};
1532 static const WCHAR microsoft_jheng_hei_uiW[] =
1533 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',0};
1534 static const WCHAR microsoft_jheng_hei_ui_boldW[] =
1535 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','B','o','l','d',0};
1536 static const WCHAR microsoft_jheng_hei_ui_lightW[] =
1537 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','L','i','g','h','t',0};
1538 static const WCHAR yu_gothic_uiW[] =
1539 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',0};
1540 static const WCHAR yu_gothic_ui_boldW[] =
1541 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','B','o','l','d',0};
1542 static const WCHAR yu_gothic_ui_lightW[] =
1543 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','L','i','g','h','t',0};
1544 static const WCHAR yu_gothic_ui_semilightW[] =
1545 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','S','e','m','i','l','i','g','h','t',0};
1546 static const WCHAR yu_gothic_ui_semiboldW[] =
1547 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','S','e','m','i','b','o','l','d',0};
1548 static const WCHAR meiryoW[] =
1549 {'M','e','i','r','y','o',0};
1550 static const WCHAR meiryo_boldW[] =
1551 {'M','e','i','r','y','o',' ','B','o','l','d',0};
1552 static const WCHAR meiryo_uiW[] =
1553 {'M','e','i','r','y','o',' ','U','I',0};
1554 static const WCHAR meiryo_ui_boldW[] =
1555 {'M','e','i','r','y','o',' ','U','I',' ','B','o','l','d',0};
1556 static const WCHAR ms_minchoW[] =
1557 {'M','S',' ','M','i','n','c','h','o',0};
1558 static const WCHAR ms_p_minchoW[] =
1559 {'M','S',' ','P','M','i','n','c','h','o',0};
1561 static const WCHAR * const font_links_list[] =
1563 lucida_sans_unicodeW,
1564 microsoft_sans_serifW,
1565 tahomaW
1568 static const struct font_links_defaults_list
1570 /* Keyed off substitution for "MS Shell Dlg" */
1571 const WCHAR *shelldlg;
1572 /* Maximum of four substitutes, plus terminating NULL pointer */
1573 const WCHAR *substitutes[5];
1574 } font_links_defaults_list[] =
1576 /* Non East-Asian */
1577 { tahomaW, /* FIXME unverified ordering */
1578 { ms_ui_gothicW, sim_sunW, gulimW, p_ming_li_uW, NULL }
1580 /* Below lists are courtesy of
1581 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1583 /* Japanese */
1584 { ms_ui_gothicW,
1585 { ms_ui_gothicW, p_ming_li_uW, sim_sunW, gulimW, NULL }
1587 /* Chinese Simplified */
1588 { sim_sunW,
1589 { sim_sunW, p_ming_li_uW, ms_ui_gothicW, batangW, NULL }
1591 /* Korean */
1592 { gulimW,
1593 { gulimW, p_ming_li_uW, ms_ui_gothicW, sim_sunW, NULL }
1595 /* Chinese Traditional */
1596 { p_ming_li_uW,
1597 { p_ming_li_uW, sim_sunW, ms_ui_gothicW, batangW, NULL }
1601 static const char system_link_tahoma_sc[] =
1602 "SIMSUN.TTC,SimSun\0"
1603 "MINGLIU.TTC,PMingLiu\0"
1604 "MSGOTHIC.TTC,MS UI Gothic\0"
1605 "BATANG.TTC,Batang\0"
1606 "MSYH.TTC,Microsoft YaHei UI\0"
1607 "MSJH.TTC,Microsoft JhengHei UI\0"
1608 "YUGOTHM.TTC,Yu Gothic UI\0"
1609 "MALGUN.TTF,Malgun Gothic\0"
1610 "SEGUISYM.TTF,Segoe UI Symbol\0";
1612 static const char system_link_tahoma_tc[] =
1613 "MINGLIU.TTC,PMingLiu\0"
1614 "SIMSUN.TTC,SimSun\0"
1615 "MSGOTHIC.TTC,MS UI Gothic\0"
1616 "BATANG.TTC,Batang\0"
1617 "MSJH.TTC,Microsoft JhengHei UI\0"
1618 "MSYH.TTC,Microsoft YaHei UI\0"
1619 "YUGOTHM.TTC,Yu Gothic UI\0"
1620 "MALGUN.TTF,Malgun Gothic\0"
1621 "SEGUISYM.TTF,Segoe UI Symbol\0";
1623 static const char system_link_tahoma_jp[] =
1624 "MSGOTHIC.TTC,MS UI Gothic\0"
1625 "MINGLIU.TTC,PMingLiU\0"
1626 "SIMSUN.TTC,SimSun\0"
1627 "GULIM.TTC,Gulim\0"
1628 "YUGOTHM.TTC,Yu Gothic UI\0"
1629 "MSJH.TTC,Microsoft JhengHei UI\0"
1630 "MSYH.TTC,Microsoft YaHei UI\0"
1631 "MALGUN.TTF,Malgun Gothic\0"
1632 "SEGUISYM.TTF,Segoe UI Symbol\0";
1634 static const char system_link_tahoma_kr[] =
1635 "GULIM.TTC,Gulim\0"
1636 "MSGOTHIC.TTC,MS UI Gothic\0"
1637 "MINGLIU.TTC,PMingLiU\0"
1638 "SIMSUN.TTC,SimSun\0"
1639 "MALGUN.TTF,Malgun Gothic\0"
1640 "YUGOTHM.TTC,Yu Gothic UI\0"
1641 "MSJH.TTC,Microsoft JhengHei UI\0"
1642 "MSYH.TTC,Microsoft YaHei UI\0"
1643 "SEGUISYM.TTF,Segoe UI Symbol\0";
1645 static const char system_link_tahoma_non_cjk[] =
1646 "MSGOTHIC.TTC,MS UI Gothic\0"
1647 "MINGLIU.TTC,PMingLiU\0"
1648 "SIMSUN.TTC,SimSun\0"
1649 "GULIM.TTC,Gulim\0"
1650 "YUGOTHM.TTC,Yu Gothic UI\0"
1651 "MSJH.TTC,Microsoft JhengHei UI\0"
1652 "MSYH.TTC,Microsoft YaHei UI\0"
1653 "MALGUN.TTF,Malgun Gothic\0"
1654 "SEGUISYM.TTF,Segoe UI Symbol\0";
1656 static const char system_link_ms_gothic[] =
1657 "MINGLIU.TTC,MingLiU\0"
1658 "SIMSUN.TTC,SimSun\0"
1659 "GULIM.TTC,GulimChe\0"
1660 "YUGOTHM.TTC,Yu Gothic UI\0"
1661 "MSJH.TTC,Microsoft JhengHei UI\0"
1662 "MSYH.TTC,Microsoft YaHei UI\0"
1663 "MALGUN.TTF,Malgun Gothic\0"
1664 "SEGUISYM.TTF,Segoe UI Symbol\0";
1666 static const char system_link_ms_p_gothic[] =
1667 "MINGLIU.TTC,PMingLiU\0"
1668 "SIMSUN.TTC,SimSun\0"
1669 "GULIM.TTC,Gulim\0"
1670 "YUGOTHM.TTC,Yu Gothic UI\0"
1671 "MSJH.TTC,Microsoft JhengHei UI\0"
1672 "MSYH.TTC,Microsoft YaHei UI\0"
1673 "MALGUN.TTF,Malgun Gothic\0"
1674 "SEGUISYM.TTF,Segoe UI Symbol\0";
1676 static const char system_link_ms_ui_gothic[] =
1677 "MICROSS.TTF,Microsoft Sans Serif\0"
1678 "MINGLIU.TTC,PMingLiU\0"
1679 "SIMSUN.TTC,SimSun\0"
1680 "GULIM.TTC,Gulim\0"
1681 "YUGOTHM.TTC,Yu Gothic UI\0"
1682 "MSJH.TTC,Microsoft JhengHei UI\0"
1683 "MSYH.TTC,Microsoft YaHei UI\0"
1684 "MALGUN.TTF,Malgun Gothic\0"
1685 "SEGUISYM.TTF,Segoe UI Symbol\0";
1687 static const char system_link_microsoft_jheng_hei[] =
1688 "SEGOEUI.TTF,Segoe UI\0"
1689 "MINGLIU.TTC,MingLiU\0"
1690 "MSYH.TTC,Microsoft YaHei\0"
1691 "MEIRYO.TTC,Meiryo\0"
1692 "MALGUN.TTF,Malgun Gothic\0"
1693 "YUGOTHM.TTC,Yu Gothic UI\0"
1694 "SEGUISYM.TTF,Segoe UI Symbol\0";
1696 static const char system_link_microsoft_jheng_hei_bold[] =
1697 "SEGOEUIB.TTF,Segoe UI Bold\0"
1698 "MINGLIU.TTC,MingLiU\0"
1699 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1700 "MEIRYOB.TTC,Meiryo Bold\0"
1701 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1702 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1703 "SEGUISYM.TTF,Segoe UI Symbol\0";
1705 static const char system_link_microsoft_jheng_hei_ui[] =
1706 "SEGOEUI.TTF,Segoe UI\0"
1707 "MINGLIU.TTC,MingLiU\0"
1708 "MSYH.TTC,Microsoft YaHei UI\0"
1709 "MEIRYO.TTC,Meiryo UI\0"
1710 "MALGUN.TTF,Malgun Gothic\0"
1711 "YUGOTHM.TTC,Yu Gothic UI\0"
1712 "SEGUISYM.TTF,Segoe UI Symbol\0";
1714 static const char system_link_microsoft_jheng_hei_ui_bold[] =
1715 "SEGOEUIB.TTF,Segoe UI Bold\0"
1716 "MINGLIU.TTC,MingLiU\0"
1717 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1718 "MEIRYOB.TTC,Meiryo UI Bold\0"
1719 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1720 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1721 "SEGUISYM.TTF,Segoe UI Symbol\0";
1723 static const char system_link_microsoft_jheng_hei_ui_light[] =
1724 "SEGOEUIL.TTF,Segoe UI Light\0"
1725 "MINGLIU.TTC,MingLiU\0"
1726 "MSYHL.TTC,Microsoft YaHei UI Light\0"
1727 "MEIRYO.TTC,Meiryo UI\0"
1728 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1729 "YUGOTHL.TTC,Yu Gothic UI Light\0"
1730 "SEGUISYM.TTF,Segoe UI Symbol\0";
1732 static const char system_link_ming_li_u[] =
1733 "MICROSS.TTF,Microsoft Sans Serif\0"
1734 "SIMSUN.TTC,SimSun\0"
1735 "MSMINCHO.TTC,MS Mincho\0"
1736 "BATANG.TTC,BatangChe\0"
1737 "MSJH.TTC,Microsoft JhengHei UI\0"
1738 "MSYH.TTC,Microsoft YaHei UI\0"
1739 "YUGOTHM.TTC,Yu Gothic UI\0"
1740 "MALGUN.TTF,Malgun Gothic\0"
1741 "SEGUISYM.TTF,Segoe UI Symbol\0";
1743 static const char system_link_p_ming_li_u[] =
1744 "MICROSS.TTF,Microsoft Sans Serif\0"
1745 "SIMSUN.TTC,SimSun\0"
1746 "MSMINCHO.TTC,MS PMincho\0"
1747 "BATANG.TTC,Batang\0"
1748 "MSJH.TTC,Microsoft JhengHei UI\0"
1749 "MSYH.TTC,Microsoft YaHei UI\0"
1750 "YUGOTHM.TTC,Yu Gothic UI\0"
1751 "MALGUN.TTF,Malgun Gothic\0"
1752 "SEGUISYM.TTF,Segoe UI Symbol\0";
1754 static const char system_link_ming_li_u_hkscs[] =
1755 "MICROSS.TTF,Microsoft Sans Serif\0"
1756 "MINGLIU.TTC,MingLiU\0"
1757 "SIMSUN.TTC,SimSun\0"
1758 "MSMINCHO.TTC,MS Mincho\0"
1759 "BATANG.TTC,BatangChe\0"
1760 "MSJH.TTC,Microsoft JhengHei UI\0"
1761 "MSYH.TTC,Microsoft YaHei UI\0"
1762 "YUGOTHM.TTC,Yu Gothic UI\0"
1763 "MALGUN.TTF,Malgun Gothic\0"
1764 "SEGUISYM.TTF,Segoe UI Symbol\0";
1766 static const char system_link_ming_li_u_ext_b[] =
1767 "MICROSS.TTF,Microsoft Sans Serif\0"
1768 "MINGLIU.TTC,MingLiU\0"
1769 "SIMSUN.TTC,SimSun\0"
1770 "MSMINCHO.TTC,MS Mincho\0"
1771 "BATANG.TTC,BatangChe\0"
1772 "MSJH.TTC,Microsoft JhengHei UI\0"
1773 "MSYH.TTC,Microsoft YaHei UI\0"
1774 "YUGOTHM.TTC,Yu Gothic UI\0"
1775 "MALGUN.TTF,Malgun Gothic\0"
1776 "SEGUISYM.TTF,Segoe UI Symbol\0";
1778 static const char system_link_p_ming_li_u_ext_b[] =
1779 "MICROSS.TTF,Microsoft Sans Serif\0"
1780 "MINGLIU.TTC,PMingLiU\0"
1781 "SIMSUN.TTC,SimSun\0"
1782 "MSMINCHO.TTC,MS PMincho\0"
1783 "BATANG.TTC,Batang\0"
1784 "MSJH.TTC,Microsoft JhengHei UI\0"
1785 "MSYH.TTC,Microsoft YaHei UI\0"
1786 "YUGOTHM.TTC,Yu Gothic UI\0"
1787 "MALGUN.TTF,Malgun Gothic\0"
1788 "SEGUISYM.TTF,Segoe UI Symbol\0";
1790 static const char system_link_ming_li_u_hkscs_ext_b[] =
1791 "MICROSS.TTF,Microsoft Sans Serif\0"
1792 "MINGLIU.TTC,MingLiU_HKSCS\0"
1793 "MINGLIU.TTC,MingLiU\0"
1794 "SIMSUN.TTC,SimSun\0"
1795 "MSMINCHO.TTC,MS Mincho\0"
1796 "BATANG.TTC,BatangChe\0"
1797 "MSJH.TTC,Microsoft JhengHei UI\0"
1798 "MSYH.TTC,Microsoft YaHei UI\0"
1799 "YUGOTHM.TTC,Yu Gothic UI\0"
1800 "MALGUN.TTF,Malgun Gothic\0"
1801 "SEGUISYM.TTF,Segoe UI Symbol\0";
1803 static const char system_link_yu_gothic_ui[] =
1804 "SEGOEUI.TTF,Segoe UI\0"
1805 "MSJH.TTC,Microsoft JhengHei\0"
1806 "MSYH.TTC,Microsoft YaHei\0"
1807 "MALGUN.TTF,Malgun Gothic\0"
1808 "SEGUISYM.TTF,Segoe UI Symbol\0";
1810 static const char system_link_yu_gothic_ui_bold[] =
1811 "SEGOEUIB.TTF,Segoe UI Bold\0"
1812 "MSJHBD.TTC,Microsoft Jhenghei UI Bold\0"
1813 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1814 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1815 "SEGUISYM.TTF,Segoe UI Symbol\0";
1817 static const char system_link_yu_gothic_ui_light[] =
1818 "SEGOEUIL.TTF,Segoe UI Light\0"
1819 "MSJHL.TTC,Microsoft Jhenghei UI Light\0"
1820 "MSYHL.TTC,Microsoft YaHei Light\0"
1821 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1822 "SEGUISYM.TTF,Segoe UI Symbol\0";
1824 static const char system_link_yu_gothic_ui_semilight[] =
1825 "SEGOEUISL.TTF,Segoe UI Semilight\0"
1826 "MSJH.TTC,Microsoft Jhenghei UI\0"
1827 "MSYH.TTC,Microsoft YaHei\0"
1828 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1829 "SEGUISYM.TTF,Segoe UI Symbol\0";
1831 static const char system_link_yu_gothic_ui_semibold[] =
1832 "SEGUISB.TTF,Segoe UI Semibold\0"
1833 "MSJH.TTC,Microsoft Jhenghei UI\0"
1834 "MSYH.TTC,Microsoft YaHei\0"
1835 "MALGUN.TTF,Malgun Gothic\0"
1836 "SEGUISYM.TTF,Segoe UI Symbol\0";
1838 static const char system_link_meiryo[] =
1839 "SEGOEUI.TTF,Segoe UI\0"
1840 "YUGOTHM.TTC,Yu Gothic UI\0"
1841 "MSGOTHIC.TTC,MS UI Gothic\0"
1842 "MSJH.TTC,Microsoft JhengHei\0"
1843 "MSYH.TTC,Microsoft YaHei\0"
1844 "MALGUN.TTF,Malgun Gothic\0"
1845 "SEGUISYM.TTF,Segoe UI Symbol\0";
1847 static const char system_link_meiryo_bold[] =
1848 "SEGOEUIB.TTF,Segoe UI Bold\0"
1849 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1850 "MSGOTHIC.TTC,MS UI Gothic\0"
1851 "MSJHBD.TTC,Microsoft Jhenghei Bold\0"
1852 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1853 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1854 "SEGUISYM.TTF,Segoe UI Symbol\0";
1856 static const char system_link_meiryo_ui[] =
1857 "SEGOEUI.TTF,Segoe UI\0"
1858 "YUGOTHM.TTC,Yu Gothic UI\0"
1859 "MSGOTHIC.TTC,MS UI Gothic\0"
1860 "MSJH.TTC,Microsoft Jhenghei UI\0"
1861 "MSYH.TTC,Microsoft YaHei UI\0"
1862 "MALGUN.TTF,Malgun Gothic\0"
1863 "SEGUISYM.TTF,Segoe UI Symbol\0";
1865 static const char system_link_meiryo_ui_bold[] =
1866 "SEGOEUIB.TTF,Segoe UI Bold\0"
1867 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1868 "MSGOTHIC.TTC,MS UI Gothic\0"
1869 "MSJHBD.TTC,Microsoft Jhenghei UI Bold\0"
1870 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1871 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1872 "SEGUISYM.TTF,Segoe UI Symbol\0";
1874 static const char system_link_ms_mincho[] =
1875 "MINGLIU.TTC,MingLiU\0"
1876 "SIMSUN.TTC,SimSun\0"
1877 "BATANG.TTC,Batang\0"
1878 "YUGOTHM.TTC,Yu Gothic UI\0"
1879 "MSJH.TTC,Microsoft JhengHei UI\0"
1880 "MSYH.TTC,Microsoft YaHei UI\0"
1881 "MALGUN.TTF,Malgun Gothic\0"
1882 "SEGUISYM.TTF,Segoe UI Symbol\0";
1884 static const char system_link_ms_p_mincho[] =
1885 "MINGLIU.TTC,PMingLiU\0"
1886 "SIMSUN.TTC,SimSun\0"
1887 "BATANG.TTC,Batang\0"
1888 "YUGOTHM.TTC,Yu Gothic UI\0"
1889 "MSJH.TTC,Microsoft JhengHei UI\0"
1890 "MSYH.TTC,Microsoft YaHei UI\0"
1891 "MALGUN.TTF,Malgun Gothic\0"
1892 "SEGUISYM.TTF,Segoe UI Symbol\0";
1894 static const struct system_link_reg
1896 const WCHAR *font_name;
1897 BOOL locale_dependent;
1898 const char *link_non_cjk;
1899 DWORD link_non_cjk_len;
1900 const char *link_sc;
1901 DWORD link_sc_len;
1902 const char *link_tc;
1903 DWORD link_tc_len;
1904 const char *link_jp;
1905 DWORD link_jp_len;
1906 const char *link_kr;
1907 DWORD link_kr_len;
1909 default_system_link[] =
1912 tahomaW, TRUE,
1913 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1914 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1915 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1916 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1917 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1920 microsoft_sans_serifW, TRUE,
1921 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1922 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1923 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1924 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1925 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1928 lucida_sans_unicodeW, TRUE,
1929 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1930 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1931 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1932 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1933 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1935 { ms_gothicW, FALSE, system_link_ms_gothic, sizeof(system_link_ms_gothic) },
1936 { ms_p_gothicW, FALSE, system_link_ms_p_gothic, sizeof(system_link_ms_p_gothic) },
1937 { ms_ui_gothicW, FALSE, system_link_ms_ui_gothic, sizeof(system_link_ms_ui_gothic) },
1938 { microsoft_jheng_heiW, FALSE, system_link_microsoft_jheng_hei, sizeof(system_link_microsoft_jheng_hei) },
1939 { microsoft_jheng_hei_boldW, FALSE, system_link_microsoft_jheng_hei_bold, sizeof(system_link_microsoft_jheng_hei_bold) },
1940 { microsoft_jheng_hei_uiW, FALSE, system_link_microsoft_jheng_hei_ui, sizeof(system_link_microsoft_jheng_hei_ui) },
1941 { microsoft_jheng_hei_ui_boldW, FALSE, system_link_microsoft_jheng_hei_ui_bold, sizeof(system_link_microsoft_jheng_hei_ui_bold) },
1942 { microsoft_jheng_hei_ui_lightW, FALSE, system_link_microsoft_jheng_hei_ui_light, sizeof(system_link_microsoft_jheng_hei_ui_light) },
1943 { ming_li_uW, FALSE, system_link_ming_li_u, sizeof(system_link_ming_li_u) },
1944 { p_ming_li_uW, FALSE, system_link_p_ming_li_u, sizeof(system_link_p_ming_li_u) },
1945 { ming_li_u_hkscsW, FALSE, system_link_ming_li_u_hkscs, sizeof(system_link_ming_li_u_hkscs) },
1946 { ming_li_u_ext_bW, FALSE, system_link_ming_li_u_ext_b, sizeof(system_link_ming_li_u_ext_b) },
1947 { p_ming_li_u_ext_bW, FALSE, system_link_p_ming_li_u_ext_b, sizeof(system_link_p_ming_li_u_ext_b) },
1948 { ming_li_u_hkscs_ext_bW, FALSE, system_link_ming_li_u_hkscs_ext_b, sizeof(system_link_ming_li_u_hkscs_ext_b) },
1949 { yu_gothic_uiW, FALSE, system_link_yu_gothic_ui, sizeof(system_link_yu_gothic_ui) },
1950 { yu_gothic_ui_boldW, FALSE, system_link_yu_gothic_ui_bold, sizeof(system_link_yu_gothic_ui_bold) },
1951 { yu_gothic_ui_lightW, FALSE, system_link_yu_gothic_ui_light, sizeof(system_link_yu_gothic_ui_light) },
1952 { yu_gothic_ui_semiboldW, FALSE, system_link_yu_gothic_ui_semibold, sizeof(system_link_yu_gothic_ui_semibold) },
1953 { yu_gothic_ui_semilightW, FALSE, system_link_yu_gothic_ui_semilight, sizeof(system_link_yu_gothic_ui_semilight) },
1954 { meiryoW, FALSE, system_link_meiryo, sizeof(system_link_meiryo) },
1955 { meiryo_boldW, FALSE, system_link_meiryo_bold, sizeof(system_link_meiryo_bold) },
1956 { meiryo_uiW, FALSE, system_link_meiryo_ui, sizeof(system_link_meiryo_ui) },
1957 { meiryo_ui_boldW, FALSE, system_link_meiryo_ui_bold, sizeof(system_link_meiryo_ui_bold) },
1958 { ms_minchoW, FALSE, system_link_ms_mincho, sizeof(system_link_ms_mincho) },
1959 { ms_p_minchoW, FALSE, system_link_ms_p_mincho, sizeof(system_link_ms_p_mincho) },
1962 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1964 struct gdi_font_family *family;
1965 struct gdi_font_face *face;
1966 struct gdi_font_link *font_link;
1967 const WCHAR *file, *value;
1969 /* Don't store fonts that are only substitutes for other fonts */
1970 if (get_gdi_font_subst( name, -1, NULL ))
1972 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1973 return;
1975 font_link = add_gdi_font_link( name );
1976 for ( ; *values; values++)
1978 if (!facename_compare( name, *values, -1 )) continue;
1979 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1980 if (!(family = find_family_from_name( value ))) continue;
1981 /* use first extant filename for this Family */
1982 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1984 if (!face->file) continue;
1985 file = wcsrchr(face->file, '\\');
1986 if (!file) file = face->file;
1987 else file++;
1988 if ((face = find_face_from_filename( file, value )))
1990 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1991 TRACE( "added internal SystemLink for %s to %s in %s\n",
1992 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1994 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1995 break;
2000 static void load_system_links(void)
2002 HKEY hkey;
2003 DWORD i, j;
2004 const WCHAR *shelldlg_name;
2005 struct gdi_font_link *font_link, *system_font_link;
2006 struct gdi_font_face *face;
2008 static const WCHAR ms_shell_dlgW[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2009 static const WCHAR systemW[] = {'S','y','s','t','e','m',0};
2010 static const WCHAR tahoma_ttfW[] = {'t','a','h','o','m','a','.','t','t','f',0};
2012 if ((hkey = reg_open_key( NULL, system_link_keyW, sizeof(system_link_keyW) )))
2014 char buffer[4096];
2015 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2016 WCHAR value[MAX_PATH];
2017 WCHAR *entry, *next;
2019 i = 0;
2020 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
2022 /* Don't store fonts that are only substitutes for other fonts */
2023 if (!get_gdi_font_subst( value, -1, NULL ))
2025 char *data = (char *)info + info->DataOffset;
2026 font_link = add_gdi_font_link( value );
2027 for (entry = (WCHAR *)data; (char *)entry < data + info->DataLength && *entry; entry = next)
2029 const WCHAR *family_name = NULL;
2030 WCHAR *p;
2032 TRACE( "%s: %s\n", debugstr_w(value), debugstr_w(entry) );
2034 next = entry + lstrlenW(entry) + 1;
2035 if ((p = wcschr( entry, ',' )))
2037 *p++ = 0;
2038 while (*p == ' ' || *p == '\t') p++;
2039 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
2041 if ((face = find_face_from_filename( entry, family_name )))
2043 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
2044 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
2046 else TRACE( "Unable to find file %s family %s\n",
2047 debugstr_w(entry), debugstr_w(family_name) );
2050 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2052 NtClose( hkey );
2055 if ((shelldlg_name = get_gdi_font_subst( ms_shell_dlgW, -1, NULL )))
2057 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
2059 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
2061 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
2062 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
2064 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
2065 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
2066 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
2067 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
2071 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
2073 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2074 that Tahoma has */
2076 system_font_link = add_gdi_font_link( systemW );
2077 if ((face = find_face_from_filename( tahoma_ttfW, tahomaW )))
2079 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
2080 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
2082 if ((font_link = find_gdi_font_link( tahomaW )))
2084 struct gdi_font_link_entry *entry;
2085 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2086 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
2090 /* see TranslateCharsetInfo */
2091 BOOL translate_charset_info( DWORD *src, CHARSETINFO *cs, DWORD flags )
2093 unsigned int i;
2095 switch (flags)
2097 case TCI_SRCFONTSIG:
2098 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
2099 if (charset_info[i].fs.fsCsb[0] & src[0]) goto found;
2100 return FALSE;
2101 case TCI_SRCCODEPAGE:
2102 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
2103 if (PtrToUlong(src) == charset_info[i].ciACP) goto found;
2104 return FALSE;
2105 case TCI_SRCCHARSET:
2106 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
2107 if (PtrToUlong(src) == charset_info[i].ciCharset) goto found;
2108 return FALSE;
2109 default:
2110 return FALSE;
2112 found:
2113 *cs = charset_info[i];
2114 return TRUE;
2117 /* font matching */
2119 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
2121 struct gdi_font_link *font_link;
2123 if (!face->scalable && !can_use_bitmap) return FALSE;
2124 if (!fs.fsCsb[0]) return TRUE;
2125 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
2126 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
2127 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
2128 return FALSE;
2131 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
2132 const LOGFONTW *lf, FONTSIGNATURE fs,
2133 BOOL can_use_bitmap )
2135 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
2136 unsigned int best_score = 4;
2137 int best_diff = 0;
2138 int it = !!lf->lfItalic;
2139 int bd = lf->lfWeight > 550;
2140 int height = lf->lfHeight;
2142 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2144 int italic = !!(face->ntmFlags & NTM_ITALIC);
2145 int bold = !!(face->ntmFlags & NTM_BOLD);
2146 int score = (italic ^ it) + (bold ^ bd);
2148 if (!can_select_face( face, fs, can_use_bitmap )) continue;
2149 if (score > best_score) continue;
2150 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
2151 best_score = score;
2152 best = face;
2153 if (best->scalable && best_score == 0) break;
2154 if (!best->scalable)
2156 int diff;
2157 if (height > 0)
2158 diff = height - (signed int)best->size.height;
2159 else
2160 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
2161 if (!best_bitmap ||
2162 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
2163 (best_diff < 0 && diff > best_diff))
2165 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
2166 best_diff = diff;
2167 best_bitmap = best;
2168 if (best_score == 0 && best_diff == 0) break;
2172 if (!best) return NULL;
2173 return best->scalable ? best : best_bitmap;
2176 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
2177 const LOGFONTW *lf, FONTSIGNATURE fs,
2178 BOOL can_use_bitmap, const WCHAR **orig_name )
2180 struct gdi_font_family *family;
2181 struct gdi_font_face *face;
2183 family = find_family_from_any_name( name );
2184 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
2185 if (subst)
2187 family = find_family_from_any_name( subst );
2188 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
2191 /* search by full face name */
2192 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2193 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2194 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
2195 can_select_face( face, fs, can_use_bitmap ))
2196 return face;
2198 if ((family = find_family_from_font_links( name, subst, fs )))
2200 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
2202 return NULL;
2204 found:
2205 if (orig_name && family != face->family)
2206 *orig_name = family->family_name;
2207 return face;
2210 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
2211 BOOL can_use_bitmap, BOOL want_vertical )
2213 struct gdi_font_family *family;
2214 struct gdi_font_face *face;
2215 WCHAR name[LF_FACESIZE + 1];
2216 int i = 0;
2218 /* first try the family fallbacks */
2219 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
2221 if (want_vertical)
2223 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
2224 name[0] = '@';
2227 if (!(family = find_family_from_any_name(name))) continue;
2228 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
2230 /* otherwise try only scalable */
2231 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2233 if ((family->family_name[0] == '@') == !want_vertical) continue;
2234 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
2236 if (!can_use_bitmap) return NULL;
2237 /* then also bitmap fonts */
2238 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2240 if ((family->family_name[0] == '@') == !want_vertical) continue;
2241 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
2243 return NULL;
2246 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
2247 BOOL *substituted, const WCHAR **orig_name )
2249 BOOL want_vertical = (lf->lfFaceName[0] == '@');
2250 struct gdi_font_face *face;
2252 if (!translate_charset_info( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
2254 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
2255 csi->fs.fsCsb[0] = 0;
2258 if (lf->lfFaceName[0])
2260 int subst_charset;
2261 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
2263 if (subst)
2265 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
2266 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
2267 if (subst_charset != -1)
2268 translate_charset_info( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
2269 *substituted = TRUE;
2272 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap, orig_name )))
2273 return face;
2275 *substituted = FALSE; /* substitution is no longer relevant */
2277 /* If requested charset was DEFAULT_CHARSET then try using charset
2278 corresponding to the current ansi codepage */
2279 if (!csi->fs.fsCsb[0])
2281 if (!translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
2283 FIXME( "TCI failed on codepage %d\n", ansi_cp.CodePage );
2284 csi->fs.fsCsb[0] = 0;
2288 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
2289 if (csi->fs.fsCsb[0])
2291 csi->fs.fsCsb[0] = 0;
2292 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
2294 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
2295 return NULL;
2298 /* realized font objects */
2300 #define FIRST_FONT_HANDLE 1
2301 #define MAX_FONT_HANDLES 256
2303 struct font_handle_entry
2305 struct gdi_font *font;
2306 WORD generation; /* generation count for reusing handle values */
2309 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
2310 static struct font_handle_entry *next_free;
2311 static struct font_handle_entry *next_unused = font_handles;
2313 static struct font_handle_entry *handle_entry( unsigned int handle )
2315 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
2317 if (idx < MAX_FONT_HANDLES)
2319 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
2320 return &font_handles[idx];
2322 if (handle) WARN( "invalid handle 0x%08x\n", handle );
2323 return NULL;
2326 static struct gdi_font *get_font_from_handle( unsigned int handle )
2328 struct font_handle_entry *entry = handle_entry( handle );
2330 if (entry) return entry->font;
2331 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
2332 return NULL;
2335 static DWORD alloc_font_handle( struct gdi_font *font )
2337 struct font_handle_entry *entry;
2339 entry = next_free;
2340 if (entry)
2341 next_free = (struct font_handle_entry *)entry->font;
2342 else if (next_unused < font_handles + MAX_FONT_HANDLES)
2343 entry = next_unused++;
2344 else
2346 ERR( "out of realized font handles\n" );
2347 return 0;
2349 entry->font = font;
2350 if (++entry->generation == 0xffff) entry->generation = 1;
2351 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
2354 static void free_font_handle( DWORD handle )
2356 struct font_handle_entry *entry;
2358 if ((entry = handle_entry( handle )))
2360 entry->font = (struct gdi_font *)next_free;
2361 next_free = entry;
2365 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
2367 UINT len = file ? lstrlenW(file) : 0;
2368 struct gdi_font *font = calloc( 1, offsetof( struct gdi_font, file[len + 1] ));
2370 font->refcount = 1;
2371 font->matrix.eM11 = font->matrix.eM22 = 1.0;
2372 font->scale_y = 1;
2373 font->kern_count = -1;
2374 list_init( &font->child_fonts );
2376 if (file)
2378 FILE_NETWORK_OPEN_INFORMATION info;
2379 UNICODE_STRING nt_name;
2380 OBJECT_ATTRIBUTES attr;
2382 nt_name.Buffer = (WCHAR *)file;
2383 nt_name.Length = nt_name.MaximumLength = len * sizeof(WCHAR);
2385 attr.Length = sizeof(attr);
2386 attr.RootDirectory = 0;
2387 attr.Attributes = OBJ_CASE_INSENSITIVE;
2388 attr.ObjectName = &nt_name;
2389 attr.SecurityDescriptor = NULL;
2390 attr.SecurityQualityOfService = NULL;
2392 if (!NtQueryFullAttributesFile( &attr, &info ))
2394 font->writetime.dwLowDateTime = info.LastWriteTime.LowPart;
2395 font->writetime.dwHighDateTime = info.LastWriteTime.HighPart;
2396 font->data_size = info.EndOfFile.QuadPart;
2397 memcpy( font->file, file, len * sizeof(WCHAR) );
2400 else
2402 font->data_ptr = data_ptr;
2403 font->data_size = data_size;
2406 font->handle = alloc_font_handle( font );
2407 return font;
2410 static void free_gdi_font( struct gdi_font *font )
2412 DWORD i;
2413 struct gdi_font *child, *child_next;
2415 if (font->private) font_funcs->destroy_font( font );
2416 free_font_handle( font->handle );
2417 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
2419 list_remove( &child->entry );
2420 free_gdi_font( child );
2422 for (i = 0; i < font->gm_size; i++) free( font->gm[i] );
2423 free( font->otm.otmpFamilyName );
2424 free( font->otm.otmpStyleName );
2425 free( font->otm.otmpFaceName );
2426 free( font->otm.otmpFullName );
2427 free( font->gm );
2428 free( font->kern_pairs );
2429 free( font->gsub_table );
2430 free( font );
2433 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
2435 return font->use_logfont_name ? font->lf.lfFaceName : (WCHAR *)font->otm.otmpFamilyName;
2438 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
2439 const LOGFONTW *lf )
2441 struct gdi_font *font;
2443 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
2444 font->fs = face->fs;
2445 font->lf = *lf;
2446 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
2447 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
2448 font->scalable = face->scalable;
2449 font->face_index = face->face_index;
2450 font->ntmFlags = face->ntmFlags;
2451 font->aa_flags = HIWORD( face->flags );
2452 if (!family_name) family_name = face->family->family_name;
2453 font->otm.otmpFamilyName = (char *)wcsdup( family_name );
2454 font->otm.otmpStyleName = (char *)wcsdup( face->style_name );
2455 font->otm.otmpFaceName = (char *)wcsdup( face->full_name );
2456 return font;
2459 struct glyph_metrics
2461 GLYPHMETRICS gm;
2462 ABC abc; /* metrics of the unrotated char */
2463 BOOL init;
2466 #define GM_BLOCK_SIZE 128
2468 /* TODO: GGO format support */
2469 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
2471 UINT block = index / GM_BLOCK_SIZE;
2472 UINT entry = index % GM_BLOCK_SIZE;
2474 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
2476 *gm = font->gm[block][entry].gm;
2477 *abc = font->gm[block][entry].abc;
2479 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2480 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
2481 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2482 return TRUE;
2485 return FALSE;
2488 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
2489 const GLYPHMETRICS *gm, const ABC *abc )
2491 UINT block = index / GM_BLOCK_SIZE;
2492 UINT entry = index % GM_BLOCK_SIZE;
2494 if (block >= font->gm_size)
2496 struct glyph_metrics **ptr;
2498 if (!(ptr = realloc( font->gm, (block + 1) * sizeof(*ptr) ))) return;
2499 memset( ptr + font->gm_size, 0, (block + 1 - font->gm_size) * sizeof(*ptr) );
2500 font->gm_size = block + 1;
2501 font->gm = ptr;
2503 if (!font->gm[block])
2505 font->gm[block] = calloc( sizeof(**font->gm), GM_BLOCK_SIZE );
2506 if (!font->gm[block]) return;
2508 font->gm[block][entry].gm = *gm;
2509 font->gm[block][entry].abc = *abc;
2510 font->gm[block][entry].init = TRUE;
2514 /* GSUB table support */
2516 typedef struct
2518 DWORD version;
2519 WORD ScriptList;
2520 WORD FeatureList;
2521 WORD LookupList;
2522 } GSUB_Header;
2524 typedef struct
2526 CHAR ScriptTag[4];
2527 WORD Script;
2528 } GSUB_ScriptRecord;
2530 typedef struct
2532 WORD ScriptCount;
2533 GSUB_ScriptRecord ScriptRecord[1];
2534 } GSUB_ScriptList;
2536 typedef struct
2538 CHAR LangSysTag[4];
2539 WORD LangSys;
2540 } GSUB_LangSysRecord;
2542 typedef struct
2544 WORD DefaultLangSys;
2545 WORD LangSysCount;
2546 GSUB_LangSysRecord LangSysRecord[1];
2547 } GSUB_Script;
2549 typedef struct
2551 WORD LookupOrder; /* Reserved */
2552 WORD ReqFeatureIndex;
2553 WORD FeatureCount;
2554 WORD FeatureIndex[1];
2555 } GSUB_LangSys;
2557 typedef struct
2559 CHAR FeatureTag[4];
2560 WORD Feature;
2561 } GSUB_FeatureRecord;
2563 typedef struct
2565 WORD FeatureCount;
2566 GSUB_FeatureRecord FeatureRecord[1];
2567 } GSUB_FeatureList;
2569 typedef struct
2571 WORD FeatureParams; /* Reserved */
2572 WORD LookupCount;
2573 WORD LookupListIndex[1];
2574 } GSUB_Feature;
2576 typedef struct
2578 WORD LookupCount;
2579 WORD Lookup[1];
2580 } GSUB_LookupList;
2582 typedef struct
2584 WORD LookupType;
2585 WORD LookupFlag;
2586 WORD SubTableCount;
2587 WORD SubTable[1];
2588 } GSUB_LookupTable;
2590 typedef struct
2592 WORD CoverageFormat;
2593 WORD GlyphCount;
2594 WORD GlyphArray[1];
2595 } GSUB_CoverageFormat1;
2597 typedef struct
2599 WORD Start;
2600 WORD End;
2601 WORD StartCoverageIndex;
2602 } GSUB_RangeRecord;
2604 typedef struct
2606 WORD CoverageFormat;
2607 WORD RangeCount;
2608 GSUB_RangeRecord RangeRecord[1];
2609 } GSUB_CoverageFormat2;
2611 typedef struct
2613 WORD SubstFormat; /* = 1 */
2614 WORD Coverage;
2615 WORD DeltaGlyphID;
2616 } GSUB_SingleSubstFormat1;
2618 typedef struct
2620 WORD SubstFormat; /* = 2 */
2621 WORD Coverage;
2622 WORD GlyphCount;
2623 WORD Substitute[1];
2624 } GSUB_SingleSubstFormat2;
2626 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
2628 GSUB_ScriptList *script;
2629 GSUB_Script *deflt = NULL;
2630 int i;
2632 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
2633 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
2634 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
2636 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
2637 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
2638 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
2639 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
2641 return deflt;
2644 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
2646 int i, offset;
2647 GSUB_LangSys *lang;
2649 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
2651 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
2653 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
2654 lang = (GSUB_LangSys *)((BYTE *)script + offset);
2655 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
2657 offset = GET_BE_WORD(script->DefaultLangSys);
2658 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
2659 return NULL;
2662 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
2664 int i;
2665 const GSUB_FeatureList *feature;
2667 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
2668 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
2669 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
2671 int index = GET_BE_WORD(lang->FeatureIndex[i]);
2672 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
2673 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
2675 return NULL;
2678 static const char *get_opentype_script( const struct gdi_font *font )
2681 * I am not sure if this is the correct way to generate our script tag
2683 switch (font->charset)
2685 case ANSI_CHARSET: return "latn";
2686 case BALTIC_CHARSET: return "latn"; /* ?? */
2687 case CHINESEBIG5_CHARSET: return "hani";
2688 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
2689 case GB2312_CHARSET: return "hani";
2690 case GREEK_CHARSET: return "grek";
2691 case HANGUL_CHARSET: return "hang";
2692 case RUSSIAN_CHARSET: return "cyrl";
2693 case SHIFTJIS_CHARSET: return "kana";
2694 case TURKISH_CHARSET: return "latn"; /* ?? */
2695 case VIETNAMESE_CHARSET: return "latn";
2696 case JOHAB_CHARSET: return "latn"; /* ?? */
2697 case ARABIC_CHARSET: return "arab";
2698 case HEBREW_CHARSET: return "hebr";
2699 case THAI_CHARSET: return "thai";
2700 default: return "latn";
2704 static void *get_GSUB_vert_feature( struct gdi_font *font )
2706 GSUB_Header *header;
2707 GSUB_Script *script;
2708 GSUB_LangSys *language;
2709 GSUB_Feature *feature;
2710 UINT length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2712 if (length == GDI_ERROR) return NULL;
2714 header = malloc( length );
2715 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2716 TRACE( "Loaded GSUB table of %i bytes\n", length );
2718 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2720 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2722 feature = GSUB_get_feature( header, language, "vrt2" );
2723 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2724 if (feature)
2726 font->gsub_table = header;
2727 return feature;
2729 TRACE("vrt2/vert feature not found\n");
2731 else TRACE("Language not found\n");
2733 else TRACE("Script not found\n");
2735 free( header );
2736 return NULL;
2739 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2741 GSUB_CoverageFormat1 *cf1 = table;
2743 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2745 int i, count = GET_BE_WORD(cf1->GlyphCount);
2747 TRACE("Coverage Format 1, %i glyphs\n",count);
2748 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2749 return -1;
2751 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2753 int i, count;
2754 GSUB_CoverageFormat2 *cf2 = table;
2756 count = GET_BE_WORD(cf2->RangeCount);
2757 TRACE("Coverage Format 2, %i ranges\n",count);
2758 for (i = 0; i < count; i++)
2760 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2761 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2762 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2764 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2765 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2768 return -1;
2770 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2772 return -1;
2775 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2777 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2778 int i, j, offset;
2780 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2781 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2783 GSUB_LookupTable *look;
2784 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2785 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2786 TRACE("type %i, flag %x, subtables %i\n",
2787 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2788 if (GET_BE_WORD(look->LookupType) == 1)
2790 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2792 GSUB_SingleSubstFormat1 *ssf1;
2793 offset = GET_BE_WORD(look->SubTable[j]);
2794 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2795 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2797 int offset = GET_BE_WORD(ssf1->Coverage);
2798 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2799 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2801 TRACE(" Glyph 0x%x ->",glyph);
2802 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2803 TRACE(" 0x%x\n",glyph);
2806 else
2808 GSUB_SingleSubstFormat2 *ssf2;
2809 int index, offset;
2811 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2812 offset = GET_BE_WORD(ssf1->Coverage);
2813 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2814 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2815 TRACE(" Coverage index %i\n",index);
2816 if (index != -1)
2818 TRACE(" Glyph is 0x%x ->",glyph);
2819 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2820 TRACE("0x%x\n",glyph);
2825 else FIXME("We only handle SubType 1\n");
2827 return glyph;
2830 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2832 if (!glyph) return glyph;
2833 if (!font->gsub_table) return glyph;
2834 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2837 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2839 FONTSIGNATURE fs = {{0}};
2840 struct gdi_font *child;
2841 struct gdi_font_face *face;
2843 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE, NULL ))) return;
2845 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2846 child->matrix = font->matrix;
2847 child->can_use_bitmap = font->can_use_bitmap;
2848 child->scale_y = font->scale_y;
2849 child->aveWidth = font->aveWidth;
2850 child->charset = font->charset;
2851 child->codepage = font->codepage;
2852 child->base_font = font;
2853 list_add_tail( &font->child_fonts, &child->entry );
2854 TRACE( "created child font %p for base %p\n", child, font );
2857 static void create_child_font_list( struct gdi_font *font )
2859 struct gdi_font_link *font_link;
2860 struct gdi_font_link_entry *entry;
2861 const WCHAR* font_name = (WCHAR *)font->otm.otmpFaceName;
2863 if ((font_link = find_gdi_font_link( font_name )))
2865 TRACE("found entry in system list\n");
2866 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2867 add_child_font( font, entry->family_name );
2870 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2871 * Sans Serif. This is how asian windows get default fallbacks for fonts
2873 if (ansi_cp.MaximumCharacterSize == 2 && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2874 facename_compare( font_name, microsoft_sans_serifW, -1 ) != 0)
2876 if ((font_link = find_gdi_font_link( microsoft_sans_serifW )))
2878 TRACE("found entry in default fallback list\n");
2879 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2880 add_child_font( font, entry->family_name );
2885 /* font cache */
2887 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2888 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2889 static unsigned int unused_font_count;
2890 #define UNUSED_CACHE_SIZE 10
2892 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2893 const FMAT2 *matrix, BOOL can_use_bitmap )
2895 if (font->hash != hash) return TRUE;
2896 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2897 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2898 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2899 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2902 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2904 DWORD hash = 0, *ptr, two_chars;
2905 WORD *pwc;
2906 unsigned int i;
2908 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2909 hash ^= *ptr;
2910 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2911 hash ^= *ptr;
2912 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2914 two_chars = *ptr;
2915 pwc = (WCHAR *)&two_chars;
2916 if(!*pwc) break;
2917 *pwc = towupper(*pwc);
2918 pwc++;
2919 *pwc = towupper(*pwc);
2920 hash ^= two_chars;
2921 if(!*pwc) break;
2923 hash ^= !can_use_bitmap;
2924 return hash;
2927 static void cache_gdi_font( struct gdi_font *font )
2929 static DWORD cache_num = 1;
2931 font->cache_num = cache_num++;
2932 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2933 list_add_head( &gdi_font_list, &font->entry );
2934 TRACE( "font %p\n", font );
2937 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2939 struct gdi_font *font;
2940 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2942 /* try the in-use list */
2943 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2945 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2946 list_remove( &font->entry );
2947 list_add_head( &gdi_font_list, &font->entry );
2948 if (!font->refcount++)
2950 list_remove( &font->unused_entry );
2951 unused_font_count--;
2953 return font;
2955 return NULL;
2958 static void release_gdi_font( struct gdi_font *font )
2960 if (!font) return;
2962 TRACE( "font %p\n", font );
2964 /* add it to the unused list */
2965 pthread_mutex_lock( &font_lock );
2966 if (!--font->refcount)
2968 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2969 if (unused_font_count > UNUSED_CACHE_SIZE)
2971 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2972 TRACE( "freeing %p\n", font );
2973 list_remove( &font->entry );
2974 list_remove( &font->unused_entry );
2975 free_gdi_font( font );
2977 else unused_font_count++;
2979 pthread_mutex_unlock( &font_lock );
2982 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2984 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2986 set_reg_ascii_value( hkey, "Courier", fl->courier );
2987 set_reg_ascii_value( hkey, "MS Serif", fl->serif );
2988 set_reg_ascii_value( hkey, "MS Sans Serif", sserif );
2989 set_reg_ascii_value( hkey, "Small Fonts", fl->small );
2992 static void set_value_key(HKEY hkey, const char *name, const char *value)
2994 if (value)
2995 set_reg_ascii_value( hkey, name, value );
2996 else if (name)
2998 WCHAR nameW[64];
2999 asciiz_to_unicode( nameW, name );
3000 reg_delete_value( hkey, nameW );
3004 static void update_font_association_info(void)
3006 static const WCHAR associated_charsetW[] =
3007 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
3009 if (ansi_cp.MaximumCharacterSize == 2)
3011 HKEY hkey;
3012 if ((hkey = reg_create_key( NULL, font_assoc_keyW, sizeof(font_assoc_keyW), 0, NULL )))
3014 HKEY hsubkey;
3015 if ((hsubkey = reg_create_key( hkey, associated_charsetW, sizeof(associated_charsetW),
3016 0, NULL )))
3018 switch (ansi_cp.CodePage)
3020 case 932:
3021 set_value_key(hsubkey, "ANSI(00)", "NO");
3022 set_value_key(hsubkey, "OEM(FF)", "NO");
3023 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3024 break;
3025 case 936:
3026 case 949:
3027 case 950:
3028 set_value_key(hsubkey, "ANSI(00)", "YES");
3029 set_value_key(hsubkey, "OEM(FF)", "YES");
3030 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3031 break;
3033 NtClose( hsubkey );
3036 /* TODO: Associated DefaultFonts */
3038 NtClose( hkey );
3041 else
3042 reg_delete_tree( NULL, font_assoc_keyW, sizeof(font_assoc_keyW) );
3045 static void set_multi_value_key( HKEY hkey, const WCHAR *name, const char *value, UINT len )
3047 WCHAR *valueW;
3049 if (!(valueW = malloc( len * sizeof(WCHAR) )))
3051 ERR( "malloc of %d * WCHAR failed\n", len );
3052 return;
3054 ascii_to_unicode( valueW, value, len );
3055 if (value)
3056 set_reg_value( hkey, name, REG_MULTI_SZ, valueW, len * sizeof(WCHAR) );
3057 else if (name)
3058 reg_delete_value( hkey, name );
3059 free( valueW );
3062 static void update_font_system_link_info(void)
3064 HKEY hkey;
3066 if ((hkey = reg_create_key( NULL, system_link_keyW, sizeof(system_link_keyW), 0, NULL )))
3068 const char *link;
3069 DWORD len, i;
3071 for (i = 0; i < ARRAY_SIZE(default_system_link); ++i)
3073 const struct system_link_reg *link_reg = &default_system_link[i];
3075 link = link_reg->link_non_cjk;
3076 len = link_reg->link_non_cjk_len;
3078 if (link_reg->locale_dependent)
3080 switch (ansi_cp.CodePage)
3082 case 932:
3083 link = link_reg->link_jp;
3084 len = link_reg->link_jp_len;
3085 break;
3086 case 936:
3087 link = link_reg->link_sc;
3088 len = link_reg->link_sc_len;
3089 break;
3090 case 949:
3091 link = link_reg->link_kr;
3092 len = link_reg->link_kr_len;
3093 break;
3094 case 950:
3095 link = link_reg->link_tc;
3096 len = link_reg->link_tc_len;
3097 break;
3100 set_multi_value_key(hkey, link_reg->font_name, link, len);
3102 NtClose( hkey );
3106 static void update_codepage( UINT screen_dpi )
3108 USHORT utf8_hdr[2] = { 0, CP_UTF8 };
3109 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[40 * sizeof(WCHAR)])];
3110 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
3111 char cpbuf[40];
3112 WCHAR cpbufW[40];
3113 HKEY hkey;
3114 DWORD size;
3115 UINT i;
3116 UINT font_dpi = 0;
3117 BOOL done = FALSE, cp_match = FALSE;
3119 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
3121 size = query_reg_value( wine_fonts_key, log_pixelsW, info, sizeof(value_buffer) );
3122 if (size == sizeof(DWORD) && info->Type == REG_DWORD)
3123 font_dpi = *(DWORD *)info->Data;
3125 RtlInitCodePageTable( utf8_hdr, &utf8_cp );
3126 if (NtCurrentTeb()->Peb->AnsiCodePageData)
3127 RtlInitCodePageTable( NtCurrentTeb()->Peb->AnsiCodePageData, &ansi_cp );
3128 else
3129 ansi_cp = utf8_cp;
3130 if (NtCurrentTeb()->Peb->OemCodePageData)
3131 RtlInitCodePageTable( NtCurrentTeb()->Peb->OemCodePageData, &oem_cp );
3132 else
3133 oem_cp = utf8_cp;
3134 snprintf( cpbuf, sizeof(cpbuf), "%u,%u", ansi_cp.CodePage, oem_cp.CodePage );
3135 asciiz_to_unicode( cpbufW, cpbuf );
3137 if (query_reg_ascii_value( wine_fonts_key, "Codepages", info, sizeof(value_buffer) ))
3139 cp_match = !wcscmp( (const WCHAR *)info->Data, cpbufW );
3140 if (cp_match && screen_dpi == font_dpi) return; /* already set correctly */
3141 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3142 debugstr_w((const WCHAR *)info->Data), font_dpi, ansi_cp.CodePage, oem_cp.CodePage, screen_dpi );
3144 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3145 ansi_cp.CodePage, oem_cp.CodePage, screen_dpi);
3147 set_reg_ascii_value( wine_fonts_key, "Codepages", cpbuf );
3148 set_reg_value( wine_fonts_key, log_pixelsW, REG_DWORD, &screen_dpi, sizeof(screen_dpi) );
3150 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
3152 if (nls_update_font_list[i].ansi_cp == ansi_cp.CodePage &&
3153 nls_update_font_list[i].oem_cp == oem_cp.CodePage)
3155 HKEY software_hkey;
3156 if ((software_hkey = reg_create_key( NULL, software_config_keyW,
3157 sizeof(software_config_keyW), 0, NULL )))
3159 static const WCHAR fontsW[] = {'F','o','n','t','s'};
3160 hkey = reg_create_key( software_hkey, fontsW, sizeof(fontsW), 0, NULL );
3161 NtClose( software_hkey );
3162 if (hkey)
3164 set_reg_ascii_value( hkey, "OEMFONT.FON", nls_update_font_list[i].oem );
3165 set_reg_ascii_value( hkey, "FIXEDFON.FON", nls_update_font_list[i].fixed );
3166 set_reg_ascii_value( hkey, "FONTS.FON", nls_update_font_list[i].system );
3167 NtClose( hkey );
3170 if ((hkey = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW),
3171 0, NULL )))
3173 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3174 NtClose( hkey );
3176 if ((hkey = reg_create_key( NULL, fonts_win9x_config_keyW,
3177 sizeof(fonts_win9x_config_keyW), 0, NULL )))
3179 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3180 NtClose( hkey );
3182 /* Only update these if the Codepage changed. */
3183 if (!cp_match &&
3184 (hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
3185 0, NULL )))
3187 set_reg_ascii_value( hkey, "MS Shell Dlg", nls_update_font_list[i].shelldlg );
3188 set_reg_ascii_value( hkey, "Tms Rmn", nls_update_font_list[i].tmsrmn );
3190 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3191 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3192 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3193 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3194 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3195 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3196 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3197 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3199 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3200 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3201 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3203 NtClose( hkey );
3205 done = TRUE;
3207 else
3209 /* Delete the FontSubstitutes from other locales */
3210 if ((hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
3211 0, NULL )))
3213 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3214 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3215 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3216 NtClose( hkey );
3220 if (!done)
3221 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp.CodePage, oem_cp.CodePage);
3223 /* update locale dependent font association info and font system link info in registry.
3224 update only when codepages changed, not logpixels. */
3225 if (!cp_match)
3227 update_font_association_info();
3228 update_font_system_link_info();
3233 /*************************************************************
3234 * font_CreateDC
3236 static BOOL font_CreateDC( PHYSDEV *dev, LPCWSTR device, LPCWSTR output, const DEVMODEW *devmode )
3238 struct font_physdev *physdev;
3240 if (!font_funcs) return TRUE;
3241 if (!(physdev = calloc( 1, sizeof(*physdev) ))) return FALSE;
3242 push_dc_driver( dev, &physdev->dev, &font_driver );
3243 return TRUE;
3247 /*************************************************************
3248 * font_DeleteDC
3250 static BOOL font_DeleteDC( PHYSDEV dev )
3252 struct font_physdev *physdev = get_font_dev( dev );
3254 release_gdi_font( physdev->font );
3255 free( physdev );
3256 return TRUE;
3260 struct gdi_font_enum_data
3262 ENUMLOGFONTEXW elf;
3263 NEWTEXTMETRICEXW ntm;
3266 struct enum_charset
3268 DWORD mask;
3269 DWORD charset;
3270 DWORD script;
3273 static BOOL is_complex_script_ansi_cp(void)
3275 return (ansi_cp.CodePage == 874 /* Thai */
3276 || ansi_cp.CodePage == 1255 /* Hebrew */
3277 || ansi_cp.CodePage == 1256 /* Arabic */
3281 /***************************************************
3282 * create_enum_charset_list
3284 * This function creates charset enumeration list because in DEFAULT_CHARSET
3285 * case, the ANSI codepage's charset takes precedence over other charsets.
3286 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
3287 * This function works as a filter other than DEFAULT_CHARSET case.
3289 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
3291 struct enum_charset *start = list;
3292 CHARSETINFO csi;
3293 int i;
3295 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && csi.fs.fsCsb[0] != 0)
3297 list->mask = csi.fs.fsCsb[0];
3298 list->charset = csi.ciCharset;
3299 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
3300 list++;
3302 else /* charset is DEFAULT_CHARSET or invalid. */
3304 DWORD mask = 0;
3306 /* Set the current codepage's charset as the first element. */
3307 if (!is_complex_script_ansi_cp() &&
3308 translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, &csi, TCI_SRCCODEPAGE ) &&
3309 csi.fs.fsCsb[0] != 0)
3311 list->mask = csi.fs.fsCsb[0];
3312 list->charset = csi.ciCharset;
3313 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
3314 mask |= csi.fs.fsCsb[0];
3315 list++;
3318 /* Fill out left elements. */
3319 for (i = 0; i < 32; i++)
3321 FONTSIGNATURE fs;
3322 fs.fsCsb[0] = 1u << i;
3323 fs.fsCsb[1] = 0;
3324 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
3325 if (!translate_charset_info( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
3326 continue; /* skip, this is an invalid fsCsb bit. */
3327 list->mask = fs.fsCsb[0];
3328 list->charset = csi.ciCharset;
3329 list->script = i;
3330 mask |= fs.fsCsb[0];
3331 list++;
3333 /* add catch all mask for remaining bits */
3334 if (~mask)
3336 list->mask = ~mask;
3337 list->charset = DEFAULT_CHARSET;
3338 list->script = 33; /* other */
3339 list++;
3342 return list - start;
3345 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
3347 UINT ret = 0;
3349 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
3350 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
3351 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
3352 return ret;
3355 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
3357 struct gdi_font *font;
3358 LOGFONTW lf = { .lfHeight = -4096 /* preferable EM Square size */ };
3360 if (!face->scalable) lf.lfHeight = 0;
3362 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
3364 if (!font_funcs->load_font( font ))
3366 free_gdi_font( font );
3367 return FALSE;
3370 if (font->scalable && -lf.lfHeight % font->otm.otmEMSquare != 0)
3372 /* reload with the original EM Square size */
3373 lf.lfHeight = -font->otm.otmEMSquare;
3374 free_gdi_font( font );
3376 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
3377 if (!font_funcs->load_font( font ))
3379 free_gdi_font( font );
3380 return FALSE;
3384 if (font_funcs->set_outline_text_metrics( font ))
3386 static const DWORD ntm_ppem = 32;
3387 UINT cell_height;
3389 #define TM font->otm.otmTextMetrics
3390 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
3391 cell_height = TM.tmHeight / ( -lf.lfHeight / font->otm.otmEMSquare );
3392 ntm->ntmTm.tmHeight = muldiv( ntm_ppem, cell_height, font->otm.otmEMSquare );
3393 ntm->ntmTm.tmAscent = SCALE_NTM( TM.tmAscent );
3394 ntm->ntmTm.tmDescent = ntm->ntmTm.tmHeight - ntm->ntmTm.tmAscent;
3395 ntm->ntmTm.tmInternalLeading = SCALE_NTM( TM.tmInternalLeading );
3396 ntm->ntmTm.tmExternalLeading = SCALE_NTM( TM.tmExternalLeading );
3397 ntm->ntmTm.tmAveCharWidth = SCALE_NTM( TM.tmAveCharWidth );
3398 ntm->ntmTm.tmMaxCharWidth = SCALE_NTM( TM.tmMaxCharWidth );
3400 memcpy((char *)&ntm->ntmTm + offsetof( TEXTMETRICW, tmWeight ),
3401 (const char *)&TM + offsetof( TEXTMETRICW, tmWeight ),
3402 sizeof(TEXTMETRICW) - offsetof( TEXTMETRICW, tmWeight ));
3403 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
3404 ntm->ntmTm.ntmCellHeight = cell_height;
3405 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
3406 #undef SCALE_NTM
3407 #undef TM
3409 else if (font_funcs->set_bitmap_text_metrics( font ))
3411 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
3412 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
3413 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
3414 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
3416 ntm->ntmTm.ntmFlags = font->ntmFlags;
3417 ntm->ntmFontSig = font->fs;
3419 elf->elfLogFont.lfEscapement = 0;
3420 elf->elfLogFont.lfOrientation = 0;
3421 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
3422 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
3423 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
3424 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
3425 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
3426 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
3427 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
3428 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3429 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3430 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
3431 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3432 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
3433 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
3434 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
3436 free_gdi_font( font );
3437 return TRUE;
3440 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
3442 struct gdi_font_face *face;
3444 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
3445 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3446 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
3447 return FALSE;
3450 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
3452 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
3453 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
3456 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
3457 struct enum_charset *list, DWORD count, font_enum_proc proc, LPARAM lparam,
3458 const WCHAR *subst )
3460 ENUMLOGFONTEXW elf;
3461 NEWTEXTMETRICEXW ntm;
3462 UINT type, i;
3464 if (!face->cached_enum_data)
3466 struct gdi_font_enum_data *data;
3468 if (!(data = calloc( 1, sizeof(*data) )) ||
3469 !get_face_enum_data( face, &data->elf, &data->ntm ))
3471 free( data );
3472 return TRUE;
3474 face->cached_enum_data = data;
3477 elf = face->cached_enum_data->elf;
3478 ntm = face->cached_enum_data->ntm;
3479 type = get_font_type( &ntm );
3481 /* font replacement */
3482 if (family != face->family)
3484 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
3485 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
3487 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
3489 for (i = 0; i < count; i++)
3491 if (face->fs.fsCsb[0] == 0) /* OEM */
3493 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3494 elf.elfScript[0] = 32;
3495 i = count; /* break out of loop after enumeration */
3497 else
3499 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
3500 /* use the DEFAULT_CHARSET case only if no other charset is present */
3501 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
3502 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
3503 /* caller may fill elfScript with the actual string, see load_script_name */
3504 elf.elfScript[0] = list[i].script;
3506 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3507 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3508 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
3509 elf.elfLogFont.lfItalic, (int)elf.elfLogFont.lfWeight, (int)ntm.ntmTm.ntmFlags );
3510 /* release section before callback (FIXME) */
3511 pthread_mutex_unlock( &font_lock );
3512 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
3513 pthread_mutex_lock( &font_lock );
3515 return TRUE;
3518 /*************************************************************
3519 * font_EnumFonts
3521 static BOOL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, font_enum_proc proc, LPARAM lparam )
3523 struct gdi_font_family *family;
3524 struct gdi_font_face *face;
3525 struct enum_charset enum_charsets[32];
3526 UINT count, charset;
3528 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
3530 count = create_enum_charset_list( charset, enum_charsets );
3532 pthread_mutex_lock( &font_lock );
3534 if (lf && lf->lfFaceName[0])
3536 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
3537 const WCHAR *orig_name = NULL;
3539 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
3540 if (face_name)
3542 orig_name = lf->lfFaceName;
3543 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
3545 else face_name = lf->lfFaceName;
3547 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3549 if (!family_matches(family, face_name)) continue;
3550 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3552 if (!face_matches( family->family_name, face, face_name )) continue;
3553 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
3554 return FALSE; /* enum_face_charsets() unlocked font_lock */
3558 else
3560 TRACE( "charset %d\n", charset );
3561 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3563 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
3564 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
3565 return FALSE; /* enum_face_charsets() unlocked font_lock */
3568 pthread_mutex_unlock( &font_lock );
3569 return TRUE;
3573 static BOOL check_unicode_tategaki( WCHAR ch )
3575 extern const unsigned short vertical_orientation_table[];
3576 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
3578 /* We only reach this code if typographical substitution did not occur */
3579 /* Type: U or Type: Tu */
3580 return (orientation == 1 || orientation == 3);
3583 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
3585 UINT index;
3587 if (glyph < 0x100) glyph += 0xf000;
3588 /* there are a number of old pre-Unicode "broken" TTFs, which
3589 do have symbols at U+00XX instead of U+f0XX */
3590 index = glyph;
3591 font_funcs->get_glyph_index( font, &index, FALSE );
3592 if (!index)
3594 index = glyph - 0xf000;
3595 font_funcs->get_glyph_index( font, &index, FALSE );
3597 return index;
3600 CPTABLEINFO *get_cptable( WORD cp )
3602 static CPTABLEINFO tables[100];
3603 unsigned int i;
3604 USHORT *ptr;
3605 SIZE_T size;
3607 if (cp == CP_ACP) return &ansi_cp;
3608 if (cp == CP_UTF8) return &utf8_cp;
3610 for (i = 0; i < ARRAY_SIZE(tables) && tables[i].CodePage; i++)
3611 if (tables[i].CodePage == cp) return &tables[i];
3612 if (NtGetNlsSectionPtr( 11, cp, NULL, (void **)&ptr, &size )) return NULL;
3613 if (i == ARRAY_SIZE(tables))
3615 ERR( "too many code pages\n" );
3616 return NULL;
3618 RtlInitCodePageTable( ptr, &tables[i] );
3619 return &tables[i];
3622 /* Based on NlsValidateLocale */
3623 const NLS_LOCALE_DATA *get_locale_data( LCID lcid )
3625 static const NLS_LOCALE_HEADER *locale_table;
3626 static const NLS_LOCALE_LCID_INDEX *lcids_index;
3627 int min = 0, max;
3629 if (!locale_table)
3631 LARGE_INTEGER size;
3632 void *addr;
3633 LCID lcid;
3634 NTSTATUS status;
3635 static struct
3637 UINT ctypes;
3638 UINT unknown1;
3639 UINT unknown2;
3640 UINT unknown3;
3641 UINT locales;
3642 UINT charmaps;
3643 UINT geoids;
3644 UINT scripts;
3645 } *header;
3647 status = NtInitializeNlsFiles( &addr, &lcid, &size );
3648 if (status)
3650 ERR( "Failed to load nls file\n" );
3651 return NULL;
3654 if (InterlockedCompareExchangePointer( (void **)&header, addr, NULL ))
3655 NtUnmapViewOfSection( GetCurrentProcess(), addr );
3657 locale_table = (const NLS_LOCALE_HEADER *)((char *)header + header->locales);
3658 lcids_index = (const NLS_LOCALE_LCID_INDEX *)((char *)locale_table + locale_table->lcids_offset);
3661 max = locale_table->nb_lcids - 1;
3662 while (min <= max)
3664 int pos = (min + max) / 2;
3665 if (lcid < lcids_index[pos].id) max = pos - 1;
3666 else if (lcid > lcids_index[pos].id) min = pos + 1;
3667 else
3669 ULONG offset = locale_table->locales_offset + pos * locale_table->locale_size;
3670 return (const NLS_LOCALE_DATA *)((const char *)locale_table + offset);
3673 return NULL;
3676 DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, DWORD srclen )
3678 DWORD ret;
3680 if (info->CodePage == CP_UTF8)
3681 RtlUnicodeToUTF8N( dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3682 else
3683 RtlUnicodeToCustomCPN( info, dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3685 return ret;
3688 DWORD win32u_wctomb_size( CPTABLEINFO *info, const WCHAR *src, DWORD srclen )
3690 DWORD ret;
3692 if (info->CodePage == CP_UTF8)
3694 RtlUnicodeToUTF8N( NULL, 0, &ret, src, srclen * sizeof(WCHAR) );
3696 else if(info->DBCSCodePage)
3698 WCHAR *uni2cp = info->WideCharTable;
3699 for (ret = srclen; srclen; srclen--, src++)
3700 if (uni2cp[*src] & 0xff00) ret++;
3702 else
3704 ret = srclen;
3707 return ret;
3710 DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *src, DWORD srclen )
3712 DWORD ret;
3714 if (info->CodePage == CP_UTF8)
3715 RtlUTF8ToUnicodeN( dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3716 else
3717 RtlCustomCPToUnicodeN( info, dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3719 return ret / sizeof(WCHAR);
3722 DWORD win32u_mbtowc_size( CPTABLEINFO *info, const char *src, DWORD srclen )
3724 DWORD ret;
3726 if (info->CodePage == CP_UTF8)
3728 RtlUTF8ToUnicodeN( NULL, 0, &ret, src, srclen );
3729 ret /= sizeof(WCHAR);
3731 else if (info->DBCSCodePage)
3733 for (ret = 0; srclen; srclen--, src++, ret++)
3735 if (info->DBCSOffsets[(unsigned char)*src] && srclen > 1)
3737 src++;
3738 srclen--;
3742 else
3744 ret = srclen;
3747 return ret;
3750 static BOOL wc_to_index( UINT cp, WCHAR wc, unsigned char *dst, BOOL allow_default )
3752 const CPTABLEINFO *info;
3754 if (!(info = get_cptable( cp ))) return FALSE;
3756 if (info->CodePage == CP_UTF8)
3758 if (wc < 0x80)
3760 *dst = wc;
3761 return TRUE;
3763 if (!allow_default) return FALSE;
3764 *dst = info->DefaultChar;
3765 return TRUE;
3767 else if (info->DBCSCodePage)
3769 WCHAR *uni2cp = info->WideCharTable;
3770 if (uni2cp[wc] & 0xff00) return FALSE;
3771 *dst = uni2cp[wc];
3773 else
3775 char *uni2cp = info->WideCharTable;
3776 *dst = uni2cp[wc];
3779 if (info->MultiByteTable[*dst] != wc)
3781 if (!allow_default) return FALSE;
3782 *dst = info->DefaultChar;
3785 return TRUE;
3788 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
3790 WCHAR wc = glyph;
3791 unsigned char ch;
3793 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
3795 if (font->codepage == CP_SYMBOL)
3797 glyph = get_glyph_index_symbol( font, wc );
3798 if (!glyph)
3800 if (wc_to_index( CP_ACP, wc, &ch, TRUE ))
3801 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
3804 else if (wc_to_index( font->codepage, wc, &ch, FALSE ))
3806 glyph = (unsigned char)ch;
3807 font_funcs->get_glyph_index( font, &glyph, FALSE );
3809 else return 0;
3811 return glyph;
3814 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
3816 struct gdi_font *child;
3817 UINT res;
3819 if ((res = get_glyph_index( *font, glyph ))) return res;
3820 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
3822 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
3824 if (!child->private && !font_funcs->load_font( child )) continue;
3825 if ((res = get_glyph_index( child, glyph )))
3827 *font = child;
3828 return res;
3831 return 0;
3834 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3835 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
3836 const MAT2 *mat )
3838 GLYPHMETRICS gm;
3839 ABC abc;
3840 DWORD ret = 1;
3841 UINT index = glyph;
3842 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
3844 if (format & GGO_GLYPH_INDEX)
3846 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3847 as glyph index. "Treasure Adventure Game" depends on this. */
3848 font_funcs->get_glyph_index( font, &index, FALSE );
3849 format &= ~GGO_GLYPH_INDEX;
3850 /* TODO: Window also turns off tategaki for glyphs passed in by index
3851 if their unicode code points fall outside of the range that is
3852 rotated. */
3854 else
3856 index = get_glyph_index_linked( &font, glyph );
3857 if (tategaki)
3859 UINT orig = index;
3860 index = get_GSUB_vert_glyph( font, index );
3861 if (index == orig) tategaki = check_unicode_tategaki( glyph );
3865 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
3867 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
3868 goto done;
3870 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
3871 if (ret == GDI_ERROR) return ret;
3873 if (format == GGO_METRICS && !mat)
3874 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
3876 done:
3877 if (gm_ret) *gm_ret = gm;
3878 if (abc_ret) *abc_ret = abc;
3879 return ret;
3883 /*************************************************************
3884 * font_FontIsLinked
3886 static BOOL font_FontIsLinked( PHYSDEV dev )
3888 struct font_physdev *physdev = get_font_dev( dev );
3890 if (!physdev->font)
3892 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
3893 return dev->funcs->pFontIsLinked( dev );
3895 return !list_empty( &physdev->font->child_fonts );
3899 /*************************************************************
3900 * font_GetCharABCWidths
3902 static BOOL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT count, WCHAR *chars, ABC *buffer )
3904 struct font_physdev *physdev = get_font_dev( dev );
3905 UINT c, i;
3907 if (!physdev->font)
3909 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3910 return dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
3913 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3915 pthread_mutex_lock( &font_lock );
3916 for (i = 0; i < count; i++)
3918 c = chars ? chars[i] : first + i;
3919 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &buffer[i], 0, NULL, NULL );
3921 pthread_mutex_unlock( &font_lock );
3922 return TRUE;
3926 /*************************************************************
3927 * font_GetCharABCWidthsI
3929 static BOOL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3931 struct font_physdev *physdev = get_font_dev( dev );
3932 UINT c;
3934 if (!physdev->font)
3936 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3937 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3940 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3942 pthread_mutex_lock( &font_lock );
3943 for (c = 0; c < count; c++, buffer++)
3944 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3945 NULL, buffer, 0, NULL, NULL );
3946 pthread_mutex_unlock( &font_lock );
3947 return TRUE;
3951 /*************************************************************
3952 * font_GetCharWidth
3954 static BOOL font_GetCharWidth( PHYSDEV dev, UINT first, UINT count, const WCHAR *chars, INT *buffer )
3956 struct font_physdev *physdev = get_font_dev( dev );
3957 UINT c, i;
3958 ABC abc;
3960 if (!physdev->font)
3962 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3963 return dev->funcs->pGetCharWidth( dev, first, count, chars, buffer );
3966 TRACE( "%p, %d, %d, %p\n", physdev->font, first, count, buffer );
3968 pthread_mutex_lock( &font_lock );
3969 for (i = 0; i < count; i++)
3971 c = chars ? chars[i] : i + first;
3972 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3973 buffer[i] = 0;
3974 else
3975 buffer[i] = abc.abcA + abc.abcB + abc.abcC;
3977 pthread_mutex_unlock( &font_lock );
3978 return TRUE;
3982 /*************************************************************
3983 * font_GetCharWidthInfo
3985 static BOOL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3987 struct font_physdev *physdev = get_font_dev( dev );
3988 struct char_width_info *info = ptr;
3990 if (!physdev->font)
3992 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3993 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3996 info->unk = 0;
3997 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3998 info->lsb = info->rsb = 0;
4000 return TRUE;
4004 /*************************************************************
4005 * font_GetFontData
4007 static DWORD font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
4009 struct font_physdev *physdev = get_font_dev( dev );
4011 if (!physdev->font)
4013 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
4014 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
4016 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
4020 /*************************************************************
4021 * font_GetFontRealizationInfo
4023 static BOOL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
4025 struct font_physdev *physdev = get_font_dev( dev );
4026 struct font_realization_info *info = ptr;
4028 if (!physdev->font)
4030 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
4031 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
4034 TRACE( "(%p, %p)\n", physdev->font, info);
4036 info->flags = 1;
4037 if (physdev->font->scalable) info->flags |= 2;
4039 info->cache_num = physdev->font->cache_num;
4040 info->instance_id = physdev->font->handle;
4041 if (info->size == sizeof(*info))
4043 info->file_count = 1;
4044 info->face_index = physdev->font->face_index;
4045 info->simulations = 0;
4046 if (physdev->font->fake_bold) info->simulations |= 0x1;
4047 if (physdev->font->fake_italic) info->simulations |= 0x2;
4049 return TRUE;
4053 /*************************************************************
4054 * font_GetFontUnicodeRanges
4056 static DWORD font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
4058 struct font_physdev *physdev = get_font_dev( dev );
4059 DWORD size, num_ranges;
4061 if (!physdev->font)
4063 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
4064 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
4067 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
4068 size = offsetof( GLYPHSET, ranges[num_ranges] );
4069 if (glyphset)
4071 glyphset->cbThis = size;
4072 glyphset->cRanges = num_ranges;
4073 glyphset->flAccel = 0;
4075 return size;
4079 /*************************************************************
4080 * font_GetGlyphIndices
4082 static DWORD font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
4084 struct font_physdev *physdev = get_font_dev( dev );
4085 UINT default_char;
4086 unsigned char ch;
4087 BOOL got_default = FALSE;
4088 int i;
4090 if (!physdev->font)
4092 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
4093 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
4096 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4098 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4099 got_default = TRUE;
4102 pthread_mutex_lock( &font_lock );
4104 for (i = 0; i < count; i++)
4106 UINT glyph = str[i];
4108 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
4110 glyph = 0;
4111 if (physdev->font->codepage == CP_SYMBOL)
4113 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
4114 else if (str[i] < 0x100) glyph = str[i];
4116 else if (wc_to_index( physdev->font->codepage, str[i], &ch, FALSE ))
4117 glyph = (unsigned char)ch;
4119 if (!glyph)
4121 if (!got_default)
4123 default_char = font_funcs->get_default_glyph( physdev->font );
4124 got_default = TRUE;
4126 gi[i] = default_char;
4128 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
4131 pthread_mutex_unlock( &font_lock );
4132 return count;
4136 /*************************************************************
4137 * font_GetGlyphOutline
4139 static DWORD font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
4140 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
4142 struct font_physdev *physdev = get_font_dev( dev );
4143 DWORD ret;
4145 if (!physdev->font)
4147 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
4148 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
4150 pthread_mutex_lock( &font_lock );
4151 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
4152 pthread_mutex_unlock( &font_lock );
4153 return ret;
4157 /*************************************************************
4158 * font_GetKerningPairs
4160 static DWORD font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
4162 struct font_physdev *physdev = get_font_dev( dev );
4164 if (!physdev->font)
4166 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
4167 return dev->funcs->pGetKerningPairs( dev, count, pairs );
4170 pthread_mutex_lock( &font_lock );
4171 if (physdev->font->kern_count == -1)
4172 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
4173 &physdev->font->kern_pairs );
4174 pthread_mutex_unlock( &font_lock );
4176 if (count && pairs)
4178 count = min( count, physdev->font->kern_count );
4179 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
4181 else count = physdev->font->kern_count;
4183 return count;
4187 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
4189 double scale_x, scale_y;
4191 if (font->aveWidth)
4193 scale_x = (double)font->aveWidth;
4194 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
4196 else
4197 scale_x = font->scale_y;
4199 scale_x *= fabs(font->matrix.eM11);
4200 scale_y = font->scale_y * fabs(font->matrix.eM22);
4202 /* Windows scales these values as signed integers even if they are unsigned */
4203 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
4204 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
4206 SCALE_Y(otm->otmTextMetrics.tmHeight);
4207 SCALE_Y(otm->otmTextMetrics.tmAscent);
4208 SCALE_Y(otm->otmTextMetrics.tmDescent);
4209 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
4210 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
4212 SCALE_X(otm->otmTextMetrics.tmOverhang);
4213 if (font->fake_bold)
4215 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
4216 otm->otmTextMetrics.tmAveCharWidth++;
4217 otm->otmTextMetrics.tmMaxCharWidth++;
4219 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
4220 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
4222 SCALE_Y(otm->otmAscent);
4223 SCALE_Y(otm->otmDescent);
4224 SCALE_Y(otm->otmLineGap);
4225 SCALE_Y(otm->otmsCapEmHeight);
4226 SCALE_Y(otm->otmsXHeight);
4227 SCALE_Y(otm->otmrcFontBox.top);
4228 SCALE_Y(otm->otmrcFontBox.bottom);
4229 SCALE_X(otm->otmrcFontBox.left);
4230 SCALE_X(otm->otmrcFontBox.right);
4231 SCALE_Y(otm->otmMacAscent);
4232 SCALE_Y(otm->otmMacDescent);
4233 SCALE_Y(otm->otmMacLineGap);
4234 SCALE_X(otm->otmptSubscriptSize.x);
4235 SCALE_Y(otm->otmptSubscriptSize.y);
4236 SCALE_X(otm->otmptSubscriptOffset.x);
4237 SCALE_Y(otm->otmptSubscriptOffset.y);
4238 SCALE_X(otm->otmptSuperscriptSize.x);
4239 SCALE_Y(otm->otmptSuperscriptSize.y);
4240 SCALE_X(otm->otmptSuperscriptOffset.x);
4241 SCALE_Y(otm->otmptSuperscriptOffset.y);
4242 SCALE_Y(otm->otmsStrikeoutSize);
4243 SCALE_Y(otm->otmsStrikeoutPosition);
4244 SCALE_Y(otm->otmsUnderscoreSize);
4245 SCALE_Y(otm->otmsUnderscorePosition);
4247 #undef SCALE_X
4248 #undef SCALE_Y
4251 /*************************************************************
4252 * font_GetOutlineTextMetrics
4254 static UINT font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
4256 struct font_physdev *physdev = get_font_dev( dev );
4257 UINT ret = 0;
4259 if (!physdev->font)
4261 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
4262 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
4265 if (!physdev->font->scalable) return 0;
4267 pthread_mutex_lock( &font_lock );
4268 if (font_funcs->set_outline_text_metrics( physdev->font ))
4270 ret = physdev->font->otm.otmSize;
4271 if (metrics && size >= physdev->font->otm.otmSize)
4273 WCHAR *ptr = (WCHAR *)(metrics + 1);
4274 *metrics = physdev->font->otm;
4275 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
4276 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
4277 ptr += lstrlenW(ptr) + 1;
4278 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
4279 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
4280 ptr += lstrlenW(ptr) + 1;
4281 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
4282 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
4283 ptr += lstrlenW(ptr) + 1;
4284 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
4285 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
4286 scale_outline_font_metrics( physdev->font, metrics );
4289 pthread_mutex_unlock( &font_lock );
4290 return ret;
4294 /*************************************************************
4295 * font_GetTextCharsetInfo
4297 static UINT font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
4299 struct font_physdev *physdev = get_font_dev( dev );
4301 if (!physdev->font)
4303 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
4304 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4306 if (fs) *fs = physdev->font->fs;
4307 return physdev->font->charset;
4311 /*************************************************************
4312 * font_GetTextExtentExPoint
4314 static BOOL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
4316 struct font_physdev *physdev = get_font_dev( dev );
4317 INT i, pos;
4318 ABC abc;
4320 if (!physdev->font)
4322 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
4323 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
4326 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
4328 pthread_mutex_lock( &font_lock );
4329 for (i = pos = 0; i < count; i++)
4331 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
4332 pos += abc.abcA + abc.abcB + abc.abcC;
4333 dxs[i] = pos;
4335 pthread_mutex_unlock( &font_lock );
4336 return TRUE;
4340 /*************************************************************
4341 * font_GetTextExtentExPointI
4343 static BOOL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
4345 struct font_physdev *physdev = get_font_dev( dev );
4346 INT i, pos;
4347 ABC abc;
4349 if (!physdev->font)
4351 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
4352 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
4355 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
4357 pthread_mutex_lock( &font_lock );
4358 for (i = pos = 0; i < count; i++)
4360 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
4361 NULL, &abc, 0, NULL, NULL );
4362 pos += abc.abcA + abc.abcB + abc.abcC;
4363 dxs[i] = pos;
4365 pthread_mutex_unlock( &font_lock );
4366 return TRUE;
4370 /*************************************************************
4371 * font_GetTextFace
4373 static INT font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
4375 struct font_physdev *physdev = get_font_dev( dev );
4376 const WCHAR *font_name;
4377 INT len;
4379 if (!physdev->font)
4381 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
4382 return dev->funcs->pGetTextFace( dev, count, str );
4384 font_name = get_gdi_font_name( physdev->font );
4385 len = lstrlenW( font_name ) + 1;
4386 if (str)
4388 lstrcpynW( str, font_name, count );
4389 len = min( count, len );
4391 return len;
4395 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
4397 double scale_x, scale_y;
4399 /* Make sure that the font has sane width/height ratio */
4400 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
4402 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
4403 font->aveWidth = 0;
4406 if (font->aveWidth)
4408 scale_x = (double)font->aveWidth;
4409 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
4411 else
4412 scale_x = font->scale_y;
4414 scale_x *= fabs(font->matrix.eM11);
4415 scale_y = font->scale_y * fabs(font->matrix.eM22);
4417 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
4418 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
4420 SCALE_Y(tm->tmHeight);
4421 SCALE_Y(tm->tmAscent);
4422 SCALE_Y(tm->tmDescent);
4423 SCALE_Y(tm->tmInternalLeading);
4424 SCALE_Y(tm->tmExternalLeading);
4426 SCALE_X(tm->tmOverhang);
4427 if (font->fake_bold)
4429 if (!font->scalable) tm->tmOverhang++;
4430 tm->tmAveCharWidth++;
4431 tm->tmMaxCharWidth++;
4433 SCALE_X(tm->tmAveCharWidth);
4434 SCALE_X(tm->tmMaxCharWidth);
4436 #undef SCALE_X
4437 #undef SCALE_Y
4440 /*************************************************************
4441 * font_GetTextMetrics
4443 static BOOL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
4445 struct font_physdev *physdev = get_font_dev( dev );
4446 BOOL ret = FALSE;
4448 if (!physdev->font)
4450 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
4451 return dev->funcs->pGetTextMetrics( dev, metrics );
4454 pthread_mutex_lock( &font_lock );
4455 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
4456 font_funcs->set_bitmap_text_metrics( physdev->font ))
4458 *metrics = physdev->font->otm.otmTextMetrics;
4459 scale_font_metrics( physdev->font, metrics );
4460 ret = TRUE;
4462 pthread_mutex_unlock( &font_lock );
4463 return ret;
4467 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
4469 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4470 a single face with the requested charset. The idea is to check if
4471 the selected font supports the current ANSI codepage, if it does
4472 return the corresponding charset, else return the first charset */
4474 int i;
4476 if (translate_charset_info( (DWORD*)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
4478 const struct gdi_font_link *font_link;
4480 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
4481 font_link = find_gdi_font_link(family_name);
4482 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
4484 for (i = 0; i < 32; i++)
4486 DWORD fs0 = 1u << i;
4487 if (face->fs.fsCsb[0] & fs0)
4489 if (translate_charset_info(&fs0, csi, TCI_SRCFONTSIG)) return;
4490 FIXME("TCI failing on %x\n", (int)fs0);
4494 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4495 (int)face->fs.fsCsb[0], debugstr_w(face->file));
4496 csi->ciACP = ansi_cp.CodePage;
4497 csi->ciCharset = DEFAULT_CHARSET;
4500 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
4502 struct gdi_font *font;
4503 struct gdi_font_face *face;
4504 INT height;
4505 CHARSETINFO csi;
4506 const WCHAR *orig_name = NULL;
4507 BOOL substituted = FALSE;
4509 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
4511 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4512 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4513 original value lfCharSet. Note this is a special case for
4514 Symbol and doesn't happen at least for "Wingdings*" */
4515 if (!facename_compare( lf->lfFaceName, symbolW, -1 )) lf->lfCharSet = SYMBOL_CHARSET;
4517 /* check the cache first */
4518 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4520 TRACE( "returning cached gdiFont(%p)\n", font );
4521 return font;
4523 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &substituted, &orig_name )))
4525 FIXME( "can't find a single appropriate font - bailing\n" );
4526 return NULL;
4528 height = lf->lfHeight;
4530 font = create_gdi_font( face, orig_name, lf );
4531 font->use_logfont_name = substituted;
4532 font->matrix = dcmat;
4533 font->can_use_bitmap = can_use_bitmap;
4534 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
4535 font->charset = csi.ciCharset;
4536 font->codepage = csi.ciACP;
4538 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
4539 face->data_ptr, face->face_index );
4541 font->aveWidth = height ? lf->lfWidth : 0;
4542 if (!face->scalable)
4544 /* Windows uses integer scaling factors for bitmap fonts */
4545 INT scale, scaled_height, diff;
4546 struct gdi_font *cachedfont;
4548 if (height > 0)
4549 diff = height - (signed int)face->size.height;
4550 else
4551 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
4553 /* FIXME: rotation of bitmap fonts is ignored */
4554 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
4555 if (font->aveWidth)
4556 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
4557 font->matrix.eM11 = font->matrix.eM22 = 1.0;
4558 dcmat.eM11 = dcmat.eM22 = 1.0;
4559 /* As we changed the matrix, we need to search the cache for the font again,
4560 * otherwise we might explode the cache. */
4561 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4563 TRACE("Found cached font after non-scalable matrix rescale!\n");
4564 free_gdi_font( font );
4565 return cachedfont;
4568 if (height != 0) height = diff;
4569 height += face->size.height;
4571 scale = (height + face->size.height - 1) / face->size.height;
4572 scaled_height = scale * face->size.height;
4573 /* Only jump to the next height if the difference <= 25% original height */
4574 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4575 /* The jump between unscaled and doubled is delayed by 1 */
4576 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4577 font->scale_y = scale;
4578 TRACE("font scale y: %d\n", font->scale_y);
4581 if (!font_funcs->load_font( font ))
4583 free_gdi_font( font );
4584 return NULL;
4587 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
4588 font->vert_feature = get_GSUB_vert_feature( font );
4590 create_child_font_list( font );
4592 TRACE( "caching: gdiFont=%p\n", font );
4593 cache_gdi_font( font );
4594 return font;
4597 /*************************************************************
4598 * font_SelectFont
4600 static HFONT font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4602 struct font_physdev *physdev = get_font_dev( dev );
4603 struct gdi_font *font = NULL, *prev = physdev->font;
4604 DC *dc = get_physdev_dc( dev );
4606 if (hfont)
4608 LOGFONTW lf;
4609 FMAT2 dcmat;
4610 BOOL can_use_bitmap = !!(NtGdiGetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
4612 NtGdiExtGetObjectW( hfont, sizeof(lf), &lf );
4613 switch (lf.lfQuality)
4615 case NONANTIALIASED_QUALITY:
4616 if (!*aa_flags) *aa_flags = GGO_BITMAP;
4617 break;
4618 case ANTIALIASED_QUALITY:
4619 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
4620 break;
4623 if (lf.lfOutPrecision == OUT_TT_ONLY_PRECIS)
4624 can_use_bitmap = FALSE;
4626 lf.lfWidth = abs(lf.lfWidth);
4628 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4629 debugstr_w(lf.lfFaceName), (int)lf.lfHeight, lf.lfItalic,
4630 (int)lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, (int)lf.lfOrientation,
4631 (int)lf.lfEscapement );
4633 if (dc->attr->graphics_mode == GM_ADVANCED)
4635 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
4636 /* try to avoid not necessary glyph transformations */
4637 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4639 lf.lfHeight *= fabs(dcmat.eM11);
4640 lf.lfWidth *= fabs(dcmat.eM11);
4641 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4644 else
4646 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4647 dcmat.eM11 = dcmat.eM22 = 1.0;
4648 dcmat.eM21 = dcmat.eM12 = 0;
4649 lf.lfOrientation = lf.lfEscapement;
4650 if (dc->vport2WorldValid)
4652 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4653 lf.lfOrientation = -lf.lfOrientation;
4654 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4655 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4658 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
4660 pthread_mutex_lock( &font_lock );
4662 font = select_font( &lf, dcmat, can_use_bitmap );
4664 if (font)
4666 if (!*aa_flags) *aa_flags = font->aa_flags;
4667 if (!*aa_flags)
4669 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
4670 *aa_flags = subpixel_orientation;
4671 else
4672 *aa_flags = font_smoothing;
4674 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
4676 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), (int)lf.lfHeight, *aa_flags );
4677 pthread_mutex_unlock( &font_lock );
4679 physdev->font = font;
4680 if (prev) release_gdi_font( prev );
4681 return font ? hfont : 0;
4685 const struct gdi_dc_funcs font_driver =
4687 NULL, /* pAbortDoc */
4688 NULL, /* pAbortPath */
4689 NULL, /* pAlphaBlend */
4690 NULL, /* pAngleArc */
4691 NULL, /* pArc */
4692 NULL, /* pArcTo */
4693 NULL, /* pBeginPath */
4694 NULL, /* pBlendImage */
4695 NULL, /* pChord */
4696 NULL, /* pCloseFigure */
4697 NULL, /* pCreateCompatibleDC */
4698 font_CreateDC, /* pCreateDC */
4699 font_DeleteDC, /* pDeleteDC */
4700 NULL, /* pDeleteObject */
4701 NULL, /* pEllipse */
4702 NULL, /* pEndDoc */
4703 NULL, /* pEndPage */
4704 NULL, /* pEndPath */
4705 font_EnumFonts, /* pEnumFonts */
4706 NULL, /* pExtEscape */
4707 NULL, /* pExtFloodFill */
4708 NULL, /* pExtTextOut */
4709 NULL, /* pFillPath */
4710 NULL, /* pFillRgn */
4711 font_FontIsLinked, /* pFontIsLinked */
4712 NULL, /* pFrameRgn */
4713 NULL, /* pGetBoundsRect */
4714 font_GetCharABCWidths, /* pGetCharABCWidths */
4715 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
4716 font_GetCharWidth, /* pGetCharWidth */
4717 font_GetCharWidthInfo, /* pGetCharWidthInfo */
4718 NULL, /* pGetDeviceCaps */
4719 NULL, /* pGetDeviceGammaRamp */
4720 font_GetFontData, /* pGetFontData */
4721 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
4722 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
4723 font_GetGlyphIndices, /* pGetGlyphIndices */
4724 font_GetGlyphOutline, /* pGetGlyphOutline */
4725 NULL, /* pGetICMProfile */
4726 NULL, /* pGetImage */
4727 font_GetKerningPairs, /* pGetKerningPairs */
4728 NULL, /* pGetNearestColor */
4729 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
4730 NULL, /* pGetPixel */
4731 NULL, /* pGetSystemPaletteEntries */
4732 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
4733 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
4734 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
4735 font_GetTextFace, /* pGetTextFace */
4736 font_GetTextMetrics, /* pGetTextMetrics */
4737 NULL, /* pGradientFill */
4738 NULL, /* pInvertRgn */
4739 NULL, /* pLineTo */
4740 NULL, /* pMoveTo */
4741 NULL, /* pPaintRgn */
4742 NULL, /* pPatBlt */
4743 NULL, /* pPie */
4744 NULL, /* pPolyBezier */
4745 NULL, /* pPolyBezierTo */
4746 NULL, /* pPolyDraw */
4747 NULL, /* pPolyPolygon */
4748 NULL, /* pPolyPolyline */
4749 NULL, /* pPolylineTo */
4750 NULL, /* pPutImage */
4751 NULL, /* pRealizeDefaultPalette */
4752 NULL, /* pRealizePalette */
4753 NULL, /* pRectangle */
4754 NULL, /* pResetDC */
4755 NULL, /* pRoundRect */
4756 NULL, /* pSelectBitmap */
4757 NULL, /* pSelectBrush */
4758 font_SelectFont, /* pSelectFont */
4759 NULL, /* pSelectPen */
4760 NULL, /* pSetBkColor */
4761 NULL, /* pSetBoundsRect */
4762 NULL, /* pSetDCBrushColor */
4763 NULL, /* pSetDCPenColor */
4764 NULL, /* pSetDIBitsToDevice */
4765 NULL, /* pSetDeviceClipping */
4766 NULL, /* pSetDeviceGammaRamp */
4767 NULL, /* pSetPixel */
4768 NULL, /* pSetTextColor */
4769 NULL, /* pStartDoc */
4770 NULL, /* pStartPage */
4771 NULL, /* pStretchBlt */
4772 NULL, /* pStretchDIBits */
4773 NULL, /* pStrokeAndFillPath */
4774 NULL, /* pStrokePath */
4775 NULL, /* pUnrealizePalette */
4776 GDI_PRIORITY_FONT_DRV /* priority */
4779 static BOOL get_key_value( HKEY key, const char *name, DWORD *value )
4781 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[12 * sizeof(WCHAR)])];
4782 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4783 DWORD count;
4785 count = query_reg_ascii_value( key, name, info, sizeof(value_buffer) );
4786 if (count)
4788 if (info->Type == REG_DWORD) memcpy( value, info->Data, sizeof(*value) );
4789 else *value = wcstol( (const WCHAR *)info->Data, NULL, 10 );
4791 return !!count;
4794 static UINT init_font_options(void)
4796 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[20 * sizeof(WCHAR)])];
4797 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4798 HKEY key;
4799 DWORD i, val, gamma = 1400;
4800 UINT dpi = 0;
4802 if (query_reg_ascii_value( wine_fonts_key, "AntialiasFakeBoldOrItalic",
4803 info, sizeof(value_buffer) ) && info->Type == REG_SZ)
4805 static const WCHAR valsW[] = {'y','Y','t','T','1',0};
4806 antialias_fakes = (wcschr( valsW, *(const WCHAR *)info->Data ) != NULL);
4809 if ((key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
4811 /* FIXME: handle vertical orientations even though Windows doesn't */
4812 if (get_key_value( key, "FontSmoothingOrientation", &val ))
4814 switch (val)
4816 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4817 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
4818 break;
4819 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4820 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
4821 break;
4824 if (get_key_value( key, "FontSmoothing", &val ) && val /* enabled */)
4826 if (get_key_value( key, "FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4827 font_smoothing = subpixel_orientation;
4828 else
4829 font_smoothing = GGO_GRAY4_BITMAP;
4831 if (get_key_value( key, "FontSmoothingGamma", &val ) && val)
4833 gamma = min( max( val, 1000 ), 2200 );
4835 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4836 NtClose( key );
4839 /* Calibrating the difference between the registry value and the Wine gamma value.
4840 This looks roughly similar to Windows Native with the same registry value.
4841 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4842 gamma = 1000 * gamma / 1400;
4843 if (gamma != 1000)
4845 for (i = 0; i < 256; i++)
4847 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
4848 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
4852 if (!dpi && (key = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) )))
4854 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4855 NtClose( key );
4857 if (!dpi) dpi = 96;
4859 font_gamma_ramp.gamma = gamma;
4860 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp.gamma, dpi );
4861 return dpi;
4865 /* compute positions for text rendering, in device coords */
4866 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4868 TEXTMETRICW tm;
4869 PHYSDEV dev;
4871 size->cx = size->cy = 0;
4872 if (!count) return TRUE;
4874 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4875 dev->funcs->pGetTextMetrics( dev, &tm );
4877 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4878 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4880 if (dc->breakExtra || dc->breakRem)
4882 int i, space = 0, rem = dc->breakRem;
4884 for (i = 0; i < count; i++)
4886 if (str[i] == tm.tmBreakChar)
4888 space += dc->breakExtra;
4889 if (rem > 0)
4891 space++;
4892 rem--;
4895 dx[i] += space;
4898 size->cx = dx[count - 1];
4899 size->cy = tm.tmHeight;
4900 return TRUE;
4903 /* compute positions for text rendering, in device coords */
4904 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4906 TEXTMETRICW tm;
4907 PHYSDEV dev;
4909 size->cx = size->cy = 0;
4910 if (!count) return TRUE;
4912 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4913 dev->funcs->pGetTextMetrics( dev, &tm );
4915 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4916 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4918 if (dc->breakExtra || dc->breakRem)
4920 WORD space_index;
4921 int i, space = 0, rem = dc->breakRem;
4923 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4924 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4926 for (i = 0; i < count; i++)
4928 if (indices[i] == space_index)
4930 space += dc->breakExtra;
4931 if (rem > 0)
4933 space++;
4934 rem--;
4937 dx[i] += space;
4940 size->cx = dx[count - 1];
4941 size->cy = tm.tmHeight;
4942 return TRUE;
4945 /***********************************************************************
4946 * get_text_charset_info
4948 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4950 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4952 UINT ret = DEFAULT_CHARSET;
4953 PHYSDEV dev;
4955 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4956 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4958 if (ret == DEFAULT_CHARSET && fs)
4959 memset(fs, 0, sizeof(FONTSIGNATURE));
4960 return ret;
4963 /***********************************************************************
4964 * NtGdiGetTextCharsetInfo (win32u.@)
4966 UINT WINAPI NtGdiGetTextCharsetInfo( HDC hdc, FONTSIGNATURE *fs, DWORD flags )
4968 UINT ret = DEFAULT_CHARSET;
4969 DC *dc = get_dc_ptr(hdc);
4971 if (dc)
4973 ret = get_text_charset_info( dc, fs, flags );
4974 release_dc_ptr( dc );
4976 return ret;
4979 /***********************************************************************
4980 * NtGdiHfontCreate (win32u.@)
4982 HFONT WINAPI NtGdiHfontCreate( const void *logfont, ULONG size, ULONG type,
4983 ULONG flags, void *data )
4985 HFONT hFont;
4986 FONTOBJ *fontPtr;
4987 const LOGFONTW *plf;
4989 if (!logfont) return 0;
4991 if (size == sizeof(ENUMLOGFONTEXDVW) || size == sizeof(ENUMLOGFONTEXW))
4993 const ENUMLOGFONTEXW *lfex = logfont;
4995 if (lfex->elfFullName[0] || lfex->elfStyle[0] || lfex->elfScript[0])
4997 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
4998 debugstr_w( lfex->elfFullName ), debugstr_w( lfex->elfStyle ),
4999 debugstr_w( lfex->elfScript ));
5002 plf = &lfex->elfLogFont;
5004 else if (size != sizeof(LOGFONTW))
5006 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
5007 return 0;
5009 else plf = logfont;
5011 if (!(fontPtr = malloc( sizeof(*fontPtr) ))) return 0;
5013 fontPtr->logfont = *plf;
5015 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, NTGDI_OBJ_FONT, &fontobj_funcs )))
5017 free( fontPtr );
5018 return 0;
5021 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
5022 (int)plf->lfHeight, (int)plf->lfWidth,
5023 (int)plf->lfEscapement, (int)plf->lfOrientation,
5024 plf->lfPitchAndFamily,
5025 plf->lfOutPrecision, plf->lfClipPrecision,
5026 plf->lfQuality, plf->lfCharSet,
5027 debugstr_w(plf->lfFaceName),
5028 plf->lfWeight > 400 ? "Bold" : "",
5029 plf->lfItalic ? "Italic" : "",
5030 plf->lfUnderline ? "Underline" : "", hFont);
5032 return hFont;
5035 #define ASSOC_CHARSET_OEM 1
5036 #define ASSOC_CHARSET_ANSI 2
5037 #define ASSOC_CHARSET_SYMBOL 4
5039 static DWORD get_associated_charset_info(void)
5041 static int associated_charset = -1;
5043 if (associated_charset == -1)
5045 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[32 * sizeof(WCHAR)])];
5046 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
5047 HKEY hkey;
5049 static const WCHAR yesW[] = {'y','e','s',0};
5051 associated_charset = 0;
5053 if (!(hkey = reg_open_key( NULL, associated_charset_keyW, sizeof(associated_charset_keyW) )))
5054 return 0;
5056 if (query_reg_ascii_value( hkey, "ANSI(00)", info, sizeof(value_buffer) ) &&
5057 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5058 associated_charset |= ASSOC_CHARSET_ANSI;
5060 if (query_reg_ascii_value( hkey, "OEM(FF)", info, sizeof(value_buffer) ) &&
5061 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5062 associated_charset |= ASSOC_CHARSET_OEM;
5064 if (query_reg_ascii_value( hkey, "SYMBOL(02)", info, sizeof(value_buffer) ) &&
5065 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5066 associated_charset |= ASSOC_CHARSET_SYMBOL;
5068 NtClose( hkey );
5070 TRACE("associated_charset = %d\n", associated_charset);
5073 return associated_charset;
5076 static void update_font_code_page( DC *dc, HANDLE font )
5078 CHARSETINFO csi;
5079 int charset = get_text_charset_info( dc, NULL, 0 );
5081 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
5083 LOGFONTW lf;
5085 NtGdiExtGetObjectW( font, sizeof(lf), &lf );
5086 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
5087 charset = DEFAULT_CHARSET;
5090 /* Hmm, nicely designed api this one! */
5091 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
5092 dc->attr->font_code_page = csi.ciACP;
5093 else {
5094 switch(charset) {
5095 case OEM_CHARSET:
5096 dc->attr->font_code_page = oem_cp.CodePage;
5097 break;
5098 case DEFAULT_CHARSET:
5099 dc->attr->font_code_page = ansi_cp.CodePage;
5100 break;
5102 case VISCII_CHARSET:
5103 case TCVN_CHARSET:
5104 case KOI8_CHARSET:
5105 case ISO3_CHARSET:
5106 case ISO4_CHARSET:
5107 case ISO10_CHARSET:
5108 case CELTIC_CHARSET:
5109 /* FIXME: These have no place here, but because x11drv
5110 enumerates fonts with these (made up) charsets some apps
5111 might use them and then the FIXME below would become
5112 annoying. Now we could pick the intended codepage for
5113 each of these, but since it's broken anyway we'll just
5114 use CP_ACP and hope it'll go away...
5116 dc->attr->font_code_page = CP_ACP;
5117 break;
5119 default:
5120 FIXME("Can't find codepage for charset %d\n", charset);
5121 dc->attr->font_code_page = CP_ACP;
5122 break;
5126 TRACE( "charset %d => cp %d\n", charset, dc->attr->font_code_page );
5129 /***********************************************************************
5130 * NtGdiSelectFont (win32u.@)
5132 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
5134 HGDIOBJ ret = 0;
5135 DC *dc = get_dc_ptr( hdc );
5136 PHYSDEV physdev;
5137 UINT aa_flags = 0;
5139 if (!dc) return 0;
5141 if (!GDI_inc_ref_count( handle ))
5143 release_dc_ptr( dc );
5144 return 0;
5147 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
5148 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
5150 ret = dc->hFont;
5151 dc->hFont = handle;
5152 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
5153 update_font_code_page( dc, handle );
5154 if (dc->font_gamma_ramp == NULL)
5155 dc->font_gamma_ramp = &font_gamma_ramp;
5156 GDI_dec_ref_count( ret );
5158 else GDI_dec_ref_count( handle );
5160 release_dc_ptr( dc );
5161 return ret;
5165 /***********************************************************************
5166 * FONT_GetObjectW
5168 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
5170 FONTOBJ *font = GDI_GetObjPtr( handle, NTGDI_OBJ_FONT );
5172 if (!font) return 0;
5173 if (buffer)
5175 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
5176 memcpy( buffer, &font->logfont, count );
5178 else count = sizeof(LOGFONTW);
5179 GDI_ReleaseObj( handle );
5180 return count;
5184 /***********************************************************************
5185 * FONT_DeleteObject
5187 static BOOL FONT_DeleteObject( HGDIOBJ handle )
5189 FONTOBJ *obj;
5191 if (!(obj = free_gdi_handle( handle ))) return FALSE;
5192 free( obj );
5193 return TRUE;
5197 struct font_enum
5199 HDC hdc;
5200 struct font_enum_entry *buf;
5201 ULONG size;
5202 ULONG count;
5203 ULONG charset;
5206 static INT enum_fonts( const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lp )
5208 struct font_enum *fe = (struct font_enum *)lp;
5210 if (fe->charset != DEFAULT_CHARSET && lf->lfCharSet != fe->charset) return 1;
5211 if ((type & RASTER_FONTTYPE) && !(NtGdiGetDeviceCaps( fe->hdc, TEXTCAPS ) & TC_RA_ABLE))
5212 return 1;
5214 if (fe->buf && fe->count < fe->size)
5216 fe->buf[fe->count].type = type;
5217 fe->buf[fe->count].lf = *(const ENUMLOGFONTEXW *)lf;
5218 fe->buf[fe->count].tm = *(const NEWTEXTMETRICEXW *)tm;
5220 fe->count++;
5221 return 1;
5224 /***********************************************************************
5225 * NtGdiEnumFonts (win32u.@)
5227 BOOL WINAPI NtGdiEnumFonts( HDC hdc, ULONG type, ULONG win32_compat, ULONG face_name_len,
5228 const WCHAR *face_name, ULONG charset, ULONG *count, void *buf )
5230 struct font_enum fe;
5231 PHYSDEV physdev;
5232 LOGFONTW lf;
5233 BOOL ret;
5234 DC *dc;
5236 if (!(dc = get_dc_ptr( hdc ))) return 0;
5238 memset( &lf, 0, sizeof(lf) );
5239 lf.lfCharSet = charset;
5240 if (face_name_len) memcpy( lf.lfFaceName, face_name, face_name_len * sizeof(WCHAR) );
5242 fe.hdc = hdc;
5243 fe.buf = buf;
5244 fe.size = *count / sizeof(*fe.buf);
5245 fe.count = 0;
5246 fe.charset = charset;
5248 physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
5249 ret = physdev->funcs->pEnumFonts( physdev, &lf, enum_fonts, (LPARAM)&fe );
5250 if (ret && buf) ret = fe.count <= fe.size;
5251 *count = fe.count * sizeof(*fe.buf);
5253 release_dc_ptr( dc );
5254 return ret;
5258 /***********************************************************************
5259 * NtGdiSetTextJustification (win32u.@)
5261 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
5263 DC *dc;
5265 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5267 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
5268 dc->attr->wnd_ext.cx );
5269 if (!extra) breaks = 0;
5270 if (breaks)
5272 dc->breakExtra = extra / breaks;
5273 dc->breakRem = extra - (breaks * dc->breakExtra);
5275 else
5277 dc->breakExtra = 0;
5278 dc->breakRem = 0;
5281 release_dc_ptr( dc );
5282 return TRUE;
5286 /***********************************************************************
5287 * NtGdiGetTextFaceW (win32u.@)
5289 INT WINAPI NtGdiGetTextFaceW( HDC hdc, INT count, WCHAR *name, BOOL alias_name )
5291 PHYSDEV dev;
5292 INT ret;
5294 DC * dc = get_dc_ptr( hdc );
5295 if (!dc) return 0;
5297 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
5298 ret = dev->funcs->pGetTextFace( dev, count, name );
5299 release_dc_ptr( dc );
5300 return ret;
5304 /***********************************************************************
5305 * NtGdiGetTextExtentExW (win32u.@)
5307 * Return the size of the string as it would be if it was output properly by
5308 * e.g. TextOut.
5310 BOOL WINAPI NtGdiGetTextExtentExW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
5311 INT *nfit, INT *dxs, SIZE *size, UINT flags )
5313 DC *dc;
5314 int i;
5315 BOOL ret;
5316 INT buffer[256], *pos = dxs;
5318 if (count < 0) return FALSE;
5320 dc = get_dc_ptr(hdc);
5321 if (!dc) return FALSE;
5323 if (!dxs)
5325 pos = buffer;
5326 if (count > 256 && !(pos = malloc( count * sizeof(*pos) )))
5328 release_dc_ptr( dc );
5329 return FALSE;
5334 if (flags)
5335 ret = get_char_positions_indices( dc, str, count, pos, size );
5336 else
5337 ret = get_char_positions( dc, str, count, pos, size );
5338 if (ret)
5340 if (dxs || nfit)
5342 for (i = 0; i < count; i++)
5344 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
5345 (i + 1) * dc->attr->char_extra;
5346 if (nfit && dx > (unsigned int)max_ext) break;
5347 if (dxs) dxs[i] = dx;
5349 if (nfit) *nfit = i;
5352 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
5353 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5356 if (pos != buffer && pos != dxs) free( pos );
5357 release_dc_ptr( dc );
5359 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count),
5360 max_ext, (int)size->cx, (int)size->cy );
5361 return ret;
5364 /***********************************************************************
5365 * NtGdiGetTextMetricsW (win32u.@)
5367 BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags )
5369 PHYSDEV physdev;
5370 BOOL ret = FALSE;
5371 DC * dc = get_dc_ptr( hdc );
5372 if (!dc) return FALSE;
5374 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5375 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5377 if (ret)
5379 /* device layer returns values in device units
5380 * therefore we have to convert them to logical */
5382 metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5383 metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5384 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5385 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5386 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5387 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5388 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5389 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5390 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5391 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5392 ret = TRUE;
5394 TRACE("text metrics:\n"
5395 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5396 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5397 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5398 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5399 " PitchAndFamily = %02x\n"
5400 " --------------------\n"
5401 " InternalLeading = %i\n"
5402 " Ascent = %i\n"
5403 " Descent = %i\n"
5404 " Height = %i\n",
5405 (int)metrics->tmWeight, metrics->tmFirstChar, (int)metrics->tmAveCharWidth,
5406 metrics->tmItalic, metrics->tmLastChar, (int)metrics->tmMaxCharWidth,
5407 metrics->tmUnderlined, metrics->tmDefaultChar, (int)metrics->tmOverhang,
5408 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5409 metrics->tmPitchAndFamily,
5410 (int)metrics->tmInternalLeading,
5411 (int)metrics->tmAscent,
5412 (int)metrics->tmDescent,
5413 (int)metrics->tmHeight );
5415 release_dc_ptr( dc );
5416 return ret;
5420 /***********************************************************************
5421 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
5423 UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData,
5424 OUTLINETEXTMETRICW *lpOTM, ULONG opts )
5426 DC *dc = get_dc_ptr( hdc );
5427 OUTLINETEXTMETRICW *output = lpOTM;
5428 PHYSDEV dev;
5429 UINT ret;
5431 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5432 if(!dc) return 0;
5434 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5435 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5437 if (lpOTM && ret > cbData)
5439 output = malloc( ret );
5440 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5443 if (lpOTM && ret)
5445 output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5446 output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5447 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5448 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5449 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5450 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5451 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5452 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5453 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5454 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5455 output->otmAscent = height_to_LP( dc, output->otmAscent);
5456 output->otmDescent = height_to_LP( dc, output->otmDescent);
5457 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5458 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5459 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5460 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5461 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5462 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5463 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5464 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5465 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5466 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5467 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5468 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5469 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5470 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5471 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5472 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5473 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5474 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5475 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5476 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5477 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5478 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5480 if(output != lpOTM)
5482 memcpy(lpOTM, output, cbData);
5483 free( output );
5484 ret = cbData;
5487 release_dc_ptr(dc);
5488 return ret;
5491 /***********************************************************************
5492 * NtGdiGetCharWidthW (win32u.@)
5494 BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5495 ULONG flags, void *buf )
5497 UINT i, count = last;
5498 BOOL ret;
5499 PHYSDEV dev;
5500 DC *dc;
5502 if (flags & NTGDI_GETCHARWIDTH_INDICES)
5504 ABC *abc;
5505 unsigned int i;
5507 if (!(abc = malloc( count * sizeof(ABC) )))
5508 return FALSE;
5510 if (!NtGdiGetCharABCWidthsW( hdc, first, last, chars,
5511 NTGDI_GETCHARABCWIDTHS_INT | NTGDI_GETCHARABCWIDTHS_INDICES,
5512 abc ))
5514 free( abc );
5515 return FALSE;
5518 for (i = 0; i < count; i++)
5519 ((INT *)buf)[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5521 free( abc );
5522 return TRUE;
5525 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5527 if (!chars) count = last - first + 1;
5528 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5529 ret = dev->funcs->pGetCharWidth( dev, first, count, chars, buf );
5531 if (ret)
5533 if (flags & NTGDI_GETCHARWIDTH_INT)
5535 INT *buffer = buf;
5536 /* convert device units to logical */
5537 for (i = 0; i < count; i++)
5538 buffer[i] = width_to_LP( dc, buffer[i] );
5540 else
5542 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
5543 for (i = 0; i < count; i++)
5544 ((float *)buf)[i] = ((int *)buf)[i] * scale;
5547 release_dc_ptr( dc );
5548 return ret;
5552 /* helper for nulldrv_ExtTextOut */
5553 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5554 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5556 UINT indices[3] = {0, 0, 0x20};
5557 unsigned int i;
5558 DWORD ret, size;
5559 int stride;
5561 indices[0] = index;
5562 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5564 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5566 index = indices[i];
5567 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, 0, NULL, &identity, FALSE );
5568 if (ret != GDI_ERROR) break;
5571 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5572 if (!image) return ERROR_SUCCESS;
5574 image->ptr = NULL;
5575 image->free = NULL;
5576 if (!ret) /* empty glyph */
5578 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5579 return ERROR_SUCCESS;
5582 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5583 size = metrics->gmBlackBoxY * stride;
5585 if (!(image->ptr = malloc( size ))) return ERROR_OUTOFMEMORY;
5586 image->is_copy = TRUE;
5587 image->free = free_heap_bits;
5589 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, size, image->ptr,
5590 &identity, FALSE );
5591 if (ret == GDI_ERROR)
5593 free( image->ptr );
5594 return ERROR_NOT_FOUND;
5596 return ERROR_SUCCESS;
5599 /* helper for nulldrv_ExtTextOut */
5600 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5601 LPCWSTR str, UINT count, const INT *dx )
5603 UINT i;
5604 RECT rect, bounds;
5606 reset_bounds( &bounds );
5607 for (i = 0; i < count; i++)
5609 GLYPHMETRICS metrics;
5611 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5613 rect.left = x + metrics.gmptGlyphOrigin.x;
5614 rect.top = y - metrics.gmptGlyphOrigin.y;
5615 rect.right = rect.left + metrics.gmBlackBoxX;
5616 rect.bottom = rect.top + metrics.gmBlackBoxY;
5617 add_bounds_rect( &bounds, &rect );
5619 if (dx)
5621 if (flags & ETO_PDY)
5623 x += dx[ i * 2 ];
5624 y += dx[ i * 2 + 1];
5626 else x += dx[ i ];
5628 else
5630 x += metrics.gmCellIncX;
5631 y += metrics.gmCellIncY;
5634 return bounds;
5637 /* helper for nulldrv_ExtTextOut */
5638 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5639 const struct gdi_image_bits *image, const RECT *clip )
5641 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5642 UINT i, count, max_count;
5643 LONG x, y;
5644 BYTE *ptr = image->ptr;
5645 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5646 POINT *pts;
5647 RECT rect, clipped_rect;
5649 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5650 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5651 rect.right = rect.left + metrics->gmBlackBoxX;
5652 rect.bottom = rect.top + metrics->gmBlackBoxY;
5653 if (!clip) clipped_rect = rect;
5654 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5656 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5657 pts = malloc( max_count * sizeof(*pts) );
5658 if (!pts) return;
5660 count = 0;
5661 ptr += (clipped_rect.top - rect.top) * stride;
5662 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5664 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5666 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5667 pts[count].x = rect.left + x;
5668 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5669 pts[count + 1].x = rect.left + x;
5670 if (pts[count + 1].x > pts[count].x)
5672 pts[count].y = pts[count + 1].y = y;
5673 count += 2;
5677 assert( count <= max_count );
5678 dp_to_lp( dc, pts, count );
5679 for (i = 0; i < count; i += 2)
5681 const ULONG pts_count = 2;
5682 NtGdiPolyPolyDraw( dc->hSelf, pts + i, &pts_count, 1, NtGdiPolyPolyline );
5684 free( pts );
5687 /***********************************************************************
5688 * nulldrv_ExtTextOut
5690 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5691 LPCWSTR str, UINT count, const INT *dx )
5693 DC *dc = get_nulldrv_dc( dev );
5694 UINT i;
5695 DWORD err;
5696 HGDIOBJ orig;
5697 HPEN pen;
5699 if (flags & ETO_OPAQUE)
5701 RECT rc = *rect;
5702 COLORREF brush_color = NtGdiGetNearestColor( dev->hdc, dc->attr->background_color );
5703 HBRUSH brush = NtGdiCreateSolidBrush( brush_color, NULL);
5705 if (brush)
5707 orig = NtGdiSelectBrush( dev->hdc, brush );
5708 dp_to_lp( dc, (POINT *)&rc, 2 );
5709 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5710 NtGdiSelectBrush( dev->hdc, orig );
5711 NtGdiDeleteObjectApp( brush );
5715 if (!count) return TRUE;
5717 if (dc->aa_flags != GGO_BITMAP)
5719 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5720 BITMAPINFO *info = (BITMAPINFO *)buffer;
5721 struct gdi_image_bits bits;
5722 struct bitblt_coords src, dst;
5723 PHYSDEV dst_dev;
5724 /* FIXME Subpixel modes */
5725 UINT aa_flags = GGO_GRAY4_BITMAP;
5727 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5728 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5729 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5730 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5732 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5733 src.x = src.visrect.left;
5734 src.y = src.visrect.top;
5735 src.width = src.visrect.right - src.visrect.left;
5736 src.height = src.visrect.bottom - src.visrect.top;
5737 dst = src;
5738 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5739 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5741 /* we can avoid the GetImage, just query the needed format */
5742 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5743 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5744 info->bmiHeader.biWidth = src.width;
5745 info->bmiHeader.biHeight = -src.height;
5746 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5747 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5748 if (!err || err == ERROR_BAD_FORMAT)
5750 /* make the source rectangle relative to the source bits */
5751 src.x = src.y = 0;
5752 src.visrect.left = src.visrect.top = 0;
5753 src.visrect.right = src.width;
5754 src.visrect.bottom = src.height;
5756 bits.ptr = malloc( info->bmiHeader.biSizeImage );
5757 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5758 bits.is_copy = TRUE;
5759 bits.free = free_heap_bits;
5760 err = ERROR_SUCCESS;
5763 else
5765 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5766 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5767 if (!err && !bits.is_copy)
5769 void *ptr = malloc( info->bmiHeader.biSizeImage );
5770 if (!ptr)
5772 if (bits.free) bits.free( &bits );
5773 return ERROR_OUTOFMEMORY;
5775 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5776 if (bits.free) bits.free( &bits );
5777 bits.ptr = ptr;
5778 bits.is_copy = TRUE;
5779 bits.free = free_heap_bits;
5782 if (!err)
5784 /* make x,y relative to the image bits */
5785 x += src.visrect.left - dst.visrect.left;
5786 y += src.visrect.top - dst.visrect.top;
5787 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5788 aa_flags, str, count, dx );
5789 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5790 if (bits.free) bits.free( &bits );
5791 return !err;
5795 pen = NtGdiCreatePen( PS_SOLID, 1, dc->attr->text_color, NULL );
5796 orig = NtGdiSelectPen( dev->hdc, pen );
5798 for (i = 0; i < count; i++)
5800 GLYPHMETRICS metrics;
5801 struct gdi_image_bits image;
5803 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5804 if (err) continue;
5806 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5807 if (image.free) image.free( &image );
5809 if (dx)
5811 if (flags & ETO_PDY)
5813 x += dx[ i * 2 ];
5814 y += dx[ i * 2 + 1];
5816 else x += dx[ i ];
5818 else
5820 x += metrics.gmCellIncX;
5821 y += metrics.gmCellIncY;
5825 NtGdiSelectPen( dev->hdc, orig );
5826 NtGdiDeleteObjectApp( pen );
5827 return TRUE;
5830 /***********************************************************************
5831 * get_line_width
5833 * Scale the underline / strikeout line width.
5835 static inline int get_line_width( DC *dc, int metric_size )
5837 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5838 if (width == 0) width = 1;
5839 if (metric_size < 0) width = -width;
5840 return width;
5843 /***********************************************************************
5844 * NtGdiExtTextOutW (win32u.@)
5846 * Draws text using the currently selected font, background color, and text color.
5849 * PARAMS
5850 * x,y [I] coordinates of string
5851 * flags [I]
5852 * ETO_GRAYED - undocumented on MSDN
5853 * ETO_OPAQUE - use background color for fill the rectangle
5854 * ETO_CLIPPED - clipping text to the rectangle
5855 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5856 * than encoded characters. Implies ETO_IGNORELANGUAGE
5857 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5858 * Affects BiDi ordering
5859 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5860 * ETO_PDY - unimplemented
5861 * ETO_NUMERICSLATIN - unimplemented always assumed -
5862 * do not translate numbers into locale representations
5863 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5864 * lprect [I] dimensions for clipping or/and opaquing
5865 * str [I] text string
5866 * count [I] number of symbols in string
5867 * lpDx [I] optional parameter with distance between drawing characters
5869 * RETURNS
5870 * Success: TRUE
5871 * Failure: FALSE
5873 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5874 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5876 BOOL ret = FALSE;
5877 UINT align;
5878 DWORD layout;
5879 POINT pt;
5880 TEXTMETRICW tm;
5881 LOGFONTW lf;
5882 double cosEsc, sinEsc;
5883 INT char_extra;
5884 SIZE sz;
5885 RECT rc;
5886 POINT *deltas = NULL, width = {0, 0};
5887 DC * dc = get_dc_ptr( hdc );
5888 PHYSDEV physdev;
5889 INT breakRem;
5890 static int quietfixme = 0;
5892 if (!dc) return FALSE;
5893 if (count > INT_MAX) return FALSE;
5895 align = dc->attr->text_align;
5896 breakRem = dc->breakRem;
5897 layout = dc->attr->layout;
5899 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5901 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5902 quietfixme = 1;
5905 update_dc( dc );
5906 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5908 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5909 if (layout & LAYOUT_RTL)
5911 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5912 align ^= TA_RTLREADING;
5915 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5916 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5917 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5918 dc->attr->map_mode);
5920 if(align & TA_UPDATECP)
5922 pt = dc->attr->cur_pos;
5923 x = pt.x;
5924 y = pt.y;
5927 NtGdiGetTextMetricsW( hdc, &tm, 0 );
5928 NtGdiExtGetObjectW( dc->hFont, sizeof(lf), &lf );
5930 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5931 lf.lfEscapement = 0;
5933 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5934 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5936 lf.lfEscapement = -lf.lfEscapement;
5939 if(lf.lfEscapement != 0)
5941 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5942 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5944 else
5946 cosEsc = 1;
5947 sinEsc = 0;
5950 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5952 rc = *lprect;
5953 lp_to_dp(dc, (POINT*)&rc, 2);
5954 order_rect( &rc );
5955 if (flags & ETO_OPAQUE)
5956 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5958 else flags &= ~ETO_CLIPPED;
5960 if(count == 0)
5962 ret = TRUE;
5963 goto done;
5966 pt.x = x;
5967 pt.y = y;
5968 lp_to_dp(dc, &pt, 1);
5969 x = pt.x;
5970 y = pt.y;
5972 char_extra = dc->attr->char_extra;
5973 if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5974 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5976 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
5978 UINT i;
5979 POINT total = {0, 0}, desired[2];
5981 deltas = malloc( count * sizeof(*deltas) );
5982 if (lpDx)
5984 if (flags & ETO_PDY)
5986 for (i = 0; i < count; i++)
5988 deltas[i].x = lpDx[i * 2] + char_extra;
5989 deltas[i].y = -lpDx[i * 2 + 1];
5992 else
5994 for (i = 0; i < count; i++)
5996 deltas[i].x = lpDx[i] + char_extra;
5997 deltas[i].y = 0;
6001 else
6003 INT *dx = malloc( count * sizeof(*dx) );
6005 NtGdiGetTextExtentExW( hdc, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX) );
6007 deltas[0].x = dx[0];
6008 deltas[0].y = 0;
6009 for (i = 1; i < count; i++)
6011 deltas[i].x = dx[i] - dx[i - 1];
6012 deltas[i].y = 0;
6014 free( dx );
6017 for(i = 0; i < count; i++)
6019 total.x += deltas[i].x;
6020 total.y += deltas[i].y;
6022 desired[0].x = desired[0].y = 0;
6024 desired[1].x = cosEsc * total.x + sinEsc * total.y;
6025 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
6027 lp_to_dp(dc, desired, 2);
6028 desired[1].x -= desired[0].x;
6029 desired[1].y -= desired[0].y;
6031 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6033 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6034 desired[1].x = -desired[1].x;
6035 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6036 desired[1].y = -desired[1].y;
6039 deltas[i].x = desired[1].x - width.x;
6040 deltas[i].y = desired[1].y - width.y;
6042 width = desired[1];
6044 flags |= ETO_PDY;
6046 else
6048 POINT desired[2];
6050 NtGdiGetTextExtentExW( hdc, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX) );
6051 desired[0].x = desired[0].y = 0;
6052 desired[1].x = sz.cx;
6053 desired[1].y = 0;
6054 lp_to_dp(dc, desired, 2);
6055 desired[1].x -= desired[0].x;
6056 desired[1].y -= desired[0].y;
6058 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6060 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6061 desired[1].x = -desired[1].x;
6062 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6063 desired[1].y = -desired[1].y;
6065 width = desired[1];
6068 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
6069 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
6070 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
6072 case TA_LEFT:
6073 if (align & TA_UPDATECP)
6075 pt.x = x + width.x;
6076 pt.y = y + width.y;
6077 dp_to_lp(dc, &pt, 1);
6078 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6080 break;
6082 case TA_CENTER:
6083 x -= width.x / 2;
6084 y -= width.y / 2;
6085 break;
6087 case TA_RIGHT:
6088 x -= width.x;
6089 y -= width.y;
6090 if (align & TA_UPDATECP)
6092 pt.x = x;
6093 pt.y = y;
6094 dp_to_lp(dc, &pt, 1);
6095 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6097 break;
6100 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
6102 case TA_TOP:
6103 y += tm.tmAscent * cosEsc;
6104 x += tm.tmAscent * sinEsc;
6105 break;
6107 case TA_BOTTOM:
6108 y -= tm.tmDescent * cosEsc;
6109 x -= tm.tmDescent * sinEsc;
6110 break;
6112 case TA_BASELINE:
6113 break;
6116 if (dc->attr->background_mode != TRANSPARENT)
6118 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
6120 if(!(flags & ETO_OPAQUE) || !lprect ||
6121 x < rc.left || x + width.x >= rc.right ||
6122 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
6124 RECT text_box;
6125 text_box.left = x;
6126 text_box.right = x + width.x;
6127 text_box.top = y - tm.tmAscent;
6128 text_box.bottom = y + tm.tmDescent;
6130 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
6131 if (!IsRectEmpty( &text_box ))
6132 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
6137 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
6138 str, count, (INT*)deltas );
6140 done:
6141 free( deltas );
6143 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
6145 int underlinePos, strikeoutPos;
6146 int underlineWidth, strikeoutWidth;
6147 UINT size = NtGdiGetOutlineTextMetricsInternalW( hdc, 0, NULL, 0 );
6148 OUTLINETEXTMETRICW* otm = NULL;
6149 POINT pts[5];
6150 HPEN hpen = NtGdiSelectPen( hdc, GetStockObject(NULL_PEN) );
6151 HBRUSH hbrush = NtGdiCreateSolidBrush( dc->attr->text_color, NULL );
6153 hbrush = NtGdiSelectBrush(hdc, hbrush);
6155 if(!size)
6157 underlinePos = 0;
6158 underlineWidth = tm.tmAscent / 20 + 1;
6159 strikeoutPos = tm.tmAscent / 2;
6160 strikeoutWidth = underlineWidth;
6162 else
6164 otm = malloc( size );
6165 NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
6166 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
6167 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
6168 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
6169 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
6170 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
6171 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
6172 free( otm );
6176 if (lf.lfUnderline)
6178 const ULONG cnt = 5;
6179 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
6180 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
6181 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
6182 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
6183 pts[2].x = pts[1].x + underlineWidth * sinEsc;
6184 pts[2].y = pts[1].y + underlineWidth * cosEsc;
6185 pts[3].x = pts[0].x + underlineWidth * sinEsc;
6186 pts[3].y = pts[0].y + underlineWidth * cosEsc;
6187 pts[4].x = pts[0].x;
6188 pts[4].y = pts[0].y;
6189 dp_to_lp(dc, pts, 5);
6190 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6193 if (lf.lfStrikeOut)
6195 const ULONG cnt = 5;
6196 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6197 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6198 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6199 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6200 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
6201 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
6202 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
6203 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
6204 pts[4].x = pts[0].x;
6205 pts[4].y = pts[0].y;
6206 dp_to_lp(dc, pts, 5);
6207 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6210 NtGdiSelectPen(hdc, hpen);
6211 hbrush = NtGdiSelectBrush(hdc, hbrush);
6212 NtGdiDeleteObjectApp( hbrush );
6215 release_dc_ptr( dc );
6217 return ret;
6221 /******************************************************************************
6222 * NtGdiGetCharABCWidthsW (win32u.@)
6224 * Retrieves widths of characters in range.
6226 * PARAMS
6227 * hdc [I] Handle of device context
6228 * firstChar [I] First character in range to query
6229 * lastChar [I] Last character in range to query
6230 * abc [O] Address of character-width structure
6232 * NOTES
6233 * Only works with TrueType fonts
6235 BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars,
6236 ULONG flags, void *buffer )
6238 DC *dc = get_dc_ptr(hdc);
6239 PHYSDEV dev;
6240 unsigned int i, count = last;
6241 BOOL ret;
6243 if (!dc) return FALSE;
6245 if (!buffer)
6247 release_dc_ptr( dc );
6248 return FALSE;
6251 if (flags & NTGDI_GETCHARABCWIDTHS_INDICES)
6253 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6254 ret = dev->funcs->pGetCharABCWidthsI( dev, first, count, chars, buffer );
6256 else
6258 if (!chars) count = last - first + 1;
6259 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6260 ret = dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
6263 if (ret)
6265 ABC *abc = buffer;
6266 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6268 /* convert device units to logical */
6269 for (i = 0; i < count; i++)
6271 abc[i].abcA = width_to_LP( dc, abc[i].abcA );
6272 abc[i].abcB = width_to_LP( dc, abc[i].abcB );
6273 abc[i].abcC = width_to_LP( dc, abc[i].abcC );
6276 else
6278 /* convert device units to logical */
6279 FLOAT scale = fabs( dc->xformVport2World.eM11 );
6280 ABCFLOAT *abcf = buffer;
6282 for (i = 0; i < count; i++)
6284 abcf[i].abcfA = abc[i].abcA * scale;
6285 abcf[i].abcfB = abc[i].abcB * scale;
6286 abcf[i].abcfC = abc[i].abcC * scale;
6291 release_dc_ptr( dc );
6292 return ret;
6296 /***********************************************************************
6297 * NtGdiGetGlyphOutline (win32u.@)
6299 DWORD WINAPI NtGdiGetGlyphOutline( HDC hdc, UINT ch, UINT format, GLYPHMETRICS *metrics,
6300 DWORD size, void *buffer, const MAT2 *mat2,
6301 BOOL ignore_rotation )
6303 DC *dc;
6304 DWORD ret;
6305 PHYSDEV dev;
6307 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc, ch, format, metrics, (int)size, buffer, mat2 );
6309 if (!mat2) return GDI_ERROR;
6311 dc = get_dc_ptr(hdc);
6312 if(!dc) return GDI_ERROR;
6314 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6315 ret = dev->funcs->pGetGlyphOutline( dev, ch & 0xffff, format, metrics, size, buffer, mat2 );
6316 release_dc_ptr( dc );
6317 return ret;
6321 /**********************************************************************
6322 * __wine_get_file_outline_text_metric (win32u.@)
6324 BOOL WINAPI __wine_get_file_outline_text_metric( const WCHAR *path, TEXTMETRICW *otm,
6325 UINT *em_square, WCHAR *face_name )
6327 struct gdi_font *font = NULL;
6329 if (!path || !font_funcs) return FALSE;
6331 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6332 font->lf.lfHeight = 100;
6333 if (!font_funcs->load_font( font )) goto done;
6334 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6335 *otm = font->otm.otmTextMetrics;
6336 *em_square = font->otm.otmEMSquare;
6337 wcscpy( face_name, (const WCHAR *)font->otm.otmpFamilyName );
6338 free_gdi_font( font );
6339 return TRUE;
6341 done:
6342 if (font) free_gdi_font( font );
6343 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6344 return FALSE;
6347 /*************************************************************************
6348 * NtGdiGetKerningPairs (win32u.@)
6350 DWORD WINAPI NtGdiGetKerningPairs( HDC hdc, DWORD count, KERNINGPAIR *kern_pair )
6352 DC *dc;
6353 DWORD ret;
6354 PHYSDEV dev;
6356 TRACE( "(%p,%d,%p)\n", hdc, (int)count, kern_pair );
6358 if (!count && kern_pair)
6360 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6361 return 0;
6364 dc = get_dc_ptr( hdc );
6365 if (!dc) return 0;
6367 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
6368 ret = dev->funcs->pGetKerningPairs( dev, count, kern_pair );
6369 release_dc_ptr( dc );
6370 return ret;
6373 /*************************************************************************
6374 * NtGdiGetFontData (win32u.@)
6376 * Retrieve data for TrueType font.
6378 * RETURNS
6380 * success: Number of bytes returned
6381 * failure: GDI_ERROR
6383 * NOTES
6385 * Calls RtlSetLastWin32Error()
6388 DWORD WINAPI NtGdiGetFontData( HDC hdc, DWORD table, DWORD offset, void *buffer, DWORD length )
6390 DC *dc = get_dc_ptr(hdc);
6391 PHYSDEV dev;
6392 DWORD ret;
6394 if(!dc) return GDI_ERROR;
6396 dev = GET_DC_PHYSDEV( dc, pGetFontData );
6397 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
6398 release_dc_ptr( dc );
6399 return ret;
6402 /*************************************************************************
6403 * NtGdiGetGlyphIndicesW (win32u.@)
6405 DWORD WINAPI NtGdiGetGlyphIndicesW( HDC hdc, const WCHAR *str, INT count,
6406 WORD *indices, DWORD flags )
6408 DC *dc = get_dc_ptr(hdc);
6409 PHYSDEV dev;
6410 DWORD ret;
6412 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc, debugstr_wn(str, count), count, indices, (int)flags );
6414 if(!dc) return GDI_ERROR;
6416 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
6417 ret = dev->funcs->pGetGlyphIndices( dev, str, count, indices, flags );
6418 release_dc_ptr( dc );
6419 return ret;
6422 /***********************************************************************
6424 * Font Resource API *
6426 ***********************************************************************/
6429 static int add_system_font_resource( const WCHAR *file, DWORD flags )
6431 WCHAR path[MAX_PATH];
6432 int ret;
6434 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6435 get_fonts_win_dir_path( file, path );
6436 pthread_mutex_lock( &font_lock );
6437 ret = font_funcs->add_font( path, flags );
6438 pthread_mutex_unlock( &font_lock );
6439 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6440 if (!ret)
6442 get_fonts_data_dir_path( file, path );
6443 pthread_mutex_lock( &font_lock );
6444 ret = font_funcs->add_font( path, flags );
6445 pthread_mutex_unlock( &font_lock );
6447 return ret;
6450 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
6452 WCHAR path[MAX_PATH];
6453 int ret;
6455 get_fonts_win_dir_path( file, path );
6456 if (!(ret = remove_font( path, flags )))
6458 get_fonts_data_dir_path( file, path );
6459 ret = remove_font( path, flags );
6461 return ret;
6464 static int add_font_resource( LPCWSTR file, DWORD flags )
6466 int ret = 0;
6468 if (*file == '\\')
6470 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6472 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6473 pthread_mutex_lock( &font_lock );
6474 ret = font_funcs->add_font( file, addfont_flags );
6475 pthread_mutex_unlock( &font_lock );
6477 else if (!wcschr( file, '\\' ))
6478 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6480 return ret;
6483 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
6485 BOOL ret = FALSE;
6487 if (*file == '\\')
6489 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6491 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6492 ret = remove_font( file, addfont_flags );
6494 else if (!wcschr( file, '\\' ))
6495 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6497 return ret;
6500 static void load_system_bitmap_fonts(void)
6502 static const char * const fonts[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6503 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6504 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6505 HKEY hkey;
6506 DWORD i;
6508 if (!(hkey = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) ))) return;
6509 for (i = 0; i < ARRAY_SIZE(fonts); i++)
6511 if (query_reg_ascii_value( hkey, fonts[i], info, sizeof(value_buffer) ) && info->Type == REG_SZ)
6512 add_system_font_resource( (const WCHAR *)info->Data, ADDFONT_ALLOW_BITMAP );
6514 NtClose( hkey );
6517 static void load_directory_fonts( WCHAR *path, UINT flags )
6519 IO_STATUS_BLOCK io = {{0}};
6520 OBJECT_ATTRIBUTES attr;
6521 UNICODE_STRING nt_name;
6522 HANDLE handle;
6523 char buf[8192];
6524 size_t len;
6526 len = lstrlenW( path );
6527 while (len && path[len - 1] == '\\') len--;
6529 nt_name.Buffer = path;
6530 nt_name.MaximumLength = nt_name.Length = len * sizeof(WCHAR);
6532 attr.Length = sizeof(attr);
6533 attr.RootDirectory = 0;
6534 attr.Attributes = OBJ_CASE_INSENSITIVE;
6535 attr.ObjectName = &nt_name;
6536 attr.SecurityDescriptor = NULL;
6537 attr.SecurityQualityOfService = NULL;
6539 if (NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
6540 FILE_SHARE_READ | FILE_SHARE_WRITE,
6541 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ))
6542 return;
6544 path[len++] = '\\';
6546 while (!NtQueryDirectoryFile( handle, 0, NULL, NULL, &io, buf, sizeof(buf),
6547 FileBothDirectoryInformation, FALSE, NULL, FALSE ) &&
6548 io.Information)
6550 FILE_BOTH_DIR_INFORMATION *info = (FILE_BOTH_DIR_INFORMATION *)buf;
6551 for (;;)
6553 if (!(info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
6555 memcpy( path + len, info->FileName, info->FileNameLength );
6556 path[len + info->FileNameLength / sizeof(WCHAR)] = 0;
6557 font_funcs->add_font( path, flags );
6559 if (!info->NextEntryOffset) break;
6560 info = (FILE_BOTH_DIR_INFORMATION *)((char *)info + info->NextEntryOffset);
6564 NtClose( handle );
6567 static void load_file_system_fonts(void)
6569 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024 * sizeof(WCHAR)])];
6570 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6571 WCHAR *ptr, *next, path[MAX_PATH];
6573 /* Windows directory */
6574 get_fonts_win_dir_path( NULL, path );
6575 load_directory_fonts( path, 0 );
6577 /* Wine data directory */
6578 get_fonts_data_dir_path( NULL, path );
6579 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6581 /* custom paths */
6582 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6583 if (query_reg_ascii_value( wine_fonts_key, "Path", info, sizeof(value_buffer) ) &&
6584 info->Type == REG_SZ)
6586 for (ptr = (WCHAR *)info->Data; ptr; ptr = next)
6588 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
6589 if (next && next - ptr < 2) continue;
6590 lstrcpynW( path, ptr, MAX_PATH );
6591 if (path[1] == ':')
6593 memmove( path + ARRAYSIZE(nt_prefixW), path, (lstrlenW( path ) + 1) * sizeof(WCHAR) );
6594 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6596 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6601 struct external_key
6603 struct list entry;
6604 WCHAR value[LF_FULLFACESIZE + 12];
6607 static void update_external_font_keys(void)
6609 struct list external_keys = LIST_INIT(external_keys);
6610 HKEY winnt_key = 0, win9x_key = 0;
6611 struct gdi_font_family *family;
6612 struct external_key *key, *next;
6613 struct gdi_font_face *face;
6614 DWORD len, i = 0;
6615 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6616 char buffer[2048];
6617 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
6618 WCHAR *file;
6619 HKEY hkey;
6621 static const WCHAR external_fontsW[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6623 winnt_key = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW), 0, NULL );
6624 win9x_key = reg_create_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW), 0, NULL );
6626 /* enumerate the fonts and add external ones to the two keys */
6628 if (!(hkey = reg_create_key( wine_fonts_key, external_fontsW, sizeof(external_fontsW), 0, NULL )))
6629 return;
6631 while (reg_enum_value( hkey, i++, info, sizeof(buffer) - sizeof(nt_prefixW),
6632 value, LF_FULLFACESIZE * sizeof(WCHAR) ))
6634 if (info->Type != REG_SZ) continue;
6636 path = (WCHAR *)(buffer + info->DataOffset);
6637 if (path[0] && path[1] == ':')
6639 memmove( path + ARRAYSIZE(nt_prefixW), path, info->DataLength );
6640 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6643 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6644 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
6646 face->flags |= ADDFONT_EXTERNAL_FOUND;
6647 continue;
6649 if (tmp && !*tmp) *tmp = ' ';
6650 if (!(key = malloc( sizeof(*key) ))) break;
6651 lstrcpyW( key->value, value );
6652 list_add_tail( &external_keys, &key->entry );
6655 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
6657 reg_delete_value( win9x_key, key->value );
6658 reg_delete_value( winnt_key, key->value );
6659 reg_delete_value( hkey, key->value );
6660 list_remove( &key->entry );
6661 free( key );
6663 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
6665 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
6667 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
6668 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
6670 lstrcpyW( value, face->full_name );
6671 if (face->scalable) lstrcatW( value, true_type_suffixW );
6673 if (face->file[0] == '\\')
6675 file = face->file;
6676 if (file[5] == ':') file += ARRAYSIZE(nt_prefixW);
6678 else if ((file = wcsrchr( face->file, '\\' )))
6679 file++;
6680 else
6681 file = face->file;
6683 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
6684 set_reg_value( winnt_key, value, REG_SZ, file, len );
6685 set_reg_value( win9x_key, value, REG_SZ, file, len );
6686 set_reg_value( hkey, value, REG_SZ, file, len );
6689 NtClose( win9x_key );
6690 NtClose( winnt_key );
6691 NtClose( hkey );
6694 static void load_registry_fonts(void)
6696 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6697 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6698 KEY_VALUE_FULL_INFORMATION *enum_info = (KEY_VALUE_FULL_INFORMATION *)value_buffer;
6699 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6700 DWORD i = 0, dlen;
6701 HKEY hkey;
6703 static const WCHAR dot_fonW[] = {'.','f','o','n',0};
6705 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6706 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6707 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6708 will skip these. */
6709 if (is_win9x())
6710 hkey = reg_open_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW) );
6711 else
6712 hkey = reg_open_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW) );
6713 if (!hkey) return;
6715 while (reg_enum_value( hkey, i++, enum_info, sizeof(value_buffer), value, sizeof(value) ))
6717 if (enum_info->Type != REG_SZ) continue;
6718 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6719 if (find_face_from_full_name( value )) continue;
6720 if (tmp && !*tmp) *tmp = ' ';
6722 if (!(dlen = query_reg_value( hkey, value, info, sizeof(value_buffer) - sizeof(nt_prefixW) )) ||
6723 info->Type != REG_SZ)
6725 WARN( "Unable to get face path %s\n", debugstr_w(value) );
6726 continue;
6729 path = (WCHAR *)info->Data;
6730 if (path[0] && path[1] == ':')
6732 memmove( path + ARRAYSIZE(nt_prefixW), path, dlen );
6733 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6734 dlen += sizeof(nt_prefixW);
6737 dlen /= sizeof(WCHAR);
6738 if (*path == '\\')
6739 add_font_resource( path, ADDFONT_ALLOW_BITMAP );
6740 else if (dlen >= 6 && !wcsicmp( path + dlen - 5, dot_fonW ))
6741 add_system_font_resource( path, ADDFONT_ALLOW_BITMAP );
6743 NtClose( hkey );
6746 static HKEY open_hkcu(void)
6748 char buffer[256];
6749 WCHAR bufferW[256];
6750 DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
6751 DWORD i, len = sizeof(sid_data);
6752 SID *sid;
6754 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
6755 return 0;
6757 sid = ((TOKEN_USER *)sid_data)->User.Sid;
6758 len = snprintf( buffer, sizeof(buffer), "\\Registry\\User\\S-%u-%u", (int)sid->Revision,
6759 (int)MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
6760 MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
6761 for (i = 0; i < sid->SubAuthorityCount; i++)
6762 len += snprintf( buffer + len, sizeof(buffer) - len, "-%u", (int)sid->SubAuthority[i] );
6763 ascii_to_unicode( bufferW, buffer, len + 1 );
6765 return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
6768 /***********************************************************************
6769 * font_init
6771 UINT font_init(void)
6773 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
6774 UNICODE_STRING name;
6775 HANDLE mutex;
6776 DWORD disposition;
6777 UINT dpi = 0;
6779 static WCHAR wine_font_mutexW[] =
6780 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6781 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6782 static const WCHAR wine_fonts_keyW[] =
6783 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6784 static const WCHAR cacheW[] = {'C','a','c','h','e'};
6786 if (!(hkcu_key = open_hkcu())) return 0;
6787 wine_fonts_key = reg_create_key( hkcu_key, wine_fonts_keyW, sizeof(wine_fonts_keyW), 0, NULL );
6788 if (wine_fonts_key) dpi = init_font_options();
6789 if (!dpi) return 96;
6790 update_codepage( dpi );
6792 if (!(font_funcs = init_freetype_lib()))
6793 return dpi;
6795 load_system_bitmap_fonts();
6796 load_file_system_fonts();
6797 font_funcs->load_fonts();
6799 attr.Attributes = OBJ_OPENIF;
6800 attr.ObjectName = &name;
6801 name.Buffer = wine_font_mutexW;
6802 name.Length = name.MaximumLength = sizeof(wine_font_mutexW);
6804 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return dpi;
6805 NtWaitForSingleObject( mutex, FALSE, NULL );
6807 wine_fonts_cache_key = reg_create_key( wine_fonts_key, cacheW, sizeof(cacheW),
6808 REG_OPTION_VOLATILE, &disposition );
6810 if (disposition == REG_CREATED_NEW_KEY)
6812 load_registry_fonts();
6813 update_external_font_keys();
6816 NtReleaseMutant( mutex, NULL );
6818 if (disposition != REG_CREATED_NEW_KEY)
6820 load_registry_fonts();
6821 load_font_list_from_cache();
6824 reorder_font_list();
6825 load_gdi_font_subst();
6826 load_gdi_font_replacements();
6827 load_system_links();
6828 dump_gdi_font_list();
6829 dump_gdi_font_subst();
6830 return dpi;
6833 /***********************************************************************
6834 * NtGdiAddFontResourceW (win32u.@)
6836 INT WINAPI NtGdiAddFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6837 DWORD tid, void *dv )
6839 if (!font_funcs) return 1;
6840 return add_font_resource( str, flags );
6843 /***********************************************************************
6844 * NtGdiAddFontMemResourceEx (win32u.@)
6846 HANDLE WINAPI NtGdiAddFontMemResourceEx( void *ptr, DWORD size, void *dv, ULONG dv_size,
6847 DWORD *count )
6849 HANDLE ret;
6850 DWORD num_fonts;
6851 void *copy;
6853 if (!ptr || !size || !count)
6855 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER);
6856 return NULL;
6858 if (!font_funcs) return NULL;
6859 if (!(copy = malloc( size ))) return NULL;
6860 memcpy( copy, ptr, size );
6862 pthread_mutex_lock( &font_lock );
6863 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6864 pthread_mutex_unlock( &font_lock );
6866 if (!num_fonts)
6868 free( copy );
6869 return NULL;
6872 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6873 * For now return something unique but quite random
6875 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
6877 __TRY
6879 *count = num_fonts;
6881 __EXCEPT
6883 WARN( "page fault while writing to *count (%p)\n", count );
6884 NtGdiRemoveFontMemResourceEx( ret );
6885 ret = 0;
6887 __ENDTRY
6888 TRACE( "Returning handle %p\n", ret );
6889 return ret;
6892 /***********************************************************************
6893 * NtGdiRemoveFontMemResourceEx (win32u.@)
6895 BOOL WINAPI NtGdiRemoveFontMemResourceEx( HANDLE handle )
6897 FIXME( "(%p) stub\n", handle );
6898 return TRUE;
6901 /***********************************************************************
6902 * NtGdiRemoveFontResourceW (win32u.@)
6904 BOOL WINAPI NtGdiRemoveFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6905 DWORD tid, void *dv )
6907 if (!font_funcs) return TRUE;
6908 return remove_font_resource( str, flags );
6911 /***********************************************************************
6912 * NtGdiGetFontUnicodeRanges (win32u.@)
6914 * Retrieve a list of supported Unicode characters in a font.
6916 * PARAMS
6917 * hdc [I] Handle to a device context.
6918 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6920 * RETURNS
6921 * Success: Number of bytes written to the buffer pointed to by lpgs.
6922 * Failure: 0
6925 DWORD WINAPI NtGdiGetFontUnicodeRanges( HDC hdc, GLYPHSET *lpgs )
6927 DWORD ret;
6928 PHYSDEV dev;
6929 DC *dc = get_dc_ptr(hdc);
6931 TRACE("(%p, %p)\n", hdc, lpgs);
6933 if (!dc) return 0;
6935 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
6936 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
6937 release_dc_ptr(dc);
6938 return ret;
6942 /*************************************************************
6943 * NtGdiFontIsLinked (win32u.@)
6945 BOOL WINAPI NtGdiFontIsLinked( HDC hdc )
6947 DC *dc = get_dc_ptr(hdc);
6948 PHYSDEV dev;
6949 BOOL ret;
6951 if (!dc) return FALSE;
6952 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
6953 ret = dev->funcs->pFontIsLinked( dev );
6954 release_dc_ptr(dc);
6955 TRACE("returning %d\n", ret);
6956 return ret;
6959 /*************************************************************
6960 * NtGdiGetRealizationInfo (win32u.@)
6962 BOOL WINAPI NtGdiGetRealizationInfo( HDC hdc, struct font_realization_info *info )
6964 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, file_count);
6965 PHYSDEV dev;
6966 BOOL ret;
6967 DC *dc;
6969 if (info->size != sizeof(*info) && !is_v0)
6970 return FALSE;
6972 dc = get_dc_ptr(hdc);
6973 if (!dc) return FALSE;
6974 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
6975 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
6976 release_dc_ptr(dc);
6977 return ret;
6980 /*************************************************************************
6981 * NtGdiGetRasterizerCaps (win32u.@)
6983 BOOL WINAPI NtGdiGetRasterizerCaps( RASTERIZER_STATUS *status, UINT size )
6985 status->nSize = sizeof(RASTERIZER_STATUS);
6986 status->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
6987 status->nLanguageID = 0;
6988 return TRUE;
6991 /*************************************************************************
6992 * NtGdiGetFontFileData (win32u.@)
6994 BOOL WINAPI NtGdiGetFontFileData( DWORD instance_id, DWORD file_index, UINT64 *offset,
6995 void *buff, SIZE_T buff_size )
6997 struct gdi_font *font;
6998 DWORD tag = 0, size;
6999 BOOL ret = FALSE;
7001 if (!font_funcs) return FALSE;
7002 pthread_mutex_lock( &font_lock );
7003 if ((font = get_font_from_handle( instance_id )))
7005 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
7006 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
7007 if (size != GDI_ERROR && size >= buff_size && *offset <= size - buff_size)
7008 ret = font_funcs->get_font_data( font, tag, *offset, buff, buff_size ) != GDI_ERROR;
7009 else
7010 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
7012 pthread_mutex_unlock( &font_lock );
7013 return ret;
7016 /*************************************************************************
7017 * NtGdiGetFontFileInfo (win32u.@)
7019 BOOL WINAPI NtGdiGetFontFileInfo( DWORD instance_id, DWORD file_index, struct font_fileinfo *info,
7020 SIZE_T size, SIZE_T *needed )
7022 SIZE_T required_size = 0;
7023 struct gdi_font *font;
7024 BOOL ret = FALSE;
7026 pthread_mutex_lock( &font_lock );
7028 if ((font = get_font_from_handle( instance_id )))
7030 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
7031 if (required_size <= size)
7033 info->writetime = font->writetime;
7034 info->size.QuadPart = font->data_size;
7035 lstrcpyW( info->path, font->file );
7036 ret = TRUE;
7038 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
7041 pthread_mutex_unlock( &font_lock );
7042 if (needed) *needed = required_size;
7043 return ret;
7046 /*************************************************************
7047 * NtGdiGetCharWidthInfo (win32u.@)
7049 BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info )
7051 PHYSDEV dev;
7052 BOOL ret;
7053 DC *dc;
7055 dc = get_dc_ptr(hdc);
7056 if (!dc) return FALSE;
7057 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
7058 ret = dev->funcs->pGetCharWidthInfo( dev, info );
7060 if (ret)
7062 info->lsb = width_to_LP( dc, info->lsb );
7063 info->rsb = width_to_LP( dc, info->rsb );
7065 release_dc_ptr(dc);
7066 return ret;
7069 /***********************************************************************
7070 * DrawTextW (win32u.so)
7072 INT WINAPI DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags )
7074 struct draw_text_params *params;
7075 struct draw_text_result *result;
7076 ULONG ret_len, size;
7077 NTSTATUS status;
7078 int ret = 0;
7080 if (count == -1) count = wcslen( str );
7081 size = FIELD_OFFSET( struct draw_text_params, str[count] );
7082 if (!(params = malloc( size ))) return 0;
7083 params->hdc = hdc;
7084 params->rect = *rect;
7085 params->flags = flags;
7086 if (count) memcpy( params->str, str, count * sizeof(WCHAR) );
7088 status = KeUserModeCallback( NtUserDrawText, params, size, (void **)&result, &ret_len );
7089 if (!status && ret_len == sizeof(*result))
7091 ret = result->height;
7092 *rect = result->rect;
7094 free( params );
7095 return ret;