win32u: Don't allow bitmap fonts if OUT_TT_ONLY_PRECIS output precision is specified.
[wine.git] / dlls / win32u / font.c
blobcdac88836b9953c01cbca4e225b48b578bdbc70a
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 #ifndef WINE_FONT_DIR
466 #define WINE_FONT_DIR "fonts"
467 #endif
469 #ifdef WORDS_BIGENDIAN
470 #define GET_BE_WORD(x) (x)
471 #define GET_BE_DWORD(x) (x)
472 #else
473 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
474 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
475 #endif
477 static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
479 const char *dir;
480 ULONG len = MAX_PATH;
482 if ((dir = ntdll_get_data_dir()))
484 wine_unix_to_nt_file_name( dir, path, &len );
485 asciiz_to_unicode( path + len - 1, "\\" WINE_FONT_DIR "\\" );
487 else if ((dir = ntdll_get_build_dir()))
489 wine_unix_to_nt_file_name( dir, path, &len );
490 asciiz_to_unicode( path + len - 1, "\\fonts\\" );
493 if (file) lstrcatW( path, file );
496 static void get_fonts_win_dir_path( const WCHAR *file, WCHAR *path )
498 asciiz_to_unicode( path, "\\??\\C:\\windows\\fonts\\" );
499 if (file) lstrcatW( path, file );
502 HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len )
504 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
505 OBJECT_ATTRIBUTES attr;
506 HANDLE ret;
508 attr.Length = sizeof(attr);
509 attr.RootDirectory = root;
510 attr.ObjectName = &nameW;
511 attr.Attributes = 0;
512 attr.SecurityDescriptor = NULL;
513 attr.SecurityQualityOfService = NULL;
515 if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0;
516 return ret;
519 /* wrapper for NtCreateKey that creates the key recursively if necessary */
520 HKEY reg_create_key( HKEY root, const WCHAR *name, ULONG name_len,
521 DWORD options, DWORD *disposition )
523 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
524 OBJECT_ATTRIBUTES attr;
525 NTSTATUS status;
526 HANDLE ret;
528 attr.Length = sizeof(attr);
529 attr.RootDirectory = root;
530 attr.ObjectName = &nameW;
531 attr.Attributes = 0;
532 attr.SecurityDescriptor = NULL;
533 attr.SecurityQualityOfService = NULL;
535 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, options, disposition );
536 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
538 static const WCHAR registry_rootW[] = { '\\','R','e','g','i','s','t','r','y','\\' };
539 DWORD pos = 0, i = 0, len = name_len / sizeof(WCHAR);
541 /* don't try to create registry root */
542 if (!root && len > ARRAY_SIZE(registry_rootW) &&
543 !memcmp( name, registry_rootW, sizeof(registry_rootW) ))
544 i += ARRAY_SIZE(registry_rootW);
546 while (i < len && name[i] != '\\') i++;
547 if (i == len) return 0;
548 for (;;)
550 unsigned int subkey_options = options;
551 if (i < len) subkey_options &= ~(REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK);
552 nameW.Buffer = (WCHAR *)name + pos;
553 nameW.Length = (i - pos) * sizeof(WCHAR);
554 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, subkey_options, disposition );
556 if (attr.RootDirectory != root) NtClose( attr.RootDirectory );
557 if (!NT_SUCCESS(status)) return 0;
558 if (i == len) break;
559 attr.RootDirectory = ret;
560 while (i < len && name[i] == '\\') i++;
561 pos = i;
562 while (i < len && name[i] != '\\') i++;
565 return ret;
568 HKEY reg_open_hkcu_key( const char *name )
570 WCHAR nameW[128];
571 return reg_open_key( hkcu_key, nameW, asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) );
574 BOOL set_reg_value( HKEY hkey, const WCHAR *name, UINT type, const void *value, DWORD count )
576 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
577 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
578 return !NtSetValueKey( hkey, &nameW, 0, type, value, count );
581 void set_reg_ascii_value( HKEY hkey, const char *name, const char *value )
583 WCHAR nameW[64], valueW[128];
584 asciiz_to_unicode( nameW, name );
585 set_reg_value( hkey, nameW, REG_SZ, valueW, asciiz_to_unicode( valueW, value ));
588 ULONG query_reg_value( HKEY hkey, const WCHAR *name,
589 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
591 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
592 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
594 if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
595 info, size, &size ))
596 return 0;
598 return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
601 ULONG query_reg_ascii_value( HKEY hkey, const char *name,
602 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
604 WCHAR nameW[64];
605 asciiz_to_unicode( nameW, name );
606 return query_reg_value( hkey, nameW, info, size );
609 static BOOL reg_enum_value( HKEY hkey, unsigned int index, KEY_VALUE_FULL_INFORMATION *info,
610 ULONG size, WCHAR *name, ULONG name_size )
612 ULONG full_size;
614 if (NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
615 info, size, &full_size ))
616 return FALSE;
618 if (name_size)
620 if (name_size < info->NameLength + sizeof(WCHAR)) return FALSE;
621 memcpy( name, info->Name, info->NameLength );
622 name[info->NameLength / sizeof(WCHAR)] = 0;
624 return TRUE;
627 void reg_delete_value( HKEY hkey, const WCHAR *name )
629 unsigned int name_size = lstrlenW( name ) * sizeof(WCHAR);
630 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
631 NtDeleteValueKey( hkey, &nameW );
634 BOOL reg_delete_tree( HKEY parent, const WCHAR *name, ULONG name_len )
636 char buffer[4096];
637 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
638 DWORD size;
639 HKEY key;
640 BOOL ret = TRUE;
642 if (!(key = reg_open_key( parent, name, name_len ))) return FALSE;
644 while (ret && !NtEnumerateKey( key, 0, KeyNodeInformation, key_info, sizeof(buffer), &size ))
645 ret = reg_delete_tree( key, key_info->Name, key_info->NameLength );
647 if (ret) ret = !NtDeleteKey( key );
648 NtClose( key );
649 return ret;
652 /* font substitutions */
654 struct gdi_font_subst
656 struct list entry;
657 int from_charset;
658 int to_charset;
659 WCHAR names[1];
662 static struct list font_subst_list = LIST_INIT(font_subst_list);
664 static inline WCHAR *get_subst_to_name( struct gdi_font_subst *subst )
666 return subst->names + lstrlenW( subst->names ) + 1;
669 static void dump_gdi_font_subst(void)
671 struct gdi_font_subst *subst;
673 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
675 if (subst->from_charset != -1 || subst->to_charset != -1)
676 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst->names),
677 subst->from_charset, debugstr_w(get_subst_to_name(subst)), subst->to_charset);
678 else
679 TRACE("%s -> %s\n", debugstr_w(subst->names), debugstr_w(get_subst_to_name(subst)));
683 static const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset )
685 struct gdi_font_subst *subst;
687 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
689 if (!facename_compare( subst->names, from_name, -1 ) &&
690 (subst->from_charset == from_charset || subst->from_charset == -1))
692 if (to_charset) *to_charset = subst->to_charset;
693 return get_subst_to_name( subst );
696 return NULL;
699 static BOOL add_gdi_font_subst( const WCHAR *from_name, int from_charset, const WCHAR *to_name, int to_charset )
701 struct gdi_font_subst *subst;
702 int len = lstrlenW( from_name ) + lstrlenW( to_name ) + 2;
704 if (get_gdi_font_subst( from_name, from_charset, NULL )) return FALSE; /* already exists */
706 if (!(subst = malloc( offsetof( struct gdi_font_subst, names[len] ) )))
707 return FALSE;
708 lstrcpyW( subst->names, from_name );
709 lstrcpyW( get_subst_to_name(subst), to_name );
710 subst->from_charset = from_charset;
711 subst->to_charset = to_charset;
712 list_add_tail( &font_subst_list, &subst->entry );
713 return TRUE;
716 static void load_gdi_font_subst(void)
718 char buffer[512];
719 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
720 HKEY hkey;
721 DWORD i = 0;
722 WCHAR *data, *p, value[64];
724 if (!(hkey = reg_open_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW) )))
725 return;
727 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
729 int from_charset = -1, to_charset = -1;
731 if (info->Type != REG_SZ) continue;
732 data = (WCHAR *)((char *)info + info->DataOffset);
734 TRACE( "Got %s=%s\n", debugstr_w(value), debugstr_w(data) );
735 if ((p = wcsrchr( value, ',' )) && p[1])
737 *p++ = 0;
738 from_charset = wcstol( p, NULL, 10 );
740 if ((p = wcsrchr( data, ',' )) && p[1])
742 *p++ = 0;
743 to_charset = wcstol( p, NULL, 10 );
746 /* Win 2000 doesn't allow mapping between different charsets
747 or mapping of DEFAULT_CHARSET */
748 if ((!from_charset || to_charset == from_charset) && to_charset != DEFAULT_CHARSET)
749 add_gdi_font_subst( value, from_charset, data, to_charset );
751 NtClose( hkey );
754 /* font families */
756 static int family_namecmp( const WCHAR *str1, const WCHAR *str2 )
758 int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0);
760 if (!facename_compare( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0;
761 else if (!facename_compare( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1;
762 else if (!facename_compare( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2;
763 else prio1 = 3;
765 if (!facename_compare( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0;
766 else if (!facename_compare( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1;
767 else if (!facename_compare( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2;
768 else prio2 = 3;
770 if (prio1 != prio2) return prio1 - prio2;
771 if (vert1 != vert2) return vert1 - vert2;
772 return facename_compare( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 );
775 static int family_name_compare( const void *key, const struct wine_rb_entry *entry )
777 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, name_entry );
778 return family_namecmp( (const WCHAR *)key, family->family_name );
781 static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry )
783 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, second_name_entry );
784 return family_namecmp( (const WCHAR *)key, family->second_name );
787 static int face_full_name_compare( const void *key, const struct wine_rb_entry *entry )
789 const struct gdi_font_face *face = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_face, full_name_entry );
790 return facename_compare( (const WCHAR *)key, face->full_name, LF_FULLFACESIZE - 1 );
793 static struct wine_rb_tree family_name_tree = { family_name_compare };
794 static struct wine_rb_tree family_second_name_tree = { family_second_name_compare };
795 static struct wine_rb_tree face_full_name_tree = { face_full_name_compare };
797 static int face_is_in_full_name_tree( const struct gdi_font_face *face )
799 return face->full_name_entry.parent || face_full_name_tree.root == &face->full_name_entry;
802 static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name )
804 struct gdi_font_family *family = malloc( sizeof(*family) );
806 family->refcount = 1;
807 lstrcpynW( family->family_name, name, LF_FACESIZE );
808 if (second_name && second_name[0] && wcsicmp( name, second_name ))
810 lstrcpynW( family->second_name, second_name, LF_FACESIZE );
811 add_gdi_font_subst( second_name, -1, name, -1 );
813 else family->second_name[0] = 0;
814 list_init( &family->faces );
815 family->replacement = NULL;
816 wine_rb_put( &family_name_tree, family->family_name, &family->name_entry );
817 if (family->second_name[0]) wine_rb_put( &family_second_name_tree, family->second_name, &family->second_name_entry );
818 return family;
821 static void release_family( struct gdi_font_family *family )
823 if (--family->refcount) return;
824 assert( list_empty( &family->faces ));
825 wine_rb_remove( &family_name_tree, &family->name_entry );
826 if (family->second_name[0]) wine_rb_remove( &family_second_name_tree, &family->second_name_entry );
827 if (family->replacement) release_family( family->replacement );
828 free( family );
831 static struct gdi_font_family *find_family_from_name( const WCHAR *name )
833 struct wine_rb_entry *entry;
834 if (!(entry = wine_rb_get( &family_name_tree, name ))) return NULL;
835 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, name_entry );
838 static struct gdi_font_family *find_family_from_any_name( const WCHAR *name )
840 struct wine_rb_entry *entry;
841 struct gdi_font_family *family;
842 if ((family = find_family_from_name( name ))) return family;
843 if (!(entry = wine_rb_get( &family_second_name_tree, name ))) return NULL;
844 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, second_name_entry );
847 static struct gdi_font_face *find_face_from_full_name( const WCHAR *full_name )
849 struct wine_rb_entry *entry;
850 if (!(entry = wine_rb_get( &face_full_name_tree, full_name ))) return NULL;
851 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_face, full_name_entry );
854 static const struct list *get_family_face_list( const struct gdi_font_family *family )
856 return family->replacement ? &family->replacement->faces : &family->faces;
859 static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name )
861 struct gdi_font_face *face;
862 const WCHAR *file;
863 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
865 if (!face->file) continue;
866 file = wcsrchr(face->file, '\\');
867 if (!file) file = face->file;
868 else file++;
869 if (wcsicmp( file, file_name )) continue;
870 face->refcount++;
871 return face;
873 return NULL;
876 static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name )
878 struct gdi_font_family *family;
879 struct gdi_font_face *face;
881 TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
883 if (!family_name)
885 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
886 if ((face = family_find_face_from_filename( family, file_name ))) return face;
887 return NULL;
890 if (!(family = find_family_from_name( family_name ))) return NULL;
891 return family_find_face_from_filename( family, file_name );
894 static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
896 struct gdi_font_family *new_family, *family;
897 struct gdi_font_face *face;
898 WCHAR new_name_vert[LF_FACESIZE], replace_vert[LF_FACESIZE];
900 if (!(family = find_family_from_any_name( replace )))
902 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace) );
903 return FALSE;
906 if (family->replacement)
908 TRACE( "%s is replaced by another font, skipping.\n", debugstr_w(replace) );
909 return FALSE;
912 if (!(new_family = create_family( new_name, NULL ))) return FALSE;
913 new_family->replacement = family;
914 family->refcount++;
915 TRACE( "mapping %s to %s\n", debugstr_w(replace), debugstr_w(new_name) );
917 /* also add replacement for vertical font if necessary */
918 if (replace[0] == '@') return TRUE;
919 if (list_empty( &family->faces )) return TRUE;
920 face = LIST_ENTRY( list_head(&family->faces), struct gdi_font_face, entry );
921 if (!(face->fs.fsCsb[0] & FS_DBCS_MASK)) return TRUE;
923 new_name_vert[0] = '@';
924 lstrcpynW( new_name_vert + 1, new_name, LF_FACESIZE - 1 );
925 if (find_family_from_any_name( new_name_vert )) return TRUE; /* already exists */
927 replace_vert[0] = '@';
928 lstrcpynW( replace_vert + 1, replace, LF_FACESIZE - 1 );
929 add_family_replacement( new_name_vert, replace_vert );
930 return TRUE;
934 * The replacement list is a way to map an entire font
935 * family onto another family. For example adding
937 * [HKCU\Software\Wine\Fonts\Replacements]
938 * "Wingdings"="Winedings"
940 * would enumerate the Winedings font both as Winedings and
941 * Wingdings. However if a real Wingdings font is present the
942 * replacement does not take place.
944 static void load_gdi_font_replacements(void)
946 char buffer[2048];
947 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
948 HKEY hkey;
949 DWORD i = 0;
950 WCHAR value[LF_FACESIZE];
952 static const WCHAR replacementsW[] = {'R','e','p','l','a','c','e','m','e','n','t','s'};
954 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
955 if (!(hkey = reg_open_key( wine_fonts_key, replacementsW, sizeof(replacementsW) ))) return;
957 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
959 WCHAR *data = (WCHAR *)((char *)info + info->DataOffset);
960 /* "NewName"="Oldname" */
961 if (!find_family_from_any_name( value ))
963 if (info->Type == REG_MULTI_SZ)
965 WCHAR *replace = data;
966 while (*replace)
968 if (add_family_replacement( value, replace )) break;
969 replace += lstrlenW(replace) + 1;
972 else if (info->Type == REG_SZ) add_family_replacement( value, data );
974 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
976 NtClose( hkey );
979 static void dump_gdi_font_list(void)
981 struct gdi_font_family *family;
982 struct gdi_font_face *face;
984 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
986 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
987 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
989 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
990 (int)face->fs.fsCsb[0] );
991 if (!face->scalable) TRACE(" %d", face->size.height );
992 TRACE("\n");
997 static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
999 if (index < 3)
1001 const char * const *defaults;
1003 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
1004 defaults = default_fixed_list;
1005 else if ((pitch_and_family & 0xf0) == FF_ROMAN)
1006 defaults = default_serif_list;
1007 else
1008 defaults = default_sans_list;
1009 asciiz_to_unicode( buffer, defaults[index] );
1010 return TRUE;
1012 return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
1015 static void set_default_family( DWORD pitch_and_family, WCHAR *default_name )
1017 struct wine_rb_entry *entry;
1018 WCHAR name[LF_FACESIZE];
1019 int i = 0;
1021 while (enum_fallbacks( pitch_and_family, i++, name ))
1023 if (!(entry = wine_rb_get( &family_name_tree, name ))) continue;
1024 wine_rb_remove( &family_name_tree, entry );
1025 lstrcpynW( default_name, name, LF_FACESIZE - 1 );
1026 wine_rb_put( &family_name_tree, name, entry );
1027 return;
1031 static void reorder_font_list(void)
1033 set_default_family( FF_ROMAN, ff_roman_default );
1034 set_default_family( FF_MODERN, ff_modern_default );
1035 set_default_family( FF_SWISS, ff_swiss_default );
1038 static void release_face( struct gdi_font_face *face )
1040 if (--face->refcount) return;
1041 if (face->family)
1043 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1044 list_remove( &face->entry );
1045 release_family( face->family );
1047 if (face_is_in_full_name_tree( face )) wine_rb_remove( &face_full_name_tree, &face->full_name_entry );
1048 free( face->file );
1049 free( face->style_name );
1050 free( face->full_name );
1051 free( face->cached_enum_data );
1052 free( face );
1055 static int remove_font( const WCHAR *file, DWORD flags )
1057 struct gdi_font_family *family, *family_next;
1058 struct gdi_font_face *face, *face_next;
1059 int count = 0;
1061 pthread_mutex_lock( &font_lock );
1062 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_name_tree, struct gdi_font_family, name_entry )
1064 family->refcount++;
1065 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry )
1067 if (!face->file) continue;
1068 if (LOWORD(face->flags) != LOWORD(flags)) continue;
1069 if (!wcsicmp( face->file, file ))
1071 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
1072 release_face( face );
1073 count++;
1076 release_family( family );
1078 pthread_mutex_unlock( &font_lock );
1079 return count;
1082 static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
1084 if (facename_compare( f1->full_name, f2->full_name, -1 )) return FALSE;
1085 if (f1->scalable) return TRUE;
1086 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1087 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1090 static inline int style_order( const struct gdi_font_face *face )
1092 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1094 case NTM_REGULAR:
1095 return 0;
1096 case NTM_BOLD:
1097 return 1;
1098 case NTM_ITALIC:
1099 return 2;
1100 case NTM_BOLD | NTM_ITALIC:
1101 return 3;
1102 default:
1103 WARN( "Don't know how to order face %s with flags 0x%08x\n",
1104 debugstr_w(face->full_name), face->ntmFlags );
1105 return 9999;
1109 static BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
1111 struct gdi_font_face *cursor;
1113 LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
1115 if (faces_equal( face, cursor ))
1117 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
1118 debugstr_w(face->full_name), debugstr_w(family->family_name),
1119 cursor->version, face->version );
1121 if (face->file && cursor->file && !wcsicmp( face->file, cursor->file ))
1123 cursor->refcount++;
1124 TRACE("Font %s already in list, refcount now %d\n",
1125 debugstr_w(face->file), cursor->refcount);
1126 return FALSE;
1128 if (face->version <= cursor->version)
1130 TRACE("Original font %s is newer so skipping %s\n",
1131 debugstr_w(cursor->file), debugstr_w(face->file));
1132 return FALSE;
1134 else
1136 TRACE("Replacing original %s with %s\n",
1137 debugstr_w(cursor->file), debugstr_w(face->file));
1138 list_add_before( &cursor->entry, &face->entry );
1139 face->family = family;
1140 family->refcount++;
1141 face->refcount++;
1142 if (face_is_in_full_name_tree( cursor ))
1144 wine_rb_replace( &face_full_name_tree, &cursor->full_name_entry, &face->full_name_entry );
1145 memset( &cursor->full_name_entry, 0, sizeof(cursor->full_name_entry) );
1147 release_face( cursor );
1148 return TRUE;
1151 if (style_order( face ) < style_order( cursor )) break;
1154 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
1155 debugstr_w(family->family_name), debugstr_w(face->file) );
1156 list_add_before( &cursor->entry, &face->entry );
1157 if (face->scalable) wine_rb_put( &face_full_name_tree, face->full_name, &face->full_name_entry );
1158 face->family = family;
1159 family->refcount++;
1160 face->refcount++;
1161 return TRUE;
1164 static struct gdi_font_face *create_face( struct gdi_font_family *family, const WCHAR *style,
1165 const WCHAR *fullname, const WCHAR *file,
1166 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1167 DWORD ntmflags, DWORD version, DWORD flags,
1168 const struct bitmap_font_size *size )
1170 struct gdi_font_face *face = calloc( 1, sizeof(*face) );
1172 face->refcount = 1;
1173 face->style_name = wcsdup( style );
1174 face->full_name = wcsdup( fullname );
1175 face->face_index = index;
1176 face->fs = fs;
1177 face->ntmFlags = ntmflags;
1178 face->version = version;
1179 face->flags = flags;
1180 face->data_ptr = data_ptr;
1181 face->data_size = data_size;
1182 if (file) face->file = wcsdup( file );
1183 if (size) face->size = *size;
1184 else face->scalable = TRUE;
1185 if (insert_face_in_family_list( face, family )) return face;
1186 release_face( face );
1187 return NULL;
1190 int add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
1191 const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
1192 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1193 DWORD ntmflags, DWORD version, DWORD flags,
1194 const struct bitmap_font_size *size )
1196 struct gdi_font_face *face;
1197 struct gdi_font_family *family;
1198 int ret = 0;
1200 if ((family = find_family_from_name( family_name ))) family->refcount++;
1201 else if (!(family = create_family( family_name, second_name ))) return ret;
1203 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1204 index, fs, ntmflags, version, flags, size )))
1206 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1207 release_face( face );
1209 release_family( family );
1210 ret++;
1212 if (fs.fsCsb[0] & FS_DBCS_MASK)
1214 WCHAR vert_family[LF_FACESIZE], vert_second[LF_FACESIZE], vert_full[LF_FULLFACESIZE];
1216 vert_family[0] = '@';
1217 lstrcpynW( vert_family + 1, family_name, LF_FACESIZE - 1 );
1219 if (second_name && second_name[0])
1221 vert_second[0] = '@';
1222 lstrcpynW( vert_second + 1, second_name, LF_FACESIZE - 1 );
1224 else vert_second[0] = 0;
1226 if (fullname)
1228 vert_full[0] = '@';
1229 lstrcpynW( vert_full + 1, fullname, LF_FULLFACESIZE - 1 );
1230 fullname = vert_full;
1233 if ((family = find_family_from_name( vert_family ))) family->refcount++;
1234 else if (!(family = create_family( vert_family, vert_second ))) return ret;
1236 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1237 index, fs, ntmflags, version, flags | ADDFONT_VERTICAL_FONT, size )))
1239 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1240 release_face( face );
1242 release_family( family );
1243 ret++;
1245 return ret;
1248 /* font cache */
1250 struct cached_face
1252 DWORD index;
1253 DWORD flags;
1254 DWORD ntmflags;
1255 DWORD version;
1256 struct bitmap_font_size size;
1257 FONTSIGNATURE fs;
1258 WCHAR full_name[1];
1259 /* WCHAR file_name[]; */
1262 static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
1263 void *buffer, DWORD buffer_size, BOOL scalable )
1265 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1266 KEY_NODE_INFORMATION *node_info = (KEY_NODE_INFORMATION *)buffer;
1267 DWORD index = 0, total_size;
1268 struct gdi_font_face *face;
1269 HKEY hkey_strike;
1270 WCHAR name[256];
1271 struct cached_face *cached;
1273 while (reg_enum_value( hkey_family, index++, info,
1274 buffer_size - sizeof(DWORD), name, sizeof(name) ))
1276 cached = (struct cached_face *)((char *)info + info->DataOffset);
1277 if (info->Type == REG_BINARY && info->DataLength > sizeof(*cached))
1279 ((DWORD *)cached)[info->DataLength / sizeof(DWORD)] = 0;
1280 if ((face = create_face( family, name, cached->full_name,
1281 cached->full_name + lstrlenW(cached->full_name) + 1,
1282 NULL, 0, cached->index, cached->fs, cached->ntmflags, cached->version,
1283 cached->flags, scalable ? NULL : &cached->size )))
1285 if (!scalable)
1286 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1287 face->size.height, face->size.width, face->size.size >> 6,
1288 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1290 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1291 (int)face->fs.fsCsb[0], (int)face->fs.fsCsb[1],
1292 (int)face->fs.fsUsb[0], (int)face->fs.fsUsb[1],
1293 (int)face->fs.fsUsb[2], (int)face->fs.fsUsb[3]);
1295 release_face( face );
1300 /* load bitmap strikes */
1302 index = 0;
1303 while (!NtEnumerateKey( hkey_family, index++, KeyNodeInformation, node_info,
1304 buffer_size, &total_size ))
1306 if ((hkey_strike = reg_open_key( hkey_family, node_info->Name, node_info->NameLength )))
1308 load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
1309 NtClose( hkey_strike );
1314 static void load_font_list_from_cache(void)
1316 WCHAR buffer[4096];
1317 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer;
1318 KEY_NODE_INFORMATION *enum_info = (KEY_NODE_INFORMATION *)buffer;
1319 DWORD family_index = 0, total_size;
1320 struct gdi_font_family *family;
1321 HKEY hkey_family;
1322 WCHAR *second_name = (WCHAR *)info->Data;
1324 while (!NtEnumerateKey( wine_fonts_cache_key, family_index++, KeyNodeInformation, enum_info,
1325 sizeof(buffer), &total_size ))
1327 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, enum_info->Name,
1328 enum_info->NameLength )))
1329 continue;
1330 TRACE( "opened family key %s\n", debugstr_wn(enum_info->Name, enum_info->NameLength / sizeof(WCHAR)) );
1331 if (!query_reg_value( hkey_family, NULL, info, sizeof(buffer) ))
1332 second_name[0] = 0;
1334 family = create_family( buffer, second_name );
1336 load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
1338 NtClose( hkey_family );
1339 release_family( family );
1343 static void add_face_to_cache( struct gdi_font_face *face )
1345 HKEY hkey_family, hkey_face;
1346 DWORD len, buffer[1024];
1347 struct cached_face *cached = (struct cached_face *)buffer;
1349 if (!(hkey_family = reg_create_key( wine_fonts_cache_key, face->family->family_name,
1350 lstrlenW( face->family->family_name ) * sizeof(WCHAR),
1351 REG_OPTION_VOLATILE, NULL )))
1352 return;
1354 if (face->family->second_name[0])
1355 set_reg_value( hkey_family, NULL, REG_SZ, face->family->second_name,
1356 (lstrlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1358 if (!face->scalable)
1360 WCHAR nameW[10];
1361 char name[10];
1363 sprintf( name, "%d", face->size.y_ppem );
1364 hkey_face = reg_create_key( hkey_family, nameW,
1365 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR),
1366 REG_OPTION_VOLATILE, NULL );
1368 else hkey_face = hkey_family;
1370 memset( cached, 0, sizeof(*cached) );
1371 cached->index = face->face_index;
1372 cached->flags = face->flags;
1373 cached->ntmflags = face->ntmFlags;
1374 cached->version = face->version;
1375 cached->fs = face->fs;
1376 if (!face->scalable) cached->size = face->size;
1377 lstrcpyW( cached->full_name, face->full_name );
1378 len = lstrlenW( face->full_name ) + 1;
1379 lstrcpyW( cached->full_name + len, face->file );
1380 len += lstrlenW( face->file ) + 1;
1382 set_reg_value( hkey_face, face->style_name, REG_BINARY, cached,
1383 offsetof( struct cached_face, full_name[len] ));
1385 if (hkey_face != hkey_family) NtClose( hkey_face );
1386 NtClose( hkey_family );
1389 static void remove_face_from_cache( struct gdi_font_face *face )
1391 HKEY hkey_family, hkey;
1393 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, face->family->family_name,
1394 lstrlenW( face->family->family_name ) * sizeof(WCHAR) )))
1395 return;
1397 if (!face->scalable)
1399 WCHAR nameW[10];
1400 char name[10];
1401 sprintf( name, "%d", face->size.y_ppem );
1402 if ((hkey = reg_open_key( hkey_family, nameW,
1403 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) )))
1405 NtDeleteKey( hkey );
1406 NtClose( hkey );
1409 else reg_delete_value( hkey_family, face->style_name );
1411 NtClose( hkey_family );
1414 /* font links */
1416 struct gdi_font_link
1418 struct list entry;
1419 struct list links;
1420 WCHAR name[LF_FACESIZE];
1421 FONTSIGNATURE fs;
1424 struct gdi_font_link_entry
1426 struct list entry;
1427 FONTSIGNATURE fs;
1428 WCHAR family_name[LF_FACESIZE];
1431 static struct list font_links = LIST_INIT(font_links);
1433 static struct gdi_font_link *find_gdi_font_link( const WCHAR *name )
1435 struct gdi_font_link *link;
1437 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1438 if (!facename_compare( link->name, name, LF_FACESIZE - 1 )) return link;
1439 return NULL;
1442 static struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
1443 FONTSIGNATURE fs )
1445 struct gdi_font_link *link;
1446 struct gdi_font_link_entry *entry;
1447 struct gdi_font_family *family;
1449 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1451 if (!facename_compare( link->name, name, LF_FACESIZE - 1 ) ||
1452 (subst && !facename_compare( link->name, subst, LF_FACESIZE - 1 )))
1454 TRACE("found entry in system list\n");
1455 LIST_FOR_EACH_ENTRY( entry, &link->links, struct gdi_font_link_entry, entry )
1457 const struct gdi_font_link *links;
1459 family = find_family_from_name( entry->family_name );
1460 if (!fs.fsCsb[0]) return family;
1461 if (fs.fsCsb[0] & entry->fs.fsCsb[0]) return family;
1462 if ((links = find_gdi_font_link( family->family_name )) && fs.fsCsb[0] & links->fs.fsCsb[0])
1463 return family;
1467 return NULL;
1470 static struct gdi_font_link *add_gdi_font_link( const WCHAR *name )
1472 struct gdi_font_link *link = find_gdi_font_link( name );
1474 if (link) return link;
1475 if ((link = malloc( sizeof(*link) )))
1477 lstrcpynW( link->name, name, LF_FACESIZE );
1478 memset( &link->fs, 0, sizeof(link->fs) );
1479 list_init( &link->links );
1480 list_add_tail( &font_links, &link->entry );
1482 return link;
1485 static void add_gdi_font_link_entry( struct gdi_font_link *link, const WCHAR *family_name, FONTSIGNATURE fs )
1487 struct gdi_font_link_entry *entry;
1489 entry = malloc( sizeof(*entry) );
1490 lstrcpynW( entry->family_name, family_name, LF_FACESIZE );
1491 entry->fs = fs;
1492 link->fs.fsCsb[0] |= fs.fsCsb[0];
1493 link->fs.fsCsb[1] |= fs.fsCsb[1];
1494 list_add_tail( &link->links, &entry->entry );
1497 static const WCHAR lucida_sans_unicodeW[] =
1498 {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
1499 static const WCHAR microsoft_sans_serifW[] =
1500 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1501 static const WCHAR tahomaW[] =
1502 {'T','a','h','o','m','a',0};
1503 static const WCHAR ms_gothicW[] =
1504 {'M','S',' ','G','o','t','h','i','c',0};
1505 static const WCHAR ms_p_gothicW[] =
1506 {'M','S',' ','P','G','o','t','h','i','c',0};
1507 static const WCHAR ms_ui_gothicW[] =
1508 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1509 static const WCHAR sim_sunW[] =
1510 {'S','i','m','S','u','n',0};
1511 static const WCHAR gulimW[] =
1512 {'G','u','l','i','m',0};
1513 static const WCHAR ming_li_uW[] =
1514 {'M','i','n','g','L','i','U',0};
1515 static const WCHAR p_ming_li_uW[] =
1516 {'P','M','i','n','g','L','i','U',0};
1517 static const WCHAR ming_li_u_hkscsW[] =
1518 {'M','i','n','g','L','i','U','_','H','K','S','C','S',0};
1519 static const WCHAR ming_li_u_ext_bW[] =
1520 {'M','i','n','g','L','i','U','-','E','x','t','B',0};
1521 static const WCHAR p_ming_li_u_ext_bW[] =
1522 {'P','M','i','n','g','L','i','U','-','E','x','t','B',0};
1523 static const WCHAR ming_li_u_hkscs_ext_bW[] =
1524 {'M','i','n','g','L','i','U','_','H','K','S','C','S','-','E','x','t','B',0};
1525 static const WCHAR batangW[] =
1526 {'B','a','t','a','n','g',0};
1527 static const WCHAR microsoft_jheng_heiW[] =
1528 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',0};
1529 static const WCHAR microsoft_jheng_hei_boldW[] =
1530 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','B','o','l','d',0};
1531 static const WCHAR microsoft_jheng_hei_uiW[] =
1532 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',0};
1533 static const WCHAR microsoft_jheng_hei_ui_boldW[] =
1534 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','B','o','l','d',0};
1535 static const WCHAR microsoft_jheng_hei_ui_lightW[] =
1536 {'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};
1537 static const WCHAR yu_gothic_uiW[] =
1538 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',0};
1539 static const WCHAR yu_gothic_ui_boldW[] =
1540 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','B','o','l','d',0};
1541 static const WCHAR yu_gothic_ui_lightW[] =
1542 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','L','i','g','h','t',0};
1543 static const WCHAR yu_gothic_ui_semilightW[] =
1544 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','S','e','m','i','l','i','g','h','t',0};
1545 static const WCHAR yu_gothic_ui_semiboldW[] =
1546 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','S','e','m','i','b','o','l','d',0};
1547 static const WCHAR meiryoW[] =
1548 {'M','e','i','r','y','o',0};
1549 static const WCHAR meiryo_boldW[] =
1550 {'M','e','i','r','y','o',' ','B','o','l','d',0};
1551 static const WCHAR meiryo_uiW[] =
1552 {'M','e','i','r','y','o',' ','U','I',0};
1553 static const WCHAR meiryo_ui_boldW[] =
1554 {'M','e','i','r','y','o',' ','U','I',' ','B','o','l','d',0};
1555 static const WCHAR ms_minchoW[] =
1556 {'M','S',' ','M','i','n','c','h','o',0};
1557 static const WCHAR ms_p_minchoW[] =
1558 {'M','S',' ','P','M','i','n','c','h','o',0};
1560 static const WCHAR * const font_links_list[] =
1562 lucida_sans_unicodeW,
1563 microsoft_sans_serifW,
1564 tahomaW
1567 static const struct font_links_defaults_list
1569 /* Keyed off substitution for "MS Shell Dlg" */
1570 const WCHAR *shelldlg;
1571 /* Maximum of four substitutes, plus terminating NULL pointer */
1572 const WCHAR *substitutes[5];
1573 } font_links_defaults_list[] =
1575 /* Non East-Asian */
1576 { tahomaW, /* FIXME unverified ordering */
1577 { ms_ui_gothicW, sim_sunW, gulimW, p_ming_li_uW, NULL }
1579 /* Below lists are courtesy of
1580 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1582 /* Japanese */
1583 { ms_ui_gothicW,
1584 { ms_ui_gothicW, p_ming_li_uW, sim_sunW, gulimW, NULL }
1586 /* Chinese Simplified */
1587 { sim_sunW,
1588 { sim_sunW, p_ming_li_uW, ms_ui_gothicW, batangW, NULL }
1590 /* Korean */
1591 { gulimW,
1592 { gulimW, p_ming_li_uW, ms_ui_gothicW, sim_sunW, NULL }
1594 /* Chinese Traditional */
1595 { p_ming_li_uW,
1596 { p_ming_li_uW, sim_sunW, ms_ui_gothicW, batangW, NULL }
1600 static const char system_link_tahoma_sc[] =
1601 "SIMSUN.TTC,SimSun\0"
1602 "MINGLIU.TTC,PMingLiu\0"
1603 "MSGOTHIC.TTC,MS UI Gothic\0"
1604 "BATANG.TTC,Batang\0"
1605 "MSYH.TTC,Microsoft YaHei UI\0"
1606 "MSJH.TTC,Microsoft JhengHei UI\0"
1607 "YUGOTHM.TTC,Yu Gothic UI\0"
1608 "MALGUN.TTF,Malgun Gothic\0"
1609 "SEGUISYM.TTF,Segoe UI Symbol\0";
1611 static const char system_link_tahoma_tc[] =
1612 "MINGLIU.TTC,PMingLiu\0"
1613 "SIMSUN.TTC,SimSun\0"
1614 "MSGOTHIC.TTC,MS UI Gothic\0"
1615 "BATANG.TTC,Batang\0"
1616 "MSJH.TTC,Microsoft JhengHei UI\0"
1617 "MSYH.TTC,Microsoft YaHei UI\0"
1618 "YUGOTHM.TTC,Yu Gothic UI\0"
1619 "MALGUN.TTF,Malgun Gothic\0"
1620 "SEGUISYM.TTF,Segoe UI Symbol\0";
1622 static const char system_link_tahoma_jp[] =
1623 "MSGOTHIC.TTC,MS UI Gothic\0"
1624 "MINGLIU.TTC,PMingLiU\0"
1625 "SIMSUN.TTC,SimSun\0"
1626 "GULIM.TTC,Gulim\0"
1627 "YUGOTHM.TTC,Yu Gothic UI\0"
1628 "MSJH.TTC,Microsoft JhengHei UI\0"
1629 "MSYH.TTC,Microsoft YaHei UI\0"
1630 "MALGUN.TTF,Malgun Gothic\0"
1631 "SEGUISYM.TTF,Segoe UI Symbol\0";
1633 static const char system_link_tahoma_kr[] =
1634 "GULIM.TTC,Gulim\0"
1635 "MSGOTHIC.TTC,MS UI Gothic\0"
1636 "MINGLIU.TTC,PMingLiU\0"
1637 "SIMSUN.TTC,SimSun\0"
1638 "MALGUN.TTF,Malgun Gothic\0"
1639 "YUGOTHM.TTC,Yu Gothic UI\0"
1640 "MSJH.TTC,Microsoft JhengHei UI\0"
1641 "MSYH.TTC,Microsoft YaHei UI\0"
1642 "SEGUISYM.TTF,Segoe UI Symbol\0";
1644 static const char system_link_tahoma_non_cjk[] =
1645 "MSGOTHIC.TTC,MS UI Gothic\0"
1646 "MINGLIU.TTC,PMingLiU\0"
1647 "SIMSUN.TTC,SimSun\0"
1648 "GULIM.TTC,Gulim\0"
1649 "YUGOTHM.TTC,Yu Gothic UI\0"
1650 "MSJH.TTC,Microsoft JhengHei UI\0"
1651 "MSYH.TTC,Microsoft YaHei UI\0"
1652 "MALGUN.TTF,Malgun Gothic\0"
1653 "SEGUISYM.TTF,Segoe UI Symbol\0";
1655 static const char system_link_ms_gothic[] =
1656 "MINGLIU.TTC,MingLiU\0"
1657 "SIMSUN.TTC,SimSun\0"
1658 "GULIM.TTC,GulimChe\0"
1659 "YUGOTHM.TTC,Yu Gothic UI\0"
1660 "MSJH.TTC,Microsoft JhengHei UI\0"
1661 "MSYH.TTC,Microsoft YaHei UI\0"
1662 "MALGUN.TTF,Malgun Gothic\0"
1663 "SEGUISYM.TTF,Segoe UI Symbol\0";
1665 static const char system_link_ms_p_gothic[] =
1666 "MINGLIU.TTC,PMingLiU\0"
1667 "SIMSUN.TTC,SimSun\0"
1668 "GULIM.TTC,Gulim\0"
1669 "YUGOTHM.TTC,Yu Gothic UI\0"
1670 "MSJH.TTC,Microsoft JhengHei UI\0"
1671 "MSYH.TTC,Microsoft YaHei UI\0"
1672 "MALGUN.TTF,Malgun Gothic\0"
1673 "SEGUISYM.TTF,Segoe UI Symbol\0";
1675 static const char system_link_ms_ui_gothic[] =
1676 "MICROSS.TTF,Microsoft Sans Serif\0"
1677 "MINGLIU.TTC,PMingLiU\0"
1678 "SIMSUN.TTC,SimSun\0"
1679 "GULIM.TTC,Gulim\0"
1680 "YUGOTHM.TTC,Yu Gothic UI\0"
1681 "MSJH.TTC,Microsoft JhengHei UI\0"
1682 "MSYH.TTC,Microsoft YaHei UI\0"
1683 "MALGUN.TTF,Malgun Gothic\0"
1684 "SEGUISYM.TTF,Segoe UI Symbol\0";
1686 static const char system_link_microsoft_jheng_hei[] =
1687 "SEGOEUI.TTF,Segoe UI\0"
1688 "MINGLIU.TTC,MingLiU\0"
1689 "MSYH.TTC,Microsoft YaHei\0"
1690 "MEIRYO.TTC,Meiryo\0"
1691 "MALGUN.TTF,Malgun Gothic\0"
1692 "YUGOTHM.TTC,Yu Gothic UI\0"
1693 "SEGUISYM.TTF,Segoe UI Symbol\0";
1695 static const char system_link_microsoft_jheng_hei_bold[] =
1696 "SEGOEUIB.TTF,Segoe UI Bold\0"
1697 "MINGLIU.TTC,MingLiU\0"
1698 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1699 "MEIRYOB.TTC,Meiryo Bold\0"
1700 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1701 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1702 "SEGUISYM.TTF,Segoe UI Symbol\0";
1704 static const char system_link_microsoft_jheng_hei_ui[] =
1705 "SEGOEUI.TTF,Segoe UI\0"
1706 "MINGLIU.TTC,MingLiU\0"
1707 "MSYH.TTC,Microsoft YaHei UI\0"
1708 "MEIRYO.TTC,Meiryo UI\0"
1709 "MALGUN.TTF,Malgun Gothic\0"
1710 "YUGOTHM.TTC,Yu Gothic UI\0"
1711 "SEGUISYM.TTF,Segoe UI Symbol\0";
1713 static const char system_link_microsoft_jheng_hei_ui_bold[] =
1714 "SEGOEUIB.TTF,Segoe UI Bold\0"
1715 "MINGLIU.TTC,MingLiU\0"
1716 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1717 "MEIRYOB.TTC,Meiryo UI Bold\0"
1718 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1719 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1720 "SEGUISYM.TTF,Segoe UI Symbol\0";
1722 static const char system_link_microsoft_jheng_hei_ui_light[] =
1723 "SEGOEUIL.TTF,Segoe UI Light\0"
1724 "MINGLIU.TTC,MingLiU\0"
1725 "MSYHL.TTC,Microsoft YaHei UI Light\0"
1726 "MEIRYO.TTC,Meiryo UI\0"
1727 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1728 "YUGOTHL.TTC,Yu Gothic UI Light\0"
1729 "SEGUISYM.TTF,Segoe UI Symbol\0";
1731 static const char system_link_ming_li_u[] =
1732 "MICROSS.TTF,Microsoft Sans Serif\0"
1733 "SIMSUN.TTC,SimSun\0"
1734 "MSMINCHO.TTC,MS Mincho\0"
1735 "BATANG.TTC,BatangChe\0"
1736 "MSJH.TTC,Microsoft JhengHei UI\0"
1737 "MSYH.TTC,Microsoft YaHei UI\0"
1738 "YUGOTHM.TTC,Yu Gothic UI\0"
1739 "MALGUN.TTF,Malgun Gothic\0"
1740 "SEGUISYM.TTF,Segoe UI Symbol\0";
1742 static const char system_link_p_ming_li_u[] =
1743 "MICROSS.TTF,Microsoft Sans Serif\0"
1744 "SIMSUN.TTC,SimSun\0"
1745 "MSMINCHO.TTC,MS PMincho\0"
1746 "BATANG.TTC,Batang\0"
1747 "MSJH.TTC,Microsoft JhengHei UI\0"
1748 "MSYH.TTC,Microsoft YaHei UI\0"
1749 "YUGOTHM.TTC,Yu Gothic UI\0"
1750 "MALGUN.TTF,Malgun Gothic\0"
1751 "SEGUISYM.TTF,Segoe UI Symbol\0";
1753 static const char system_link_ming_li_u_hkscs[] =
1754 "MICROSS.TTF,Microsoft Sans Serif\0"
1755 "MINGLIU.TTC,MingLiU\0"
1756 "SIMSUN.TTC,SimSun\0"
1757 "MSMINCHO.TTC,MS Mincho\0"
1758 "BATANG.TTC,BatangChe\0"
1759 "MSJH.TTC,Microsoft JhengHei UI\0"
1760 "MSYH.TTC,Microsoft YaHei UI\0"
1761 "YUGOTHM.TTC,Yu Gothic UI\0"
1762 "MALGUN.TTF,Malgun Gothic\0"
1763 "SEGUISYM.TTF,Segoe UI Symbol\0";
1765 static const char system_link_ming_li_u_ext_b[] =
1766 "MICROSS.TTF,Microsoft Sans Serif\0"
1767 "MINGLIU.TTC,MingLiU\0"
1768 "SIMSUN.TTC,SimSun\0"
1769 "MSMINCHO.TTC,MS Mincho\0"
1770 "BATANG.TTC,BatangChe\0"
1771 "MSJH.TTC,Microsoft JhengHei UI\0"
1772 "MSYH.TTC,Microsoft YaHei UI\0"
1773 "YUGOTHM.TTC,Yu Gothic UI\0"
1774 "MALGUN.TTF,Malgun Gothic\0"
1775 "SEGUISYM.TTF,Segoe UI Symbol\0";
1777 static const char system_link_p_ming_li_u_ext_b[] =
1778 "MICROSS.TTF,Microsoft Sans Serif\0"
1779 "MINGLIU.TTC,PMingLiU\0"
1780 "SIMSUN.TTC,SimSun\0"
1781 "MSMINCHO.TTC,MS PMincho\0"
1782 "BATANG.TTC,Batang\0"
1783 "MSJH.TTC,Microsoft JhengHei UI\0"
1784 "MSYH.TTC,Microsoft YaHei UI\0"
1785 "YUGOTHM.TTC,Yu Gothic UI\0"
1786 "MALGUN.TTF,Malgun Gothic\0"
1787 "SEGUISYM.TTF,Segoe UI Symbol\0";
1789 static const char system_link_ming_li_u_hkscs_ext_b[] =
1790 "MICROSS.TTF,Microsoft Sans Serif\0"
1791 "MINGLIU.TTC,MingLiU_HKSCS\0"
1792 "MINGLIU.TTC,MingLiU\0"
1793 "SIMSUN.TTC,SimSun\0"
1794 "MSMINCHO.TTC,MS Mincho\0"
1795 "BATANG.TTC,BatangChe\0"
1796 "MSJH.TTC,Microsoft JhengHei UI\0"
1797 "MSYH.TTC,Microsoft YaHei UI\0"
1798 "YUGOTHM.TTC,Yu Gothic UI\0"
1799 "MALGUN.TTF,Malgun Gothic\0"
1800 "SEGUISYM.TTF,Segoe UI Symbol\0";
1802 static const char system_link_yu_gothic_ui[] =
1803 "SEGOEUI.TTF,Segoe UI\0"
1804 "MSJH.TTC,Microsoft JhengHei\0"
1805 "MSYH.TTC,Microsoft YaHei\0"
1806 "MALGUN.TTF,Malgun Gothic\0"
1807 "SEGUISYM.TTF,Segoe UI Symbol\0";
1809 static const char system_link_yu_gothic_ui_bold[] =
1810 "SEGOEUIB.TTF,Segoe UI Bold\0"
1811 "MSJHBD.TTC,Microsoft Jhenghei UI Bold\0"
1812 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1813 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1814 "SEGUISYM.TTF,Segoe UI Symbol\0";
1816 static const char system_link_yu_gothic_ui_light[] =
1817 "SEGOEUIL.TTF,Segoe UI Light\0"
1818 "MSJHL.TTC,Microsoft Jhenghei UI Light\0"
1819 "MSYHL.TTC,Microsoft YaHei Light\0"
1820 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1821 "SEGUISYM.TTF,Segoe UI Symbol\0";
1823 static const char system_link_yu_gothic_ui_semilight[] =
1824 "SEGOEUISL.TTF,Segoe UI Semilight\0"
1825 "MSJH.TTC,Microsoft Jhenghei UI\0"
1826 "MSYH.TTC,Microsoft YaHei\0"
1827 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1828 "SEGUISYM.TTF,Segoe UI Symbol\0";
1830 static const char system_link_yu_gothic_ui_semibold[] =
1831 "SEGUISB.TTF,Segoe UI Semibold\0"
1832 "MSJH.TTC,Microsoft Jhenghei UI\0"
1833 "MSYH.TTC,Microsoft YaHei\0"
1834 "MALGUN.TTF,Malgun Gothic\0"
1835 "SEGUISYM.TTF,Segoe UI Symbol\0";
1837 static const char system_link_meiryo[] =
1838 "SEGOEUI.TTF,Segoe UI\0"
1839 "YUGOTHM.TTC,Yu Gothic UI\0"
1840 "MSGOTHIC.TTC,MS UI Gothic\0"
1841 "MSJH.TTC,Microsoft JhengHei\0"
1842 "MSYH.TTC,Microsoft YaHei\0"
1843 "MALGUN.TTF,Malgun Gothic\0"
1844 "SEGUISYM.TTF,Segoe UI Symbol\0";
1846 static const char system_link_meiryo_bold[] =
1847 "SEGOEUIB.TTF,Segoe UI Bold\0"
1848 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1849 "MSGOTHIC.TTC,MS UI Gothic\0"
1850 "MSJHBD.TTC,Microsoft Jhenghei Bold\0"
1851 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1852 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1853 "SEGUISYM.TTF,Segoe UI Symbol\0";
1855 static const char system_link_meiryo_ui[] =
1856 "SEGOEUI.TTF,Segoe UI\0"
1857 "YUGOTHM.TTC,Yu Gothic UI\0"
1858 "MSGOTHIC.TTC,MS UI Gothic\0"
1859 "MSJH.TTC,Microsoft Jhenghei UI\0"
1860 "MSYH.TTC,Microsoft YaHei UI\0"
1861 "MALGUN.TTF,Malgun Gothic\0"
1862 "SEGUISYM.TTF,Segoe UI Symbol\0";
1864 static const char system_link_meiryo_ui_bold[] =
1865 "SEGOEUIB.TTF,Segoe UI Bold\0"
1866 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1867 "MSGOTHIC.TTC,MS UI Gothic\0"
1868 "MSJHBD.TTC,Microsoft Jhenghei UI Bold\0"
1869 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1870 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1871 "SEGUISYM.TTF,Segoe UI Symbol\0";
1873 static const char system_link_ms_mincho[] =
1874 "MINGLIU.TTC,MingLiU\0"
1875 "SIMSUN.TTC,SimSun\0"
1876 "BATANG.TTC,Batang\0"
1877 "YUGOTHM.TTC,Yu Gothic UI\0"
1878 "MSJH.TTC,Microsoft JhengHei UI\0"
1879 "MSYH.TTC,Microsoft YaHei UI\0"
1880 "MALGUN.TTF,Malgun Gothic\0"
1881 "SEGUISYM.TTF,Segoe UI Symbol\0";
1883 static const char system_link_ms_p_mincho[] =
1884 "MINGLIU.TTC,PMingLiU\0"
1885 "SIMSUN.TTC,SimSun\0"
1886 "BATANG.TTC,Batang\0"
1887 "YUGOTHM.TTC,Yu Gothic UI\0"
1888 "MSJH.TTC,Microsoft JhengHei UI\0"
1889 "MSYH.TTC,Microsoft YaHei UI\0"
1890 "MALGUN.TTF,Malgun Gothic\0"
1891 "SEGUISYM.TTF,Segoe UI Symbol\0";
1893 static const struct system_link_reg
1895 const WCHAR *font_name;
1896 BOOL locale_dependent;
1897 const char *link_non_cjk;
1898 DWORD link_non_cjk_len;
1899 const char *link_sc;
1900 DWORD link_sc_len;
1901 const char *link_tc;
1902 DWORD link_tc_len;
1903 const char *link_jp;
1904 DWORD link_jp_len;
1905 const char *link_kr;
1906 DWORD link_kr_len;
1908 default_system_link[] =
1911 tahomaW, TRUE,
1912 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1913 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1914 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1915 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1916 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1919 microsoft_sans_serifW, TRUE,
1920 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1921 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1922 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1923 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1924 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1927 lucida_sans_unicodeW, TRUE,
1928 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1929 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1930 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1931 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1932 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1934 { ms_gothicW, FALSE, system_link_ms_gothic, sizeof(system_link_ms_gothic) },
1935 { ms_p_gothicW, FALSE, system_link_ms_p_gothic, sizeof(system_link_ms_p_gothic) },
1936 { ms_ui_gothicW, FALSE, system_link_ms_ui_gothic, sizeof(system_link_ms_ui_gothic) },
1937 { microsoft_jheng_heiW, FALSE, system_link_microsoft_jheng_hei, sizeof(system_link_microsoft_jheng_hei) },
1938 { microsoft_jheng_hei_boldW, FALSE, system_link_microsoft_jheng_hei_bold, sizeof(system_link_microsoft_jheng_hei_bold) },
1939 { microsoft_jheng_hei_uiW, FALSE, system_link_microsoft_jheng_hei_ui, sizeof(system_link_microsoft_jheng_hei_ui) },
1940 { microsoft_jheng_hei_ui_boldW, FALSE, system_link_microsoft_jheng_hei_ui_bold, sizeof(system_link_microsoft_jheng_hei_ui_bold) },
1941 { microsoft_jheng_hei_ui_lightW, FALSE, system_link_microsoft_jheng_hei_ui_light, sizeof(system_link_microsoft_jheng_hei_ui_light) },
1942 { ming_li_uW, FALSE, system_link_ming_li_u, sizeof(system_link_ming_li_u) },
1943 { p_ming_li_uW, FALSE, system_link_p_ming_li_u, sizeof(system_link_p_ming_li_u) },
1944 { ming_li_u_hkscsW, FALSE, system_link_ming_li_u_hkscs, sizeof(system_link_ming_li_u_hkscs) },
1945 { ming_li_u_ext_bW, FALSE, system_link_ming_li_u_ext_b, sizeof(system_link_ming_li_u_ext_b) },
1946 { p_ming_li_u_ext_bW, FALSE, system_link_p_ming_li_u_ext_b, sizeof(system_link_p_ming_li_u_ext_b) },
1947 { ming_li_u_hkscs_ext_bW, FALSE, system_link_ming_li_u_hkscs_ext_b, sizeof(system_link_ming_li_u_hkscs_ext_b) },
1948 { yu_gothic_uiW, FALSE, system_link_yu_gothic_ui, sizeof(system_link_yu_gothic_ui) },
1949 { yu_gothic_ui_boldW, FALSE, system_link_yu_gothic_ui_bold, sizeof(system_link_yu_gothic_ui_bold) },
1950 { yu_gothic_ui_lightW, FALSE, system_link_yu_gothic_ui_light, sizeof(system_link_yu_gothic_ui_light) },
1951 { yu_gothic_ui_semiboldW, FALSE, system_link_yu_gothic_ui_semibold, sizeof(system_link_yu_gothic_ui_semibold) },
1952 { yu_gothic_ui_semilightW, FALSE, system_link_yu_gothic_ui_semilight, sizeof(system_link_yu_gothic_ui_semilight) },
1953 { meiryoW, FALSE, system_link_meiryo, sizeof(system_link_meiryo) },
1954 { meiryo_boldW, FALSE, system_link_meiryo_bold, sizeof(system_link_meiryo_bold) },
1955 { meiryo_uiW, FALSE, system_link_meiryo_ui, sizeof(system_link_meiryo_ui) },
1956 { meiryo_ui_boldW, FALSE, system_link_meiryo_ui_bold, sizeof(system_link_meiryo_ui_bold) },
1957 { ms_minchoW, FALSE, system_link_ms_mincho, sizeof(system_link_ms_mincho) },
1958 { ms_p_minchoW, FALSE, system_link_ms_p_mincho, sizeof(system_link_ms_p_mincho) },
1961 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1963 struct gdi_font_family *family;
1964 struct gdi_font_face *face;
1965 struct gdi_font_link *font_link;
1966 const WCHAR *file, *value;
1968 /* Don't store fonts that are only substitutes for other fonts */
1969 if (get_gdi_font_subst( name, -1, NULL ))
1971 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1972 return;
1974 font_link = add_gdi_font_link( name );
1975 for ( ; *values; values++)
1977 if (!facename_compare( name, *values, -1 )) continue;
1978 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1979 if (!(family = find_family_from_name( value ))) continue;
1980 /* use first extant filename for this Family */
1981 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1983 if (!face->file) continue;
1984 file = wcsrchr(face->file, '\\');
1985 if (!file) file = face->file;
1986 else file++;
1987 if ((face = find_face_from_filename( file, value )))
1989 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1990 TRACE( "added internal SystemLink for %s to %s in %s\n",
1991 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1993 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1994 break;
1999 static void load_system_links(void)
2001 HKEY hkey;
2002 DWORD i, j;
2003 const WCHAR *shelldlg_name;
2004 struct gdi_font_link *font_link, *system_font_link;
2005 struct gdi_font_face *face;
2007 static const WCHAR ms_shell_dlgW[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2008 static const WCHAR systemW[] = {'S','y','s','t','e','m',0};
2009 static const WCHAR tahoma_ttfW[] = {'t','a','h','o','m','a','.','t','t','f',0};
2011 if ((hkey = reg_open_key( NULL, system_link_keyW, sizeof(system_link_keyW) )))
2013 char buffer[4096];
2014 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2015 WCHAR value[MAX_PATH];
2016 WCHAR *entry, *next;
2018 i = 0;
2019 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
2021 /* Don't store fonts that are only substitutes for other fonts */
2022 if (!get_gdi_font_subst( value, -1, NULL ))
2024 char *data = (char *)info + info->DataOffset;
2025 font_link = add_gdi_font_link( value );
2026 for (entry = (WCHAR *)data; (char *)entry < data + info->DataLength && *entry; entry = next)
2028 const WCHAR *family_name = NULL;
2029 WCHAR *p;
2031 TRACE( "%s: %s\n", debugstr_w(value), debugstr_w(entry) );
2033 next = entry + lstrlenW(entry) + 1;
2034 if ((p = wcschr( entry, ',' )))
2036 *p++ = 0;
2037 while (*p == ' ' || *p == '\t') p++;
2038 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
2040 if ((face = find_face_from_filename( entry, family_name )))
2042 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
2043 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
2045 else TRACE( "Unable to find file %s family %s\n",
2046 debugstr_w(entry), debugstr_w(family_name) );
2049 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2051 NtClose( hkey );
2054 if ((shelldlg_name = get_gdi_font_subst( ms_shell_dlgW, -1, NULL )))
2056 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
2058 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
2060 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
2061 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
2063 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
2064 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
2065 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
2066 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
2070 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
2072 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2073 that Tahoma has */
2075 system_font_link = add_gdi_font_link( systemW );
2076 if ((face = find_face_from_filename( tahoma_ttfW, tahomaW )))
2078 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
2079 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
2081 if ((font_link = find_gdi_font_link( tahomaW )))
2083 struct gdi_font_link_entry *entry;
2084 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2085 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
2089 /* see TranslateCharsetInfo */
2090 BOOL translate_charset_info( DWORD *src, CHARSETINFO *cs, DWORD flags )
2092 unsigned int i;
2094 switch (flags)
2096 case TCI_SRCFONTSIG:
2097 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
2098 if (charset_info[i].fs.fsCsb[0] & src[0]) goto found;
2099 return FALSE;
2100 case TCI_SRCCODEPAGE:
2101 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
2102 if (PtrToUlong(src) == charset_info[i].ciACP) goto found;
2103 return FALSE;
2104 case TCI_SRCCHARSET:
2105 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
2106 if (PtrToUlong(src) == charset_info[i].ciCharset) goto found;
2107 return FALSE;
2108 default:
2109 return FALSE;
2111 found:
2112 *cs = charset_info[i];
2113 return TRUE;
2116 /* font matching */
2118 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
2120 struct gdi_font_link *font_link;
2122 if (!face->scalable && !can_use_bitmap) return FALSE;
2123 if (!fs.fsCsb[0]) return TRUE;
2124 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
2125 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
2126 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
2127 return FALSE;
2130 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
2131 const LOGFONTW *lf, FONTSIGNATURE fs,
2132 BOOL can_use_bitmap )
2134 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
2135 unsigned int best_score = 4;
2136 int best_diff = 0;
2137 int it = !!lf->lfItalic;
2138 int bd = lf->lfWeight > 550;
2139 int height = lf->lfHeight;
2141 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2143 int italic = !!(face->ntmFlags & NTM_ITALIC);
2144 int bold = !!(face->ntmFlags & NTM_BOLD);
2145 int score = (italic ^ it) + (bold ^ bd);
2147 if (!can_select_face( face, fs, can_use_bitmap )) continue;
2148 if (score > best_score) continue;
2149 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
2150 best_score = score;
2151 best = face;
2152 if (best->scalable && best_score == 0) break;
2153 if (!best->scalable)
2155 int diff;
2156 if (height > 0)
2157 diff = height - (signed int)best->size.height;
2158 else
2159 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
2160 if (!best_bitmap ||
2161 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
2162 (best_diff < 0 && diff > best_diff))
2164 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
2165 best_diff = diff;
2166 best_bitmap = best;
2167 if (best_score == 0 && best_diff == 0) break;
2171 if (!best) return NULL;
2172 return best->scalable ? best : best_bitmap;
2175 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
2176 const LOGFONTW *lf, FONTSIGNATURE fs,
2177 BOOL can_use_bitmap, const WCHAR **orig_name )
2179 struct gdi_font_family *family;
2180 struct gdi_font_face *face;
2182 family = find_family_from_any_name( name );
2183 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
2184 if (subst)
2186 family = find_family_from_any_name( subst );
2187 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
2190 /* search by full face name */
2191 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2192 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2193 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
2194 can_select_face( face, fs, can_use_bitmap ))
2195 return face;
2197 if ((family = find_family_from_font_links( name, subst, fs )))
2199 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
2201 return NULL;
2203 found:
2204 if (orig_name && family != face->family)
2205 *orig_name = family->family_name;
2206 return face;
2209 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
2210 BOOL can_use_bitmap, BOOL want_vertical )
2212 struct gdi_font_family *family;
2213 struct gdi_font_face *face;
2214 WCHAR name[LF_FACESIZE + 1];
2215 int i = 0;
2217 /* first try the family fallbacks */
2218 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
2220 if (want_vertical)
2222 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
2223 name[0] = '@';
2226 if (!(family = find_family_from_any_name(name))) continue;
2227 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
2229 /* otherwise try only scalable */
2230 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2232 if ((family->family_name[0] == '@') == !want_vertical) continue;
2233 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
2235 if (!can_use_bitmap) return NULL;
2236 /* then also bitmap fonts */
2237 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2239 if ((family->family_name[0] == '@') == !want_vertical) continue;
2240 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
2242 return NULL;
2245 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
2246 BOOL *substituted, const WCHAR **orig_name )
2248 BOOL want_vertical = (lf->lfFaceName[0] == '@');
2249 struct gdi_font_face *face;
2251 if (!translate_charset_info( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
2253 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
2254 csi->fs.fsCsb[0] = 0;
2257 if (lf->lfFaceName[0])
2259 int subst_charset;
2260 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
2262 if (subst)
2264 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
2265 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
2266 if (subst_charset != -1)
2267 translate_charset_info( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
2268 *substituted = TRUE;
2271 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap, orig_name )))
2272 return face;
2274 *substituted = FALSE; /* substitution is no longer relevant */
2276 /* If requested charset was DEFAULT_CHARSET then try using charset
2277 corresponding to the current ansi codepage */
2278 if (!csi->fs.fsCsb[0])
2280 if (!translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
2282 FIXME( "TCI failed on codepage %d\n", ansi_cp.CodePage );
2283 csi->fs.fsCsb[0] = 0;
2287 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
2288 if (csi->fs.fsCsb[0])
2290 csi->fs.fsCsb[0] = 0;
2291 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
2293 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
2294 return NULL;
2297 /* realized font objects */
2299 #define FIRST_FONT_HANDLE 1
2300 #define MAX_FONT_HANDLES 256
2302 struct font_handle_entry
2304 struct gdi_font *font;
2305 WORD generation; /* generation count for reusing handle values */
2308 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
2309 static struct font_handle_entry *next_free;
2310 static struct font_handle_entry *next_unused = font_handles;
2312 static struct font_handle_entry *handle_entry( unsigned int handle )
2314 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
2316 if (idx < MAX_FONT_HANDLES)
2318 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
2319 return &font_handles[idx];
2321 if (handle) WARN( "invalid handle 0x%08x\n", handle );
2322 return NULL;
2325 static struct gdi_font *get_font_from_handle( unsigned int handle )
2327 struct font_handle_entry *entry = handle_entry( handle );
2329 if (entry) return entry->font;
2330 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
2331 return NULL;
2334 static DWORD alloc_font_handle( struct gdi_font *font )
2336 struct font_handle_entry *entry;
2338 entry = next_free;
2339 if (entry)
2340 next_free = (struct font_handle_entry *)entry->font;
2341 else if (next_unused < font_handles + MAX_FONT_HANDLES)
2342 entry = next_unused++;
2343 else
2345 ERR( "out of realized font handles\n" );
2346 return 0;
2348 entry->font = font;
2349 if (++entry->generation == 0xffff) entry->generation = 1;
2350 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
2353 static void free_font_handle( DWORD handle )
2355 struct font_handle_entry *entry;
2357 if ((entry = handle_entry( handle )))
2359 entry->font = (struct gdi_font *)next_free;
2360 next_free = entry;
2364 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
2366 UINT len = file ? lstrlenW(file) : 0;
2367 struct gdi_font *font = calloc( 1, offsetof( struct gdi_font, file[len + 1] ));
2369 font->refcount = 1;
2370 font->matrix.eM11 = font->matrix.eM22 = 1.0;
2371 font->scale_y = 1;
2372 font->kern_count = -1;
2373 list_init( &font->child_fonts );
2375 if (file)
2377 FILE_NETWORK_OPEN_INFORMATION info;
2378 UNICODE_STRING nt_name;
2379 OBJECT_ATTRIBUTES attr;
2381 nt_name.Buffer = (WCHAR *)file;
2382 nt_name.Length = nt_name.MaximumLength = len * sizeof(WCHAR);
2384 attr.Length = sizeof(attr);
2385 attr.RootDirectory = 0;
2386 attr.Attributes = OBJ_CASE_INSENSITIVE;
2387 attr.ObjectName = &nt_name;
2388 attr.SecurityDescriptor = NULL;
2389 attr.SecurityQualityOfService = NULL;
2391 if (!NtQueryFullAttributesFile( &attr, &info ))
2393 font->writetime.dwLowDateTime = info.LastWriteTime.LowPart;
2394 font->writetime.dwHighDateTime = info.LastWriteTime.HighPart;
2395 font->data_size = info.EndOfFile.QuadPart;
2396 memcpy( font->file, file, len * sizeof(WCHAR) );
2399 else
2401 font->data_ptr = data_ptr;
2402 font->data_size = data_size;
2405 font->handle = alloc_font_handle( font );
2406 return font;
2409 static void free_gdi_font( struct gdi_font *font )
2411 DWORD i;
2412 struct gdi_font *child, *child_next;
2414 if (font->private) font_funcs->destroy_font( font );
2415 free_font_handle( font->handle );
2416 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
2418 list_remove( &child->entry );
2419 free_gdi_font( child );
2421 for (i = 0; i < font->gm_size; i++) free( font->gm[i] );
2422 free( font->otm.otmpFamilyName );
2423 free( font->otm.otmpStyleName );
2424 free( font->otm.otmpFaceName );
2425 free( font->otm.otmpFullName );
2426 free( font->gm );
2427 free( font->kern_pairs );
2428 free( font->gsub_table );
2429 free( font );
2432 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
2434 return font->use_logfont_name ? font->lf.lfFaceName : (WCHAR *)font->otm.otmpFamilyName;
2437 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
2438 const LOGFONTW *lf )
2440 struct gdi_font *font;
2442 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
2443 font->fs = face->fs;
2444 font->lf = *lf;
2445 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
2446 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
2447 font->scalable = face->scalable;
2448 font->face_index = face->face_index;
2449 font->ntmFlags = face->ntmFlags;
2450 font->aa_flags = HIWORD( face->flags );
2451 if (!family_name) family_name = face->family->family_name;
2452 font->otm.otmpFamilyName = (char *)wcsdup( family_name );
2453 font->otm.otmpStyleName = (char *)wcsdup( face->style_name );
2454 font->otm.otmpFaceName = (char *)wcsdup( face->full_name );
2455 return font;
2458 struct glyph_metrics
2460 GLYPHMETRICS gm;
2461 ABC abc; /* metrics of the unrotated char */
2462 BOOL init;
2465 #define GM_BLOCK_SIZE 128
2467 /* TODO: GGO format support */
2468 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
2470 UINT block = index / GM_BLOCK_SIZE;
2471 UINT entry = index % GM_BLOCK_SIZE;
2473 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
2475 *gm = font->gm[block][entry].gm;
2476 *abc = font->gm[block][entry].abc;
2478 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2479 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
2480 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2481 return TRUE;
2484 return FALSE;
2487 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
2488 const GLYPHMETRICS *gm, const ABC *abc )
2490 UINT block = index / GM_BLOCK_SIZE;
2491 UINT entry = index % GM_BLOCK_SIZE;
2493 if (block >= font->gm_size)
2495 struct glyph_metrics **ptr;
2497 if (!(ptr = realloc( font->gm, (block + 1) * sizeof(*ptr) ))) return;
2498 memset( ptr + font->gm_size, 0, (block + 1 - font->gm_size) * sizeof(*ptr) );
2499 font->gm_size = block + 1;
2500 font->gm = ptr;
2502 if (!font->gm[block])
2504 font->gm[block] = calloc( sizeof(**font->gm), GM_BLOCK_SIZE );
2505 if (!font->gm[block]) return;
2507 font->gm[block][entry].gm = *gm;
2508 font->gm[block][entry].abc = *abc;
2509 font->gm[block][entry].init = TRUE;
2513 /* GSUB table support */
2515 typedef struct
2517 DWORD version;
2518 WORD ScriptList;
2519 WORD FeatureList;
2520 WORD LookupList;
2521 } GSUB_Header;
2523 typedef struct
2525 CHAR ScriptTag[4];
2526 WORD Script;
2527 } GSUB_ScriptRecord;
2529 typedef struct
2531 WORD ScriptCount;
2532 GSUB_ScriptRecord ScriptRecord[1];
2533 } GSUB_ScriptList;
2535 typedef struct
2537 CHAR LangSysTag[4];
2538 WORD LangSys;
2539 } GSUB_LangSysRecord;
2541 typedef struct
2543 WORD DefaultLangSys;
2544 WORD LangSysCount;
2545 GSUB_LangSysRecord LangSysRecord[1];
2546 } GSUB_Script;
2548 typedef struct
2550 WORD LookupOrder; /* Reserved */
2551 WORD ReqFeatureIndex;
2552 WORD FeatureCount;
2553 WORD FeatureIndex[1];
2554 } GSUB_LangSys;
2556 typedef struct
2558 CHAR FeatureTag[4];
2559 WORD Feature;
2560 } GSUB_FeatureRecord;
2562 typedef struct
2564 WORD FeatureCount;
2565 GSUB_FeatureRecord FeatureRecord[1];
2566 } GSUB_FeatureList;
2568 typedef struct
2570 WORD FeatureParams; /* Reserved */
2571 WORD LookupCount;
2572 WORD LookupListIndex[1];
2573 } GSUB_Feature;
2575 typedef struct
2577 WORD LookupCount;
2578 WORD Lookup[1];
2579 } GSUB_LookupList;
2581 typedef struct
2583 WORD LookupType;
2584 WORD LookupFlag;
2585 WORD SubTableCount;
2586 WORD SubTable[1];
2587 } GSUB_LookupTable;
2589 typedef struct
2591 WORD CoverageFormat;
2592 WORD GlyphCount;
2593 WORD GlyphArray[1];
2594 } GSUB_CoverageFormat1;
2596 typedef struct
2598 WORD Start;
2599 WORD End;
2600 WORD StartCoverageIndex;
2601 } GSUB_RangeRecord;
2603 typedef struct
2605 WORD CoverageFormat;
2606 WORD RangeCount;
2607 GSUB_RangeRecord RangeRecord[1];
2608 } GSUB_CoverageFormat2;
2610 typedef struct
2612 WORD SubstFormat; /* = 1 */
2613 WORD Coverage;
2614 WORD DeltaGlyphID;
2615 } GSUB_SingleSubstFormat1;
2617 typedef struct
2619 WORD SubstFormat; /* = 2 */
2620 WORD Coverage;
2621 WORD GlyphCount;
2622 WORD Substitute[1];
2623 } GSUB_SingleSubstFormat2;
2625 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
2627 GSUB_ScriptList *script;
2628 GSUB_Script *deflt = NULL;
2629 int i;
2631 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
2632 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
2633 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
2635 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
2636 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
2637 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
2638 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
2640 return deflt;
2643 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
2645 int i, offset;
2646 GSUB_LangSys *lang;
2648 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
2650 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
2652 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
2653 lang = (GSUB_LangSys *)((BYTE *)script + offset);
2654 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
2656 offset = GET_BE_WORD(script->DefaultLangSys);
2657 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
2658 return NULL;
2661 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
2663 int i;
2664 const GSUB_FeatureList *feature;
2666 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
2667 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
2668 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
2670 int index = GET_BE_WORD(lang->FeatureIndex[i]);
2671 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
2672 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
2674 return NULL;
2677 static const char *get_opentype_script( const struct gdi_font *font )
2680 * I am not sure if this is the correct way to generate our script tag
2682 switch (font->charset)
2684 case ANSI_CHARSET: return "latn";
2685 case BALTIC_CHARSET: return "latn"; /* ?? */
2686 case CHINESEBIG5_CHARSET: return "hani";
2687 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
2688 case GB2312_CHARSET: return "hani";
2689 case GREEK_CHARSET: return "grek";
2690 case HANGUL_CHARSET: return "hang";
2691 case RUSSIAN_CHARSET: return "cyrl";
2692 case SHIFTJIS_CHARSET: return "kana";
2693 case TURKISH_CHARSET: return "latn"; /* ?? */
2694 case VIETNAMESE_CHARSET: return "latn";
2695 case JOHAB_CHARSET: return "latn"; /* ?? */
2696 case ARABIC_CHARSET: return "arab";
2697 case HEBREW_CHARSET: return "hebr";
2698 case THAI_CHARSET: return "thai";
2699 default: return "latn";
2703 static void *get_GSUB_vert_feature( struct gdi_font *font )
2705 GSUB_Header *header;
2706 GSUB_Script *script;
2707 GSUB_LangSys *language;
2708 GSUB_Feature *feature;
2709 UINT length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2711 if (length == GDI_ERROR) return NULL;
2713 header = malloc( length );
2714 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2715 TRACE( "Loaded GSUB table of %i bytes\n", length );
2717 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2719 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2721 feature = GSUB_get_feature( header, language, "vrt2" );
2722 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2723 if (feature)
2725 font->gsub_table = header;
2726 return feature;
2728 TRACE("vrt2/vert feature not found\n");
2730 else TRACE("Language not found\n");
2732 else TRACE("Script not found\n");
2734 free( header );
2735 return NULL;
2738 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2740 GSUB_CoverageFormat1 *cf1 = table;
2742 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2744 int i, count = GET_BE_WORD(cf1->GlyphCount);
2746 TRACE("Coverage Format 1, %i glyphs\n",count);
2747 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2748 return -1;
2750 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2752 int i, count;
2753 GSUB_CoverageFormat2 *cf2 = table;
2755 count = GET_BE_WORD(cf2->RangeCount);
2756 TRACE("Coverage Format 2, %i ranges\n",count);
2757 for (i = 0; i < count; i++)
2759 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2760 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2761 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2763 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2764 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2767 return -1;
2769 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2771 return -1;
2774 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2776 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2777 int i, j, offset;
2779 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2780 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2782 GSUB_LookupTable *look;
2783 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2784 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2785 TRACE("type %i, flag %x, subtables %i\n",
2786 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2787 if (GET_BE_WORD(look->LookupType) == 1)
2789 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2791 GSUB_SingleSubstFormat1 *ssf1;
2792 offset = GET_BE_WORD(look->SubTable[j]);
2793 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2794 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2796 int offset = GET_BE_WORD(ssf1->Coverage);
2797 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2798 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2800 TRACE(" Glyph 0x%x ->",glyph);
2801 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2802 TRACE(" 0x%x\n",glyph);
2805 else
2807 GSUB_SingleSubstFormat2 *ssf2;
2808 int index, offset;
2810 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2811 offset = GET_BE_WORD(ssf1->Coverage);
2812 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2813 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2814 TRACE(" Coverage index %i\n",index);
2815 if (index != -1)
2817 TRACE(" Glyph is 0x%x ->",glyph);
2818 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2819 TRACE("0x%x\n",glyph);
2824 else FIXME("We only handle SubType 1\n");
2826 return glyph;
2829 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2831 if (!glyph) return glyph;
2832 if (!font->gsub_table) return glyph;
2833 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2836 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2838 FONTSIGNATURE fs = {{0}};
2839 struct gdi_font *child;
2840 struct gdi_font_face *face;
2842 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE, NULL ))) return;
2844 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2845 child->matrix = font->matrix;
2846 child->can_use_bitmap = font->can_use_bitmap;
2847 child->scale_y = font->scale_y;
2848 child->aveWidth = font->aveWidth;
2849 child->charset = font->charset;
2850 child->codepage = font->codepage;
2851 child->base_font = font;
2852 list_add_tail( &font->child_fonts, &child->entry );
2853 TRACE( "created child font %p for base %p\n", child, font );
2856 static void create_child_font_list( struct gdi_font *font )
2858 struct gdi_font_link *font_link;
2859 struct gdi_font_link_entry *entry;
2860 const WCHAR* font_name = (WCHAR *)font->otm.otmpFaceName;
2862 if ((font_link = find_gdi_font_link( font_name )))
2864 TRACE("found entry in system list\n");
2865 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2866 add_child_font( font, entry->family_name );
2869 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2870 * Sans Serif. This is how asian windows get default fallbacks for fonts
2872 if (ansi_cp.MaximumCharacterSize == 2 && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2873 facename_compare( font_name, microsoft_sans_serifW, -1 ) != 0)
2875 if ((font_link = find_gdi_font_link( microsoft_sans_serifW )))
2877 TRACE("found entry in default fallback list\n");
2878 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2879 add_child_font( font, entry->family_name );
2884 /* font cache */
2886 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2887 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2888 static unsigned int unused_font_count;
2889 #define UNUSED_CACHE_SIZE 10
2891 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2892 const FMAT2 *matrix, BOOL can_use_bitmap )
2894 if (font->hash != hash) return TRUE;
2895 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2896 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2897 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2898 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2901 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2903 DWORD hash = 0, *ptr, two_chars;
2904 WORD *pwc;
2905 unsigned int i;
2907 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2908 hash ^= *ptr;
2909 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2910 hash ^= *ptr;
2911 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2913 two_chars = *ptr;
2914 pwc = (WCHAR *)&two_chars;
2915 if(!*pwc) break;
2916 *pwc = towupper(*pwc);
2917 pwc++;
2918 *pwc = towupper(*pwc);
2919 hash ^= two_chars;
2920 if(!*pwc) break;
2922 hash ^= !can_use_bitmap;
2923 return hash;
2926 static void cache_gdi_font( struct gdi_font *font )
2928 static DWORD cache_num = 1;
2930 font->cache_num = cache_num++;
2931 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2932 list_add_head( &gdi_font_list, &font->entry );
2933 TRACE( "font %p\n", font );
2936 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2938 struct gdi_font *font;
2939 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2941 /* try the in-use list */
2942 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2944 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2945 list_remove( &font->entry );
2946 list_add_head( &gdi_font_list, &font->entry );
2947 if (!font->refcount++)
2949 list_remove( &font->unused_entry );
2950 unused_font_count--;
2952 return font;
2954 return NULL;
2957 static void release_gdi_font( struct gdi_font *font )
2959 if (!font) return;
2961 TRACE( "font %p\n", font );
2963 /* add it to the unused list */
2964 pthread_mutex_lock( &font_lock );
2965 if (!--font->refcount)
2967 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2968 if (unused_font_count > UNUSED_CACHE_SIZE)
2970 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2971 TRACE( "freeing %p\n", font );
2972 list_remove( &font->entry );
2973 list_remove( &font->unused_entry );
2974 free_gdi_font( font );
2976 else unused_font_count++;
2978 pthread_mutex_unlock( &font_lock );
2981 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2983 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2985 set_reg_ascii_value( hkey, "Courier", fl->courier );
2986 set_reg_ascii_value( hkey, "MS Serif", fl->serif );
2987 set_reg_ascii_value( hkey, "MS Sans Serif", sserif );
2988 set_reg_ascii_value( hkey, "Small Fonts", fl->small );
2991 static void set_value_key(HKEY hkey, const char *name, const char *value)
2993 if (value)
2994 set_reg_ascii_value( hkey, name, value );
2995 else if (name)
2997 WCHAR nameW[64];
2998 asciiz_to_unicode( nameW, name );
2999 reg_delete_value( hkey, nameW );
3003 static void update_font_association_info(void)
3005 static const WCHAR associated_charsetW[] =
3006 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
3008 if (ansi_cp.MaximumCharacterSize == 2)
3010 HKEY hkey;
3011 if ((hkey = reg_create_key( NULL, font_assoc_keyW, sizeof(font_assoc_keyW), 0, NULL )))
3013 HKEY hsubkey;
3014 if ((hsubkey = reg_create_key( hkey, associated_charsetW, sizeof(associated_charsetW),
3015 0, NULL )))
3017 switch (ansi_cp.CodePage)
3019 case 932:
3020 set_value_key(hsubkey, "ANSI(00)", "NO");
3021 set_value_key(hsubkey, "OEM(FF)", "NO");
3022 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3023 break;
3024 case 936:
3025 case 949:
3026 case 950:
3027 set_value_key(hsubkey, "ANSI(00)", "YES");
3028 set_value_key(hsubkey, "OEM(FF)", "YES");
3029 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3030 break;
3032 NtClose( hsubkey );
3035 /* TODO: Associated DefaultFonts */
3037 NtClose( hkey );
3040 else
3041 reg_delete_tree( NULL, font_assoc_keyW, sizeof(font_assoc_keyW) );
3044 static void set_multi_value_key( HKEY hkey, const WCHAR *name, const char *value, UINT len )
3046 WCHAR *valueW;
3048 if (!(valueW = malloc( len * sizeof(WCHAR) )))
3050 ERR( "malloc of %d * WCHAR failed\n", len );
3051 return;
3053 ascii_to_unicode( valueW, value, len );
3054 if (value)
3055 set_reg_value( hkey, name, REG_MULTI_SZ, valueW, len * sizeof(WCHAR) );
3056 else if (name)
3057 reg_delete_value( hkey, name );
3058 free( valueW );
3061 static void update_font_system_link_info(void)
3063 HKEY hkey;
3065 if ((hkey = reg_create_key( NULL, system_link_keyW, sizeof(system_link_keyW), 0, NULL )))
3067 const char *link;
3068 DWORD len, i;
3070 for (i = 0; i < ARRAY_SIZE(default_system_link); ++i)
3072 const struct system_link_reg *link_reg = &default_system_link[i];
3074 link = link_reg->link_non_cjk;
3075 len = link_reg->link_non_cjk_len;
3077 if (link_reg->locale_dependent)
3079 switch (ansi_cp.CodePage)
3081 case 932:
3082 link = link_reg->link_jp;
3083 len = link_reg->link_jp_len;
3084 break;
3085 case 936:
3086 link = link_reg->link_sc;
3087 len = link_reg->link_sc_len;
3088 break;
3089 case 949:
3090 link = link_reg->link_kr;
3091 len = link_reg->link_kr_len;
3092 break;
3093 case 950:
3094 link = link_reg->link_tc;
3095 len = link_reg->link_tc_len;
3096 break;
3099 set_multi_value_key(hkey, link_reg->font_name, link, len);
3101 NtClose( hkey );
3105 static void update_codepage( UINT screen_dpi )
3107 USHORT utf8_hdr[2] = { 0, CP_UTF8 };
3108 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[40 * sizeof(WCHAR)])];
3109 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
3110 char cpbuf[40];
3111 WCHAR cpbufW[40];
3112 HKEY hkey;
3113 DWORD size;
3114 UINT i;
3115 UINT font_dpi = 0;
3116 BOOL done = FALSE, cp_match = FALSE;
3118 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
3120 size = query_reg_value( wine_fonts_key, log_pixelsW, info, sizeof(value_buffer) );
3121 if (size == sizeof(DWORD) && info->Type == REG_DWORD)
3122 font_dpi = *(DWORD *)info->Data;
3124 RtlInitCodePageTable( utf8_hdr, &utf8_cp );
3125 if (NtCurrentTeb()->Peb->AnsiCodePageData)
3126 RtlInitCodePageTable( NtCurrentTeb()->Peb->AnsiCodePageData, &ansi_cp );
3127 else
3128 ansi_cp = utf8_cp;
3129 if (NtCurrentTeb()->Peb->OemCodePageData)
3130 RtlInitCodePageTable( NtCurrentTeb()->Peb->OemCodePageData, &oem_cp );
3131 else
3132 oem_cp = utf8_cp;
3133 sprintf( cpbuf, "%u,%u", ansi_cp.CodePage, oem_cp.CodePage );
3134 asciiz_to_unicode( cpbufW, cpbuf );
3136 if (query_reg_ascii_value( wine_fonts_key, "Codepages", info, sizeof(value_buffer) ))
3138 cp_match = !wcscmp( (const WCHAR *)info->Data, cpbufW );
3139 if (cp_match && screen_dpi == font_dpi) return; /* already set correctly */
3140 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3141 debugstr_w((const WCHAR *)info->Data), font_dpi, ansi_cp.CodePage, oem_cp.CodePage, screen_dpi );
3143 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3144 ansi_cp.CodePage, oem_cp.CodePage, screen_dpi);
3146 set_reg_ascii_value( wine_fonts_key, "Codepages", cpbuf );
3147 set_reg_value( wine_fonts_key, log_pixelsW, REG_DWORD, &screen_dpi, sizeof(screen_dpi) );
3149 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
3151 if (nls_update_font_list[i].ansi_cp == ansi_cp.CodePage &&
3152 nls_update_font_list[i].oem_cp == oem_cp.CodePage)
3154 HKEY software_hkey;
3155 if ((software_hkey = reg_create_key( NULL, software_config_keyW,
3156 sizeof(software_config_keyW), 0, NULL )))
3158 static const WCHAR fontsW[] = {'F','o','n','t','s'};
3159 hkey = reg_create_key( software_hkey, fontsW, sizeof(fontsW), 0, NULL );
3160 NtClose( software_hkey );
3161 if (hkey)
3163 set_reg_ascii_value( hkey, "OEMFONT.FON", nls_update_font_list[i].oem );
3164 set_reg_ascii_value( hkey, "FIXEDFON.FON", nls_update_font_list[i].fixed );
3165 set_reg_ascii_value( hkey, "FONTS.FON", nls_update_font_list[i].system );
3166 NtClose( hkey );
3169 if ((hkey = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW),
3170 0, NULL )))
3172 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3173 NtClose( hkey );
3175 if ((hkey = reg_create_key( NULL, fonts_win9x_config_keyW,
3176 sizeof(fonts_win9x_config_keyW), 0, NULL )))
3178 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3179 NtClose( hkey );
3181 /* Only update these if the Codepage changed. */
3182 if (!cp_match &&
3183 (hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
3184 0, NULL )))
3186 set_reg_ascii_value( hkey, "MS Shell Dlg", nls_update_font_list[i].shelldlg );
3187 set_reg_ascii_value( hkey, "Tms Rmn", nls_update_font_list[i].tmsrmn );
3189 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3190 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3191 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3192 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3193 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3194 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3195 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3196 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3198 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3199 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3200 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3202 NtClose( hkey );
3204 done = TRUE;
3206 else
3208 /* Delete the FontSubstitutes from other locales */
3209 if ((hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
3210 0, NULL )))
3212 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3213 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3214 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3215 NtClose( hkey );
3219 if (!done)
3220 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp.CodePage, oem_cp.CodePage);
3222 /* update locale dependent font association info and font system link info in registry.
3223 update only when codepages changed, not logpixels. */
3224 if (!cp_match)
3226 update_font_association_info();
3227 update_font_system_link_info();
3232 /*************************************************************
3233 * font_CreateDC
3235 static BOOL CDECL font_CreateDC( PHYSDEV *dev, LPCWSTR device, LPCWSTR output,
3236 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 CDECL 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, FONTENUMPROCW 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 CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW 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[] DECLSPEC_HIDDEN;
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 CDECL 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 CDECL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT count,
3903 WCHAR *chars, ABC *buffer )
3905 struct font_physdev *physdev = get_font_dev( dev );
3906 UINT c, i;
3908 if (!physdev->font)
3910 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3911 return dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
3914 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3916 pthread_mutex_lock( &font_lock );
3917 for (i = 0; i < count; i++)
3919 c = chars ? chars[i] : first + i;
3920 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &buffer[i], 0, NULL, NULL );
3922 pthread_mutex_unlock( &font_lock );
3923 return TRUE;
3927 /*************************************************************
3928 * font_GetCharABCWidthsI
3930 static BOOL CDECL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3932 struct font_physdev *physdev = get_font_dev( dev );
3933 UINT c;
3935 if (!physdev->font)
3937 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3938 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3941 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3943 pthread_mutex_lock( &font_lock );
3944 for (c = 0; c < count; c++, buffer++)
3945 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3946 NULL, buffer, 0, NULL, NULL );
3947 pthread_mutex_unlock( &font_lock );
3948 return TRUE;
3952 /*************************************************************
3953 * font_GetCharWidth
3955 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT count,
3956 const WCHAR *chars, INT *buffer )
3958 struct font_physdev *physdev = get_font_dev( dev );
3959 UINT c, i;
3960 ABC abc;
3962 if (!physdev->font)
3964 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3965 return dev->funcs->pGetCharWidth( dev, first, count, chars, buffer );
3968 TRACE( "%p, %d, %d, %p\n", physdev->font, first, count, buffer );
3970 pthread_mutex_lock( &font_lock );
3971 for (i = 0; i < count; i++)
3973 c = chars ? chars[i] : i + first;
3974 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3975 buffer[i] = 0;
3976 else
3977 buffer[i] = abc.abcA + abc.abcB + abc.abcC;
3979 pthread_mutex_unlock( &font_lock );
3980 return TRUE;
3984 /*************************************************************
3985 * font_GetCharWidthInfo
3987 static BOOL CDECL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3989 struct font_physdev *physdev = get_font_dev( dev );
3990 struct char_width_info *info = ptr;
3992 if (!physdev->font)
3994 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3995 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3998 info->unk = 0;
3999 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
4000 info->lsb = info->rsb = 0;
4002 return TRUE;
4006 /*************************************************************
4007 * font_GetFontData
4009 static DWORD CDECL font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
4011 struct font_physdev *physdev = get_font_dev( dev );
4013 if (!physdev->font)
4015 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
4016 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
4018 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
4022 /*************************************************************
4023 * font_GetFontRealizationInfo
4025 static BOOL CDECL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
4027 struct font_physdev *physdev = get_font_dev( dev );
4028 struct font_realization_info *info = ptr;
4030 if (!physdev->font)
4032 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
4033 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
4036 TRACE( "(%p, %p)\n", physdev->font, info);
4038 info->flags = 1;
4039 if (physdev->font->scalable) info->flags |= 2;
4041 info->cache_num = physdev->font->cache_num;
4042 info->instance_id = physdev->font->handle;
4043 if (info->size == sizeof(*info))
4045 info->file_count = 1;
4046 info->face_index = physdev->font->face_index;
4047 info->simulations = 0;
4048 if (physdev->font->fake_bold) info->simulations |= 0x1;
4049 if (physdev->font->fake_italic) info->simulations |= 0x2;
4051 return TRUE;
4055 /*************************************************************
4056 * font_GetFontUnicodeRanges
4058 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
4060 struct font_physdev *physdev = get_font_dev( dev );
4061 DWORD size, num_ranges;
4063 if (!physdev->font)
4065 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
4066 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
4069 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
4070 size = offsetof( GLYPHSET, ranges[num_ranges] );
4071 if (glyphset)
4073 glyphset->cbThis = size;
4074 glyphset->cRanges = num_ranges;
4075 glyphset->flAccel = 0;
4077 return size;
4081 /*************************************************************
4082 * font_GetGlyphIndices
4084 static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
4086 struct font_physdev *physdev = get_font_dev( dev );
4087 UINT default_char;
4088 unsigned char ch;
4089 BOOL got_default = FALSE;
4090 int i;
4092 if (!physdev->font)
4094 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
4095 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
4098 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4100 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4101 got_default = TRUE;
4104 pthread_mutex_lock( &font_lock );
4106 for (i = 0; i < count; i++)
4108 UINT glyph = str[i];
4110 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
4112 glyph = 0;
4113 if (physdev->font->codepage == CP_SYMBOL)
4115 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
4116 else if (str[i] < 0x100) glyph = str[i];
4118 else if (wc_to_index( physdev->font->codepage, str[i], &ch, FALSE ))
4119 glyph = (unsigned char)ch;
4121 if (!glyph)
4123 if (!got_default)
4125 default_char = font_funcs->get_default_glyph( physdev->font );
4126 got_default = TRUE;
4128 gi[i] = default_char;
4130 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
4133 pthread_mutex_unlock( &font_lock );
4134 return count;
4138 /*************************************************************
4139 * font_GetGlyphOutline
4141 static DWORD CDECL font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
4142 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
4144 struct font_physdev *physdev = get_font_dev( dev );
4145 DWORD ret;
4147 if (!physdev->font)
4149 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
4150 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
4152 pthread_mutex_lock( &font_lock );
4153 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
4154 pthread_mutex_unlock( &font_lock );
4155 return ret;
4159 /*************************************************************
4160 * font_GetKerningPairs
4162 static DWORD CDECL font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
4164 struct font_physdev *physdev = get_font_dev( dev );
4166 if (!physdev->font)
4168 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
4169 return dev->funcs->pGetKerningPairs( dev, count, pairs );
4172 pthread_mutex_lock( &font_lock );
4173 if (physdev->font->kern_count == -1)
4174 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
4175 &physdev->font->kern_pairs );
4176 pthread_mutex_unlock( &font_lock );
4178 if (count && pairs)
4180 count = min( count, physdev->font->kern_count );
4181 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
4183 else count = physdev->font->kern_count;
4185 return count;
4189 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
4191 double scale_x, scale_y;
4193 if (font->aveWidth)
4195 scale_x = (double)font->aveWidth;
4196 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
4198 else
4199 scale_x = font->scale_y;
4201 scale_x *= fabs(font->matrix.eM11);
4202 scale_y = font->scale_y * fabs(font->matrix.eM22);
4204 /* Windows scales these values as signed integers even if they are unsigned */
4205 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
4206 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
4208 SCALE_Y(otm->otmTextMetrics.tmHeight);
4209 SCALE_Y(otm->otmTextMetrics.tmAscent);
4210 SCALE_Y(otm->otmTextMetrics.tmDescent);
4211 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
4212 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
4214 SCALE_X(otm->otmTextMetrics.tmOverhang);
4215 if (font->fake_bold)
4217 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
4218 otm->otmTextMetrics.tmAveCharWidth++;
4219 otm->otmTextMetrics.tmMaxCharWidth++;
4221 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
4222 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
4224 SCALE_Y(otm->otmAscent);
4225 SCALE_Y(otm->otmDescent);
4226 SCALE_Y(otm->otmLineGap);
4227 SCALE_Y(otm->otmsCapEmHeight);
4228 SCALE_Y(otm->otmsXHeight);
4229 SCALE_Y(otm->otmrcFontBox.top);
4230 SCALE_Y(otm->otmrcFontBox.bottom);
4231 SCALE_X(otm->otmrcFontBox.left);
4232 SCALE_X(otm->otmrcFontBox.right);
4233 SCALE_Y(otm->otmMacAscent);
4234 SCALE_Y(otm->otmMacDescent);
4235 SCALE_Y(otm->otmMacLineGap);
4236 SCALE_X(otm->otmptSubscriptSize.x);
4237 SCALE_Y(otm->otmptSubscriptSize.y);
4238 SCALE_X(otm->otmptSubscriptOffset.x);
4239 SCALE_Y(otm->otmptSubscriptOffset.y);
4240 SCALE_X(otm->otmptSuperscriptSize.x);
4241 SCALE_Y(otm->otmptSuperscriptSize.y);
4242 SCALE_X(otm->otmptSuperscriptOffset.x);
4243 SCALE_Y(otm->otmptSuperscriptOffset.y);
4244 SCALE_Y(otm->otmsStrikeoutSize);
4245 SCALE_Y(otm->otmsStrikeoutPosition);
4246 SCALE_Y(otm->otmsUnderscoreSize);
4247 SCALE_Y(otm->otmsUnderscorePosition);
4249 #undef SCALE_X
4250 #undef SCALE_Y
4253 /*************************************************************
4254 * font_GetOutlineTextMetrics
4256 static UINT CDECL font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
4258 struct font_physdev *physdev = get_font_dev( dev );
4259 UINT ret = 0;
4261 if (!physdev->font)
4263 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
4264 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
4267 if (!physdev->font->scalable) return 0;
4269 pthread_mutex_lock( &font_lock );
4270 if (font_funcs->set_outline_text_metrics( physdev->font ))
4272 ret = physdev->font->otm.otmSize;
4273 if (metrics && size >= physdev->font->otm.otmSize)
4275 WCHAR *ptr = (WCHAR *)(metrics + 1);
4276 *metrics = physdev->font->otm;
4277 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
4278 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
4279 ptr += lstrlenW(ptr) + 1;
4280 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
4281 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
4282 ptr += lstrlenW(ptr) + 1;
4283 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
4284 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
4285 ptr += lstrlenW(ptr) + 1;
4286 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
4287 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
4288 scale_outline_font_metrics( physdev->font, metrics );
4291 pthread_mutex_unlock( &font_lock );
4292 return ret;
4296 /*************************************************************
4297 * font_GetTextCharsetInfo
4299 static UINT CDECL font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
4301 struct font_physdev *physdev = get_font_dev( dev );
4303 if (!physdev->font)
4305 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
4306 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4308 if (fs) *fs = physdev->font->fs;
4309 return physdev->font->charset;
4313 /*************************************************************
4314 * font_GetTextExtentExPoint
4316 static BOOL CDECL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
4318 struct font_physdev *physdev = get_font_dev( dev );
4319 INT i, pos;
4320 ABC abc;
4322 if (!physdev->font)
4324 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
4325 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
4328 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
4330 pthread_mutex_lock( &font_lock );
4331 for (i = pos = 0; i < count; i++)
4333 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
4334 pos += abc.abcA + abc.abcB + abc.abcC;
4335 dxs[i] = pos;
4337 pthread_mutex_unlock( &font_lock );
4338 return TRUE;
4342 /*************************************************************
4343 * font_GetTextExtentExPointI
4345 static BOOL CDECL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
4347 struct font_physdev *physdev = get_font_dev( dev );
4348 INT i, pos;
4349 ABC abc;
4351 if (!physdev->font)
4353 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
4354 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
4357 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
4359 pthread_mutex_lock( &font_lock );
4360 for (i = pos = 0; i < count; i++)
4362 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
4363 NULL, &abc, 0, NULL, NULL );
4364 pos += abc.abcA + abc.abcB + abc.abcC;
4365 dxs[i] = pos;
4367 pthread_mutex_unlock( &font_lock );
4368 return TRUE;
4372 /*************************************************************
4373 * font_GetTextFace
4375 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
4377 struct font_physdev *physdev = get_font_dev( dev );
4378 const WCHAR *font_name;
4379 INT len;
4381 if (!physdev->font)
4383 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
4384 return dev->funcs->pGetTextFace( dev, count, str );
4386 font_name = get_gdi_font_name( physdev->font );
4387 len = lstrlenW( font_name ) + 1;
4388 if (str)
4390 lstrcpynW( str, font_name, count );
4391 len = min( count, len );
4393 return len;
4397 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
4399 double scale_x, scale_y;
4401 /* Make sure that the font has sane width/height ratio */
4402 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
4404 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
4405 font->aveWidth = 0;
4408 if (font->aveWidth)
4410 scale_x = (double)font->aveWidth;
4411 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
4413 else
4414 scale_x = font->scale_y;
4416 scale_x *= fabs(font->matrix.eM11);
4417 scale_y = font->scale_y * fabs(font->matrix.eM22);
4419 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
4420 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
4422 SCALE_Y(tm->tmHeight);
4423 SCALE_Y(tm->tmAscent);
4424 SCALE_Y(tm->tmDescent);
4425 SCALE_Y(tm->tmInternalLeading);
4426 SCALE_Y(tm->tmExternalLeading);
4428 SCALE_X(tm->tmOverhang);
4429 if (font->fake_bold)
4431 if (!font->scalable) tm->tmOverhang++;
4432 tm->tmAveCharWidth++;
4433 tm->tmMaxCharWidth++;
4435 SCALE_X(tm->tmAveCharWidth);
4436 SCALE_X(tm->tmMaxCharWidth);
4438 #undef SCALE_X
4439 #undef SCALE_Y
4442 /*************************************************************
4443 * font_GetTextMetrics
4445 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
4447 struct font_physdev *physdev = get_font_dev( dev );
4448 BOOL ret = FALSE;
4450 if (!physdev->font)
4452 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
4453 return dev->funcs->pGetTextMetrics( dev, metrics );
4456 pthread_mutex_lock( &font_lock );
4457 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
4458 font_funcs->set_bitmap_text_metrics( physdev->font ))
4460 *metrics = physdev->font->otm.otmTextMetrics;
4461 scale_font_metrics( physdev->font, metrics );
4462 ret = TRUE;
4464 pthread_mutex_unlock( &font_lock );
4465 return ret;
4469 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
4471 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4472 a single face with the requested charset. The idea is to check if
4473 the selected font supports the current ANSI codepage, if it does
4474 return the corresponding charset, else return the first charset */
4476 int i;
4478 if (translate_charset_info( (DWORD*)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
4480 const struct gdi_font_link *font_link;
4482 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
4483 font_link = find_gdi_font_link(family_name);
4484 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
4486 for (i = 0; i < 32; i++)
4488 DWORD fs0 = 1u << i;
4489 if (face->fs.fsCsb[0] & fs0)
4491 if (translate_charset_info(&fs0, csi, TCI_SRCFONTSIG)) return;
4492 FIXME("TCI failing on %x\n", (int)fs0);
4496 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4497 (int)face->fs.fsCsb[0], debugstr_w(face->file));
4498 csi->ciACP = ansi_cp.CodePage;
4499 csi->ciCharset = DEFAULT_CHARSET;
4502 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
4504 struct gdi_font *font;
4505 struct gdi_font_face *face;
4506 INT height;
4507 CHARSETINFO csi;
4508 const WCHAR *orig_name = NULL;
4509 BOOL substituted = FALSE;
4511 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
4513 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4514 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4515 original value lfCharSet. Note this is a special case for
4516 Symbol and doesn't happen at least for "Wingdings*" */
4517 if (!facename_compare( lf->lfFaceName, symbolW, -1 )) lf->lfCharSet = SYMBOL_CHARSET;
4519 /* check the cache first */
4520 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4522 TRACE( "returning cached gdiFont(%p)\n", font );
4523 return font;
4525 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &substituted, &orig_name )))
4527 FIXME( "can't find a single appropriate font - bailing\n" );
4528 return NULL;
4530 height = lf->lfHeight;
4532 font = create_gdi_font( face, orig_name, lf );
4533 font->use_logfont_name = substituted;
4534 font->matrix = dcmat;
4535 font->can_use_bitmap = can_use_bitmap;
4536 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
4537 font->charset = csi.ciCharset;
4538 font->codepage = csi.ciACP;
4540 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
4541 face->data_ptr, face->face_index );
4543 font->aveWidth = height ? lf->lfWidth : 0;
4544 if (!face->scalable)
4546 /* Windows uses integer scaling factors for bitmap fonts */
4547 INT scale, scaled_height, diff;
4548 struct gdi_font *cachedfont;
4550 if (height > 0)
4551 diff = height - (signed int)face->size.height;
4552 else
4553 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
4555 /* FIXME: rotation of bitmap fonts is ignored */
4556 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
4557 if (font->aveWidth)
4558 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
4559 font->matrix.eM11 = font->matrix.eM22 = 1.0;
4560 dcmat.eM11 = dcmat.eM22 = 1.0;
4561 /* As we changed the matrix, we need to search the cache for the font again,
4562 * otherwise we might explode the cache. */
4563 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4565 TRACE("Found cached font after non-scalable matrix rescale!\n");
4566 free_gdi_font( font );
4567 return cachedfont;
4570 if (height != 0) height = diff;
4571 height += face->size.height;
4573 scale = (height + face->size.height - 1) / face->size.height;
4574 scaled_height = scale * face->size.height;
4575 /* Only jump to the next height if the difference <= 25% original height */
4576 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4577 /* The jump between unscaled and doubled is delayed by 1 */
4578 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4579 font->scale_y = scale;
4580 TRACE("font scale y: %d\n", font->scale_y);
4583 if (!font_funcs->load_font( font ))
4585 free_gdi_font( font );
4586 return NULL;
4589 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
4590 font->vert_feature = get_GSUB_vert_feature( font );
4592 create_child_font_list( font );
4594 TRACE( "caching: gdiFont=%p\n", font );
4595 cache_gdi_font( font );
4596 return font;
4599 /*************************************************************
4600 * font_SelectFont
4602 static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4604 struct font_physdev *physdev = get_font_dev( dev );
4605 struct gdi_font *font = NULL, *prev = physdev->font;
4606 DC *dc = get_physdev_dc( dev );
4608 if (hfont)
4610 LOGFONTW lf;
4611 FMAT2 dcmat;
4612 BOOL can_use_bitmap = !!(NtGdiGetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
4614 NtGdiExtGetObjectW( hfont, sizeof(lf), &lf );
4615 switch (lf.lfQuality)
4617 case NONANTIALIASED_QUALITY:
4618 if (!*aa_flags) *aa_flags = GGO_BITMAP;
4619 break;
4620 case ANTIALIASED_QUALITY:
4621 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
4622 break;
4625 if (lf.lfOutPrecision == OUT_TT_ONLY_PRECIS)
4626 can_use_bitmap = FALSE;
4628 lf.lfWidth = abs(lf.lfWidth);
4630 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4631 debugstr_w(lf.lfFaceName), (int)lf.lfHeight, lf.lfItalic,
4632 (int)lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, (int)lf.lfOrientation,
4633 (int)lf.lfEscapement );
4635 if (dc->attr->graphics_mode == GM_ADVANCED)
4637 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
4638 /* try to avoid not necessary glyph transformations */
4639 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4641 lf.lfHeight *= fabs(dcmat.eM11);
4642 lf.lfWidth *= fabs(dcmat.eM11);
4643 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4646 else
4648 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4649 dcmat.eM11 = dcmat.eM22 = 1.0;
4650 dcmat.eM21 = dcmat.eM12 = 0;
4651 lf.lfOrientation = lf.lfEscapement;
4652 if (dc->vport2WorldValid)
4654 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4655 lf.lfOrientation = -lf.lfOrientation;
4656 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4657 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4660 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
4662 pthread_mutex_lock( &font_lock );
4664 font = select_font( &lf, dcmat, can_use_bitmap );
4666 if (font)
4668 if (!*aa_flags) *aa_flags = font->aa_flags;
4669 if (!*aa_flags)
4671 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
4672 *aa_flags = subpixel_orientation;
4673 else
4674 *aa_flags = font_smoothing;
4676 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
4678 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), (int)lf.lfHeight, *aa_flags );
4679 pthread_mutex_unlock( &font_lock );
4681 physdev->font = font;
4682 if (prev) release_gdi_font( prev );
4683 return font ? hfont : 0;
4687 const struct gdi_dc_funcs font_driver =
4689 NULL, /* pAbortDoc */
4690 NULL, /* pAbortPath */
4691 NULL, /* pAlphaBlend */
4692 NULL, /* pAngleArc */
4693 NULL, /* pArc */
4694 NULL, /* pArcTo */
4695 NULL, /* pBeginPath */
4696 NULL, /* pBlendImage */
4697 NULL, /* pChord */
4698 NULL, /* pCloseFigure */
4699 NULL, /* pCreateCompatibleDC */
4700 font_CreateDC, /* pCreateDC */
4701 font_DeleteDC, /* pDeleteDC */
4702 NULL, /* pDeleteObject */
4703 NULL, /* pEllipse */
4704 NULL, /* pEndDoc */
4705 NULL, /* pEndPage */
4706 NULL, /* pEndPath */
4707 font_EnumFonts, /* pEnumFonts */
4708 NULL, /* pExtEscape */
4709 NULL, /* pExtFloodFill */
4710 NULL, /* pExtTextOut */
4711 NULL, /* pFillPath */
4712 NULL, /* pFillRgn */
4713 font_FontIsLinked, /* pFontIsLinked */
4714 NULL, /* pFrameRgn */
4715 NULL, /* pGetBoundsRect */
4716 font_GetCharABCWidths, /* pGetCharABCWidths */
4717 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
4718 font_GetCharWidth, /* pGetCharWidth */
4719 font_GetCharWidthInfo, /* pGetCharWidthInfo */
4720 NULL, /* pGetDeviceCaps */
4721 NULL, /* pGetDeviceGammaRamp */
4722 font_GetFontData, /* pGetFontData */
4723 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
4724 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
4725 font_GetGlyphIndices, /* pGetGlyphIndices */
4726 font_GetGlyphOutline, /* pGetGlyphOutline */
4727 NULL, /* pGetICMProfile */
4728 NULL, /* pGetImage */
4729 font_GetKerningPairs, /* pGetKerningPairs */
4730 NULL, /* pGetNearestColor */
4731 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
4732 NULL, /* pGetPixel */
4733 NULL, /* pGetSystemPaletteEntries */
4734 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
4735 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
4736 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
4737 font_GetTextFace, /* pGetTextFace */
4738 font_GetTextMetrics, /* pGetTextMetrics */
4739 NULL, /* pGradientFill */
4740 NULL, /* pInvertRgn */
4741 NULL, /* pLineTo */
4742 NULL, /* pMoveTo */
4743 NULL, /* pPaintRgn */
4744 NULL, /* pPatBlt */
4745 NULL, /* pPie */
4746 NULL, /* pPolyBezier */
4747 NULL, /* pPolyBezierTo */
4748 NULL, /* pPolyDraw */
4749 NULL, /* pPolyPolygon */
4750 NULL, /* pPolyPolyline */
4751 NULL, /* pPolylineTo */
4752 NULL, /* pPutImage */
4753 NULL, /* pRealizeDefaultPalette */
4754 NULL, /* pRealizePalette */
4755 NULL, /* pRectangle */
4756 NULL, /* pResetDC */
4757 NULL, /* pRoundRect */
4758 NULL, /* pSelectBitmap */
4759 NULL, /* pSelectBrush */
4760 font_SelectFont, /* pSelectFont */
4761 NULL, /* pSelectPen */
4762 NULL, /* pSetBkColor */
4763 NULL, /* pSetBoundsRect */
4764 NULL, /* pSetDCBrushColor */
4765 NULL, /* pSetDCPenColor */
4766 NULL, /* pSetDIBitsToDevice */
4767 NULL, /* pSetDeviceClipping */
4768 NULL, /* pSetDeviceGammaRamp */
4769 NULL, /* pSetPixel */
4770 NULL, /* pSetTextColor */
4771 NULL, /* pStartDoc */
4772 NULL, /* pStartPage */
4773 NULL, /* pStretchBlt */
4774 NULL, /* pStretchDIBits */
4775 NULL, /* pStrokeAndFillPath */
4776 NULL, /* pStrokePath */
4777 NULL, /* pUnrealizePalette */
4778 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
4779 NULL, /* pD3DKMTCloseAdapter */
4780 NULL, /* pD3DKMTOpenAdapterFromLuid */
4781 NULL, /* pD3DKMTQueryVideoMemoryInfo */
4782 NULL, /* pD3DKMTSetVidPnSourceOwner */
4783 GDI_PRIORITY_FONT_DRV /* priority */
4786 static BOOL get_key_value( HKEY key, const char *name, DWORD *value )
4788 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[12 * sizeof(WCHAR)])];
4789 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4790 DWORD count;
4792 count = query_reg_ascii_value( key, name, info, sizeof(value_buffer) );
4793 if (count)
4795 if (info->Type == REG_DWORD) memcpy( value, info->Data, sizeof(*value) );
4796 else *value = wcstol( (const WCHAR *)info->Data, NULL, 10 );
4798 return !!count;
4801 static UINT init_font_options(void)
4803 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[20 * sizeof(WCHAR)])];
4804 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4805 HKEY key;
4806 DWORD i, val, gamma = 1400;
4807 UINT dpi = 0;
4809 if (query_reg_ascii_value( wine_fonts_key, "AntialiasFakeBoldOrItalic",
4810 info, sizeof(value_buffer) ) && info->Type == REG_SZ)
4812 static const WCHAR valsW[] = {'y','Y','t','T','1',0};
4813 antialias_fakes = (wcschr( valsW, *(const WCHAR *)info->Data ) != NULL);
4816 if ((key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
4818 /* FIXME: handle vertical orientations even though Windows doesn't */
4819 if (get_key_value( key, "FontSmoothingOrientation", &val ))
4821 switch (val)
4823 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4824 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
4825 break;
4826 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4827 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
4828 break;
4831 if (get_key_value( key, "FontSmoothing", &val ) && val /* enabled */)
4833 if (get_key_value( key, "FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4834 font_smoothing = subpixel_orientation;
4835 else
4836 font_smoothing = GGO_GRAY4_BITMAP;
4838 if (get_key_value( key, "FontSmoothingGamma", &val ) && val)
4840 gamma = min( max( val, 1000 ), 2200 );
4842 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4843 NtClose( key );
4846 /* Calibrating the difference between the registry value and the Wine gamma value.
4847 This looks roughly similar to Windows Native with the same registry value.
4848 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4849 gamma = 1000 * gamma / 1400;
4850 if (gamma != 1000)
4852 for (i = 0; i < 256; i++)
4854 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
4855 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
4859 if (!dpi && (key = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) )))
4861 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4862 NtClose( key );
4864 if (!dpi) dpi = 96;
4866 font_gamma_ramp.gamma = gamma;
4867 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp.gamma, dpi );
4868 return dpi;
4872 /* compute positions for text rendering, in device coords */
4873 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4875 TEXTMETRICW tm;
4876 PHYSDEV dev;
4878 size->cx = size->cy = 0;
4879 if (!count) return TRUE;
4881 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4882 dev->funcs->pGetTextMetrics( dev, &tm );
4884 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4885 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4887 if (dc->breakExtra || dc->breakRem)
4889 int i, space = 0, rem = dc->breakRem;
4891 for (i = 0; i < count; i++)
4893 if (str[i] == tm.tmBreakChar)
4895 space += dc->breakExtra;
4896 if (rem > 0)
4898 space++;
4899 rem--;
4902 dx[i] += space;
4905 size->cx = dx[count - 1];
4906 size->cy = tm.tmHeight;
4907 return TRUE;
4910 /* compute positions for text rendering, in device coords */
4911 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4913 TEXTMETRICW tm;
4914 PHYSDEV dev;
4916 size->cx = size->cy = 0;
4917 if (!count) return TRUE;
4919 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4920 dev->funcs->pGetTextMetrics( dev, &tm );
4922 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4923 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4925 if (dc->breakExtra || dc->breakRem)
4927 WORD space_index;
4928 int i, space = 0, rem = dc->breakRem;
4930 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4931 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4933 for (i = 0; i < count; i++)
4935 if (indices[i] == space_index)
4937 space += dc->breakExtra;
4938 if (rem > 0)
4940 space++;
4941 rem--;
4944 dx[i] += space;
4947 size->cx = dx[count - 1];
4948 size->cy = tm.tmHeight;
4949 return TRUE;
4952 /***********************************************************************
4953 * get_text_charset_info
4955 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4957 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4959 UINT ret = DEFAULT_CHARSET;
4960 PHYSDEV dev;
4962 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4963 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4965 if (ret == DEFAULT_CHARSET && fs)
4966 memset(fs, 0, sizeof(FONTSIGNATURE));
4967 return ret;
4970 /***********************************************************************
4971 * NtGdiGetTextCharsetInfo (win32u.@)
4973 UINT WINAPI NtGdiGetTextCharsetInfo( HDC hdc, FONTSIGNATURE *fs, DWORD flags )
4975 UINT ret = DEFAULT_CHARSET;
4976 DC *dc = get_dc_ptr(hdc);
4978 if (dc)
4980 ret = get_text_charset_info( dc, fs, flags );
4981 release_dc_ptr( dc );
4983 return ret;
4986 /***********************************************************************
4987 * NtGdiHfontCreate (win32u.@)
4989 HFONT WINAPI NtGdiHfontCreate( const void *logfont, ULONG size, ULONG type,
4990 ULONG flags, void *data )
4992 HFONT hFont;
4993 FONTOBJ *fontPtr;
4994 const LOGFONTW *plf;
4996 if (!logfont) return 0;
4998 if (size == sizeof(ENUMLOGFONTEXDVW) || size == sizeof(ENUMLOGFONTEXW))
5000 const ENUMLOGFONTEXW *lfex = logfont;
5002 if (lfex->elfFullName[0] || lfex->elfStyle[0] || lfex->elfScript[0])
5004 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
5005 debugstr_w( lfex->elfFullName ), debugstr_w( lfex->elfStyle ),
5006 debugstr_w( lfex->elfScript ));
5009 plf = &lfex->elfLogFont;
5011 else if (size != sizeof(LOGFONTW))
5013 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
5014 return 0;
5016 else plf = logfont;
5018 if (!(fontPtr = malloc( sizeof(*fontPtr) ))) return 0;
5020 fontPtr->logfont = *plf;
5022 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, NTGDI_OBJ_FONT, &fontobj_funcs )))
5024 free( fontPtr );
5025 return 0;
5028 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
5029 (int)plf->lfHeight, (int)plf->lfWidth,
5030 (int)plf->lfEscapement, (int)plf->lfOrientation,
5031 plf->lfPitchAndFamily,
5032 plf->lfOutPrecision, plf->lfClipPrecision,
5033 plf->lfQuality, plf->lfCharSet,
5034 debugstr_w(plf->lfFaceName),
5035 plf->lfWeight > 400 ? "Bold" : "",
5036 plf->lfItalic ? "Italic" : "",
5037 plf->lfUnderline ? "Underline" : "", hFont);
5039 return hFont;
5042 #define ASSOC_CHARSET_OEM 1
5043 #define ASSOC_CHARSET_ANSI 2
5044 #define ASSOC_CHARSET_SYMBOL 4
5046 static DWORD get_associated_charset_info(void)
5048 static int associated_charset = -1;
5050 if (associated_charset == -1)
5052 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[32 * sizeof(WCHAR)])];
5053 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
5054 HKEY hkey;
5056 static const WCHAR yesW[] = {'y','e','s',0};
5058 associated_charset = 0;
5060 if (!(hkey = reg_open_key( NULL, associated_charset_keyW, sizeof(associated_charset_keyW) )))
5061 return 0;
5063 if (query_reg_ascii_value( hkey, "ANSI(00)", info, sizeof(value_buffer) ) &&
5064 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5065 associated_charset |= ASSOC_CHARSET_ANSI;
5067 if (query_reg_ascii_value( hkey, "OEM(FF)", info, sizeof(value_buffer) ) &&
5068 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5069 associated_charset |= ASSOC_CHARSET_OEM;
5071 if (query_reg_ascii_value( hkey, "SYMBOL(02)", info, sizeof(value_buffer) ) &&
5072 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5073 associated_charset |= ASSOC_CHARSET_SYMBOL;
5075 NtClose( hkey );
5077 TRACE("associated_charset = %d\n", associated_charset);
5080 return associated_charset;
5083 static void update_font_code_page( DC *dc, HANDLE font )
5085 CHARSETINFO csi;
5086 int charset = get_text_charset_info( dc, NULL, 0 );
5088 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
5090 LOGFONTW lf;
5092 NtGdiExtGetObjectW( font, sizeof(lf), &lf );
5093 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
5094 charset = DEFAULT_CHARSET;
5097 /* Hmm, nicely designed api this one! */
5098 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
5099 dc->attr->font_code_page = csi.ciACP;
5100 else {
5101 switch(charset) {
5102 case OEM_CHARSET:
5103 dc->attr->font_code_page = oem_cp.CodePage;
5104 break;
5105 case DEFAULT_CHARSET:
5106 dc->attr->font_code_page = ansi_cp.CodePage;
5107 break;
5109 case VISCII_CHARSET:
5110 case TCVN_CHARSET:
5111 case KOI8_CHARSET:
5112 case ISO3_CHARSET:
5113 case ISO4_CHARSET:
5114 case ISO10_CHARSET:
5115 case CELTIC_CHARSET:
5116 /* FIXME: These have no place here, but because x11drv
5117 enumerates fonts with these (made up) charsets some apps
5118 might use them and then the FIXME below would become
5119 annoying. Now we could pick the intended codepage for
5120 each of these, but since it's broken anyway we'll just
5121 use CP_ACP and hope it'll go away...
5123 dc->attr->font_code_page = CP_ACP;
5124 break;
5126 default:
5127 FIXME("Can't find codepage for charset %d\n", charset);
5128 dc->attr->font_code_page = CP_ACP;
5129 break;
5133 TRACE( "charset %d => cp %d\n", charset, dc->attr->font_code_page );
5136 /***********************************************************************
5137 * NtGdiSelectFont (win32u.@)
5139 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
5141 HGDIOBJ ret = 0;
5142 DC *dc = get_dc_ptr( hdc );
5143 PHYSDEV physdev;
5144 UINT aa_flags = 0;
5146 if (!dc) return 0;
5148 if (!GDI_inc_ref_count( handle ))
5150 release_dc_ptr( dc );
5151 return 0;
5154 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
5155 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
5157 ret = dc->hFont;
5158 dc->hFont = handle;
5159 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
5160 update_font_code_page( dc, handle );
5161 if (dc->font_gamma_ramp == NULL)
5162 dc->font_gamma_ramp = &font_gamma_ramp;
5163 GDI_dec_ref_count( ret );
5165 else GDI_dec_ref_count( handle );
5167 release_dc_ptr( dc );
5168 return ret;
5172 /***********************************************************************
5173 * FONT_GetObjectW
5175 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
5177 FONTOBJ *font = GDI_GetObjPtr( handle, NTGDI_OBJ_FONT );
5179 if (!font) return 0;
5180 if (buffer)
5182 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
5183 memcpy( buffer, &font->logfont, count );
5185 else count = sizeof(LOGFONTW);
5186 GDI_ReleaseObj( handle );
5187 return count;
5191 /***********************************************************************
5192 * FONT_DeleteObject
5194 static BOOL FONT_DeleteObject( HGDIOBJ handle )
5196 FONTOBJ *obj;
5198 if (!(obj = free_gdi_handle( handle ))) return FALSE;
5199 free( obj );
5200 return TRUE;
5204 struct font_enum
5206 HDC hdc;
5207 struct font_enum_entry *buf;
5208 ULONG size;
5209 ULONG count;
5210 ULONG charset;
5213 static INT WINAPI font_enum_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
5214 DWORD type, LPARAM lp )
5216 struct font_enum *fe = (struct font_enum *)lp;
5218 if (fe->charset != DEFAULT_CHARSET && lf->lfCharSet != fe->charset) return 1;
5219 if ((type & RASTER_FONTTYPE) && !(NtGdiGetDeviceCaps( fe->hdc, TEXTCAPS ) & TC_RA_ABLE))
5220 return 1;
5222 if (fe->buf && fe->count < fe->size)
5224 fe->buf[fe->count].type = type;
5225 fe->buf[fe->count].lf = *(const ENUMLOGFONTEXW *)lf;
5226 fe->buf[fe->count].tm = *(const NEWTEXTMETRICEXW *)tm;
5228 fe->count++;
5229 return 1;
5232 /***********************************************************************
5233 * NtGdiEnumFonts (win32u.@)
5235 BOOL WINAPI NtGdiEnumFonts( HDC hdc, ULONG type, ULONG win32_compat, ULONG face_name_len,
5236 const WCHAR *face_name, ULONG charset, ULONG *count, void *buf )
5238 struct font_enum fe;
5239 PHYSDEV physdev;
5240 LOGFONTW lf;
5241 BOOL ret;
5242 DC *dc;
5244 if (!(dc = get_dc_ptr( hdc ))) return 0;
5246 memset( &lf, 0, sizeof(lf) );
5247 lf.lfCharSet = charset;
5248 if (face_name_len) memcpy( lf.lfFaceName, face_name, face_name_len * sizeof(WCHAR) );
5250 fe.hdc = hdc;
5251 fe.buf = buf;
5252 fe.size = *count / sizeof(*fe.buf);
5253 fe.count = 0;
5254 fe.charset = charset;
5256 physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
5257 ret = physdev->funcs->pEnumFonts( physdev, &lf, font_enum_proc, (LPARAM)&fe );
5258 if (ret && buf) ret = fe.count <= fe.size;
5259 *count = fe.count * sizeof(*fe.buf);
5261 release_dc_ptr( dc );
5262 return ret;
5266 /***********************************************************************
5267 * NtGdiSetTextJustification (win32u.@)
5269 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
5271 DC *dc;
5273 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5275 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
5276 dc->attr->wnd_ext.cx );
5277 if (!extra) breaks = 0;
5278 if (breaks)
5280 dc->breakExtra = extra / breaks;
5281 dc->breakRem = extra - (breaks * dc->breakExtra);
5283 else
5285 dc->breakExtra = 0;
5286 dc->breakRem = 0;
5289 release_dc_ptr( dc );
5290 return TRUE;
5294 /***********************************************************************
5295 * NtGdiGetTextFaceW (win32u.@)
5297 INT WINAPI NtGdiGetTextFaceW( HDC hdc, INT count, WCHAR *name, BOOL alias_name )
5299 PHYSDEV dev;
5300 INT ret;
5302 DC * dc = get_dc_ptr( hdc );
5303 if (!dc) return 0;
5305 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
5306 ret = dev->funcs->pGetTextFace( dev, count, name );
5307 release_dc_ptr( dc );
5308 return ret;
5312 /***********************************************************************
5313 * NtGdiGetTextExtentExW (win32u.@)
5315 * Return the size of the string as it would be if it was output properly by
5316 * e.g. TextOut.
5318 BOOL WINAPI NtGdiGetTextExtentExW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
5319 INT *nfit, INT *dxs, SIZE *size, UINT flags )
5321 DC *dc;
5322 int i;
5323 BOOL ret;
5324 INT buffer[256], *pos = dxs;
5326 if (count < 0) return FALSE;
5328 dc = get_dc_ptr(hdc);
5329 if (!dc) return FALSE;
5331 if (!dxs)
5333 pos = buffer;
5334 if (count > 256 && !(pos = malloc( count * sizeof(*pos) )))
5336 release_dc_ptr( dc );
5337 return FALSE;
5342 if (flags)
5343 ret = get_char_positions_indices( dc, str, count, pos, size );
5344 else
5345 ret = get_char_positions( dc, str, count, pos, size );
5346 if (ret)
5348 if (dxs || nfit)
5350 for (i = 0; i < count; i++)
5352 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
5353 (i + 1) * dc->attr->char_extra;
5354 if (nfit && dx > (unsigned int)max_ext) break;
5355 if (dxs) dxs[i] = dx;
5357 if (nfit) *nfit = i;
5360 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
5361 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5364 if (pos != buffer && pos != dxs) free( pos );
5365 release_dc_ptr( dc );
5367 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count),
5368 max_ext, (int)size->cx, (int)size->cy );
5369 return ret;
5372 /***********************************************************************
5373 * NtGdiGetTextMetricsW (win32u.@)
5375 BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags )
5377 PHYSDEV physdev;
5378 BOOL ret = FALSE;
5379 DC * dc = get_dc_ptr( hdc );
5380 if (!dc) return FALSE;
5382 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5383 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5385 if (ret)
5387 /* device layer returns values in device units
5388 * therefore we have to convert them to logical */
5390 metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5391 metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5392 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5393 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5394 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5395 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5396 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5397 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5398 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5399 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5400 ret = TRUE;
5402 TRACE("text metrics:\n"
5403 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5404 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5405 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5406 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5407 " PitchAndFamily = %02x\n"
5408 " --------------------\n"
5409 " InternalLeading = %i\n"
5410 " Ascent = %i\n"
5411 " Descent = %i\n"
5412 " Height = %i\n",
5413 (int)metrics->tmWeight, metrics->tmFirstChar, (int)metrics->tmAveCharWidth,
5414 metrics->tmItalic, metrics->tmLastChar, (int)metrics->tmMaxCharWidth,
5415 metrics->tmUnderlined, metrics->tmDefaultChar, (int)metrics->tmOverhang,
5416 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5417 metrics->tmPitchAndFamily,
5418 (int)metrics->tmInternalLeading,
5419 (int)metrics->tmAscent,
5420 (int)metrics->tmDescent,
5421 (int)metrics->tmHeight );
5423 release_dc_ptr( dc );
5424 return ret;
5428 /***********************************************************************
5429 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
5431 UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData,
5432 OUTLINETEXTMETRICW *lpOTM, ULONG opts )
5434 DC *dc = get_dc_ptr( hdc );
5435 OUTLINETEXTMETRICW *output = lpOTM;
5436 PHYSDEV dev;
5437 UINT ret;
5439 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5440 if(!dc) return 0;
5442 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5443 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5445 if (lpOTM && ret > cbData)
5447 output = malloc( ret );
5448 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5451 if (lpOTM && ret)
5453 output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5454 output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5455 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5456 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5457 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5458 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5459 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5460 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5461 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5462 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5463 output->otmAscent = height_to_LP( dc, output->otmAscent);
5464 output->otmDescent = height_to_LP( dc, output->otmDescent);
5465 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5466 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5467 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5468 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5469 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5470 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5471 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5472 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5473 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5474 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5475 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5476 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5477 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5478 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5479 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5480 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5481 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5482 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5483 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5484 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5485 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5486 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5488 if(output != lpOTM)
5490 memcpy(lpOTM, output, cbData);
5491 free( output );
5492 ret = cbData;
5495 release_dc_ptr(dc);
5496 return ret;
5499 /***********************************************************************
5500 * NtGdiGetCharWidthW (win32u.@)
5502 BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5503 ULONG flags, void *buf )
5505 UINT i, count = last;
5506 BOOL ret;
5507 PHYSDEV dev;
5508 DC *dc;
5510 if (flags & NTGDI_GETCHARWIDTH_INDICES)
5512 ABC *abc;
5513 unsigned int i;
5515 if (!(abc = malloc( count * sizeof(ABC) )))
5516 return FALSE;
5518 if (!NtGdiGetCharABCWidthsW( hdc, first, last, chars,
5519 NTGDI_GETCHARABCWIDTHS_INT | NTGDI_GETCHARABCWIDTHS_INDICES,
5520 abc ))
5522 free( abc );
5523 return FALSE;
5526 for (i = 0; i < count; i++)
5527 ((INT *)buf)[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5529 free( abc );
5530 return TRUE;
5533 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5535 if (!chars) count = last - first + 1;
5536 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5537 ret = dev->funcs->pGetCharWidth( dev, first, count, chars, buf );
5539 if (ret)
5541 if (flags & NTGDI_GETCHARWIDTH_INT)
5543 INT *buffer = buf;
5544 /* convert device units to logical */
5545 for (i = 0; i < count; i++)
5546 buffer[i] = width_to_LP( dc, buffer[i] );
5548 else
5550 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
5551 for (i = 0; i < count; i++)
5552 ((float *)buf)[i] = ((int *)buf)[i] * scale;
5555 release_dc_ptr( dc );
5556 return ret;
5560 /* helper for nulldrv_ExtTextOut */
5561 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5562 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5564 UINT indices[3] = {0, 0, 0x20};
5565 unsigned int i;
5566 DWORD ret, size;
5567 int stride;
5569 indices[0] = index;
5570 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5572 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5574 index = indices[i];
5575 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, 0, NULL, &identity, FALSE );
5576 if (ret != GDI_ERROR) break;
5579 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5580 if (!image) return ERROR_SUCCESS;
5582 image->ptr = NULL;
5583 image->free = NULL;
5584 if (!ret) /* empty glyph */
5586 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5587 return ERROR_SUCCESS;
5590 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5591 size = metrics->gmBlackBoxY * stride;
5593 if (!(image->ptr = malloc( size ))) return ERROR_OUTOFMEMORY;
5594 image->is_copy = TRUE;
5595 image->free = free_heap_bits;
5597 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, size, image->ptr,
5598 &identity, FALSE );
5599 if (ret == GDI_ERROR)
5601 free( image->ptr );
5602 return ERROR_NOT_FOUND;
5604 return ERROR_SUCCESS;
5607 /* helper for nulldrv_ExtTextOut */
5608 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5609 LPCWSTR str, UINT count, const INT *dx )
5611 UINT i;
5612 RECT rect, bounds;
5614 reset_bounds( &bounds );
5615 for (i = 0; i < count; i++)
5617 GLYPHMETRICS metrics;
5619 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5621 rect.left = x + metrics.gmptGlyphOrigin.x;
5622 rect.top = y - metrics.gmptGlyphOrigin.y;
5623 rect.right = rect.left + metrics.gmBlackBoxX;
5624 rect.bottom = rect.top + metrics.gmBlackBoxY;
5625 add_bounds_rect( &bounds, &rect );
5627 if (dx)
5629 if (flags & ETO_PDY)
5631 x += dx[ i * 2 ];
5632 y += dx[ i * 2 + 1];
5634 else x += dx[ i ];
5636 else
5638 x += metrics.gmCellIncX;
5639 y += metrics.gmCellIncY;
5642 return bounds;
5645 /* helper for nulldrv_ExtTextOut */
5646 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5647 const struct gdi_image_bits *image, const RECT *clip )
5649 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5650 UINT i, count, max_count;
5651 LONG x, y;
5652 BYTE *ptr = image->ptr;
5653 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5654 POINT *pts;
5655 RECT rect, clipped_rect;
5657 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5658 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5659 rect.right = rect.left + metrics->gmBlackBoxX;
5660 rect.bottom = rect.top + metrics->gmBlackBoxY;
5661 if (!clip) clipped_rect = rect;
5662 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5664 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5665 pts = malloc( max_count * sizeof(*pts) );
5666 if (!pts) return;
5668 count = 0;
5669 ptr += (clipped_rect.top - rect.top) * stride;
5670 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5672 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5674 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5675 pts[count].x = rect.left + x;
5676 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5677 pts[count + 1].x = rect.left + x;
5678 if (pts[count + 1].x > pts[count].x)
5680 pts[count].y = pts[count + 1].y = y;
5681 count += 2;
5685 assert( count <= max_count );
5686 dp_to_lp( dc, pts, count );
5687 for (i = 0; i < count; i += 2)
5689 const ULONG pts_count = 2;
5690 NtGdiPolyPolyDraw( dc->hSelf, pts + i, &pts_count, 1, NtGdiPolyPolyline );
5692 free( pts );
5695 /***********************************************************************
5696 * nulldrv_ExtTextOut
5698 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5699 LPCWSTR str, UINT count, const INT *dx )
5701 DC *dc = get_nulldrv_dc( dev );
5702 UINT i;
5703 DWORD err;
5704 HGDIOBJ orig;
5705 HPEN pen;
5707 if (flags & ETO_OPAQUE)
5709 RECT rc = *rect;
5710 COLORREF brush_color = NtGdiGetNearestColor( dev->hdc, dc->attr->background_color );
5711 HBRUSH brush = NtGdiCreateSolidBrush( brush_color, NULL);
5713 if (brush)
5715 orig = NtGdiSelectBrush( dev->hdc, brush );
5716 dp_to_lp( dc, (POINT *)&rc, 2 );
5717 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5718 NtGdiSelectBrush( dev->hdc, orig );
5719 NtGdiDeleteObjectApp( brush );
5723 if (!count) return TRUE;
5725 if (dc->aa_flags != GGO_BITMAP)
5727 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5728 BITMAPINFO *info = (BITMAPINFO *)buffer;
5729 struct gdi_image_bits bits;
5730 struct bitblt_coords src, dst;
5731 PHYSDEV dst_dev;
5732 /* FIXME Subpixel modes */
5733 UINT aa_flags = GGO_GRAY4_BITMAP;
5735 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5736 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5737 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5738 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5740 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5741 src.x = src.visrect.left;
5742 src.y = src.visrect.top;
5743 src.width = src.visrect.right - src.visrect.left;
5744 src.height = src.visrect.bottom - src.visrect.top;
5745 dst = src;
5746 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5747 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5749 /* we can avoid the GetImage, just query the needed format */
5750 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5751 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5752 info->bmiHeader.biWidth = src.width;
5753 info->bmiHeader.biHeight = -src.height;
5754 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5755 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5756 if (!err || err == ERROR_BAD_FORMAT)
5758 /* make the source rectangle relative to the source bits */
5759 src.x = src.y = 0;
5760 src.visrect.left = src.visrect.top = 0;
5761 src.visrect.right = src.width;
5762 src.visrect.bottom = src.height;
5764 bits.ptr = malloc( info->bmiHeader.biSizeImage );
5765 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5766 bits.is_copy = TRUE;
5767 bits.free = free_heap_bits;
5768 err = ERROR_SUCCESS;
5771 else
5773 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5774 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5775 if (!err && !bits.is_copy)
5777 void *ptr = malloc( info->bmiHeader.biSizeImage );
5778 if (!ptr)
5780 if (bits.free) bits.free( &bits );
5781 return ERROR_OUTOFMEMORY;
5783 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5784 if (bits.free) bits.free( &bits );
5785 bits.ptr = ptr;
5786 bits.is_copy = TRUE;
5787 bits.free = free_heap_bits;
5790 if (!err)
5792 /* make x,y relative to the image bits */
5793 x += src.visrect.left - dst.visrect.left;
5794 y += src.visrect.top - dst.visrect.top;
5795 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5796 aa_flags, str, count, dx );
5797 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5798 if (bits.free) bits.free( &bits );
5799 return !err;
5803 pen = NtGdiCreatePen( PS_SOLID, 1, dc->attr->text_color, NULL );
5804 orig = NtGdiSelectPen( dev->hdc, pen );
5806 for (i = 0; i < count; i++)
5808 GLYPHMETRICS metrics;
5809 struct gdi_image_bits image;
5811 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5812 if (err) continue;
5814 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5815 if (image.free) image.free( &image );
5817 if (dx)
5819 if (flags & ETO_PDY)
5821 x += dx[ i * 2 ];
5822 y += dx[ i * 2 + 1];
5824 else x += dx[ i ];
5826 else
5828 x += metrics.gmCellIncX;
5829 y += metrics.gmCellIncY;
5833 NtGdiSelectPen( dev->hdc, orig );
5834 NtGdiDeleteObjectApp( pen );
5835 return TRUE;
5838 /***********************************************************************
5839 * get_line_width
5841 * Scale the underline / strikeout line width.
5843 static inline int get_line_width( DC *dc, int metric_size )
5845 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5846 if (width == 0) width = 1;
5847 if (metric_size < 0) width = -width;
5848 return width;
5851 /***********************************************************************
5852 * NtGdiExtTextOutW (win32u.@)
5854 * Draws text using the currently selected font, background color, and text color.
5857 * PARAMS
5858 * x,y [I] coordinates of string
5859 * flags [I]
5860 * ETO_GRAYED - undocumented on MSDN
5861 * ETO_OPAQUE - use background color for fill the rectangle
5862 * ETO_CLIPPED - clipping text to the rectangle
5863 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5864 * than encoded characters. Implies ETO_IGNORELANGUAGE
5865 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5866 * Affects BiDi ordering
5867 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5868 * ETO_PDY - unimplemented
5869 * ETO_NUMERICSLATIN - unimplemented always assumed -
5870 * do not translate numbers into locale representations
5871 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5872 * lprect [I] dimensions for clipping or/and opaquing
5873 * str [I] text string
5874 * count [I] number of symbols in string
5875 * lpDx [I] optional parameter with distance between drawing characters
5877 * RETURNS
5878 * Success: TRUE
5879 * Failure: FALSE
5881 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5882 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5884 BOOL ret = FALSE;
5885 UINT align;
5886 DWORD layout;
5887 POINT pt;
5888 TEXTMETRICW tm;
5889 LOGFONTW lf;
5890 double cosEsc, sinEsc;
5891 INT char_extra;
5892 SIZE sz;
5893 RECT rc;
5894 POINT *deltas = NULL, width = {0, 0};
5895 DC * dc = get_dc_ptr( hdc );
5896 PHYSDEV physdev;
5897 INT breakRem;
5898 static int quietfixme = 0;
5900 if (!dc) return FALSE;
5901 if (count > INT_MAX) return FALSE;
5903 align = dc->attr->text_align;
5904 breakRem = dc->breakRem;
5905 layout = dc->attr->layout;
5907 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5909 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5910 quietfixme = 1;
5913 update_dc( dc );
5914 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5916 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5917 if (layout & LAYOUT_RTL)
5919 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5920 align ^= TA_RTLREADING;
5923 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5924 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5925 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5926 dc->attr->map_mode);
5928 if(align & TA_UPDATECP)
5930 pt = dc->attr->cur_pos;
5931 x = pt.x;
5932 y = pt.y;
5935 NtGdiGetTextMetricsW( hdc, &tm, 0 );
5936 NtGdiExtGetObjectW( dc->hFont, sizeof(lf), &lf );
5938 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5939 lf.lfEscapement = 0;
5941 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5942 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5944 lf.lfEscapement = -lf.lfEscapement;
5947 if(lf.lfEscapement != 0)
5949 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5950 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5952 else
5954 cosEsc = 1;
5955 sinEsc = 0;
5958 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5960 rc = *lprect;
5961 lp_to_dp(dc, (POINT*)&rc, 2);
5962 order_rect( &rc );
5963 if (flags & ETO_OPAQUE)
5964 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5966 else flags &= ~ETO_CLIPPED;
5968 if(count == 0)
5970 ret = TRUE;
5971 goto done;
5974 pt.x = x;
5975 pt.y = y;
5976 lp_to_dp(dc, &pt, 1);
5977 x = pt.x;
5978 y = pt.y;
5980 char_extra = dc->attr->char_extra;
5981 if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5982 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5984 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
5986 UINT i;
5987 POINT total = {0, 0}, desired[2];
5989 deltas = malloc( count * sizeof(*deltas) );
5990 if (lpDx)
5992 if (flags & ETO_PDY)
5994 for (i = 0; i < count; i++)
5996 deltas[i].x = lpDx[i * 2] + char_extra;
5997 deltas[i].y = -lpDx[i * 2 + 1];
6000 else
6002 for (i = 0; i < count; i++)
6004 deltas[i].x = lpDx[i] + char_extra;
6005 deltas[i].y = 0;
6009 else
6011 INT *dx = malloc( count * sizeof(*dx) );
6013 NtGdiGetTextExtentExW( hdc, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX) );
6015 deltas[0].x = dx[0];
6016 deltas[0].y = 0;
6017 for (i = 1; i < count; i++)
6019 deltas[i].x = dx[i] - dx[i - 1];
6020 deltas[i].y = 0;
6022 free( dx );
6025 for(i = 0; i < count; i++)
6027 total.x += deltas[i].x;
6028 total.y += deltas[i].y;
6030 desired[0].x = desired[0].y = 0;
6032 desired[1].x = cosEsc * total.x + sinEsc * total.y;
6033 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
6035 lp_to_dp(dc, desired, 2);
6036 desired[1].x -= desired[0].x;
6037 desired[1].y -= desired[0].y;
6039 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6041 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6042 desired[1].x = -desired[1].x;
6043 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6044 desired[1].y = -desired[1].y;
6047 deltas[i].x = desired[1].x - width.x;
6048 deltas[i].y = desired[1].y - width.y;
6050 width = desired[1];
6052 flags |= ETO_PDY;
6054 else
6056 POINT desired[2];
6058 NtGdiGetTextExtentExW( hdc, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX) );
6059 desired[0].x = desired[0].y = 0;
6060 desired[1].x = sz.cx;
6061 desired[1].y = 0;
6062 lp_to_dp(dc, desired, 2);
6063 desired[1].x -= desired[0].x;
6064 desired[1].y -= desired[0].y;
6066 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6068 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6069 desired[1].x = -desired[1].x;
6070 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6071 desired[1].y = -desired[1].y;
6073 width = desired[1];
6076 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
6077 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
6078 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
6080 case TA_LEFT:
6081 if (align & TA_UPDATECP)
6083 pt.x = x + width.x;
6084 pt.y = y + width.y;
6085 dp_to_lp(dc, &pt, 1);
6086 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6088 break;
6090 case TA_CENTER:
6091 x -= width.x / 2;
6092 y -= width.y / 2;
6093 break;
6095 case TA_RIGHT:
6096 x -= width.x;
6097 y -= width.y;
6098 if (align & TA_UPDATECP)
6100 pt.x = x;
6101 pt.y = y;
6102 dp_to_lp(dc, &pt, 1);
6103 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6105 break;
6108 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
6110 case TA_TOP:
6111 y += tm.tmAscent * cosEsc;
6112 x += tm.tmAscent * sinEsc;
6113 break;
6115 case TA_BOTTOM:
6116 y -= tm.tmDescent * cosEsc;
6117 x -= tm.tmDescent * sinEsc;
6118 break;
6120 case TA_BASELINE:
6121 break;
6124 if (dc->attr->background_mode != TRANSPARENT)
6126 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
6128 if(!(flags & ETO_OPAQUE) || !lprect ||
6129 x < rc.left || x + width.x >= rc.right ||
6130 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
6132 RECT text_box;
6133 text_box.left = x;
6134 text_box.right = x + width.x;
6135 text_box.top = y - tm.tmAscent;
6136 text_box.bottom = y + tm.tmDescent;
6138 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
6139 if (!IsRectEmpty( &text_box ))
6140 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
6145 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
6146 str, count, (INT*)deltas );
6148 done:
6149 free( deltas );
6151 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
6153 int underlinePos, strikeoutPos;
6154 int underlineWidth, strikeoutWidth;
6155 UINT size = NtGdiGetOutlineTextMetricsInternalW( hdc, 0, NULL, 0 );
6156 OUTLINETEXTMETRICW* otm = NULL;
6157 POINT pts[5];
6158 HPEN hpen = NtGdiSelectPen( hdc, GetStockObject(NULL_PEN) );
6159 HBRUSH hbrush = NtGdiCreateSolidBrush( dc->attr->text_color, NULL );
6161 hbrush = NtGdiSelectBrush(hdc, hbrush);
6163 if(!size)
6165 underlinePos = 0;
6166 underlineWidth = tm.tmAscent / 20 + 1;
6167 strikeoutPos = tm.tmAscent / 2;
6168 strikeoutWidth = underlineWidth;
6170 else
6172 otm = malloc( size );
6173 NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
6174 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
6175 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
6176 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
6177 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
6178 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
6179 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
6180 free( otm );
6184 if (lf.lfUnderline)
6186 const ULONG cnt = 5;
6187 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
6188 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
6189 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
6190 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
6191 pts[2].x = pts[1].x + underlineWidth * sinEsc;
6192 pts[2].y = pts[1].y + underlineWidth * cosEsc;
6193 pts[3].x = pts[0].x + underlineWidth * sinEsc;
6194 pts[3].y = pts[0].y + underlineWidth * cosEsc;
6195 pts[4].x = pts[0].x;
6196 pts[4].y = pts[0].y;
6197 dp_to_lp(dc, pts, 5);
6198 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6201 if (lf.lfStrikeOut)
6203 const ULONG cnt = 5;
6204 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6205 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6206 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6207 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6208 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
6209 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
6210 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
6211 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
6212 pts[4].x = pts[0].x;
6213 pts[4].y = pts[0].y;
6214 dp_to_lp(dc, pts, 5);
6215 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6218 NtGdiSelectPen(hdc, hpen);
6219 hbrush = NtGdiSelectBrush(hdc, hbrush);
6220 NtGdiDeleteObjectApp( hbrush );
6223 release_dc_ptr( dc );
6225 return ret;
6229 /******************************************************************************
6230 * NtGdiGetCharABCWidthsW (win32u.@)
6232 * Retrieves widths of characters in range.
6234 * PARAMS
6235 * hdc [I] Handle of device context
6236 * firstChar [I] First character in range to query
6237 * lastChar [I] Last character in range to query
6238 * abc [O] Address of character-width structure
6240 * NOTES
6241 * Only works with TrueType fonts
6243 BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars,
6244 ULONG flags, void *buffer )
6246 DC *dc = get_dc_ptr(hdc);
6247 PHYSDEV dev;
6248 unsigned int i, count = last;
6249 BOOL ret;
6250 TEXTMETRICW tm;
6252 if (!dc) return FALSE;
6254 if (!buffer)
6256 release_dc_ptr( dc );
6257 return FALSE;
6260 if (flags & NTGDI_GETCHARABCWIDTHS_INDICES)
6262 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6263 ret = dev->funcs->pGetCharABCWidthsI( dev, first, count, chars, buffer );
6265 else
6267 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6269 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
6270 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
6271 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
6273 release_dc_ptr( dc );
6274 return FALSE;
6278 if (!chars) count = last - first + 1;
6279 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6280 ret = dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
6283 if (ret)
6285 ABC *abc = buffer;
6286 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6288 /* convert device units to logical */
6289 for (i = 0; i < count; i++)
6291 abc[i].abcA = width_to_LP( dc, abc[i].abcA );
6292 abc[i].abcB = width_to_LP( dc, abc[i].abcB );
6293 abc[i].abcC = width_to_LP( dc, abc[i].abcC );
6296 else
6298 /* convert device units to logical */
6299 FLOAT scale = fabs( dc->xformVport2World.eM11 );
6300 ABCFLOAT *abcf = buffer;
6302 for (i = 0; i < count; i++)
6304 abcf[i].abcfA = abc[i].abcA * scale;
6305 abcf[i].abcfB = abc[i].abcB * scale;
6306 abcf[i].abcfC = abc[i].abcC * scale;
6311 release_dc_ptr( dc );
6312 return ret;
6316 /***********************************************************************
6317 * NtGdiGetGlyphOutline (win32u.@)
6319 DWORD WINAPI NtGdiGetGlyphOutline( HDC hdc, UINT ch, UINT format, GLYPHMETRICS *metrics,
6320 DWORD size, void *buffer, const MAT2 *mat2,
6321 BOOL ignore_rotation )
6323 DC *dc;
6324 DWORD ret;
6325 PHYSDEV dev;
6327 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc, ch, format, metrics, (int)size, buffer, mat2 );
6329 if (!mat2) return GDI_ERROR;
6331 dc = get_dc_ptr(hdc);
6332 if(!dc) return GDI_ERROR;
6334 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6335 ret = dev->funcs->pGetGlyphOutline( dev, ch & 0xffff, format, metrics, size, buffer, mat2 );
6336 release_dc_ptr( dc );
6337 return ret;
6341 /**********************************************************************
6342 * __wine_get_file_outline_text_metric (win32u.@)
6344 BOOL CDECL __wine_get_file_outline_text_metric( const WCHAR *path, OUTLINETEXTMETRICW *otm )
6346 struct gdi_font *font = NULL;
6348 if (!path || !font_funcs) return FALSE;
6350 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6351 font->lf.lfHeight = 100;
6352 if (!font_funcs->load_font( font )) goto done;
6353 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6354 *otm = font->otm;
6355 free_gdi_font( font );
6356 return TRUE;
6358 done:
6359 if (font) free_gdi_font( font );
6360 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6361 return FALSE;
6364 /*************************************************************************
6365 * NtGdiGetKerningPairs (win32u.@)
6367 DWORD WINAPI NtGdiGetKerningPairs( HDC hdc, DWORD count, KERNINGPAIR *kern_pair )
6369 DC *dc;
6370 DWORD ret;
6371 PHYSDEV dev;
6373 TRACE( "(%p,%d,%p)\n", hdc, (int)count, kern_pair );
6375 if (!count && kern_pair)
6377 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6378 return 0;
6381 dc = get_dc_ptr( hdc );
6382 if (!dc) return 0;
6384 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
6385 ret = dev->funcs->pGetKerningPairs( dev, count, kern_pair );
6386 release_dc_ptr( dc );
6387 return ret;
6390 /*************************************************************************
6391 * NtGdiGetFontData (win32u.@)
6393 * Retrieve data for TrueType font.
6395 * RETURNS
6397 * success: Number of bytes returned
6398 * failure: GDI_ERROR
6400 * NOTES
6402 * Calls RtlSetLastWin32Error()
6405 DWORD WINAPI NtGdiGetFontData( HDC hdc, DWORD table, DWORD offset, void *buffer, DWORD length )
6407 DC *dc = get_dc_ptr(hdc);
6408 PHYSDEV dev;
6409 DWORD ret;
6411 if(!dc) return GDI_ERROR;
6413 dev = GET_DC_PHYSDEV( dc, pGetFontData );
6414 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
6415 release_dc_ptr( dc );
6416 return ret;
6419 /*************************************************************************
6420 * NtGdiGetGlyphIndicesW (win32u.@)
6422 DWORD WINAPI NtGdiGetGlyphIndicesW( HDC hdc, const WCHAR *str, INT count,
6423 WORD *indices, DWORD flags )
6425 DC *dc = get_dc_ptr(hdc);
6426 PHYSDEV dev;
6427 DWORD ret;
6429 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc, debugstr_wn(str, count), count, indices, (int)flags );
6431 if(!dc) return GDI_ERROR;
6433 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
6434 ret = dev->funcs->pGetGlyphIndices( dev, str, count, indices, flags );
6435 release_dc_ptr( dc );
6436 return ret;
6439 /***********************************************************************
6441 * Font Resource API *
6443 ***********************************************************************/
6446 static int add_system_font_resource( const WCHAR *file, DWORD flags )
6448 WCHAR path[MAX_PATH];
6449 int ret;
6451 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6452 get_fonts_win_dir_path( file, path );
6453 pthread_mutex_lock( &font_lock );
6454 ret = font_funcs->add_font( path, flags );
6455 pthread_mutex_unlock( &font_lock );
6456 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6457 if (!ret)
6459 get_fonts_data_dir_path( file, path );
6460 pthread_mutex_lock( &font_lock );
6461 ret = font_funcs->add_font( path, flags );
6462 pthread_mutex_unlock( &font_lock );
6464 return ret;
6467 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
6469 WCHAR path[MAX_PATH];
6470 int ret;
6472 get_fonts_win_dir_path( file, path );
6473 if (!(ret = remove_font( path, flags )))
6475 get_fonts_data_dir_path( file, path );
6476 ret = remove_font( path, flags );
6478 return ret;
6481 static int add_font_resource( LPCWSTR file, DWORD flags )
6483 int ret = 0;
6485 if (*file == '\\')
6487 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6489 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6490 pthread_mutex_lock( &font_lock );
6491 ret = font_funcs->add_font( file, addfont_flags );
6492 pthread_mutex_unlock( &font_lock );
6494 else if (!wcschr( file, '\\' ))
6495 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6497 return ret;
6500 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
6502 BOOL ret = FALSE;
6504 if (*file == '\\')
6506 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6508 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6509 ret = remove_font( file, addfont_flags );
6511 else if (!wcschr( file, '\\' ))
6512 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6514 return ret;
6517 static void load_system_bitmap_fonts(void)
6519 static const char * const fonts[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6520 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6521 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6522 HKEY hkey;
6523 DWORD i;
6525 if (!(hkey = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) ))) return;
6526 for (i = 0; i < ARRAY_SIZE(fonts); i++)
6528 if (query_reg_ascii_value( hkey, fonts[i], info, sizeof(value_buffer) ) && info->Type == REG_SZ)
6529 add_system_font_resource( (const WCHAR *)info->Data, ADDFONT_ALLOW_BITMAP );
6531 NtClose( hkey );
6534 static void load_directory_fonts( WCHAR *path, UINT flags )
6536 IO_STATUS_BLOCK io = {{0}};
6537 OBJECT_ATTRIBUTES attr;
6538 UNICODE_STRING nt_name;
6539 HANDLE handle;
6540 char buf[8192];
6541 size_t len;
6543 len = lstrlenW( path );
6544 while (len && path[len - 1] == '\\') len--;
6546 nt_name.Buffer = path;
6547 nt_name.MaximumLength = nt_name.Length = len * sizeof(WCHAR);
6549 attr.Length = sizeof(attr);
6550 attr.RootDirectory = 0;
6551 attr.Attributes = OBJ_CASE_INSENSITIVE;
6552 attr.ObjectName = &nt_name;
6553 attr.SecurityDescriptor = NULL;
6554 attr.SecurityQualityOfService = NULL;
6556 if (NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
6557 FILE_SHARE_READ | FILE_SHARE_WRITE,
6558 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ))
6559 return;
6561 path[len++] = '\\';
6563 while (!NtQueryDirectoryFile( handle, 0, NULL, NULL, &io, buf, sizeof(buf),
6564 FileBothDirectoryInformation, FALSE, NULL, FALSE ) &&
6565 io.Information)
6567 FILE_BOTH_DIR_INFORMATION *info = (FILE_BOTH_DIR_INFORMATION *)buf;
6568 for (;;)
6570 if (!(info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
6572 memcpy( path + len, info->FileName, info->FileNameLength );
6573 path[len + info->FileNameLength / sizeof(WCHAR)] = 0;
6574 font_funcs->add_font( path, flags );
6576 if (!info->NextEntryOffset) break;
6577 info = (FILE_BOTH_DIR_INFORMATION *)((char *)info + info->NextEntryOffset);
6581 NtClose( handle );
6584 static void load_file_system_fonts(void)
6586 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024 * sizeof(WCHAR)])];
6587 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6588 WCHAR *ptr, *next, path[MAX_PATH];
6590 /* Windows directory */
6591 get_fonts_win_dir_path( NULL, path );
6592 load_directory_fonts( path, 0 );
6594 /* Wine data directory */
6595 get_fonts_data_dir_path( NULL, path );
6596 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6598 /* custom paths */
6599 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6600 if (query_reg_ascii_value( wine_fonts_key, "Path", info, sizeof(value_buffer) ) &&
6601 info->Type == REG_SZ)
6603 for (ptr = (WCHAR *)info->Data; ptr; ptr = next)
6605 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
6606 if (next && next - ptr < 2) continue;
6607 lstrcpynW( path, ptr, MAX_PATH );
6608 if (path[1] == ':')
6610 memmove( path + ARRAYSIZE(nt_prefixW), path, (lstrlenW( path ) + 1) * sizeof(WCHAR) );
6611 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6613 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6618 struct external_key
6620 struct list entry;
6621 WCHAR value[LF_FULLFACESIZE + 12];
6624 static void update_external_font_keys(void)
6626 struct list external_keys = LIST_INIT(external_keys);
6627 HKEY winnt_key = 0, win9x_key = 0;
6628 struct gdi_font_family *family;
6629 struct external_key *key, *next;
6630 struct gdi_font_face *face;
6631 DWORD len, i = 0;
6632 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6633 char buffer[2048];
6634 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
6635 WCHAR *file;
6636 HKEY hkey;
6638 static const WCHAR external_fontsW[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6640 winnt_key = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW), 0, NULL );
6641 win9x_key = reg_create_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW), 0, NULL );
6643 /* enumerate the fonts and add external ones to the two keys */
6645 if (!(hkey = reg_create_key( wine_fonts_key, external_fontsW, sizeof(external_fontsW), 0, NULL )))
6646 return;
6648 while (reg_enum_value( hkey, i++, info, sizeof(buffer) - sizeof(nt_prefixW),
6649 value, LF_FULLFACESIZE * sizeof(WCHAR) ))
6651 if (info->Type != REG_SZ) continue;
6653 path = (WCHAR *)(buffer + info->DataOffset);
6654 if (path[0] && path[1] == ':')
6656 memmove( path + ARRAYSIZE(nt_prefixW), path, info->DataLength );
6657 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6660 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6661 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
6663 face->flags |= ADDFONT_EXTERNAL_FOUND;
6664 continue;
6666 if (tmp && !*tmp) *tmp = ' ';
6667 if (!(key = malloc( sizeof(*key) ))) break;
6668 lstrcpyW( key->value, value );
6669 list_add_tail( &external_keys, &key->entry );
6672 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
6674 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
6676 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
6677 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
6679 lstrcpyW( value, face->full_name );
6680 if (face->scalable) lstrcatW( value, true_type_suffixW );
6682 if (face->file[0] == '\\')
6684 file = face->file;
6685 if (file[5] == ':') file += ARRAYSIZE(nt_prefixW);
6687 else if ((file = wcsrchr( face->file, '\\' )))
6688 file++;
6689 else
6690 file = face->file;
6692 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
6693 set_reg_value( winnt_key, value, REG_SZ, file, len );
6694 set_reg_value( win9x_key, value, REG_SZ, file, len );
6695 set_reg_value( hkey, value, REG_SZ, file, len );
6698 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
6700 reg_delete_value( win9x_key, key->value );
6701 reg_delete_value( winnt_key, key->value );
6702 reg_delete_value( hkey, key->value );
6703 list_remove( &key->entry );
6704 free( key );
6706 NtClose( win9x_key );
6707 NtClose( winnt_key );
6708 NtClose( hkey );
6711 static void load_registry_fonts(void)
6713 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6714 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6715 KEY_VALUE_FULL_INFORMATION *enum_info = (KEY_VALUE_FULL_INFORMATION *)value_buffer;
6716 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6717 DWORD i = 0, dlen;
6718 HKEY hkey;
6720 static const WCHAR dot_fonW[] = {'.','f','o','n',0};
6722 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6723 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6724 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6725 will skip these. */
6726 if (is_win9x())
6727 hkey = reg_open_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW) );
6728 else
6729 hkey = reg_open_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW) );
6730 if (!hkey) return;
6732 while (reg_enum_value( hkey, i++, enum_info, sizeof(value_buffer), value, sizeof(value) ))
6734 if (enum_info->Type != REG_SZ) continue;
6735 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6736 if (find_face_from_full_name( value )) continue;
6737 if (tmp && !*tmp) *tmp = ' ';
6739 if (!(dlen = query_reg_value( hkey, value, info, sizeof(value_buffer) - sizeof(nt_prefixW) )) ||
6740 info->Type != REG_SZ)
6742 WARN( "Unable to get face path %s\n", debugstr_w(value) );
6743 continue;
6746 path = (WCHAR *)info->Data;
6747 if (path[0] && path[1] == ':')
6749 memmove( path + ARRAYSIZE(nt_prefixW), path, dlen );
6750 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6751 dlen += sizeof(nt_prefixW);
6754 dlen /= sizeof(WCHAR);
6755 if (*path == '\\')
6756 add_font_resource( path, ADDFONT_ALLOW_BITMAP );
6757 else if (dlen >= 6 && !wcsicmp( path + dlen - 5, dot_fonW ))
6758 add_system_font_resource( path, ADDFONT_ALLOW_BITMAP );
6760 NtClose( hkey );
6763 static HKEY open_hkcu(void)
6765 char buffer[256];
6766 WCHAR bufferW[256];
6767 DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
6768 DWORD i, len = sizeof(sid_data);
6769 SID *sid;
6771 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
6772 return 0;
6774 sid = ((TOKEN_USER *)sid_data)->User.Sid;
6775 len = sprintf( buffer, "\\Registry\\User\\S-%u-%u", (int)sid->Revision,
6776 (int)MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
6777 MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
6778 for (i = 0; i < sid->SubAuthorityCount; i++)
6779 len += sprintf( buffer + len, "-%u", (int)sid->SubAuthority[i] );
6780 ascii_to_unicode( bufferW, buffer, len + 1 );
6782 return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
6785 /***********************************************************************
6786 * font_init
6788 UINT font_init(void)
6790 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
6791 UNICODE_STRING name;
6792 HANDLE mutex;
6793 DWORD disposition;
6794 UINT dpi = 0;
6796 static WCHAR wine_font_mutexW[] =
6797 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6798 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6799 static const WCHAR wine_fonts_keyW[] =
6800 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6801 static const WCHAR cacheW[] = {'C','a','c','h','e'};
6803 if (!(hkcu_key = open_hkcu())) return 0;
6804 wine_fonts_key = reg_create_key( hkcu_key, wine_fonts_keyW, sizeof(wine_fonts_keyW), 0, NULL );
6805 if (wine_fonts_key) dpi = init_font_options();
6806 if (!dpi) return 96;
6807 update_codepage( dpi );
6809 if (!(font_funcs = init_freetype_lib()))
6810 return dpi;
6812 load_system_bitmap_fonts();
6813 load_file_system_fonts();
6814 font_funcs->load_fonts();
6816 attr.Attributes = OBJ_OPENIF;
6817 attr.ObjectName = &name;
6818 name.Buffer = wine_font_mutexW;
6819 name.Length = name.MaximumLength = sizeof(wine_font_mutexW);
6821 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return dpi;
6822 NtWaitForSingleObject( mutex, FALSE, NULL );
6824 wine_fonts_cache_key = reg_create_key( wine_fonts_key, cacheW, sizeof(cacheW),
6825 REG_OPTION_VOLATILE, &disposition );
6827 if (disposition == REG_CREATED_NEW_KEY)
6829 load_registry_fonts();
6830 update_external_font_keys();
6833 NtReleaseMutant( mutex, NULL );
6835 if (disposition != REG_CREATED_NEW_KEY)
6837 load_registry_fonts();
6838 load_font_list_from_cache();
6841 reorder_font_list();
6842 load_gdi_font_subst();
6843 load_gdi_font_replacements();
6844 load_system_links();
6845 dump_gdi_font_list();
6846 dump_gdi_font_subst();
6847 return dpi;
6850 /***********************************************************************
6851 * NtGdiAddFontResourceW (win32u.@)
6853 INT WINAPI NtGdiAddFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6854 DWORD tid, void *dv )
6856 if (!font_funcs) return 1;
6857 return add_font_resource( str, flags );
6860 /***********************************************************************
6861 * NtGdiAddFontMemResourceEx (win32u.@)
6863 HANDLE WINAPI NtGdiAddFontMemResourceEx( void *ptr, DWORD size, void *dv, ULONG dv_size,
6864 DWORD *count )
6866 HANDLE ret;
6867 DWORD num_fonts;
6868 void *copy;
6870 if (!ptr || !size || !count)
6872 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER);
6873 return NULL;
6875 if (!font_funcs) return NULL;
6876 if (!(copy = malloc( size ))) return NULL;
6877 memcpy( copy, ptr, size );
6879 pthread_mutex_lock( &font_lock );
6880 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6881 pthread_mutex_unlock( &font_lock );
6883 if (!num_fonts)
6885 free( copy );
6886 return NULL;
6889 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6890 * For now return something unique but quite random
6892 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
6894 __TRY
6896 *count = num_fonts;
6898 __EXCEPT
6900 WARN( "page fault while writing to *count (%p)\n", count );
6901 NtGdiRemoveFontMemResourceEx( ret );
6902 ret = 0;
6904 __ENDTRY
6905 TRACE( "Returning handle %p\n", ret );
6906 return ret;
6909 /***********************************************************************
6910 * NtGdiRemoveFontMemResourceEx (win32u.@)
6912 BOOL WINAPI NtGdiRemoveFontMemResourceEx( HANDLE handle )
6914 FIXME( "(%p) stub\n", handle );
6915 return TRUE;
6918 /***********************************************************************
6919 * NtGdiRemoveFontResourceW (win32u.@)
6921 BOOL WINAPI NtGdiRemoveFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6922 DWORD tid, void *dv )
6924 if (!font_funcs) return TRUE;
6925 return remove_font_resource( str, flags );
6928 /***********************************************************************
6929 * NtGdiGetFontUnicodeRanges (win32u.@)
6931 * Retrieve a list of supported Unicode characters in a font.
6933 * PARAMS
6934 * hdc [I] Handle to a device context.
6935 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6937 * RETURNS
6938 * Success: Number of bytes written to the buffer pointed to by lpgs.
6939 * Failure: 0
6942 DWORD WINAPI NtGdiGetFontUnicodeRanges( HDC hdc, GLYPHSET *lpgs )
6944 DWORD ret;
6945 PHYSDEV dev;
6946 DC *dc = get_dc_ptr(hdc);
6948 TRACE("(%p, %p)\n", hdc, lpgs);
6950 if (!dc) return 0;
6952 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
6953 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
6954 release_dc_ptr(dc);
6955 return ret;
6959 /*************************************************************
6960 * NtGdiFontIsLinked (win32u.@)
6962 BOOL WINAPI NtGdiFontIsLinked( HDC hdc )
6964 DC *dc = get_dc_ptr(hdc);
6965 PHYSDEV dev;
6966 BOOL ret;
6968 if (!dc) return FALSE;
6969 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
6970 ret = dev->funcs->pFontIsLinked( dev );
6971 release_dc_ptr(dc);
6972 TRACE("returning %d\n", ret);
6973 return ret;
6976 /*************************************************************
6977 * NtGdiGetRealizationInfo (win32u.@)
6979 BOOL WINAPI NtGdiGetRealizationInfo( HDC hdc, struct font_realization_info *info )
6981 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, file_count);
6982 PHYSDEV dev;
6983 BOOL ret;
6984 DC *dc;
6986 if (info->size != sizeof(*info) && !is_v0)
6987 return FALSE;
6989 dc = get_dc_ptr(hdc);
6990 if (!dc) return FALSE;
6991 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
6992 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
6993 release_dc_ptr(dc);
6994 return ret;
6997 /*************************************************************************
6998 * NtGdiGetRasterizerCaps (win32u.@)
7000 BOOL WINAPI NtGdiGetRasterizerCaps( RASTERIZER_STATUS *status, UINT size )
7002 status->nSize = sizeof(RASTERIZER_STATUS);
7003 status->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
7004 status->nLanguageID = 0;
7005 return TRUE;
7008 /*************************************************************************
7009 * NtGdiGetFontFileData (win32u.@)
7011 BOOL WINAPI NtGdiGetFontFileData( DWORD instance_id, DWORD file_index, UINT64 *offset,
7012 void *buff, DWORD buff_size )
7014 struct gdi_font *font;
7015 DWORD tag = 0, size;
7016 BOOL ret = FALSE;
7018 if (!font_funcs) return FALSE;
7019 pthread_mutex_lock( &font_lock );
7020 if ((font = get_font_from_handle( instance_id )))
7022 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
7023 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
7024 if (size != GDI_ERROR && size >= buff_size && *offset <= size - buff_size)
7025 ret = font_funcs->get_font_data( font, tag, *offset, buff, buff_size ) != GDI_ERROR;
7026 else
7027 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
7029 pthread_mutex_unlock( &font_lock );
7030 return ret;
7033 /*************************************************************************
7034 * NtGdiGetFontFileInfo (win32u.@)
7036 BOOL WINAPI NtGdiGetFontFileInfo( DWORD instance_id, DWORD file_index, struct font_fileinfo *info,
7037 SIZE_T size, SIZE_T *needed )
7039 SIZE_T required_size = 0;
7040 struct gdi_font *font;
7041 BOOL ret = FALSE;
7043 pthread_mutex_lock( &font_lock );
7045 if ((font = get_font_from_handle( instance_id )))
7047 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
7048 if (required_size <= size)
7050 info->writetime = font->writetime;
7051 info->size.QuadPart = font->data_size;
7052 lstrcpyW( info->path, font->file );
7053 ret = TRUE;
7055 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
7058 pthread_mutex_unlock( &font_lock );
7059 if (needed) *needed = required_size;
7060 return ret;
7063 /*************************************************************
7064 * NtGdiGetCharWidthInfo (win32u.@)
7066 BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info )
7068 PHYSDEV dev;
7069 BOOL ret;
7070 DC *dc;
7072 dc = get_dc_ptr(hdc);
7073 if (!dc) return FALSE;
7074 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
7075 ret = dev->funcs->pGetCharWidthInfo( dev, info );
7077 if (ret)
7079 info->lsb = width_to_LP( dc, info->lsb );
7080 info->rsb = width_to_LP( dc, info->rsb );
7082 release_dc_ptr(dc);
7083 return ret;
7086 /***********************************************************************
7087 * DrawTextW (win32u.so)
7089 INT WINAPI DECLSPEC_HIDDEN DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags )
7091 struct draw_text_params *params;
7092 ULONG ret_len, size;
7093 void *ret_ptr;
7094 int ret;
7096 if (count == -1) count = wcslen( str );
7097 size = FIELD_OFFSET( struct draw_text_params, str[count] );
7098 if (!(params = malloc( size ))) return 0;
7099 params->hdc = hdc;
7100 params->rect = *rect;
7101 params->ret_rect = rect;
7102 params->flags = flags;
7103 if (count) memcpy( params->str, str, count * sizeof(WCHAR) );
7104 ret = KeUserModeCallback( NtUserDrawText, params, size, &ret_ptr, &ret_len );
7105 if (ret_len == sizeof(*rect)) *rect = *(const RECT *)ret_ptr;
7106 free( params );
7107 return ret;