win32u: Don't use CDECL for gdi_dc_funcs entries.
[wine.git] / dlls / win32u / font.c
blob804cfe2a245ac46c27b5c060d7eb4f15fc0d6eaf
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 font_CreateDC( PHYSDEV *dev, LPCWSTR device, LPCWSTR output, const DEVMODEW *devmode )
3237 struct font_physdev *physdev;
3239 if (!font_funcs) return TRUE;
3240 if (!(physdev = calloc( 1, sizeof(*physdev) ))) return FALSE;
3241 push_dc_driver( dev, &physdev->dev, &font_driver );
3242 return TRUE;
3246 /*************************************************************
3247 * font_DeleteDC
3249 static BOOL font_DeleteDC( PHYSDEV dev )
3251 struct font_physdev *physdev = get_font_dev( dev );
3253 release_gdi_font( physdev->font );
3254 free( physdev );
3255 return TRUE;
3259 struct gdi_font_enum_data
3261 ENUMLOGFONTEXW elf;
3262 NEWTEXTMETRICEXW ntm;
3265 struct enum_charset
3267 DWORD mask;
3268 DWORD charset;
3269 DWORD script;
3272 static BOOL is_complex_script_ansi_cp(void)
3274 return (ansi_cp.CodePage == 874 /* Thai */
3275 || ansi_cp.CodePage == 1255 /* Hebrew */
3276 || ansi_cp.CodePage == 1256 /* Arabic */
3280 /***************************************************
3281 * create_enum_charset_list
3283 * This function creates charset enumeration list because in DEFAULT_CHARSET
3284 * case, the ANSI codepage's charset takes precedence over other charsets.
3285 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
3286 * This function works as a filter other than DEFAULT_CHARSET case.
3288 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
3290 struct enum_charset *start = list;
3291 CHARSETINFO csi;
3292 int i;
3294 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && csi.fs.fsCsb[0] != 0)
3296 list->mask = csi.fs.fsCsb[0];
3297 list->charset = csi.ciCharset;
3298 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
3299 list++;
3301 else /* charset is DEFAULT_CHARSET or invalid. */
3303 DWORD mask = 0;
3305 /* Set the current codepage's charset as the first element. */
3306 if (!is_complex_script_ansi_cp() &&
3307 translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, &csi, TCI_SRCCODEPAGE ) &&
3308 csi.fs.fsCsb[0] != 0)
3310 list->mask = csi.fs.fsCsb[0];
3311 list->charset = csi.ciCharset;
3312 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
3313 mask |= csi.fs.fsCsb[0];
3314 list++;
3317 /* Fill out left elements. */
3318 for (i = 0; i < 32; i++)
3320 FONTSIGNATURE fs;
3321 fs.fsCsb[0] = 1u << i;
3322 fs.fsCsb[1] = 0;
3323 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
3324 if (!translate_charset_info( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
3325 continue; /* skip, this is an invalid fsCsb bit. */
3326 list->mask = fs.fsCsb[0];
3327 list->charset = csi.ciCharset;
3328 list->script = i;
3329 mask |= fs.fsCsb[0];
3330 list++;
3332 /* add catch all mask for remaining bits */
3333 if (~mask)
3335 list->mask = ~mask;
3336 list->charset = DEFAULT_CHARSET;
3337 list->script = 33; /* other */
3338 list++;
3341 return list - start;
3344 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
3346 UINT ret = 0;
3348 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
3349 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
3350 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
3351 return ret;
3354 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
3356 struct gdi_font *font;
3357 LOGFONTW lf = { .lfHeight = -4096 /* preferable EM Square size */ };
3359 if (!face->scalable) lf.lfHeight = 0;
3361 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
3363 if (!font_funcs->load_font( font ))
3365 free_gdi_font( font );
3366 return FALSE;
3369 if (font->scalable && -lf.lfHeight % font->otm.otmEMSquare != 0)
3371 /* reload with the original EM Square size */
3372 lf.lfHeight = -font->otm.otmEMSquare;
3373 free_gdi_font( font );
3375 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
3376 if (!font_funcs->load_font( font ))
3378 free_gdi_font( font );
3379 return FALSE;
3383 if (font_funcs->set_outline_text_metrics( font ))
3385 static const DWORD ntm_ppem = 32;
3386 UINT cell_height;
3388 #define TM font->otm.otmTextMetrics
3389 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
3390 cell_height = TM.tmHeight / ( -lf.lfHeight / font->otm.otmEMSquare );
3391 ntm->ntmTm.tmHeight = muldiv( ntm_ppem, cell_height, font->otm.otmEMSquare );
3392 ntm->ntmTm.tmAscent = SCALE_NTM( TM.tmAscent );
3393 ntm->ntmTm.tmDescent = ntm->ntmTm.tmHeight - ntm->ntmTm.tmAscent;
3394 ntm->ntmTm.tmInternalLeading = SCALE_NTM( TM.tmInternalLeading );
3395 ntm->ntmTm.tmExternalLeading = SCALE_NTM( TM.tmExternalLeading );
3396 ntm->ntmTm.tmAveCharWidth = SCALE_NTM( TM.tmAveCharWidth );
3397 ntm->ntmTm.tmMaxCharWidth = SCALE_NTM( TM.tmMaxCharWidth );
3399 memcpy((char *)&ntm->ntmTm + offsetof( TEXTMETRICW, tmWeight ),
3400 (const char *)&TM + offsetof( TEXTMETRICW, tmWeight ),
3401 sizeof(TEXTMETRICW) - offsetof( TEXTMETRICW, tmWeight ));
3402 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
3403 ntm->ntmTm.ntmCellHeight = cell_height;
3404 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
3405 #undef SCALE_NTM
3406 #undef TM
3408 else if (font_funcs->set_bitmap_text_metrics( font ))
3410 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
3411 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
3412 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
3413 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
3415 ntm->ntmTm.ntmFlags = font->ntmFlags;
3416 ntm->ntmFontSig = font->fs;
3418 elf->elfLogFont.lfEscapement = 0;
3419 elf->elfLogFont.lfOrientation = 0;
3420 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
3421 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
3422 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
3423 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
3424 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
3425 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
3426 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
3427 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3428 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3429 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
3430 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3431 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
3432 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
3433 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
3435 free_gdi_font( font );
3436 return TRUE;
3439 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
3441 struct gdi_font_face *face;
3443 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
3444 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3445 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
3446 return FALSE;
3449 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
3451 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
3452 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
3455 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
3456 struct enum_charset *list, DWORD count, FONTENUMPROCW proc, LPARAM lparam,
3457 const WCHAR *subst )
3459 ENUMLOGFONTEXW elf;
3460 NEWTEXTMETRICEXW ntm;
3461 UINT type, i;
3463 if (!face->cached_enum_data)
3465 struct gdi_font_enum_data *data;
3467 if (!(data = calloc( 1, sizeof(*data) )) ||
3468 !get_face_enum_data( face, &data->elf, &data->ntm ))
3470 free( data );
3471 return TRUE;
3473 face->cached_enum_data = data;
3476 elf = face->cached_enum_data->elf;
3477 ntm = face->cached_enum_data->ntm;
3478 type = get_font_type( &ntm );
3480 /* font replacement */
3481 if (family != face->family)
3483 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
3484 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
3486 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
3488 for (i = 0; i < count; i++)
3490 if (face->fs.fsCsb[0] == 0) /* OEM */
3492 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3493 elf.elfScript[0] = 32;
3494 i = count; /* break out of loop after enumeration */
3496 else
3498 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
3499 /* use the DEFAULT_CHARSET case only if no other charset is present */
3500 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
3501 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
3502 /* caller may fill elfScript with the actual string, see load_script_name */
3503 elf.elfScript[0] = list[i].script;
3505 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3506 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3507 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
3508 elf.elfLogFont.lfItalic, (int)elf.elfLogFont.lfWeight, (int)ntm.ntmTm.ntmFlags );
3509 /* release section before callback (FIXME) */
3510 pthread_mutex_unlock( &font_lock );
3511 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
3512 pthread_mutex_lock( &font_lock );
3514 return TRUE;
3517 /*************************************************************
3518 * font_EnumFonts
3520 static BOOL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
3522 struct gdi_font_family *family;
3523 struct gdi_font_face *face;
3524 struct enum_charset enum_charsets[32];
3525 UINT count, charset;
3527 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
3529 count = create_enum_charset_list( charset, enum_charsets );
3531 pthread_mutex_lock( &font_lock );
3533 if (lf && lf->lfFaceName[0])
3535 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
3536 const WCHAR *orig_name = NULL;
3538 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
3539 if (face_name)
3541 orig_name = lf->lfFaceName;
3542 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
3544 else face_name = lf->lfFaceName;
3546 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3548 if (!family_matches(family, face_name)) continue;
3549 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3551 if (!face_matches( family->family_name, face, face_name )) continue;
3552 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
3553 return FALSE; /* enum_face_charsets() unlocked font_lock */
3557 else
3559 TRACE( "charset %d\n", charset );
3560 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3562 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
3563 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
3564 return FALSE; /* enum_face_charsets() unlocked font_lock */
3567 pthread_mutex_unlock( &font_lock );
3568 return TRUE;
3572 static BOOL check_unicode_tategaki( WCHAR ch )
3574 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
3575 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
3577 /* We only reach this code if typographical substitution did not occur */
3578 /* Type: U or Type: Tu */
3579 return (orientation == 1 || orientation == 3);
3582 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
3584 UINT index;
3586 if (glyph < 0x100) glyph += 0xf000;
3587 /* there are a number of old pre-Unicode "broken" TTFs, which
3588 do have symbols at U+00XX instead of U+f0XX */
3589 index = glyph;
3590 font_funcs->get_glyph_index( font, &index, FALSE );
3591 if (!index)
3593 index = glyph - 0xf000;
3594 font_funcs->get_glyph_index( font, &index, FALSE );
3596 return index;
3599 CPTABLEINFO *get_cptable( WORD cp )
3601 static CPTABLEINFO tables[100];
3602 unsigned int i;
3603 USHORT *ptr;
3604 SIZE_T size;
3606 if (cp == CP_ACP) return &ansi_cp;
3607 if (cp == CP_UTF8) return &utf8_cp;
3609 for (i = 0; i < ARRAY_SIZE(tables) && tables[i].CodePage; i++)
3610 if (tables[i].CodePage == cp) return &tables[i];
3611 if (NtGetNlsSectionPtr( 11, cp, NULL, (void **)&ptr, &size )) return NULL;
3612 if (i == ARRAY_SIZE(tables))
3614 ERR( "too many code pages\n" );
3615 return NULL;
3617 RtlInitCodePageTable( ptr, &tables[i] );
3618 return &tables[i];
3621 /* Based on NlsValidateLocale */
3622 const NLS_LOCALE_DATA *get_locale_data( LCID lcid )
3624 static const NLS_LOCALE_HEADER *locale_table;
3625 static const NLS_LOCALE_LCID_INDEX *lcids_index;
3626 int min = 0, max;
3628 if (!locale_table)
3630 LARGE_INTEGER size;
3631 void *addr;
3632 LCID lcid;
3633 NTSTATUS status;
3634 static struct
3636 UINT ctypes;
3637 UINT unknown1;
3638 UINT unknown2;
3639 UINT unknown3;
3640 UINT locales;
3641 UINT charmaps;
3642 UINT geoids;
3643 UINT scripts;
3644 } *header;
3646 status = NtInitializeNlsFiles( &addr, &lcid, &size );
3647 if (status)
3649 ERR( "Failed to load nls file\n" );
3650 return NULL;
3653 if (InterlockedCompareExchangePointer( (void **)&header, addr, NULL ))
3654 NtUnmapViewOfSection( GetCurrentProcess(), addr );
3656 locale_table = (const NLS_LOCALE_HEADER *)((char *)header + header->locales);
3657 lcids_index = (const NLS_LOCALE_LCID_INDEX *)((char *)locale_table + locale_table->lcids_offset);
3660 max = locale_table->nb_lcids - 1;
3661 while (min <= max)
3663 int pos = (min + max) / 2;
3664 if (lcid < lcids_index[pos].id) max = pos - 1;
3665 else if (lcid > lcids_index[pos].id) min = pos + 1;
3666 else
3668 ULONG offset = locale_table->locales_offset + pos * locale_table->locale_size;
3669 return (const NLS_LOCALE_DATA *)((const char *)locale_table + offset);
3672 return NULL;
3675 DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, DWORD srclen )
3677 DWORD ret;
3679 if (info->CodePage == CP_UTF8)
3680 RtlUnicodeToUTF8N( dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3681 else
3682 RtlUnicodeToCustomCPN( info, dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3684 return ret;
3687 DWORD win32u_wctomb_size( CPTABLEINFO *info, const WCHAR *src, DWORD srclen )
3689 DWORD ret;
3691 if (info->CodePage == CP_UTF8)
3693 RtlUnicodeToUTF8N( NULL, 0, &ret, src, srclen * sizeof(WCHAR) );
3695 else if(info->DBCSCodePage)
3697 WCHAR *uni2cp = info->WideCharTable;
3698 for (ret = srclen; srclen; srclen--, src++)
3699 if (uni2cp[*src] & 0xff00) ret++;
3701 else
3703 ret = srclen;
3706 return ret;
3709 DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *src, DWORD srclen )
3711 DWORD ret;
3713 if (info->CodePage == CP_UTF8)
3714 RtlUTF8ToUnicodeN( dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3715 else
3716 RtlCustomCPToUnicodeN( info, dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3718 return ret / sizeof(WCHAR);
3721 DWORD win32u_mbtowc_size( CPTABLEINFO *info, const char *src, DWORD srclen )
3723 DWORD ret;
3725 if (info->CodePage == CP_UTF8)
3727 RtlUTF8ToUnicodeN( NULL, 0, &ret, src, srclen );
3728 ret /= sizeof(WCHAR);
3730 else if (info->DBCSCodePage)
3732 for (ret = 0; srclen; srclen--, src++, ret++)
3734 if (info->DBCSOffsets[(unsigned char)*src] && srclen > 1)
3736 src++;
3737 srclen--;
3741 else
3743 ret = srclen;
3746 return ret;
3749 static BOOL wc_to_index( UINT cp, WCHAR wc, unsigned char *dst, BOOL allow_default )
3751 const CPTABLEINFO *info;
3753 if (!(info = get_cptable( cp ))) return FALSE;
3755 if (info->CodePage == CP_UTF8)
3757 if (wc < 0x80)
3759 *dst = wc;
3760 return TRUE;
3762 if (!allow_default) return FALSE;
3763 *dst = info->DefaultChar;
3764 return TRUE;
3766 else if (info->DBCSCodePage)
3768 WCHAR *uni2cp = info->WideCharTable;
3769 if (uni2cp[wc] & 0xff00) return FALSE;
3770 *dst = uni2cp[wc];
3772 else
3774 char *uni2cp = info->WideCharTable;
3775 *dst = uni2cp[wc];
3778 if (info->MultiByteTable[*dst] != wc)
3780 if (!allow_default) return FALSE;
3781 *dst = info->DefaultChar;
3784 return TRUE;
3787 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
3789 WCHAR wc = glyph;
3790 unsigned char ch;
3792 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
3794 if (font->codepage == CP_SYMBOL)
3796 glyph = get_glyph_index_symbol( font, wc );
3797 if (!glyph)
3799 if (wc_to_index( CP_ACP, wc, &ch, TRUE ))
3800 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
3803 else if (wc_to_index( font->codepage, wc, &ch, FALSE ))
3805 glyph = (unsigned char)ch;
3806 font_funcs->get_glyph_index( font, &glyph, FALSE );
3808 else return 0;
3810 return glyph;
3813 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
3815 struct gdi_font *child;
3816 UINT res;
3818 if ((res = get_glyph_index( *font, glyph ))) return res;
3819 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
3821 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
3823 if (!child->private && !font_funcs->load_font( child )) continue;
3824 if ((res = get_glyph_index( child, glyph )))
3826 *font = child;
3827 return res;
3830 return 0;
3833 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3834 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
3835 const MAT2 *mat )
3837 GLYPHMETRICS gm;
3838 ABC abc;
3839 DWORD ret = 1;
3840 UINT index = glyph;
3841 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
3843 if (format & GGO_GLYPH_INDEX)
3845 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3846 as glyph index. "Treasure Adventure Game" depends on this. */
3847 font_funcs->get_glyph_index( font, &index, FALSE );
3848 format &= ~GGO_GLYPH_INDEX;
3849 /* TODO: Window also turns off tategaki for glyphs passed in by index
3850 if their unicode code points fall outside of the range that is
3851 rotated. */
3853 else
3855 index = get_glyph_index_linked( &font, glyph );
3856 if (tategaki)
3858 UINT orig = index;
3859 index = get_GSUB_vert_glyph( font, index );
3860 if (index == orig) tategaki = check_unicode_tategaki( glyph );
3864 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
3866 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
3867 goto done;
3869 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
3870 if (ret == GDI_ERROR) return ret;
3872 if (format == GGO_METRICS && !mat)
3873 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
3875 done:
3876 if (gm_ret) *gm_ret = gm;
3877 if (abc_ret) *abc_ret = abc;
3878 return ret;
3882 /*************************************************************
3883 * font_FontIsLinked
3885 static BOOL font_FontIsLinked( PHYSDEV dev )
3887 struct font_physdev *physdev = get_font_dev( dev );
3889 if (!physdev->font)
3891 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
3892 return dev->funcs->pFontIsLinked( dev );
3894 return !list_empty( &physdev->font->child_fonts );
3898 /*************************************************************
3899 * font_GetCharABCWidths
3901 static BOOL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT count, WCHAR *chars, ABC *buffer )
3903 struct font_physdev *physdev = get_font_dev( dev );
3904 UINT c, i;
3906 if (!physdev->font)
3908 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3909 return dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
3912 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3914 pthread_mutex_lock( &font_lock );
3915 for (i = 0; i < count; i++)
3917 c = chars ? chars[i] : first + i;
3918 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &buffer[i], 0, NULL, NULL );
3920 pthread_mutex_unlock( &font_lock );
3921 return TRUE;
3925 /*************************************************************
3926 * font_GetCharABCWidthsI
3928 static BOOL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3930 struct font_physdev *physdev = get_font_dev( dev );
3931 UINT c;
3933 if (!physdev->font)
3935 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3936 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3939 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3941 pthread_mutex_lock( &font_lock );
3942 for (c = 0; c < count; c++, buffer++)
3943 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3944 NULL, buffer, 0, NULL, NULL );
3945 pthread_mutex_unlock( &font_lock );
3946 return TRUE;
3950 /*************************************************************
3951 * font_GetCharWidth
3953 static BOOL font_GetCharWidth( PHYSDEV dev, UINT first, UINT count, const WCHAR *chars, INT *buffer )
3955 struct font_physdev *physdev = get_font_dev( dev );
3956 UINT c, i;
3957 ABC abc;
3959 if (!physdev->font)
3961 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3962 return dev->funcs->pGetCharWidth( dev, first, count, chars, buffer );
3965 TRACE( "%p, %d, %d, %p\n", physdev->font, first, count, buffer );
3967 pthread_mutex_lock( &font_lock );
3968 for (i = 0; i < count; i++)
3970 c = chars ? chars[i] : i + first;
3971 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3972 buffer[i] = 0;
3973 else
3974 buffer[i] = abc.abcA + abc.abcB + abc.abcC;
3976 pthread_mutex_unlock( &font_lock );
3977 return TRUE;
3981 /*************************************************************
3982 * font_GetCharWidthInfo
3984 static BOOL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3986 struct font_physdev *physdev = get_font_dev( dev );
3987 struct char_width_info *info = ptr;
3989 if (!physdev->font)
3991 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3992 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3995 info->unk = 0;
3996 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3997 info->lsb = info->rsb = 0;
3999 return TRUE;
4003 /*************************************************************
4004 * font_GetFontData
4006 static DWORD font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
4008 struct font_physdev *physdev = get_font_dev( dev );
4010 if (!physdev->font)
4012 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
4013 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
4015 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
4019 /*************************************************************
4020 * font_GetFontRealizationInfo
4022 static BOOL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
4024 struct font_physdev *physdev = get_font_dev( dev );
4025 struct font_realization_info *info = ptr;
4027 if (!physdev->font)
4029 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
4030 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
4033 TRACE( "(%p, %p)\n", physdev->font, info);
4035 info->flags = 1;
4036 if (physdev->font->scalable) info->flags |= 2;
4038 info->cache_num = physdev->font->cache_num;
4039 info->instance_id = physdev->font->handle;
4040 if (info->size == sizeof(*info))
4042 info->file_count = 1;
4043 info->face_index = physdev->font->face_index;
4044 info->simulations = 0;
4045 if (physdev->font->fake_bold) info->simulations |= 0x1;
4046 if (physdev->font->fake_italic) info->simulations |= 0x2;
4048 return TRUE;
4052 /*************************************************************
4053 * font_GetFontUnicodeRanges
4055 static DWORD font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
4057 struct font_physdev *physdev = get_font_dev( dev );
4058 DWORD size, num_ranges;
4060 if (!physdev->font)
4062 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
4063 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
4066 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
4067 size = offsetof( GLYPHSET, ranges[num_ranges] );
4068 if (glyphset)
4070 glyphset->cbThis = size;
4071 glyphset->cRanges = num_ranges;
4072 glyphset->flAccel = 0;
4074 return size;
4078 /*************************************************************
4079 * font_GetGlyphIndices
4081 static DWORD font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
4083 struct font_physdev *physdev = get_font_dev( dev );
4084 UINT default_char;
4085 unsigned char ch;
4086 BOOL got_default = FALSE;
4087 int i;
4089 if (!physdev->font)
4091 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
4092 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
4095 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4097 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4098 got_default = TRUE;
4101 pthread_mutex_lock( &font_lock );
4103 for (i = 0; i < count; i++)
4105 UINT glyph = str[i];
4107 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
4109 glyph = 0;
4110 if (physdev->font->codepage == CP_SYMBOL)
4112 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
4113 else if (str[i] < 0x100) glyph = str[i];
4115 else if (wc_to_index( physdev->font->codepage, str[i], &ch, FALSE ))
4116 glyph = (unsigned char)ch;
4118 if (!glyph)
4120 if (!got_default)
4122 default_char = font_funcs->get_default_glyph( physdev->font );
4123 got_default = TRUE;
4125 gi[i] = default_char;
4127 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
4130 pthread_mutex_unlock( &font_lock );
4131 return count;
4135 /*************************************************************
4136 * font_GetGlyphOutline
4138 static DWORD font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
4139 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
4141 struct font_physdev *physdev = get_font_dev( dev );
4142 DWORD ret;
4144 if (!physdev->font)
4146 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
4147 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
4149 pthread_mutex_lock( &font_lock );
4150 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
4151 pthread_mutex_unlock( &font_lock );
4152 return ret;
4156 /*************************************************************
4157 * font_GetKerningPairs
4159 static DWORD font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
4161 struct font_physdev *physdev = get_font_dev( dev );
4163 if (!physdev->font)
4165 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
4166 return dev->funcs->pGetKerningPairs( dev, count, pairs );
4169 pthread_mutex_lock( &font_lock );
4170 if (physdev->font->kern_count == -1)
4171 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
4172 &physdev->font->kern_pairs );
4173 pthread_mutex_unlock( &font_lock );
4175 if (count && pairs)
4177 count = min( count, physdev->font->kern_count );
4178 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
4180 else count = physdev->font->kern_count;
4182 return count;
4186 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
4188 double scale_x, scale_y;
4190 if (font->aveWidth)
4192 scale_x = (double)font->aveWidth;
4193 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
4195 else
4196 scale_x = font->scale_y;
4198 scale_x *= fabs(font->matrix.eM11);
4199 scale_y = font->scale_y * fabs(font->matrix.eM22);
4201 /* Windows scales these values as signed integers even if they are unsigned */
4202 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
4203 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
4205 SCALE_Y(otm->otmTextMetrics.tmHeight);
4206 SCALE_Y(otm->otmTextMetrics.tmAscent);
4207 SCALE_Y(otm->otmTextMetrics.tmDescent);
4208 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
4209 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
4211 SCALE_X(otm->otmTextMetrics.tmOverhang);
4212 if (font->fake_bold)
4214 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
4215 otm->otmTextMetrics.tmAveCharWidth++;
4216 otm->otmTextMetrics.tmMaxCharWidth++;
4218 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
4219 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
4221 SCALE_Y(otm->otmAscent);
4222 SCALE_Y(otm->otmDescent);
4223 SCALE_Y(otm->otmLineGap);
4224 SCALE_Y(otm->otmsCapEmHeight);
4225 SCALE_Y(otm->otmsXHeight);
4226 SCALE_Y(otm->otmrcFontBox.top);
4227 SCALE_Y(otm->otmrcFontBox.bottom);
4228 SCALE_X(otm->otmrcFontBox.left);
4229 SCALE_X(otm->otmrcFontBox.right);
4230 SCALE_Y(otm->otmMacAscent);
4231 SCALE_Y(otm->otmMacDescent);
4232 SCALE_Y(otm->otmMacLineGap);
4233 SCALE_X(otm->otmptSubscriptSize.x);
4234 SCALE_Y(otm->otmptSubscriptSize.y);
4235 SCALE_X(otm->otmptSubscriptOffset.x);
4236 SCALE_Y(otm->otmptSubscriptOffset.y);
4237 SCALE_X(otm->otmptSuperscriptSize.x);
4238 SCALE_Y(otm->otmptSuperscriptSize.y);
4239 SCALE_X(otm->otmptSuperscriptOffset.x);
4240 SCALE_Y(otm->otmptSuperscriptOffset.y);
4241 SCALE_Y(otm->otmsStrikeoutSize);
4242 SCALE_Y(otm->otmsStrikeoutPosition);
4243 SCALE_Y(otm->otmsUnderscoreSize);
4244 SCALE_Y(otm->otmsUnderscorePosition);
4246 #undef SCALE_X
4247 #undef SCALE_Y
4250 /*************************************************************
4251 * font_GetOutlineTextMetrics
4253 static UINT font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
4255 struct font_physdev *physdev = get_font_dev( dev );
4256 UINT ret = 0;
4258 if (!physdev->font)
4260 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
4261 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
4264 if (!physdev->font->scalable) return 0;
4266 pthread_mutex_lock( &font_lock );
4267 if (font_funcs->set_outline_text_metrics( physdev->font ))
4269 ret = physdev->font->otm.otmSize;
4270 if (metrics && size >= physdev->font->otm.otmSize)
4272 WCHAR *ptr = (WCHAR *)(metrics + 1);
4273 *metrics = physdev->font->otm;
4274 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
4275 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
4276 ptr += lstrlenW(ptr) + 1;
4277 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
4278 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
4279 ptr += lstrlenW(ptr) + 1;
4280 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
4281 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
4282 ptr += lstrlenW(ptr) + 1;
4283 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
4284 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
4285 scale_outline_font_metrics( physdev->font, metrics );
4288 pthread_mutex_unlock( &font_lock );
4289 return ret;
4293 /*************************************************************
4294 * font_GetTextCharsetInfo
4296 static UINT font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
4298 struct font_physdev *physdev = get_font_dev( dev );
4300 if (!physdev->font)
4302 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
4303 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4305 if (fs) *fs = physdev->font->fs;
4306 return physdev->font->charset;
4310 /*************************************************************
4311 * font_GetTextExtentExPoint
4313 static BOOL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
4315 struct font_physdev *physdev = get_font_dev( dev );
4316 INT i, pos;
4317 ABC abc;
4319 if (!physdev->font)
4321 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
4322 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
4325 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
4327 pthread_mutex_lock( &font_lock );
4328 for (i = pos = 0; i < count; i++)
4330 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
4331 pos += abc.abcA + abc.abcB + abc.abcC;
4332 dxs[i] = pos;
4334 pthread_mutex_unlock( &font_lock );
4335 return TRUE;
4339 /*************************************************************
4340 * font_GetTextExtentExPointI
4342 static BOOL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
4344 struct font_physdev *physdev = get_font_dev( dev );
4345 INT i, pos;
4346 ABC abc;
4348 if (!physdev->font)
4350 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
4351 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
4354 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
4356 pthread_mutex_lock( &font_lock );
4357 for (i = pos = 0; i < count; i++)
4359 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
4360 NULL, &abc, 0, NULL, NULL );
4361 pos += abc.abcA + abc.abcB + abc.abcC;
4362 dxs[i] = pos;
4364 pthread_mutex_unlock( &font_lock );
4365 return TRUE;
4369 /*************************************************************
4370 * font_GetTextFace
4372 static INT font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
4374 struct font_physdev *physdev = get_font_dev( dev );
4375 const WCHAR *font_name;
4376 INT len;
4378 if (!physdev->font)
4380 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
4381 return dev->funcs->pGetTextFace( dev, count, str );
4383 font_name = get_gdi_font_name( physdev->font );
4384 len = lstrlenW( font_name ) + 1;
4385 if (str)
4387 lstrcpynW( str, font_name, count );
4388 len = min( count, len );
4390 return len;
4394 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
4396 double scale_x, scale_y;
4398 /* Make sure that the font has sane width/height ratio */
4399 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
4401 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
4402 font->aveWidth = 0;
4405 if (font->aveWidth)
4407 scale_x = (double)font->aveWidth;
4408 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
4410 else
4411 scale_x = font->scale_y;
4413 scale_x *= fabs(font->matrix.eM11);
4414 scale_y = font->scale_y * fabs(font->matrix.eM22);
4416 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
4417 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
4419 SCALE_Y(tm->tmHeight);
4420 SCALE_Y(tm->tmAscent);
4421 SCALE_Y(tm->tmDescent);
4422 SCALE_Y(tm->tmInternalLeading);
4423 SCALE_Y(tm->tmExternalLeading);
4425 SCALE_X(tm->tmOverhang);
4426 if (font->fake_bold)
4428 if (!font->scalable) tm->tmOverhang++;
4429 tm->tmAveCharWidth++;
4430 tm->tmMaxCharWidth++;
4432 SCALE_X(tm->tmAveCharWidth);
4433 SCALE_X(tm->tmMaxCharWidth);
4435 #undef SCALE_X
4436 #undef SCALE_Y
4439 /*************************************************************
4440 * font_GetTextMetrics
4442 static BOOL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
4444 struct font_physdev *physdev = get_font_dev( dev );
4445 BOOL ret = FALSE;
4447 if (!physdev->font)
4449 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
4450 return dev->funcs->pGetTextMetrics( dev, metrics );
4453 pthread_mutex_lock( &font_lock );
4454 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
4455 font_funcs->set_bitmap_text_metrics( physdev->font ))
4457 *metrics = physdev->font->otm.otmTextMetrics;
4458 scale_font_metrics( physdev->font, metrics );
4459 ret = TRUE;
4461 pthread_mutex_unlock( &font_lock );
4462 return ret;
4466 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
4468 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4469 a single face with the requested charset. The idea is to check if
4470 the selected font supports the current ANSI codepage, if it does
4471 return the corresponding charset, else return the first charset */
4473 int i;
4475 if (translate_charset_info( (DWORD*)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
4477 const struct gdi_font_link *font_link;
4479 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
4480 font_link = find_gdi_font_link(family_name);
4481 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
4483 for (i = 0; i < 32; i++)
4485 DWORD fs0 = 1u << i;
4486 if (face->fs.fsCsb[0] & fs0)
4488 if (translate_charset_info(&fs0, csi, TCI_SRCFONTSIG)) return;
4489 FIXME("TCI failing on %x\n", (int)fs0);
4493 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4494 (int)face->fs.fsCsb[0], debugstr_w(face->file));
4495 csi->ciACP = ansi_cp.CodePage;
4496 csi->ciCharset = DEFAULT_CHARSET;
4499 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
4501 struct gdi_font *font;
4502 struct gdi_font_face *face;
4503 INT height;
4504 CHARSETINFO csi;
4505 const WCHAR *orig_name = NULL;
4506 BOOL substituted = FALSE;
4508 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
4510 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4511 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4512 original value lfCharSet. Note this is a special case for
4513 Symbol and doesn't happen at least for "Wingdings*" */
4514 if (!facename_compare( lf->lfFaceName, symbolW, -1 )) lf->lfCharSet = SYMBOL_CHARSET;
4516 /* check the cache first */
4517 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4519 TRACE( "returning cached gdiFont(%p)\n", font );
4520 return font;
4522 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &substituted, &orig_name )))
4524 FIXME( "can't find a single appropriate font - bailing\n" );
4525 return NULL;
4527 height = lf->lfHeight;
4529 font = create_gdi_font( face, orig_name, lf );
4530 font->use_logfont_name = substituted;
4531 font->matrix = dcmat;
4532 font->can_use_bitmap = can_use_bitmap;
4533 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
4534 font->charset = csi.ciCharset;
4535 font->codepage = csi.ciACP;
4537 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
4538 face->data_ptr, face->face_index );
4540 font->aveWidth = height ? lf->lfWidth : 0;
4541 if (!face->scalable)
4543 /* Windows uses integer scaling factors for bitmap fonts */
4544 INT scale, scaled_height, diff;
4545 struct gdi_font *cachedfont;
4547 if (height > 0)
4548 diff = height - (signed int)face->size.height;
4549 else
4550 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
4552 /* FIXME: rotation of bitmap fonts is ignored */
4553 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
4554 if (font->aveWidth)
4555 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
4556 font->matrix.eM11 = font->matrix.eM22 = 1.0;
4557 dcmat.eM11 = dcmat.eM22 = 1.0;
4558 /* As we changed the matrix, we need to search the cache for the font again,
4559 * otherwise we might explode the cache. */
4560 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4562 TRACE("Found cached font after non-scalable matrix rescale!\n");
4563 free_gdi_font( font );
4564 return cachedfont;
4567 if (height != 0) height = diff;
4568 height += face->size.height;
4570 scale = (height + face->size.height - 1) / face->size.height;
4571 scaled_height = scale * face->size.height;
4572 /* Only jump to the next height if the difference <= 25% original height */
4573 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4574 /* The jump between unscaled and doubled is delayed by 1 */
4575 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4576 font->scale_y = scale;
4577 TRACE("font scale y: %d\n", font->scale_y);
4580 if (!font_funcs->load_font( font ))
4582 free_gdi_font( font );
4583 return NULL;
4586 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
4587 font->vert_feature = get_GSUB_vert_feature( font );
4589 create_child_font_list( font );
4591 TRACE( "caching: gdiFont=%p\n", font );
4592 cache_gdi_font( font );
4593 return font;
4596 /*************************************************************
4597 * font_SelectFont
4599 static HFONT font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4601 struct font_physdev *physdev = get_font_dev( dev );
4602 struct gdi_font *font = NULL, *prev = physdev->font;
4603 DC *dc = get_physdev_dc( dev );
4605 if (hfont)
4607 LOGFONTW lf;
4608 FMAT2 dcmat;
4609 BOOL can_use_bitmap = !!(NtGdiGetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
4611 NtGdiExtGetObjectW( hfont, sizeof(lf), &lf );
4612 switch (lf.lfQuality)
4614 case NONANTIALIASED_QUALITY:
4615 if (!*aa_flags) *aa_flags = GGO_BITMAP;
4616 break;
4617 case ANTIALIASED_QUALITY:
4618 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
4619 break;
4622 if (lf.lfOutPrecision == OUT_TT_ONLY_PRECIS)
4623 can_use_bitmap = FALSE;
4625 lf.lfWidth = abs(lf.lfWidth);
4627 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4628 debugstr_w(lf.lfFaceName), (int)lf.lfHeight, lf.lfItalic,
4629 (int)lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, (int)lf.lfOrientation,
4630 (int)lf.lfEscapement );
4632 if (dc->attr->graphics_mode == GM_ADVANCED)
4634 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
4635 /* try to avoid not necessary glyph transformations */
4636 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4638 lf.lfHeight *= fabs(dcmat.eM11);
4639 lf.lfWidth *= fabs(dcmat.eM11);
4640 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4643 else
4645 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4646 dcmat.eM11 = dcmat.eM22 = 1.0;
4647 dcmat.eM21 = dcmat.eM12 = 0;
4648 lf.lfOrientation = lf.lfEscapement;
4649 if (dc->vport2WorldValid)
4651 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4652 lf.lfOrientation = -lf.lfOrientation;
4653 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4654 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4657 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
4659 pthread_mutex_lock( &font_lock );
4661 font = select_font( &lf, dcmat, can_use_bitmap );
4663 if (font)
4665 if (!*aa_flags) *aa_flags = font->aa_flags;
4666 if (!*aa_flags)
4668 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
4669 *aa_flags = subpixel_orientation;
4670 else
4671 *aa_flags = font_smoothing;
4673 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
4675 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), (int)lf.lfHeight, *aa_flags );
4676 pthread_mutex_unlock( &font_lock );
4678 physdev->font = font;
4679 if (prev) release_gdi_font( prev );
4680 return font ? hfont : 0;
4684 const struct gdi_dc_funcs font_driver =
4686 NULL, /* pAbortDoc */
4687 NULL, /* pAbortPath */
4688 NULL, /* pAlphaBlend */
4689 NULL, /* pAngleArc */
4690 NULL, /* pArc */
4691 NULL, /* pArcTo */
4692 NULL, /* pBeginPath */
4693 NULL, /* pBlendImage */
4694 NULL, /* pChord */
4695 NULL, /* pCloseFigure */
4696 NULL, /* pCreateCompatibleDC */
4697 font_CreateDC, /* pCreateDC */
4698 font_DeleteDC, /* pDeleteDC */
4699 NULL, /* pDeleteObject */
4700 NULL, /* pEllipse */
4701 NULL, /* pEndDoc */
4702 NULL, /* pEndPage */
4703 NULL, /* pEndPath */
4704 font_EnumFonts, /* pEnumFonts */
4705 NULL, /* pExtEscape */
4706 NULL, /* pExtFloodFill */
4707 NULL, /* pExtTextOut */
4708 NULL, /* pFillPath */
4709 NULL, /* pFillRgn */
4710 font_FontIsLinked, /* pFontIsLinked */
4711 NULL, /* pFrameRgn */
4712 NULL, /* pGetBoundsRect */
4713 font_GetCharABCWidths, /* pGetCharABCWidths */
4714 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
4715 font_GetCharWidth, /* pGetCharWidth */
4716 font_GetCharWidthInfo, /* pGetCharWidthInfo */
4717 NULL, /* pGetDeviceCaps */
4718 NULL, /* pGetDeviceGammaRamp */
4719 font_GetFontData, /* pGetFontData */
4720 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
4721 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
4722 font_GetGlyphIndices, /* pGetGlyphIndices */
4723 font_GetGlyphOutline, /* pGetGlyphOutline */
4724 NULL, /* pGetICMProfile */
4725 NULL, /* pGetImage */
4726 font_GetKerningPairs, /* pGetKerningPairs */
4727 NULL, /* pGetNearestColor */
4728 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
4729 NULL, /* pGetPixel */
4730 NULL, /* pGetSystemPaletteEntries */
4731 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
4732 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
4733 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
4734 font_GetTextFace, /* pGetTextFace */
4735 font_GetTextMetrics, /* pGetTextMetrics */
4736 NULL, /* pGradientFill */
4737 NULL, /* pInvertRgn */
4738 NULL, /* pLineTo */
4739 NULL, /* pMoveTo */
4740 NULL, /* pPaintRgn */
4741 NULL, /* pPatBlt */
4742 NULL, /* pPie */
4743 NULL, /* pPolyBezier */
4744 NULL, /* pPolyBezierTo */
4745 NULL, /* pPolyDraw */
4746 NULL, /* pPolyPolygon */
4747 NULL, /* pPolyPolyline */
4748 NULL, /* pPolylineTo */
4749 NULL, /* pPutImage */
4750 NULL, /* pRealizeDefaultPalette */
4751 NULL, /* pRealizePalette */
4752 NULL, /* pRectangle */
4753 NULL, /* pResetDC */
4754 NULL, /* pRoundRect */
4755 NULL, /* pSelectBitmap */
4756 NULL, /* pSelectBrush */
4757 font_SelectFont, /* pSelectFont */
4758 NULL, /* pSelectPen */
4759 NULL, /* pSetBkColor */
4760 NULL, /* pSetBoundsRect */
4761 NULL, /* pSetDCBrushColor */
4762 NULL, /* pSetDCPenColor */
4763 NULL, /* pSetDIBitsToDevice */
4764 NULL, /* pSetDeviceClipping */
4765 NULL, /* pSetDeviceGammaRamp */
4766 NULL, /* pSetPixel */
4767 NULL, /* pSetTextColor */
4768 NULL, /* pStartDoc */
4769 NULL, /* pStartPage */
4770 NULL, /* pStretchBlt */
4771 NULL, /* pStretchDIBits */
4772 NULL, /* pStrokeAndFillPath */
4773 NULL, /* pStrokePath */
4774 NULL, /* pUnrealizePalette */
4775 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
4776 NULL, /* pD3DKMTCloseAdapter */
4777 NULL, /* pD3DKMTOpenAdapterFromLuid */
4778 NULL, /* pD3DKMTQueryVideoMemoryInfo */
4779 NULL, /* pD3DKMTSetVidPnSourceOwner */
4780 GDI_PRIORITY_FONT_DRV /* priority */
4783 static BOOL get_key_value( HKEY key, const char *name, DWORD *value )
4785 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[12 * sizeof(WCHAR)])];
4786 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4787 DWORD count;
4789 count = query_reg_ascii_value( key, name, info, sizeof(value_buffer) );
4790 if (count)
4792 if (info->Type == REG_DWORD) memcpy( value, info->Data, sizeof(*value) );
4793 else *value = wcstol( (const WCHAR *)info->Data, NULL, 10 );
4795 return !!count;
4798 static UINT init_font_options(void)
4800 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[20 * sizeof(WCHAR)])];
4801 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4802 HKEY key;
4803 DWORD i, val, gamma = 1400;
4804 UINT dpi = 0;
4806 if (query_reg_ascii_value( wine_fonts_key, "AntialiasFakeBoldOrItalic",
4807 info, sizeof(value_buffer) ) && info->Type == REG_SZ)
4809 static const WCHAR valsW[] = {'y','Y','t','T','1',0};
4810 antialias_fakes = (wcschr( valsW, *(const WCHAR *)info->Data ) != NULL);
4813 if ((key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
4815 /* FIXME: handle vertical orientations even though Windows doesn't */
4816 if (get_key_value( key, "FontSmoothingOrientation", &val ))
4818 switch (val)
4820 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4821 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
4822 break;
4823 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4824 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
4825 break;
4828 if (get_key_value( key, "FontSmoothing", &val ) && val /* enabled */)
4830 if (get_key_value( key, "FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4831 font_smoothing = subpixel_orientation;
4832 else
4833 font_smoothing = GGO_GRAY4_BITMAP;
4835 if (get_key_value( key, "FontSmoothingGamma", &val ) && val)
4837 gamma = min( max( val, 1000 ), 2200 );
4839 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4840 NtClose( key );
4843 /* Calibrating the difference between the registry value and the Wine gamma value.
4844 This looks roughly similar to Windows Native with the same registry value.
4845 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4846 gamma = 1000 * gamma / 1400;
4847 if (gamma != 1000)
4849 for (i = 0; i < 256; i++)
4851 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
4852 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
4856 if (!dpi && (key = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) )))
4858 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4859 NtClose( key );
4861 if (!dpi) dpi = 96;
4863 font_gamma_ramp.gamma = gamma;
4864 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp.gamma, dpi );
4865 return dpi;
4869 /* compute positions for text rendering, in device coords */
4870 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4872 TEXTMETRICW tm;
4873 PHYSDEV dev;
4875 size->cx = size->cy = 0;
4876 if (!count) return TRUE;
4878 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4879 dev->funcs->pGetTextMetrics( dev, &tm );
4881 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4882 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4884 if (dc->breakExtra || dc->breakRem)
4886 int i, space = 0, rem = dc->breakRem;
4888 for (i = 0; i < count; i++)
4890 if (str[i] == tm.tmBreakChar)
4892 space += dc->breakExtra;
4893 if (rem > 0)
4895 space++;
4896 rem--;
4899 dx[i] += space;
4902 size->cx = dx[count - 1];
4903 size->cy = tm.tmHeight;
4904 return TRUE;
4907 /* compute positions for text rendering, in device coords */
4908 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4910 TEXTMETRICW tm;
4911 PHYSDEV dev;
4913 size->cx = size->cy = 0;
4914 if (!count) return TRUE;
4916 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4917 dev->funcs->pGetTextMetrics( dev, &tm );
4919 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4920 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4922 if (dc->breakExtra || dc->breakRem)
4924 WORD space_index;
4925 int i, space = 0, rem = dc->breakRem;
4927 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4928 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4930 for (i = 0; i < count; i++)
4932 if (indices[i] == space_index)
4934 space += dc->breakExtra;
4935 if (rem > 0)
4937 space++;
4938 rem--;
4941 dx[i] += space;
4944 size->cx = dx[count - 1];
4945 size->cy = tm.tmHeight;
4946 return TRUE;
4949 /***********************************************************************
4950 * get_text_charset_info
4952 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4954 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4956 UINT ret = DEFAULT_CHARSET;
4957 PHYSDEV dev;
4959 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4960 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4962 if (ret == DEFAULT_CHARSET && fs)
4963 memset(fs, 0, sizeof(FONTSIGNATURE));
4964 return ret;
4967 /***********************************************************************
4968 * NtGdiGetTextCharsetInfo (win32u.@)
4970 UINT WINAPI NtGdiGetTextCharsetInfo( HDC hdc, FONTSIGNATURE *fs, DWORD flags )
4972 UINT ret = DEFAULT_CHARSET;
4973 DC *dc = get_dc_ptr(hdc);
4975 if (dc)
4977 ret = get_text_charset_info( dc, fs, flags );
4978 release_dc_ptr( dc );
4980 return ret;
4983 /***********************************************************************
4984 * NtGdiHfontCreate (win32u.@)
4986 HFONT WINAPI NtGdiHfontCreate( const void *logfont, ULONG size, ULONG type,
4987 ULONG flags, void *data )
4989 HFONT hFont;
4990 FONTOBJ *fontPtr;
4991 const LOGFONTW *plf;
4993 if (!logfont) return 0;
4995 if (size == sizeof(ENUMLOGFONTEXDVW) || size == sizeof(ENUMLOGFONTEXW))
4997 const ENUMLOGFONTEXW *lfex = logfont;
4999 if (lfex->elfFullName[0] || lfex->elfStyle[0] || lfex->elfScript[0])
5001 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
5002 debugstr_w( lfex->elfFullName ), debugstr_w( lfex->elfStyle ),
5003 debugstr_w( lfex->elfScript ));
5006 plf = &lfex->elfLogFont;
5008 else if (size != sizeof(LOGFONTW))
5010 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
5011 return 0;
5013 else plf = logfont;
5015 if (!(fontPtr = malloc( sizeof(*fontPtr) ))) return 0;
5017 fontPtr->logfont = *plf;
5019 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, NTGDI_OBJ_FONT, &fontobj_funcs )))
5021 free( fontPtr );
5022 return 0;
5025 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
5026 (int)plf->lfHeight, (int)plf->lfWidth,
5027 (int)plf->lfEscapement, (int)plf->lfOrientation,
5028 plf->lfPitchAndFamily,
5029 plf->lfOutPrecision, plf->lfClipPrecision,
5030 plf->lfQuality, plf->lfCharSet,
5031 debugstr_w(plf->lfFaceName),
5032 plf->lfWeight > 400 ? "Bold" : "",
5033 plf->lfItalic ? "Italic" : "",
5034 plf->lfUnderline ? "Underline" : "", hFont);
5036 return hFont;
5039 #define ASSOC_CHARSET_OEM 1
5040 #define ASSOC_CHARSET_ANSI 2
5041 #define ASSOC_CHARSET_SYMBOL 4
5043 static DWORD get_associated_charset_info(void)
5045 static int associated_charset = -1;
5047 if (associated_charset == -1)
5049 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[32 * sizeof(WCHAR)])];
5050 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
5051 HKEY hkey;
5053 static const WCHAR yesW[] = {'y','e','s',0};
5055 associated_charset = 0;
5057 if (!(hkey = reg_open_key( NULL, associated_charset_keyW, sizeof(associated_charset_keyW) )))
5058 return 0;
5060 if (query_reg_ascii_value( hkey, "ANSI(00)", info, sizeof(value_buffer) ) &&
5061 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5062 associated_charset |= ASSOC_CHARSET_ANSI;
5064 if (query_reg_ascii_value( hkey, "OEM(FF)", info, sizeof(value_buffer) ) &&
5065 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5066 associated_charset |= ASSOC_CHARSET_OEM;
5068 if (query_reg_ascii_value( hkey, "SYMBOL(02)", info, sizeof(value_buffer) ) &&
5069 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
5070 associated_charset |= ASSOC_CHARSET_SYMBOL;
5072 NtClose( hkey );
5074 TRACE("associated_charset = %d\n", associated_charset);
5077 return associated_charset;
5080 static void update_font_code_page( DC *dc, HANDLE font )
5082 CHARSETINFO csi;
5083 int charset = get_text_charset_info( dc, NULL, 0 );
5085 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
5087 LOGFONTW lf;
5089 NtGdiExtGetObjectW( font, sizeof(lf), &lf );
5090 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
5091 charset = DEFAULT_CHARSET;
5094 /* Hmm, nicely designed api this one! */
5095 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
5096 dc->attr->font_code_page = csi.ciACP;
5097 else {
5098 switch(charset) {
5099 case OEM_CHARSET:
5100 dc->attr->font_code_page = oem_cp.CodePage;
5101 break;
5102 case DEFAULT_CHARSET:
5103 dc->attr->font_code_page = ansi_cp.CodePage;
5104 break;
5106 case VISCII_CHARSET:
5107 case TCVN_CHARSET:
5108 case KOI8_CHARSET:
5109 case ISO3_CHARSET:
5110 case ISO4_CHARSET:
5111 case ISO10_CHARSET:
5112 case CELTIC_CHARSET:
5113 /* FIXME: These have no place here, but because x11drv
5114 enumerates fonts with these (made up) charsets some apps
5115 might use them and then the FIXME below would become
5116 annoying. Now we could pick the intended codepage for
5117 each of these, but since it's broken anyway we'll just
5118 use CP_ACP and hope it'll go away...
5120 dc->attr->font_code_page = CP_ACP;
5121 break;
5123 default:
5124 FIXME("Can't find codepage for charset %d\n", charset);
5125 dc->attr->font_code_page = CP_ACP;
5126 break;
5130 TRACE( "charset %d => cp %d\n", charset, dc->attr->font_code_page );
5133 /***********************************************************************
5134 * NtGdiSelectFont (win32u.@)
5136 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
5138 HGDIOBJ ret = 0;
5139 DC *dc = get_dc_ptr( hdc );
5140 PHYSDEV physdev;
5141 UINT aa_flags = 0;
5143 if (!dc) return 0;
5145 if (!GDI_inc_ref_count( handle ))
5147 release_dc_ptr( dc );
5148 return 0;
5151 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
5152 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
5154 ret = dc->hFont;
5155 dc->hFont = handle;
5156 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
5157 update_font_code_page( dc, handle );
5158 if (dc->font_gamma_ramp == NULL)
5159 dc->font_gamma_ramp = &font_gamma_ramp;
5160 GDI_dec_ref_count( ret );
5162 else GDI_dec_ref_count( handle );
5164 release_dc_ptr( dc );
5165 return ret;
5169 /***********************************************************************
5170 * FONT_GetObjectW
5172 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
5174 FONTOBJ *font = GDI_GetObjPtr( handle, NTGDI_OBJ_FONT );
5176 if (!font) return 0;
5177 if (buffer)
5179 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
5180 memcpy( buffer, &font->logfont, count );
5182 else count = sizeof(LOGFONTW);
5183 GDI_ReleaseObj( handle );
5184 return count;
5188 /***********************************************************************
5189 * FONT_DeleteObject
5191 static BOOL FONT_DeleteObject( HGDIOBJ handle )
5193 FONTOBJ *obj;
5195 if (!(obj = free_gdi_handle( handle ))) return FALSE;
5196 free( obj );
5197 return TRUE;
5201 struct font_enum
5203 HDC hdc;
5204 struct font_enum_entry *buf;
5205 ULONG size;
5206 ULONG count;
5207 ULONG charset;
5210 static INT WINAPI font_enum_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
5211 DWORD type, LPARAM lp )
5213 struct font_enum *fe = (struct font_enum *)lp;
5215 if (fe->charset != DEFAULT_CHARSET && lf->lfCharSet != fe->charset) return 1;
5216 if ((type & RASTER_FONTTYPE) && !(NtGdiGetDeviceCaps( fe->hdc, TEXTCAPS ) & TC_RA_ABLE))
5217 return 1;
5219 if (fe->buf && fe->count < fe->size)
5221 fe->buf[fe->count].type = type;
5222 fe->buf[fe->count].lf = *(const ENUMLOGFONTEXW *)lf;
5223 fe->buf[fe->count].tm = *(const NEWTEXTMETRICEXW *)tm;
5225 fe->count++;
5226 return 1;
5229 /***********************************************************************
5230 * NtGdiEnumFonts (win32u.@)
5232 BOOL WINAPI NtGdiEnumFonts( HDC hdc, ULONG type, ULONG win32_compat, ULONG face_name_len,
5233 const WCHAR *face_name, ULONG charset, ULONG *count, void *buf )
5235 struct font_enum fe;
5236 PHYSDEV physdev;
5237 LOGFONTW lf;
5238 BOOL ret;
5239 DC *dc;
5241 if (!(dc = get_dc_ptr( hdc ))) return 0;
5243 memset( &lf, 0, sizeof(lf) );
5244 lf.lfCharSet = charset;
5245 if (face_name_len) memcpy( lf.lfFaceName, face_name, face_name_len * sizeof(WCHAR) );
5247 fe.hdc = hdc;
5248 fe.buf = buf;
5249 fe.size = *count / sizeof(*fe.buf);
5250 fe.count = 0;
5251 fe.charset = charset;
5253 physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
5254 ret = physdev->funcs->pEnumFonts( physdev, &lf, font_enum_proc, (LPARAM)&fe );
5255 if (ret && buf) ret = fe.count <= fe.size;
5256 *count = fe.count * sizeof(*fe.buf);
5258 release_dc_ptr( dc );
5259 return ret;
5263 /***********************************************************************
5264 * NtGdiSetTextJustification (win32u.@)
5266 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
5268 DC *dc;
5270 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5272 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
5273 dc->attr->wnd_ext.cx );
5274 if (!extra) breaks = 0;
5275 if (breaks)
5277 dc->breakExtra = extra / breaks;
5278 dc->breakRem = extra - (breaks * dc->breakExtra);
5280 else
5282 dc->breakExtra = 0;
5283 dc->breakRem = 0;
5286 release_dc_ptr( dc );
5287 return TRUE;
5291 /***********************************************************************
5292 * NtGdiGetTextFaceW (win32u.@)
5294 INT WINAPI NtGdiGetTextFaceW( HDC hdc, INT count, WCHAR *name, BOOL alias_name )
5296 PHYSDEV dev;
5297 INT ret;
5299 DC * dc = get_dc_ptr( hdc );
5300 if (!dc) return 0;
5302 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
5303 ret = dev->funcs->pGetTextFace( dev, count, name );
5304 release_dc_ptr( dc );
5305 return ret;
5309 /***********************************************************************
5310 * NtGdiGetTextExtentExW (win32u.@)
5312 * Return the size of the string as it would be if it was output properly by
5313 * e.g. TextOut.
5315 BOOL WINAPI NtGdiGetTextExtentExW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
5316 INT *nfit, INT *dxs, SIZE *size, UINT flags )
5318 DC *dc;
5319 int i;
5320 BOOL ret;
5321 INT buffer[256], *pos = dxs;
5323 if (count < 0) return FALSE;
5325 dc = get_dc_ptr(hdc);
5326 if (!dc) return FALSE;
5328 if (!dxs)
5330 pos = buffer;
5331 if (count > 256 && !(pos = malloc( count * sizeof(*pos) )))
5333 release_dc_ptr( dc );
5334 return FALSE;
5339 if (flags)
5340 ret = get_char_positions_indices( dc, str, count, pos, size );
5341 else
5342 ret = get_char_positions( dc, str, count, pos, size );
5343 if (ret)
5345 if (dxs || nfit)
5347 for (i = 0; i < count; i++)
5349 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
5350 (i + 1) * dc->attr->char_extra;
5351 if (nfit && dx > (unsigned int)max_ext) break;
5352 if (dxs) dxs[i] = dx;
5354 if (nfit) *nfit = i;
5357 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
5358 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5361 if (pos != buffer && pos != dxs) free( pos );
5362 release_dc_ptr( dc );
5364 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count),
5365 max_ext, (int)size->cx, (int)size->cy );
5366 return ret;
5369 /***********************************************************************
5370 * NtGdiGetTextMetricsW (win32u.@)
5372 BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags )
5374 PHYSDEV physdev;
5375 BOOL ret = FALSE;
5376 DC * dc = get_dc_ptr( hdc );
5377 if (!dc) return FALSE;
5379 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5380 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5382 if (ret)
5384 /* device layer returns values in device units
5385 * therefore we have to convert them to logical */
5387 metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5388 metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5389 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5390 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5391 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5392 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5393 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5394 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5395 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5396 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5397 ret = TRUE;
5399 TRACE("text metrics:\n"
5400 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5401 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5402 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5403 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5404 " PitchAndFamily = %02x\n"
5405 " --------------------\n"
5406 " InternalLeading = %i\n"
5407 " Ascent = %i\n"
5408 " Descent = %i\n"
5409 " Height = %i\n",
5410 (int)metrics->tmWeight, metrics->tmFirstChar, (int)metrics->tmAveCharWidth,
5411 metrics->tmItalic, metrics->tmLastChar, (int)metrics->tmMaxCharWidth,
5412 metrics->tmUnderlined, metrics->tmDefaultChar, (int)metrics->tmOverhang,
5413 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5414 metrics->tmPitchAndFamily,
5415 (int)metrics->tmInternalLeading,
5416 (int)metrics->tmAscent,
5417 (int)metrics->tmDescent,
5418 (int)metrics->tmHeight );
5420 release_dc_ptr( dc );
5421 return ret;
5425 /***********************************************************************
5426 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
5428 UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData,
5429 OUTLINETEXTMETRICW *lpOTM, ULONG opts )
5431 DC *dc = get_dc_ptr( hdc );
5432 OUTLINETEXTMETRICW *output = lpOTM;
5433 PHYSDEV dev;
5434 UINT ret;
5436 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5437 if(!dc) return 0;
5439 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5440 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5442 if (lpOTM && ret > cbData)
5444 output = malloc( ret );
5445 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5448 if (lpOTM && ret)
5450 output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5451 output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5452 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5453 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5454 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5455 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5456 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5457 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5458 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5459 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5460 output->otmAscent = height_to_LP( dc, output->otmAscent);
5461 output->otmDescent = height_to_LP( dc, output->otmDescent);
5462 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5463 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5464 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5465 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5466 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5467 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5468 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5469 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5470 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5471 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5472 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5473 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5474 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5475 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5476 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5477 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5478 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5479 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5480 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5481 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5482 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5483 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5485 if(output != lpOTM)
5487 memcpy(lpOTM, output, cbData);
5488 free( output );
5489 ret = cbData;
5492 release_dc_ptr(dc);
5493 return ret;
5496 /***********************************************************************
5497 * NtGdiGetCharWidthW (win32u.@)
5499 BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5500 ULONG flags, void *buf )
5502 UINT i, count = last;
5503 BOOL ret;
5504 PHYSDEV dev;
5505 DC *dc;
5507 if (flags & NTGDI_GETCHARWIDTH_INDICES)
5509 ABC *abc;
5510 unsigned int i;
5512 if (!(abc = malloc( count * sizeof(ABC) )))
5513 return FALSE;
5515 if (!NtGdiGetCharABCWidthsW( hdc, first, last, chars,
5516 NTGDI_GETCHARABCWIDTHS_INT | NTGDI_GETCHARABCWIDTHS_INDICES,
5517 abc ))
5519 free( abc );
5520 return FALSE;
5523 for (i = 0; i < count; i++)
5524 ((INT *)buf)[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5526 free( abc );
5527 return TRUE;
5530 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5532 if (!chars) count = last - first + 1;
5533 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5534 ret = dev->funcs->pGetCharWidth( dev, first, count, chars, buf );
5536 if (ret)
5538 if (flags & NTGDI_GETCHARWIDTH_INT)
5540 INT *buffer = buf;
5541 /* convert device units to logical */
5542 for (i = 0; i < count; i++)
5543 buffer[i] = width_to_LP( dc, buffer[i] );
5545 else
5547 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
5548 for (i = 0; i < count; i++)
5549 ((float *)buf)[i] = ((int *)buf)[i] * scale;
5552 release_dc_ptr( dc );
5553 return ret;
5557 /* helper for nulldrv_ExtTextOut */
5558 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5559 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5561 UINT indices[3] = {0, 0, 0x20};
5562 unsigned int i;
5563 DWORD ret, size;
5564 int stride;
5566 indices[0] = index;
5567 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5569 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5571 index = indices[i];
5572 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, 0, NULL, &identity, FALSE );
5573 if (ret != GDI_ERROR) break;
5576 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5577 if (!image) return ERROR_SUCCESS;
5579 image->ptr = NULL;
5580 image->free = NULL;
5581 if (!ret) /* empty glyph */
5583 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5584 return ERROR_SUCCESS;
5587 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5588 size = metrics->gmBlackBoxY * stride;
5590 if (!(image->ptr = malloc( size ))) return ERROR_OUTOFMEMORY;
5591 image->is_copy = TRUE;
5592 image->free = free_heap_bits;
5594 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, size, image->ptr,
5595 &identity, FALSE );
5596 if (ret == GDI_ERROR)
5598 free( image->ptr );
5599 return ERROR_NOT_FOUND;
5601 return ERROR_SUCCESS;
5604 /* helper for nulldrv_ExtTextOut */
5605 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5606 LPCWSTR str, UINT count, const INT *dx )
5608 UINT i;
5609 RECT rect, bounds;
5611 reset_bounds( &bounds );
5612 for (i = 0; i < count; i++)
5614 GLYPHMETRICS metrics;
5616 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5618 rect.left = x + metrics.gmptGlyphOrigin.x;
5619 rect.top = y - metrics.gmptGlyphOrigin.y;
5620 rect.right = rect.left + metrics.gmBlackBoxX;
5621 rect.bottom = rect.top + metrics.gmBlackBoxY;
5622 add_bounds_rect( &bounds, &rect );
5624 if (dx)
5626 if (flags & ETO_PDY)
5628 x += dx[ i * 2 ];
5629 y += dx[ i * 2 + 1];
5631 else x += dx[ i ];
5633 else
5635 x += metrics.gmCellIncX;
5636 y += metrics.gmCellIncY;
5639 return bounds;
5642 /* helper for nulldrv_ExtTextOut */
5643 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5644 const struct gdi_image_bits *image, const RECT *clip )
5646 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5647 UINT i, count, max_count;
5648 LONG x, y;
5649 BYTE *ptr = image->ptr;
5650 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5651 POINT *pts;
5652 RECT rect, clipped_rect;
5654 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5655 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5656 rect.right = rect.left + metrics->gmBlackBoxX;
5657 rect.bottom = rect.top + metrics->gmBlackBoxY;
5658 if (!clip) clipped_rect = rect;
5659 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5661 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5662 pts = malloc( max_count * sizeof(*pts) );
5663 if (!pts) return;
5665 count = 0;
5666 ptr += (clipped_rect.top - rect.top) * stride;
5667 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5669 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5671 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5672 pts[count].x = rect.left + x;
5673 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5674 pts[count + 1].x = rect.left + x;
5675 if (pts[count + 1].x > pts[count].x)
5677 pts[count].y = pts[count + 1].y = y;
5678 count += 2;
5682 assert( count <= max_count );
5683 dp_to_lp( dc, pts, count );
5684 for (i = 0; i < count; i += 2)
5686 const ULONG pts_count = 2;
5687 NtGdiPolyPolyDraw( dc->hSelf, pts + i, &pts_count, 1, NtGdiPolyPolyline );
5689 free( pts );
5692 /***********************************************************************
5693 * nulldrv_ExtTextOut
5695 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5696 LPCWSTR str, UINT count, const INT *dx )
5698 DC *dc = get_nulldrv_dc( dev );
5699 UINT i;
5700 DWORD err;
5701 HGDIOBJ orig;
5702 HPEN pen;
5704 if (flags & ETO_OPAQUE)
5706 RECT rc = *rect;
5707 COLORREF brush_color = NtGdiGetNearestColor( dev->hdc, dc->attr->background_color );
5708 HBRUSH brush = NtGdiCreateSolidBrush( brush_color, NULL);
5710 if (brush)
5712 orig = NtGdiSelectBrush( dev->hdc, brush );
5713 dp_to_lp( dc, (POINT *)&rc, 2 );
5714 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5715 NtGdiSelectBrush( dev->hdc, orig );
5716 NtGdiDeleteObjectApp( brush );
5720 if (!count) return TRUE;
5722 if (dc->aa_flags != GGO_BITMAP)
5724 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5725 BITMAPINFO *info = (BITMAPINFO *)buffer;
5726 struct gdi_image_bits bits;
5727 struct bitblt_coords src, dst;
5728 PHYSDEV dst_dev;
5729 /* FIXME Subpixel modes */
5730 UINT aa_flags = GGO_GRAY4_BITMAP;
5732 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5733 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5734 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5735 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5737 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5738 src.x = src.visrect.left;
5739 src.y = src.visrect.top;
5740 src.width = src.visrect.right - src.visrect.left;
5741 src.height = src.visrect.bottom - src.visrect.top;
5742 dst = src;
5743 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5744 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5746 /* we can avoid the GetImage, just query the needed format */
5747 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5748 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5749 info->bmiHeader.biWidth = src.width;
5750 info->bmiHeader.biHeight = -src.height;
5751 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5752 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5753 if (!err || err == ERROR_BAD_FORMAT)
5755 /* make the source rectangle relative to the source bits */
5756 src.x = src.y = 0;
5757 src.visrect.left = src.visrect.top = 0;
5758 src.visrect.right = src.width;
5759 src.visrect.bottom = src.height;
5761 bits.ptr = malloc( info->bmiHeader.biSizeImage );
5762 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5763 bits.is_copy = TRUE;
5764 bits.free = free_heap_bits;
5765 err = ERROR_SUCCESS;
5768 else
5770 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5771 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5772 if (!err && !bits.is_copy)
5774 void *ptr = malloc( info->bmiHeader.biSizeImage );
5775 if (!ptr)
5777 if (bits.free) bits.free( &bits );
5778 return ERROR_OUTOFMEMORY;
5780 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5781 if (bits.free) bits.free( &bits );
5782 bits.ptr = ptr;
5783 bits.is_copy = TRUE;
5784 bits.free = free_heap_bits;
5787 if (!err)
5789 /* make x,y relative to the image bits */
5790 x += src.visrect.left - dst.visrect.left;
5791 y += src.visrect.top - dst.visrect.top;
5792 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5793 aa_flags, str, count, dx );
5794 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5795 if (bits.free) bits.free( &bits );
5796 return !err;
5800 pen = NtGdiCreatePen( PS_SOLID, 1, dc->attr->text_color, NULL );
5801 orig = NtGdiSelectPen( dev->hdc, pen );
5803 for (i = 0; i < count; i++)
5805 GLYPHMETRICS metrics;
5806 struct gdi_image_bits image;
5808 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5809 if (err) continue;
5811 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5812 if (image.free) image.free( &image );
5814 if (dx)
5816 if (flags & ETO_PDY)
5818 x += dx[ i * 2 ];
5819 y += dx[ i * 2 + 1];
5821 else x += dx[ i ];
5823 else
5825 x += metrics.gmCellIncX;
5826 y += metrics.gmCellIncY;
5830 NtGdiSelectPen( dev->hdc, orig );
5831 NtGdiDeleteObjectApp( pen );
5832 return TRUE;
5835 /***********************************************************************
5836 * get_line_width
5838 * Scale the underline / strikeout line width.
5840 static inline int get_line_width( DC *dc, int metric_size )
5842 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5843 if (width == 0) width = 1;
5844 if (metric_size < 0) width = -width;
5845 return width;
5848 /***********************************************************************
5849 * NtGdiExtTextOutW (win32u.@)
5851 * Draws text using the currently selected font, background color, and text color.
5854 * PARAMS
5855 * x,y [I] coordinates of string
5856 * flags [I]
5857 * ETO_GRAYED - undocumented on MSDN
5858 * ETO_OPAQUE - use background color for fill the rectangle
5859 * ETO_CLIPPED - clipping text to the rectangle
5860 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5861 * than encoded characters. Implies ETO_IGNORELANGUAGE
5862 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5863 * Affects BiDi ordering
5864 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5865 * ETO_PDY - unimplemented
5866 * ETO_NUMERICSLATIN - unimplemented always assumed -
5867 * do not translate numbers into locale representations
5868 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5869 * lprect [I] dimensions for clipping or/and opaquing
5870 * str [I] text string
5871 * count [I] number of symbols in string
5872 * lpDx [I] optional parameter with distance between drawing characters
5874 * RETURNS
5875 * Success: TRUE
5876 * Failure: FALSE
5878 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5879 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5881 BOOL ret = FALSE;
5882 UINT align;
5883 DWORD layout;
5884 POINT pt;
5885 TEXTMETRICW tm;
5886 LOGFONTW lf;
5887 double cosEsc, sinEsc;
5888 INT char_extra;
5889 SIZE sz;
5890 RECT rc;
5891 POINT *deltas = NULL, width = {0, 0};
5892 DC * dc = get_dc_ptr( hdc );
5893 PHYSDEV physdev;
5894 INT breakRem;
5895 static int quietfixme = 0;
5897 if (!dc) return FALSE;
5898 if (count > INT_MAX) return FALSE;
5900 align = dc->attr->text_align;
5901 breakRem = dc->breakRem;
5902 layout = dc->attr->layout;
5904 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5906 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5907 quietfixme = 1;
5910 update_dc( dc );
5911 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5913 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5914 if (layout & LAYOUT_RTL)
5916 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5917 align ^= TA_RTLREADING;
5920 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5921 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5922 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5923 dc->attr->map_mode);
5925 if(align & TA_UPDATECP)
5927 pt = dc->attr->cur_pos;
5928 x = pt.x;
5929 y = pt.y;
5932 NtGdiGetTextMetricsW( hdc, &tm, 0 );
5933 NtGdiExtGetObjectW( dc->hFont, sizeof(lf), &lf );
5935 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5936 lf.lfEscapement = 0;
5938 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5939 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5941 lf.lfEscapement = -lf.lfEscapement;
5944 if(lf.lfEscapement != 0)
5946 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5947 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5949 else
5951 cosEsc = 1;
5952 sinEsc = 0;
5955 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5957 rc = *lprect;
5958 lp_to_dp(dc, (POINT*)&rc, 2);
5959 order_rect( &rc );
5960 if (flags & ETO_OPAQUE)
5961 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5963 else flags &= ~ETO_CLIPPED;
5965 if(count == 0)
5967 ret = TRUE;
5968 goto done;
5971 pt.x = x;
5972 pt.y = y;
5973 lp_to_dp(dc, &pt, 1);
5974 x = pt.x;
5975 y = pt.y;
5977 char_extra = dc->attr->char_extra;
5978 if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5979 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5981 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
5983 UINT i;
5984 POINT total = {0, 0}, desired[2];
5986 deltas = malloc( count * sizeof(*deltas) );
5987 if (lpDx)
5989 if (flags & ETO_PDY)
5991 for (i = 0; i < count; i++)
5993 deltas[i].x = lpDx[i * 2] + char_extra;
5994 deltas[i].y = -lpDx[i * 2 + 1];
5997 else
5999 for (i = 0; i < count; i++)
6001 deltas[i].x = lpDx[i] + char_extra;
6002 deltas[i].y = 0;
6006 else
6008 INT *dx = malloc( count * sizeof(*dx) );
6010 NtGdiGetTextExtentExW( hdc, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX) );
6012 deltas[0].x = dx[0];
6013 deltas[0].y = 0;
6014 for (i = 1; i < count; i++)
6016 deltas[i].x = dx[i] - dx[i - 1];
6017 deltas[i].y = 0;
6019 free( dx );
6022 for(i = 0; i < count; i++)
6024 total.x += deltas[i].x;
6025 total.y += deltas[i].y;
6027 desired[0].x = desired[0].y = 0;
6029 desired[1].x = cosEsc * total.x + sinEsc * total.y;
6030 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
6032 lp_to_dp(dc, desired, 2);
6033 desired[1].x -= desired[0].x;
6034 desired[1].y -= desired[0].y;
6036 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6038 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6039 desired[1].x = -desired[1].x;
6040 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6041 desired[1].y = -desired[1].y;
6044 deltas[i].x = desired[1].x - width.x;
6045 deltas[i].y = desired[1].y - width.y;
6047 width = desired[1];
6049 flags |= ETO_PDY;
6051 else
6053 POINT desired[2];
6055 NtGdiGetTextExtentExW( hdc, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX) );
6056 desired[0].x = desired[0].y = 0;
6057 desired[1].x = sz.cx;
6058 desired[1].y = 0;
6059 lp_to_dp(dc, desired, 2);
6060 desired[1].x -= desired[0].x;
6061 desired[1].y -= desired[0].y;
6063 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6065 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6066 desired[1].x = -desired[1].x;
6067 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6068 desired[1].y = -desired[1].y;
6070 width = desired[1];
6073 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
6074 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
6075 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
6077 case TA_LEFT:
6078 if (align & TA_UPDATECP)
6080 pt.x = x + width.x;
6081 pt.y = y + width.y;
6082 dp_to_lp(dc, &pt, 1);
6083 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6085 break;
6087 case TA_CENTER:
6088 x -= width.x / 2;
6089 y -= width.y / 2;
6090 break;
6092 case TA_RIGHT:
6093 x -= width.x;
6094 y -= width.y;
6095 if (align & TA_UPDATECP)
6097 pt.x = x;
6098 pt.y = y;
6099 dp_to_lp(dc, &pt, 1);
6100 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6102 break;
6105 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
6107 case TA_TOP:
6108 y += tm.tmAscent * cosEsc;
6109 x += tm.tmAscent * sinEsc;
6110 break;
6112 case TA_BOTTOM:
6113 y -= tm.tmDescent * cosEsc;
6114 x -= tm.tmDescent * sinEsc;
6115 break;
6117 case TA_BASELINE:
6118 break;
6121 if (dc->attr->background_mode != TRANSPARENT)
6123 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
6125 if(!(flags & ETO_OPAQUE) || !lprect ||
6126 x < rc.left || x + width.x >= rc.right ||
6127 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
6129 RECT text_box;
6130 text_box.left = x;
6131 text_box.right = x + width.x;
6132 text_box.top = y - tm.tmAscent;
6133 text_box.bottom = y + tm.tmDescent;
6135 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
6136 if (!IsRectEmpty( &text_box ))
6137 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
6142 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
6143 str, count, (INT*)deltas );
6145 done:
6146 free( deltas );
6148 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
6150 int underlinePos, strikeoutPos;
6151 int underlineWidth, strikeoutWidth;
6152 UINT size = NtGdiGetOutlineTextMetricsInternalW( hdc, 0, NULL, 0 );
6153 OUTLINETEXTMETRICW* otm = NULL;
6154 POINT pts[5];
6155 HPEN hpen = NtGdiSelectPen( hdc, GetStockObject(NULL_PEN) );
6156 HBRUSH hbrush = NtGdiCreateSolidBrush( dc->attr->text_color, NULL );
6158 hbrush = NtGdiSelectBrush(hdc, hbrush);
6160 if(!size)
6162 underlinePos = 0;
6163 underlineWidth = tm.tmAscent / 20 + 1;
6164 strikeoutPos = tm.tmAscent / 2;
6165 strikeoutWidth = underlineWidth;
6167 else
6169 otm = malloc( size );
6170 NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
6171 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
6172 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
6173 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
6174 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
6175 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
6176 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
6177 free( otm );
6181 if (lf.lfUnderline)
6183 const ULONG cnt = 5;
6184 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
6185 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
6186 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
6187 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
6188 pts[2].x = pts[1].x + underlineWidth * sinEsc;
6189 pts[2].y = pts[1].y + underlineWidth * cosEsc;
6190 pts[3].x = pts[0].x + underlineWidth * sinEsc;
6191 pts[3].y = pts[0].y + underlineWidth * cosEsc;
6192 pts[4].x = pts[0].x;
6193 pts[4].y = pts[0].y;
6194 dp_to_lp(dc, pts, 5);
6195 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6198 if (lf.lfStrikeOut)
6200 const ULONG cnt = 5;
6201 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6202 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6203 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6204 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6205 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
6206 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
6207 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
6208 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
6209 pts[4].x = pts[0].x;
6210 pts[4].y = pts[0].y;
6211 dp_to_lp(dc, pts, 5);
6212 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6215 NtGdiSelectPen(hdc, hpen);
6216 hbrush = NtGdiSelectBrush(hdc, hbrush);
6217 NtGdiDeleteObjectApp( hbrush );
6220 release_dc_ptr( dc );
6222 return ret;
6226 /******************************************************************************
6227 * NtGdiGetCharABCWidthsW (win32u.@)
6229 * Retrieves widths of characters in range.
6231 * PARAMS
6232 * hdc [I] Handle of device context
6233 * firstChar [I] First character in range to query
6234 * lastChar [I] Last character in range to query
6235 * abc [O] Address of character-width structure
6237 * NOTES
6238 * Only works with TrueType fonts
6240 BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars,
6241 ULONG flags, void *buffer )
6243 DC *dc = get_dc_ptr(hdc);
6244 PHYSDEV dev;
6245 unsigned int i, count = last;
6246 BOOL ret;
6247 TEXTMETRICW tm;
6249 if (!dc) return FALSE;
6251 if (!buffer)
6253 release_dc_ptr( dc );
6254 return FALSE;
6257 if (flags & NTGDI_GETCHARABCWIDTHS_INDICES)
6259 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6260 ret = dev->funcs->pGetCharABCWidthsI( dev, first, count, chars, buffer );
6262 else
6264 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6266 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
6267 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
6268 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
6270 release_dc_ptr( dc );
6271 return FALSE;
6275 if (!chars) count = last - first + 1;
6276 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6277 ret = dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
6280 if (ret)
6282 ABC *abc = buffer;
6283 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6285 /* convert device units to logical */
6286 for (i = 0; i < count; i++)
6288 abc[i].abcA = width_to_LP( dc, abc[i].abcA );
6289 abc[i].abcB = width_to_LP( dc, abc[i].abcB );
6290 abc[i].abcC = width_to_LP( dc, abc[i].abcC );
6293 else
6295 /* convert device units to logical */
6296 FLOAT scale = fabs( dc->xformVport2World.eM11 );
6297 ABCFLOAT *abcf = buffer;
6299 for (i = 0; i < count; i++)
6301 abcf[i].abcfA = abc[i].abcA * scale;
6302 abcf[i].abcfB = abc[i].abcB * scale;
6303 abcf[i].abcfC = abc[i].abcC * scale;
6308 release_dc_ptr( dc );
6309 return ret;
6313 /***********************************************************************
6314 * NtGdiGetGlyphOutline (win32u.@)
6316 DWORD WINAPI NtGdiGetGlyphOutline( HDC hdc, UINT ch, UINT format, GLYPHMETRICS *metrics,
6317 DWORD size, void *buffer, const MAT2 *mat2,
6318 BOOL ignore_rotation )
6320 DC *dc;
6321 DWORD ret;
6322 PHYSDEV dev;
6324 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc, ch, format, metrics, (int)size, buffer, mat2 );
6326 if (!mat2) return GDI_ERROR;
6328 dc = get_dc_ptr(hdc);
6329 if(!dc) return GDI_ERROR;
6331 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6332 ret = dev->funcs->pGetGlyphOutline( dev, ch & 0xffff, format, metrics, size, buffer, mat2 );
6333 release_dc_ptr( dc );
6334 return ret;
6338 /**********************************************************************
6339 * __wine_get_file_outline_text_metric (win32u.@)
6341 BOOL WINAPI __wine_get_file_outline_text_metric( const WCHAR *path, TEXTMETRICW *otm,
6342 UINT *em_square, WCHAR *face_name )
6344 struct gdi_font *font = NULL;
6346 if (!path || !font_funcs) return FALSE;
6348 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6349 font->lf.lfHeight = 100;
6350 if (!font_funcs->load_font( font )) goto done;
6351 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6352 *otm = font->otm.otmTextMetrics;
6353 *em_square = font->otm.otmEMSquare;
6354 wcscpy( face_name, (const WCHAR *)font->otm.otmpFamilyName );
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;