cmd: DIR command outputs free space for the path.
[wine.git] / dlls / win32u / font.c
blob4a34145301244fca8133c746b3074d8d3d677804
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, font_enum_proc 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, font_enum_proc 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 enum_fonts( const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lp )
5212 struct font_enum *fe = (struct font_enum *)lp;
5214 if (fe->charset != DEFAULT_CHARSET && lf->lfCharSet != fe->charset) return 1;
5215 if ((type & RASTER_FONTTYPE) && !(NtGdiGetDeviceCaps( fe->hdc, TEXTCAPS ) & TC_RA_ABLE))
5216 return 1;
5218 if (fe->buf && fe->count < fe->size)
5220 fe->buf[fe->count].type = type;
5221 fe->buf[fe->count].lf = *(const ENUMLOGFONTEXW *)lf;
5222 fe->buf[fe->count].tm = *(const NEWTEXTMETRICEXW *)tm;
5224 fe->count++;
5225 return 1;
5228 /***********************************************************************
5229 * NtGdiEnumFonts (win32u.@)
5231 BOOL WINAPI NtGdiEnumFonts( HDC hdc, ULONG type, ULONG win32_compat, ULONG face_name_len,
5232 const WCHAR *face_name, ULONG charset, ULONG *count, void *buf )
5234 struct font_enum fe;
5235 PHYSDEV physdev;
5236 LOGFONTW lf;
5237 BOOL ret;
5238 DC *dc;
5240 if (!(dc = get_dc_ptr( hdc ))) return 0;
5242 memset( &lf, 0, sizeof(lf) );
5243 lf.lfCharSet = charset;
5244 if (face_name_len) memcpy( lf.lfFaceName, face_name, face_name_len * sizeof(WCHAR) );
5246 fe.hdc = hdc;
5247 fe.buf = buf;
5248 fe.size = *count / sizeof(*fe.buf);
5249 fe.count = 0;
5250 fe.charset = charset;
5252 physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
5253 ret = physdev->funcs->pEnumFonts( physdev, &lf, enum_fonts, (LPARAM)&fe );
5254 if (ret && buf) ret = fe.count <= fe.size;
5255 *count = fe.count * sizeof(*fe.buf);
5257 release_dc_ptr( dc );
5258 return ret;
5262 /***********************************************************************
5263 * NtGdiSetTextJustification (win32u.@)
5265 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
5267 DC *dc;
5269 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5271 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
5272 dc->attr->wnd_ext.cx );
5273 if (!extra) breaks = 0;
5274 if (breaks)
5276 dc->breakExtra = extra / breaks;
5277 dc->breakRem = extra - (breaks * dc->breakExtra);
5279 else
5281 dc->breakExtra = 0;
5282 dc->breakRem = 0;
5285 release_dc_ptr( dc );
5286 return TRUE;
5290 /***********************************************************************
5291 * NtGdiGetTextFaceW (win32u.@)
5293 INT WINAPI NtGdiGetTextFaceW( HDC hdc, INT count, WCHAR *name, BOOL alias_name )
5295 PHYSDEV dev;
5296 INT ret;
5298 DC * dc = get_dc_ptr( hdc );
5299 if (!dc) return 0;
5301 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
5302 ret = dev->funcs->pGetTextFace( dev, count, name );
5303 release_dc_ptr( dc );
5304 return ret;
5308 /***********************************************************************
5309 * NtGdiGetTextExtentExW (win32u.@)
5311 * Return the size of the string as it would be if it was output properly by
5312 * e.g. TextOut.
5314 BOOL WINAPI NtGdiGetTextExtentExW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
5315 INT *nfit, INT *dxs, SIZE *size, UINT flags )
5317 DC *dc;
5318 int i;
5319 BOOL ret;
5320 INT buffer[256], *pos = dxs;
5322 if (count < 0) return FALSE;
5324 dc = get_dc_ptr(hdc);
5325 if (!dc) return FALSE;
5327 if (!dxs)
5329 pos = buffer;
5330 if (count > 256 && !(pos = malloc( count * sizeof(*pos) )))
5332 release_dc_ptr( dc );
5333 return FALSE;
5338 if (flags)
5339 ret = get_char_positions_indices( dc, str, count, pos, size );
5340 else
5341 ret = get_char_positions( dc, str, count, pos, size );
5342 if (ret)
5344 if (dxs || nfit)
5346 for (i = 0; i < count; i++)
5348 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
5349 (i + 1) * dc->attr->char_extra;
5350 if (nfit && dx > (unsigned int)max_ext) break;
5351 if (dxs) dxs[i] = dx;
5353 if (nfit) *nfit = i;
5356 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
5357 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5360 if (pos != buffer && pos != dxs) free( pos );
5361 release_dc_ptr( dc );
5363 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count),
5364 max_ext, (int)size->cx, (int)size->cy );
5365 return ret;
5368 /***********************************************************************
5369 * NtGdiGetTextMetricsW (win32u.@)
5371 BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags )
5373 PHYSDEV physdev;
5374 BOOL ret = FALSE;
5375 DC * dc = get_dc_ptr( hdc );
5376 if (!dc) return FALSE;
5378 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5379 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5381 if (ret)
5383 /* device layer returns values in device units
5384 * therefore we have to convert them to logical */
5386 metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5387 metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5388 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5389 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5390 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5391 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5392 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5393 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5394 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5395 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5396 ret = TRUE;
5398 TRACE("text metrics:\n"
5399 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5400 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5401 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5402 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5403 " PitchAndFamily = %02x\n"
5404 " --------------------\n"
5405 " InternalLeading = %i\n"
5406 " Ascent = %i\n"
5407 " Descent = %i\n"
5408 " Height = %i\n",
5409 (int)metrics->tmWeight, metrics->tmFirstChar, (int)metrics->tmAveCharWidth,
5410 metrics->tmItalic, metrics->tmLastChar, (int)metrics->tmMaxCharWidth,
5411 metrics->tmUnderlined, metrics->tmDefaultChar, (int)metrics->tmOverhang,
5412 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5413 metrics->tmPitchAndFamily,
5414 (int)metrics->tmInternalLeading,
5415 (int)metrics->tmAscent,
5416 (int)metrics->tmDescent,
5417 (int)metrics->tmHeight );
5419 release_dc_ptr( dc );
5420 return ret;
5424 /***********************************************************************
5425 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
5427 UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData,
5428 OUTLINETEXTMETRICW *lpOTM, ULONG opts )
5430 DC *dc = get_dc_ptr( hdc );
5431 OUTLINETEXTMETRICW *output = lpOTM;
5432 PHYSDEV dev;
5433 UINT ret;
5435 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5436 if(!dc) return 0;
5438 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5439 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5441 if (lpOTM && ret > cbData)
5443 output = malloc( ret );
5444 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5447 if (lpOTM && ret)
5449 output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5450 output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5451 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5452 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5453 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5454 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5455 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5456 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5457 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5458 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5459 output->otmAscent = height_to_LP( dc, output->otmAscent);
5460 output->otmDescent = height_to_LP( dc, output->otmDescent);
5461 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5462 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5463 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5464 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5465 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5466 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5467 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5468 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5469 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5470 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5471 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5472 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5473 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5474 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5475 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5476 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5477 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5478 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5479 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5480 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5481 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5482 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5484 if(output != lpOTM)
5486 memcpy(lpOTM, output, cbData);
5487 free( output );
5488 ret = cbData;
5491 release_dc_ptr(dc);
5492 return ret;
5495 /***********************************************************************
5496 * NtGdiGetCharWidthW (win32u.@)
5498 BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5499 ULONG flags, void *buf )
5501 UINT i, count = last;
5502 BOOL ret;
5503 PHYSDEV dev;
5504 DC *dc;
5506 if (flags & NTGDI_GETCHARWIDTH_INDICES)
5508 ABC *abc;
5509 unsigned int i;
5511 if (!(abc = malloc( count * sizeof(ABC) )))
5512 return FALSE;
5514 if (!NtGdiGetCharABCWidthsW( hdc, first, last, chars,
5515 NTGDI_GETCHARABCWIDTHS_INT | NTGDI_GETCHARABCWIDTHS_INDICES,
5516 abc ))
5518 free( abc );
5519 return FALSE;
5522 for (i = 0; i < count; i++)
5523 ((INT *)buf)[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5525 free( abc );
5526 return TRUE;
5529 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5531 if (!chars) count = last - first + 1;
5532 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5533 ret = dev->funcs->pGetCharWidth( dev, first, count, chars, buf );
5535 if (ret)
5537 if (flags & NTGDI_GETCHARWIDTH_INT)
5539 INT *buffer = buf;
5540 /* convert device units to logical */
5541 for (i = 0; i < count; i++)
5542 buffer[i] = width_to_LP( dc, buffer[i] );
5544 else
5546 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
5547 for (i = 0; i < count; i++)
5548 ((float *)buf)[i] = ((int *)buf)[i] * scale;
5551 release_dc_ptr( dc );
5552 return ret;
5556 /* helper for nulldrv_ExtTextOut */
5557 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5558 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5560 UINT indices[3] = {0, 0, 0x20};
5561 unsigned int i;
5562 DWORD ret, size;
5563 int stride;
5565 indices[0] = index;
5566 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5568 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5570 index = indices[i];
5571 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, 0, NULL, &identity, FALSE );
5572 if (ret != GDI_ERROR) break;
5575 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5576 if (!image) return ERROR_SUCCESS;
5578 image->ptr = NULL;
5579 image->free = NULL;
5580 if (!ret) /* empty glyph */
5582 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5583 return ERROR_SUCCESS;
5586 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5587 size = metrics->gmBlackBoxY * stride;
5589 if (!(image->ptr = malloc( size ))) return ERROR_OUTOFMEMORY;
5590 image->is_copy = TRUE;
5591 image->free = free_heap_bits;
5593 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, size, image->ptr,
5594 &identity, FALSE );
5595 if (ret == GDI_ERROR)
5597 free( image->ptr );
5598 return ERROR_NOT_FOUND;
5600 return ERROR_SUCCESS;
5603 /* helper for nulldrv_ExtTextOut */
5604 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5605 LPCWSTR str, UINT count, const INT *dx )
5607 UINT i;
5608 RECT rect, bounds;
5610 reset_bounds( &bounds );
5611 for (i = 0; i < count; i++)
5613 GLYPHMETRICS metrics;
5615 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5617 rect.left = x + metrics.gmptGlyphOrigin.x;
5618 rect.top = y - metrics.gmptGlyphOrigin.y;
5619 rect.right = rect.left + metrics.gmBlackBoxX;
5620 rect.bottom = rect.top + metrics.gmBlackBoxY;
5621 add_bounds_rect( &bounds, &rect );
5623 if (dx)
5625 if (flags & ETO_PDY)
5627 x += dx[ i * 2 ];
5628 y += dx[ i * 2 + 1];
5630 else x += dx[ i ];
5632 else
5634 x += metrics.gmCellIncX;
5635 y += metrics.gmCellIncY;
5638 return bounds;
5641 /* helper for nulldrv_ExtTextOut */
5642 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5643 const struct gdi_image_bits *image, const RECT *clip )
5645 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5646 UINT i, count, max_count;
5647 LONG x, y;
5648 BYTE *ptr = image->ptr;
5649 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5650 POINT *pts;
5651 RECT rect, clipped_rect;
5653 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5654 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5655 rect.right = rect.left + metrics->gmBlackBoxX;
5656 rect.bottom = rect.top + metrics->gmBlackBoxY;
5657 if (!clip) clipped_rect = rect;
5658 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5660 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5661 pts = malloc( max_count * sizeof(*pts) );
5662 if (!pts) return;
5664 count = 0;
5665 ptr += (clipped_rect.top - rect.top) * stride;
5666 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5668 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5670 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5671 pts[count].x = rect.left + x;
5672 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5673 pts[count + 1].x = rect.left + x;
5674 if (pts[count + 1].x > pts[count].x)
5676 pts[count].y = pts[count + 1].y = y;
5677 count += 2;
5681 assert( count <= max_count );
5682 dp_to_lp( dc, pts, count );
5683 for (i = 0; i < count; i += 2)
5685 const ULONG pts_count = 2;
5686 NtGdiPolyPolyDraw( dc->hSelf, pts + i, &pts_count, 1, NtGdiPolyPolyline );
5688 free( pts );
5691 /***********************************************************************
5692 * nulldrv_ExtTextOut
5694 BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5695 LPCWSTR str, UINT count, const INT *dx )
5697 DC *dc = get_nulldrv_dc( dev );
5698 UINT i;
5699 DWORD err;
5700 HGDIOBJ orig;
5701 HPEN pen;
5703 if (flags & ETO_OPAQUE)
5705 RECT rc = *rect;
5706 COLORREF brush_color = NtGdiGetNearestColor( dev->hdc, dc->attr->background_color );
5707 HBRUSH brush = NtGdiCreateSolidBrush( brush_color, NULL);
5709 if (brush)
5711 orig = NtGdiSelectBrush( dev->hdc, brush );
5712 dp_to_lp( dc, (POINT *)&rc, 2 );
5713 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5714 NtGdiSelectBrush( dev->hdc, orig );
5715 NtGdiDeleteObjectApp( brush );
5719 if (!count) return TRUE;
5721 if (dc->aa_flags != GGO_BITMAP)
5723 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5724 BITMAPINFO *info = (BITMAPINFO *)buffer;
5725 struct gdi_image_bits bits;
5726 struct bitblt_coords src, dst;
5727 PHYSDEV dst_dev;
5728 /* FIXME Subpixel modes */
5729 UINT aa_flags = GGO_GRAY4_BITMAP;
5731 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5732 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5733 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5734 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5736 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5737 src.x = src.visrect.left;
5738 src.y = src.visrect.top;
5739 src.width = src.visrect.right - src.visrect.left;
5740 src.height = src.visrect.bottom - src.visrect.top;
5741 dst = src;
5742 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5743 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5745 /* we can avoid the GetImage, just query the needed format */
5746 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5747 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5748 info->bmiHeader.biWidth = src.width;
5749 info->bmiHeader.biHeight = -src.height;
5750 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5751 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5752 if (!err || err == ERROR_BAD_FORMAT)
5754 /* make the source rectangle relative to the source bits */
5755 src.x = src.y = 0;
5756 src.visrect.left = src.visrect.top = 0;
5757 src.visrect.right = src.width;
5758 src.visrect.bottom = src.height;
5760 bits.ptr = malloc( info->bmiHeader.biSizeImage );
5761 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5762 bits.is_copy = TRUE;
5763 bits.free = free_heap_bits;
5764 err = ERROR_SUCCESS;
5767 else
5769 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5770 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5771 if (!err && !bits.is_copy)
5773 void *ptr = malloc( info->bmiHeader.biSizeImage );
5774 if (!ptr)
5776 if (bits.free) bits.free( &bits );
5777 return ERROR_OUTOFMEMORY;
5779 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5780 if (bits.free) bits.free( &bits );
5781 bits.ptr = ptr;
5782 bits.is_copy = TRUE;
5783 bits.free = free_heap_bits;
5786 if (!err)
5788 /* make x,y relative to the image bits */
5789 x += src.visrect.left - dst.visrect.left;
5790 y += src.visrect.top - dst.visrect.top;
5791 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5792 aa_flags, str, count, dx );
5793 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5794 if (bits.free) bits.free( &bits );
5795 return !err;
5799 pen = NtGdiCreatePen( PS_SOLID, 1, dc->attr->text_color, NULL );
5800 orig = NtGdiSelectPen( dev->hdc, pen );
5802 for (i = 0; i < count; i++)
5804 GLYPHMETRICS metrics;
5805 struct gdi_image_bits image;
5807 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5808 if (err) continue;
5810 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5811 if (image.free) image.free( &image );
5813 if (dx)
5815 if (flags & ETO_PDY)
5817 x += dx[ i * 2 ];
5818 y += dx[ i * 2 + 1];
5820 else x += dx[ i ];
5822 else
5824 x += metrics.gmCellIncX;
5825 y += metrics.gmCellIncY;
5829 NtGdiSelectPen( dev->hdc, orig );
5830 NtGdiDeleteObjectApp( pen );
5831 return TRUE;
5834 /***********************************************************************
5835 * get_line_width
5837 * Scale the underline / strikeout line width.
5839 static inline int get_line_width( DC *dc, int metric_size )
5841 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5842 if (width == 0) width = 1;
5843 if (metric_size < 0) width = -width;
5844 return width;
5847 /***********************************************************************
5848 * NtGdiExtTextOutW (win32u.@)
5850 * Draws text using the currently selected font, background color, and text color.
5853 * PARAMS
5854 * x,y [I] coordinates of string
5855 * flags [I]
5856 * ETO_GRAYED - undocumented on MSDN
5857 * ETO_OPAQUE - use background color for fill the rectangle
5858 * ETO_CLIPPED - clipping text to the rectangle
5859 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5860 * than encoded characters. Implies ETO_IGNORELANGUAGE
5861 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5862 * Affects BiDi ordering
5863 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5864 * ETO_PDY - unimplemented
5865 * ETO_NUMERICSLATIN - unimplemented always assumed -
5866 * do not translate numbers into locale representations
5867 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5868 * lprect [I] dimensions for clipping or/and opaquing
5869 * str [I] text string
5870 * count [I] number of symbols in string
5871 * lpDx [I] optional parameter with distance between drawing characters
5873 * RETURNS
5874 * Success: TRUE
5875 * Failure: FALSE
5877 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5878 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5880 BOOL ret = FALSE;
5881 UINT align;
5882 DWORD layout;
5883 POINT pt;
5884 TEXTMETRICW tm;
5885 LOGFONTW lf;
5886 double cosEsc, sinEsc;
5887 INT char_extra;
5888 SIZE sz;
5889 RECT rc;
5890 POINT *deltas = NULL, width = {0, 0};
5891 DC * dc = get_dc_ptr( hdc );
5892 PHYSDEV physdev;
5893 INT breakRem;
5894 static int quietfixme = 0;
5896 if (!dc) return FALSE;
5897 if (count > INT_MAX) return FALSE;
5899 align = dc->attr->text_align;
5900 breakRem = dc->breakRem;
5901 layout = dc->attr->layout;
5903 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5905 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5906 quietfixme = 1;
5909 update_dc( dc );
5910 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5912 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5913 if (layout & LAYOUT_RTL)
5915 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5916 align ^= TA_RTLREADING;
5919 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5920 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5921 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5922 dc->attr->map_mode);
5924 if(align & TA_UPDATECP)
5926 pt = dc->attr->cur_pos;
5927 x = pt.x;
5928 y = pt.y;
5931 NtGdiGetTextMetricsW( hdc, &tm, 0 );
5932 NtGdiExtGetObjectW( dc->hFont, sizeof(lf), &lf );
5934 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5935 lf.lfEscapement = 0;
5937 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5938 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5940 lf.lfEscapement = -lf.lfEscapement;
5943 if(lf.lfEscapement != 0)
5945 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5946 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5948 else
5950 cosEsc = 1;
5951 sinEsc = 0;
5954 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5956 rc = *lprect;
5957 lp_to_dp(dc, (POINT*)&rc, 2);
5958 order_rect( &rc );
5959 if (flags & ETO_OPAQUE)
5960 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5962 else flags &= ~ETO_CLIPPED;
5964 if(count == 0)
5966 ret = TRUE;
5967 goto done;
5970 pt.x = x;
5971 pt.y = y;
5972 lp_to_dp(dc, &pt, 1);
5973 x = pt.x;
5974 y = pt.y;
5976 char_extra = dc->attr->char_extra;
5977 if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5978 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5980 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
5982 UINT i;
5983 POINT total = {0, 0}, desired[2];
5985 deltas = malloc( count * sizeof(*deltas) );
5986 if (lpDx)
5988 if (flags & ETO_PDY)
5990 for (i = 0; i < count; i++)
5992 deltas[i].x = lpDx[i * 2] + char_extra;
5993 deltas[i].y = -lpDx[i * 2 + 1];
5996 else
5998 for (i = 0; i < count; i++)
6000 deltas[i].x = lpDx[i] + char_extra;
6001 deltas[i].y = 0;
6005 else
6007 INT *dx = malloc( count * sizeof(*dx) );
6009 NtGdiGetTextExtentExW( hdc, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX) );
6011 deltas[0].x = dx[0];
6012 deltas[0].y = 0;
6013 for (i = 1; i < count; i++)
6015 deltas[i].x = dx[i] - dx[i - 1];
6016 deltas[i].y = 0;
6018 free( dx );
6021 for(i = 0; i < count; i++)
6023 total.x += deltas[i].x;
6024 total.y += deltas[i].y;
6026 desired[0].x = desired[0].y = 0;
6028 desired[1].x = cosEsc * total.x + sinEsc * total.y;
6029 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
6031 lp_to_dp(dc, desired, 2);
6032 desired[1].x -= desired[0].x;
6033 desired[1].y -= desired[0].y;
6035 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6037 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6038 desired[1].x = -desired[1].x;
6039 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6040 desired[1].y = -desired[1].y;
6043 deltas[i].x = desired[1].x - width.x;
6044 deltas[i].y = desired[1].y - width.y;
6046 width = desired[1];
6048 flags |= ETO_PDY;
6050 else
6052 POINT desired[2];
6054 NtGdiGetTextExtentExW( hdc, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX) );
6055 desired[0].x = desired[0].y = 0;
6056 desired[1].x = sz.cx;
6057 desired[1].y = 0;
6058 lp_to_dp(dc, desired, 2);
6059 desired[1].x -= desired[0].x;
6060 desired[1].y -= desired[0].y;
6062 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6064 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6065 desired[1].x = -desired[1].x;
6066 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6067 desired[1].y = -desired[1].y;
6069 width = desired[1];
6072 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
6073 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
6074 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
6076 case TA_LEFT:
6077 if (align & TA_UPDATECP)
6079 pt.x = x + width.x;
6080 pt.y = y + width.y;
6081 dp_to_lp(dc, &pt, 1);
6082 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6084 break;
6086 case TA_CENTER:
6087 x -= width.x / 2;
6088 y -= width.y / 2;
6089 break;
6091 case TA_RIGHT:
6092 x -= width.x;
6093 y -= width.y;
6094 if (align & TA_UPDATECP)
6096 pt.x = x;
6097 pt.y = y;
6098 dp_to_lp(dc, &pt, 1);
6099 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
6101 break;
6104 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
6106 case TA_TOP:
6107 y += tm.tmAscent * cosEsc;
6108 x += tm.tmAscent * sinEsc;
6109 break;
6111 case TA_BOTTOM:
6112 y -= tm.tmDescent * cosEsc;
6113 x -= tm.tmDescent * sinEsc;
6114 break;
6116 case TA_BASELINE:
6117 break;
6120 if (dc->attr->background_mode != TRANSPARENT)
6122 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
6124 if(!(flags & ETO_OPAQUE) || !lprect ||
6125 x < rc.left || x + width.x >= rc.right ||
6126 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
6128 RECT text_box;
6129 text_box.left = x;
6130 text_box.right = x + width.x;
6131 text_box.top = y - tm.tmAscent;
6132 text_box.bottom = y + tm.tmDescent;
6134 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
6135 if (!IsRectEmpty( &text_box ))
6136 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
6141 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
6142 str, count, (INT*)deltas );
6144 done:
6145 free( deltas );
6147 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
6149 int underlinePos, strikeoutPos;
6150 int underlineWidth, strikeoutWidth;
6151 UINT size = NtGdiGetOutlineTextMetricsInternalW( hdc, 0, NULL, 0 );
6152 OUTLINETEXTMETRICW* otm = NULL;
6153 POINT pts[5];
6154 HPEN hpen = NtGdiSelectPen( hdc, GetStockObject(NULL_PEN) );
6155 HBRUSH hbrush = NtGdiCreateSolidBrush( dc->attr->text_color, NULL );
6157 hbrush = NtGdiSelectBrush(hdc, hbrush);
6159 if(!size)
6161 underlinePos = 0;
6162 underlineWidth = tm.tmAscent / 20 + 1;
6163 strikeoutPos = tm.tmAscent / 2;
6164 strikeoutWidth = underlineWidth;
6166 else
6168 otm = malloc( size );
6169 NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
6170 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
6171 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
6172 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
6173 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
6174 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
6175 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
6176 free( otm );
6180 if (lf.lfUnderline)
6182 const ULONG cnt = 5;
6183 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
6184 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
6185 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
6186 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
6187 pts[2].x = pts[1].x + underlineWidth * sinEsc;
6188 pts[2].y = pts[1].y + underlineWidth * cosEsc;
6189 pts[3].x = pts[0].x + underlineWidth * sinEsc;
6190 pts[3].y = pts[0].y + underlineWidth * cosEsc;
6191 pts[4].x = pts[0].x;
6192 pts[4].y = pts[0].y;
6193 dp_to_lp(dc, pts, 5);
6194 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6197 if (lf.lfStrikeOut)
6199 const ULONG cnt = 5;
6200 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6201 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6202 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6203 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6204 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
6205 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
6206 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
6207 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
6208 pts[4].x = pts[0].x;
6209 pts[4].y = pts[0].y;
6210 dp_to_lp(dc, pts, 5);
6211 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6214 NtGdiSelectPen(hdc, hpen);
6215 hbrush = NtGdiSelectBrush(hdc, hbrush);
6216 NtGdiDeleteObjectApp( hbrush );
6219 release_dc_ptr( dc );
6221 return ret;
6225 /******************************************************************************
6226 * NtGdiGetCharABCWidthsW (win32u.@)
6228 * Retrieves widths of characters in range.
6230 * PARAMS
6231 * hdc [I] Handle of device context
6232 * firstChar [I] First character in range to query
6233 * lastChar [I] Last character in range to query
6234 * abc [O] Address of character-width structure
6236 * NOTES
6237 * Only works with TrueType fonts
6239 BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars,
6240 ULONG flags, void *buffer )
6242 DC *dc = get_dc_ptr(hdc);
6243 PHYSDEV dev;
6244 unsigned int i, count = last;
6245 BOOL ret;
6246 TEXTMETRICW tm;
6248 if (!dc) return FALSE;
6250 if (!buffer)
6252 release_dc_ptr( dc );
6253 return FALSE;
6256 if (flags & NTGDI_GETCHARABCWIDTHS_INDICES)
6258 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6259 ret = dev->funcs->pGetCharABCWidthsI( dev, first, count, chars, buffer );
6261 else
6263 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6265 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
6266 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
6267 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
6269 release_dc_ptr( dc );
6270 return FALSE;
6274 if (!chars) count = last - first + 1;
6275 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6276 ret = dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
6279 if (ret)
6281 ABC *abc = buffer;
6282 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6284 /* convert device units to logical */
6285 for (i = 0; i < count; i++)
6287 abc[i].abcA = width_to_LP( dc, abc[i].abcA );
6288 abc[i].abcB = width_to_LP( dc, abc[i].abcB );
6289 abc[i].abcC = width_to_LP( dc, abc[i].abcC );
6292 else
6294 /* convert device units to logical */
6295 FLOAT scale = fabs( dc->xformVport2World.eM11 );
6296 ABCFLOAT *abcf = buffer;
6298 for (i = 0; i < count; i++)
6300 abcf[i].abcfA = abc[i].abcA * scale;
6301 abcf[i].abcfB = abc[i].abcB * scale;
6302 abcf[i].abcfC = abc[i].abcC * scale;
6307 release_dc_ptr( dc );
6308 return ret;
6312 /***********************************************************************
6313 * NtGdiGetGlyphOutline (win32u.@)
6315 DWORD WINAPI NtGdiGetGlyphOutline( HDC hdc, UINT ch, UINT format, GLYPHMETRICS *metrics,
6316 DWORD size, void *buffer, const MAT2 *mat2,
6317 BOOL ignore_rotation )
6319 DC *dc;
6320 DWORD ret;
6321 PHYSDEV dev;
6323 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc, ch, format, metrics, (int)size, buffer, mat2 );
6325 if (!mat2) return GDI_ERROR;
6327 dc = get_dc_ptr(hdc);
6328 if(!dc) return GDI_ERROR;
6330 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6331 ret = dev->funcs->pGetGlyphOutline( dev, ch & 0xffff, format, metrics, size, buffer, mat2 );
6332 release_dc_ptr( dc );
6333 return ret;
6337 /**********************************************************************
6338 * __wine_get_file_outline_text_metric (win32u.@)
6340 BOOL WINAPI __wine_get_file_outline_text_metric( const WCHAR *path, TEXTMETRICW *otm,
6341 UINT *em_square, WCHAR *face_name )
6343 struct gdi_font *font = NULL;
6345 if (!path || !font_funcs) return FALSE;
6347 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6348 font->lf.lfHeight = 100;
6349 if (!font_funcs->load_font( font )) goto done;
6350 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6351 *otm = font->otm.otmTextMetrics;
6352 *em_square = font->otm.otmEMSquare;
6353 wcscpy( face_name, (const WCHAR *)font->otm.otmpFamilyName );
6354 free_gdi_font( font );
6355 return TRUE;
6357 done:
6358 if (font) free_gdi_font( font );
6359 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6360 return FALSE;
6363 /*************************************************************************
6364 * NtGdiGetKerningPairs (win32u.@)
6366 DWORD WINAPI NtGdiGetKerningPairs( HDC hdc, DWORD count, KERNINGPAIR *kern_pair )
6368 DC *dc;
6369 DWORD ret;
6370 PHYSDEV dev;
6372 TRACE( "(%p,%d,%p)\n", hdc, (int)count, kern_pair );
6374 if (!count && kern_pair)
6376 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6377 return 0;
6380 dc = get_dc_ptr( hdc );
6381 if (!dc) return 0;
6383 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
6384 ret = dev->funcs->pGetKerningPairs( dev, count, kern_pair );
6385 release_dc_ptr( dc );
6386 return ret;
6389 /*************************************************************************
6390 * NtGdiGetFontData (win32u.@)
6392 * Retrieve data for TrueType font.
6394 * RETURNS
6396 * success: Number of bytes returned
6397 * failure: GDI_ERROR
6399 * NOTES
6401 * Calls RtlSetLastWin32Error()
6404 DWORD WINAPI NtGdiGetFontData( HDC hdc, DWORD table, DWORD offset, void *buffer, DWORD length )
6406 DC *dc = get_dc_ptr(hdc);
6407 PHYSDEV dev;
6408 DWORD ret;
6410 if(!dc) return GDI_ERROR;
6412 dev = GET_DC_PHYSDEV( dc, pGetFontData );
6413 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
6414 release_dc_ptr( dc );
6415 return ret;
6418 /*************************************************************************
6419 * NtGdiGetGlyphIndicesW (win32u.@)
6421 DWORD WINAPI NtGdiGetGlyphIndicesW( HDC hdc, const WCHAR *str, INT count,
6422 WORD *indices, DWORD flags )
6424 DC *dc = get_dc_ptr(hdc);
6425 PHYSDEV dev;
6426 DWORD ret;
6428 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc, debugstr_wn(str, count), count, indices, (int)flags );
6430 if(!dc) return GDI_ERROR;
6432 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
6433 ret = dev->funcs->pGetGlyphIndices( dev, str, count, indices, flags );
6434 release_dc_ptr( dc );
6435 return ret;
6438 /***********************************************************************
6440 * Font Resource API *
6442 ***********************************************************************/
6445 static int add_system_font_resource( const WCHAR *file, DWORD flags )
6447 WCHAR path[MAX_PATH];
6448 int ret;
6450 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6451 get_fonts_win_dir_path( file, path );
6452 pthread_mutex_lock( &font_lock );
6453 ret = font_funcs->add_font( path, flags );
6454 pthread_mutex_unlock( &font_lock );
6455 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6456 if (!ret)
6458 get_fonts_data_dir_path( file, path );
6459 pthread_mutex_lock( &font_lock );
6460 ret = font_funcs->add_font( path, flags );
6461 pthread_mutex_unlock( &font_lock );
6463 return ret;
6466 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
6468 WCHAR path[MAX_PATH];
6469 int ret;
6471 get_fonts_win_dir_path( file, path );
6472 if (!(ret = remove_font( path, flags )))
6474 get_fonts_data_dir_path( file, path );
6475 ret = remove_font( path, flags );
6477 return ret;
6480 static int add_font_resource( LPCWSTR file, DWORD flags )
6482 int ret = 0;
6484 if (*file == '\\')
6486 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6488 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6489 pthread_mutex_lock( &font_lock );
6490 ret = font_funcs->add_font( file, addfont_flags );
6491 pthread_mutex_unlock( &font_lock );
6493 else if (!wcschr( file, '\\' ))
6494 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6496 return ret;
6499 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
6501 BOOL ret = FALSE;
6503 if (*file == '\\')
6505 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6507 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6508 ret = remove_font( file, addfont_flags );
6510 else if (!wcschr( file, '\\' ))
6511 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6513 return ret;
6516 static void load_system_bitmap_fonts(void)
6518 static const char * const fonts[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6519 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6520 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6521 HKEY hkey;
6522 DWORD i;
6524 if (!(hkey = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) ))) return;
6525 for (i = 0; i < ARRAY_SIZE(fonts); i++)
6527 if (query_reg_ascii_value( hkey, fonts[i], info, sizeof(value_buffer) ) && info->Type == REG_SZ)
6528 add_system_font_resource( (const WCHAR *)info->Data, ADDFONT_ALLOW_BITMAP );
6530 NtClose( hkey );
6533 static void load_directory_fonts( WCHAR *path, UINT flags )
6535 IO_STATUS_BLOCK io = {{0}};
6536 OBJECT_ATTRIBUTES attr;
6537 UNICODE_STRING nt_name;
6538 HANDLE handle;
6539 char buf[8192];
6540 size_t len;
6542 len = lstrlenW( path );
6543 while (len && path[len - 1] == '\\') len--;
6545 nt_name.Buffer = path;
6546 nt_name.MaximumLength = nt_name.Length = len * sizeof(WCHAR);
6548 attr.Length = sizeof(attr);
6549 attr.RootDirectory = 0;
6550 attr.Attributes = OBJ_CASE_INSENSITIVE;
6551 attr.ObjectName = &nt_name;
6552 attr.SecurityDescriptor = NULL;
6553 attr.SecurityQualityOfService = NULL;
6555 if (NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
6556 FILE_SHARE_READ | FILE_SHARE_WRITE,
6557 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ))
6558 return;
6560 path[len++] = '\\';
6562 while (!NtQueryDirectoryFile( handle, 0, NULL, NULL, &io, buf, sizeof(buf),
6563 FileBothDirectoryInformation, FALSE, NULL, FALSE ) &&
6564 io.Information)
6566 FILE_BOTH_DIR_INFORMATION *info = (FILE_BOTH_DIR_INFORMATION *)buf;
6567 for (;;)
6569 if (!(info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
6571 memcpy( path + len, info->FileName, info->FileNameLength );
6572 path[len + info->FileNameLength / sizeof(WCHAR)] = 0;
6573 font_funcs->add_font( path, flags );
6575 if (!info->NextEntryOffset) break;
6576 info = (FILE_BOTH_DIR_INFORMATION *)((char *)info + info->NextEntryOffset);
6580 NtClose( handle );
6583 static void load_file_system_fonts(void)
6585 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024 * sizeof(WCHAR)])];
6586 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6587 WCHAR *ptr, *next, path[MAX_PATH];
6589 /* Windows directory */
6590 get_fonts_win_dir_path( NULL, path );
6591 load_directory_fonts( path, 0 );
6593 /* Wine data directory */
6594 get_fonts_data_dir_path( NULL, path );
6595 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6597 /* custom paths */
6598 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6599 if (query_reg_ascii_value( wine_fonts_key, "Path", info, sizeof(value_buffer) ) &&
6600 info->Type == REG_SZ)
6602 for (ptr = (WCHAR *)info->Data; ptr; ptr = next)
6604 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
6605 if (next && next - ptr < 2) continue;
6606 lstrcpynW( path, ptr, MAX_PATH );
6607 if (path[1] == ':')
6609 memmove( path + ARRAYSIZE(nt_prefixW), path, (lstrlenW( path ) + 1) * sizeof(WCHAR) );
6610 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6612 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6617 struct external_key
6619 struct list entry;
6620 WCHAR value[LF_FULLFACESIZE + 12];
6623 static void update_external_font_keys(void)
6625 struct list external_keys = LIST_INIT(external_keys);
6626 HKEY winnt_key = 0, win9x_key = 0;
6627 struct gdi_font_family *family;
6628 struct external_key *key, *next;
6629 struct gdi_font_face *face;
6630 DWORD len, i = 0;
6631 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6632 char buffer[2048];
6633 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
6634 WCHAR *file;
6635 HKEY hkey;
6637 static const WCHAR external_fontsW[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6639 winnt_key = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW), 0, NULL );
6640 win9x_key = reg_create_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW), 0, NULL );
6642 /* enumerate the fonts and add external ones to the two keys */
6644 if (!(hkey = reg_create_key( wine_fonts_key, external_fontsW, sizeof(external_fontsW), 0, NULL )))
6645 return;
6647 while (reg_enum_value( hkey, i++, info, sizeof(buffer) - sizeof(nt_prefixW),
6648 value, LF_FULLFACESIZE * sizeof(WCHAR) ))
6650 if (info->Type != REG_SZ) continue;
6652 path = (WCHAR *)(buffer + info->DataOffset);
6653 if (path[0] && path[1] == ':')
6655 memmove( path + ARRAYSIZE(nt_prefixW), path, info->DataLength );
6656 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6659 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6660 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
6662 face->flags |= ADDFONT_EXTERNAL_FOUND;
6663 continue;
6665 if (tmp && !*tmp) *tmp = ' ';
6666 if (!(key = malloc( sizeof(*key) ))) break;
6667 lstrcpyW( key->value, value );
6668 list_add_tail( &external_keys, &key->entry );
6671 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
6673 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
6675 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
6676 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
6678 lstrcpyW( value, face->full_name );
6679 if (face->scalable) lstrcatW( value, true_type_suffixW );
6681 if (face->file[0] == '\\')
6683 file = face->file;
6684 if (file[5] == ':') file += ARRAYSIZE(nt_prefixW);
6686 else if ((file = wcsrchr( face->file, '\\' )))
6687 file++;
6688 else
6689 file = face->file;
6691 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
6692 set_reg_value( winnt_key, value, REG_SZ, file, len );
6693 set_reg_value( win9x_key, value, REG_SZ, file, len );
6694 set_reg_value( hkey, value, REG_SZ, file, len );
6697 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
6699 reg_delete_value( win9x_key, key->value );
6700 reg_delete_value( winnt_key, key->value );
6701 reg_delete_value( hkey, key->value );
6702 list_remove( &key->entry );
6703 free( key );
6705 NtClose( win9x_key );
6706 NtClose( winnt_key );
6707 NtClose( hkey );
6710 static void load_registry_fonts(void)
6712 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6713 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6714 KEY_VALUE_FULL_INFORMATION *enum_info = (KEY_VALUE_FULL_INFORMATION *)value_buffer;
6715 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6716 DWORD i = 0, dlen;
6717 HKEY hkey;
6719 static const WCHAR dot_fonW[] = {'.','f','o','n',0};
6721 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6722 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6723 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6724 will skip these. */
6725 if (is_win9x())
6726 hkey = reg_open_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW) );
6727 else
6728 hkey = reg_open_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW) );
6729 if (!hkey) return;
6731 while (reg_enum_value( hkey, i++, enum_info, sizeof(value_buffer), value, sizeof(value) ))
6733 if (enum_info->Type != REG_SZ) continue;
6734 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6735 if (find_face_from_full_name( value )) continue;
6736 if (tmp && !*tmp) *tmp = ' ';
6738 if (!(dlen = query_reg_value( hkey, value, info, sizeof(value_buffer) - sizeof(nt_prefixW) )) ||
6739 info->Type != REG_SZ)
6741 WARN( "Unable to get face path %s\n", debugstr_w(value) );
6742 continue;
6745 path = (WCHAR *)info->Data;
6746 if (path[0] && path[1] == ':')
6748 memmove( path + ARRAYSIZE(nt_prefixW), path, dlen );
6749 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6750 dlen += sizeof(nt_prefixW);
6753 dlen /= sizeof(WCHAR);
6754 if (*path == '\\')
6755 add_font_resource( path, ADDFONT_ALLOW_BITMAP );
6756 else if (dlen >= 6 && !wcsicmp( path + dlen - 5, dot_fonW ))
6757 add_system_font_resource( path, ADDFONT_ALLOW_BITMAP );
6759 NtClose( hkey );
6762 static HKEY open_hkcu(void)
6764 char buffer[256];
6765 WCHAR bufferW[256];
6766 DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
6767 DWORD i, len = sizeof(sid_data);
6768 SID *sid;
6770 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
6771 return 0;
6773 sid = ((TOKEN_USER *)sid_data)->User.Sid;
6774 len = sprintf( buffer, "\\Registry\\User\\S-%u-%u", (int)sid->Revision,
6775 (int)MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
6776 MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
6777 for (i = 0; i < sid->SubAuthorityCount; i++)
6778 len += sprintf( buffer + len, "-%u", (int)sid->SubAuthority[i] );
6779 ascii_to_unicode( bufferW, buffer, len + 1 );
6781 return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
6784 /***********************************************************************
6785 * font_init
6787 UINT font_init(void)
6789 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
6790 UNICODE_STRING name;
6791 HANDLE mutex;
6792 DWORD disposition;
6793 UINT dpi = 0;
6795 static WCHAR wine_font_mutexW[] =
6796 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6797 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6798 static const WCHAR wine_fonts_keyW[] =
6799 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6800 static const WCHAR cacheW[] = {'C','a','c','h','e'};
6802 if (!(hkcu_key = open_hkcu())) return 0;
6803 wine_fonts_key = reg_create_key( hkcu_key, wine_fonts_keyW, sizeof(wine_fonts_keyW), 0, NULL );
6804 if (wine_fonts_key) dpi = init_font_options();
6805 if (!dpi) return 96;
6806 update_codepage( dpi );
6808 if (!(font_funcs = init_freetype_lib()))
6809 return dpi;
6811 load_system_bitmap_fonts();
6812 load_file_system_fonts();
6813 font_funcs->load_fonts();
6815 attr.Attributes = OBJ_OPENIF;
6816 attr.ObjectName = &name;
6817 name.Buffer = wine_font_mutexW;
6818 name.Length = name.MaximumLength = sizeof(wine_font_mutexW);
6820 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return dpi;
6821 NtWaitForSingleObject( mutex, FALSE, NULL );
6823 wine_fonts_cache_key = reg_create_key( wine_fonts_key, cacheW, sizeof(cacheW),
6824 REG_OPTION_VOLATILE, &disposition );
6826 if (disposition == REG_CREATED_NEW_KEY)
6828 load_registry_fonts();
6829 update_external_font_keys();
6832 NtReleaseMutant( mutex, NULL );
6834 if (disposition != REG_CREATED_NEW_KEY)
6836 load_registry_fonts();
6837 load_font_list_from_cache();
6840 reorder_font_list();
6841 load_gdi_font_subst();
6842 load_gdi_font_replacements();
6843 load_system_links();
6844 dump_gdi_font_list();
6845 dump_gdi_font_subst();
6846 return dpi;
6849 /***********************************************************************
6850 * NtGdiAddFontResourceW (win32u.@)
6852 INT WINAPI NtGdiAddFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6853 DWORD tid, void *dv )
6855 if (!font_funcs) return 1;
6856 return add_font_resource( str, flags );
6859 /***********************************************************************
6860 * NtGdiAddFontMemResourceEx (win32u.@)
6862 HANDLE WINAPI NtGdiAddFontMemResourceEx( void *ptr, DWORD size, void *dv, ULONG dv_size,
6863 DWORD *count )
6865 HANDLE ret;
6866 DWORD num_fonts;
6867 void *copy;
6869 if (!ptr || !size || !count)
6871 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER);
6872 return NULL;
6874 if (!font_funcs) return NULL;
6875 if (!(copy = malloc( size ))) return NULL;
6876 memcpy( copy, ptr, size );
6878 pthread_mutex_lock( &font_lock );
6879 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6880 pthread_mutex_unlock( &font_lock );
6882 if (!num_fonts)
6884 free( copy );
6885 return NULL;
6888 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6889 * For now return something unique but quite random
6891 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
6893 __TRY
6895 *count = num_fonts;
6897 __EXCEPT
6899 WARN( "page fault while writing to *count (%p)\n", count );
6900 NtGdiRemoveFontMemResourceEx( ret );
6901 ret = 0;
6903 __ENDTRY
6904 TRACE( "Returning handle %p\n", ret );
6905 return ret;
6908 /***********************************************************************
6909 * NtGdiRemoveFontMemResourceEx (win32u.@)
6911 BOOL WINAPI NtGdiRemoveFontMemResourceEx( HANDLE handle )
6913 FIXME( "(%p) stub\n", handle );
6914 return TRUE;
6917 /***********************************************************************
6918 * NtGdiRemoveFontResourceW (win32u.@)
6920 BOOL WINAPI NtGdiRemoveFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6921 DWORD tid, void *dv )
6923 if (!font_funcs) return TRUE;
6924 return remove_font_resource( str, flags );
6927 /***********************************************************************
6928 * NtGdiGetFontUnicodeRanges (win32u.@)
6930 * Retrieve a list of supported Unicode characters in a font.
6932 * PARAMS
6933 * hdc [I] Handle to a device context.
6934 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6936 * RETURNS
6937 * Success: Number of bytes written to the buffer pointed to by lpgs.
6938 * Failure: 0
6941 DWORD WINAPI NtGdiGetFontUnicodeRanges( HDC hdc, GLYPHSET *lpgs )
6943 DWORD ret;
6944 PHYSDEV dev;
6945 DC *dc = get_dc_ptr(hdc);
6947 TRACE("(%p, %p)\n", hdc, lpgs);
6949 if (!dc) return 0;
6951 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
6952 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
6953 release_dc_ptr(dc);
6954 return ret;
6958 /*************************************************************
6959 * NtGdiFontIsLinked (win32u.@)
6961 BOOL WINAPI NtGdiFontIsLinked( HDC hdc )
6963 DC *dc = get_dc_ptr(hdc);
6964 PHYSDEV dev;
6965 BOOL ret;
6967 if (!dc) return FALSE;
6968 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
6969 ret = dev->funcs->pFontIsLinked( dev );
6970 release_dc_ptr(dc);
6971 TRACE("returning %d\n", ret);
6972 return ret;
6975 /*************************************************************
6976 * NtGdiGetRealizationInfo (win32u.@)
6978 BOOL WINAPI NtGdiGetRealizationInfo( HDC hdc, struct font_realization_info *info )
6980 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, file_count);
6981 PHYSDEV dev;
6982 BOOL ret;
6983 DC *dc;
6985 if (info->size != sizeof(*info) && !is_v0)
6986 return FALSE;
6988 dc = get_dc_ptr(hdc);
6989 if (!dc) return FALSE;
6990 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
6991 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
6992 release_dc_ptr(dc);
6993 return ret;
6996 /*************************************************************************
6997 * NtGdiGetRasterizerCaps (win32u.@)
6999 BOOL WINAPI NtGdiGetRasterizerCaps( RASTERIZER_STATUS *status, UINT size )
7001 status->nSize = sizeof(RASTERIZER_STATUS);
7002 status->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
7003 status->nLanguageID = 0;
7004 return TRUE;
7007 /*************************************************************************
7008 * NtGdiGetFontFileData (win32u.@)
7010 BOOL WINAPI NtGdiGetFontFileData( DWORD instance_id, DWORD file_index, UINT64 *offset,
7011 void *buff, DWORD buff_size )
7013 struct gdi_font *font;
7014 DWORD tag = 0, size;
7015 BOOL ret = FALSE;
7017 if (!font_funcs) return FALSE;
7018 pthread_mutex_lock( &font_lock );
7019 if ((font = get_font_from_handle( instance_id )))
7021 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
7022 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
7023 if (size != GDI_ERROR && size >= buff_size && *offset <= size - buff_size)
7024 ret = font_funcs->get_font_data( font, tag, *offset, buff, buff_size ) != GDI_ERROR;
7025 else
7026 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
7028 pthread_mutex_unlock( &font_lock );
7029 return ret;
7032 /*************************************************************************
7033 * NtGdiGetFontFileInfo (win32u.@)
7035 BOOL WINAPI NtGdiGetFontFileInfo( DWORD instance_id, DWORD file_index, struct font_fileinfo *info,
7036 SIZE_T size, SIZE_T *needed )
7038 SIZE_T required_size = 0;
7039 struct gdi_font *font;
7040 BOOL ret = FALSE;
7042 pthread_mutex_lock( &font_lock );
7044 if ((font = get_font_from_handle( instance_id )))
7046 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
7047 if (required_size <= size)
7049 info->writetime = font->writetime;
7050 info->size.QuadPart = font->data_size;
7051 lstrcpyW( info->path, font->file );
7052 ret = TRUE;
7054 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
7057 pthread_mutex_unlock( &font_lock );
7058 if (needed) *needed = required_size;
7059 return ret;
7062 /*************************************************************
7063 * NtGdiGetCharWidthInfo (win32u.@)
7065 BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info )
7067 PHYSDEV dev;
7068 BOOL ret;
7069 DC *dc;
7071 dc = get_dc_ptr(hdc);
7072 if (!dc) return FALSE;
7073 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
7074 ret = dev->funcs->pGetCharWidthInfo( dev, info );
7076 if (ret)
7078 info->lsb = width_to_LP( dc, info->lsb );
7079 info->rsb = width_to_LP( dc, info->rsb );
7081 release_dc_ptr(dc);
7082 return ret;
7085 /***********************************************************************
7086 * DrawTextW (win32u.so)
7088 INT WINAPI DECLSPEC_HIDDEN DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags )
7090 struct draw_text_params *params;
7091 ULONG ret_len, size;
7092 void *ret_ptr;
7093 int ret;
7095 if (count == -1) count = wcslen( str );
7096 size = FIELD_OFFSET( struct draw_text_params, str[count] );
7097 if (!(params = malloc( size ))) return 0;
7098 params->hdc = hdc;
7099 params->rect = *rect;
7100 params->flags = flags;
7101 if (count) memcpy( params->str, str, count * sizeof(WCHAR) );
7102 ret = KeUserModeCallback( NtUserDrawText, params, size, &ret_ptr, &ret_len );
7103 if (ret_len == sizeof(*rect)) *rect = *(const RECT *)ret_ptr;
7104 free( params );
7105 return ret;