win32u: Only cache font glyph metrics from GGO_METRICS.
[wine.git] / dlls / win32u / font.c
blob7fc4a01eb64ca956cfaef321376fcf537c175f2a
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 DWORD ntmFlags;
88 DWORD version;
89 DWORD 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 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 face->fs.fsCsb[0], face->fs.fsCsb[1],
1292 face->fs.fsUsb[0], face->fs.fsUsb[1],
1293 face->fs.fsUsb[2], 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_ui_gothicW[] =
1504 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1505 static const WCHAR sim_sunW[] =
1506 {'S','i','m','S','u','n',0};
1507 static const WCHAR gulimW[] =
1508 {'G','u','l','i','m',0};
1509 static const WCHAR p_ming_li_uW[] =
1510 {'P','M','i','n','g','L','i','U',0};
1511 static const WCHAR batangW[] =
1512 {'B','a','t','a','n','g',0};
1514 static const WCHAR * const font_links_list[] =
1516 lucida_sans_unicodeW,
1517 microsoft_sans_serifW,
1518 tahomaW
1521 static const struct font_links_defaults_list
1523 /* Keyed off substitution for "MS Shell Dlg" */
1524 const WCHAR *shelldlg;
1525 /* Maximum of four substitutes, plus terminating NULL pointer */
1526 const WCHAR *substitutes[5];
1527 } font_links_defaults_list[] =
1529 /* Non East-Asian */
1530 { tahomaW, /* FIXME unverified ordering */
1531 { ms_ui_gothicW, sim_sunW, gulimW, p_ming_li_uW, NULL }
1533 /* Below lists are courtesy of
1534 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1536 /* Japanese */
1537 { ms_ui_gothicW,
1538 { ms_ui_gothicW, p_ming_li_uW, sim_sunW, gulimW, NULL }
1540 /* Chinese Simplified */
1541 { sim_sunW,
1542 { sim_sunW, p_ming_li_uW, ms_ui_gothicW, batangW, NULL }
1544 /* Korean */
1545 { gulimW,
1546 { gulimW, p_ming_li_uW, ms_ui_gothicW, sim_sunW, NULL }
1548 /* Chinese Traditional */
1549 { p_ming_li_uW,
1550 { p_ming_li_uW, sim_sunW, ms_ui_gothicW, batangW, NULL }
1554 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1556 struct gdi_font_family *family;
1557 struct gdi_font_face *face;
1558 struct gdi_font_link *font_link;
1559 const WCHAR *file, *value;
1561 /* Don't store fonts that are only substitutes for other fonts */
1562 if (get_gdi_font_subst( name, -1, NULL ))
1564 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1565 return;
1567 font_link = add_gdi_font_link( name );
1568 for ( ; *values; values++)
1570 if (!facename_compare( name, *values, -1 )) continue;
1571 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1572 if (!(family = find_family_from_name( value ))) continue;
1573 /* use first extant filename for this Family */
1574 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1576 if (!face->file) continue;
1577 file = wcsrchr(face->file, '\\');
1578 if (!file) file = face->file;
1579 else file++;
1580 if ((face = find_face_from_filename( file, value )))
1582 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1583 TRACE( "added internal SystemLink for %s to %s in %s\n",
1584 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1586 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1587 break;
1592 static void load_system_links(void)
1594 HKEY hkey;
1595 DWORD i, j;
1596 const WCHAR *shelldlg_name;
1597 struct gdi_font_link *font_link, *system_font_link;
1598 struct gdi_font_face *face;
1600 static const WCHAR ms_shell_dlgW[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
1601 static const WCHAR systemW[] = {'S','y','s','t','e','m',0};
1602 static const WCHAR tahoma_ttfW[] = {'t','a','h','o','m','a','.','t','t','f',0};
1604 if ((hkey = reg_open_key( NULL, system_link_keyW, sizeof(system_link_keyW) )))
1606 char buffer[4096];
1607 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1608 WCHAR value[MAX_PATH];
1609 WCHAR *entry, *next;
1611 i = 0;
1612 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
1614 /* Don't store fonts that are only substitutes for other fonts */
1615 if (!get_gdi_font_subst( value, -1, NULL ))
1617 char *data = (char *)info + info->DataOffset;
1618 font_link = add_gdi_font_link( value );
1619 for (entry = (WCHAR *)data; (char *)entry < data + info->DataLength && *entry; entry = next)
1621 const WCHAR *family_name = NULL;
1622 WCHAR *p;
1624 TRACE( "%s: %s\n", debugstr_w(value), debugstr_w(entry) );
1626 next = entry + lstrlenW(entry) + 1;
1627 if ((p = wcschr( entry, ',' )))
1629 *p++ = 0;
1630 while (*p == ' ' || *p == '\t') p++;
1631 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
1633 if ((face = find_face_from_filename( entry, family_name )))
1635 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1636 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
1638 else TRACE( "Unable to find file %s family %s\n",
1639 debugstr_w(entry), debugstr_w(family_name) );
1642 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1644 NtClose( hkey );
1647 if ((shelldlg_name = get_gdi_font_subst( ms_shell_dlgW, -1, NULL )))
1649 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
1651 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
1653 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
1654 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
1656 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
1657 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
1658 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
1659 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
1663 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1665 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1666 that Tahoma has */
1668 system_font_link = add_gdi_font_link( systemW );
1669 if ((face = find_face_from_filename( tahoma_ttfW, tahomaW )))
1671 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
1672 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
1674 if ((font_link = find_gdi_font_link( tahomaW )))
1676 struct gdi_font_link_entry *entry;
1677 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
1678 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
1682 /* see TranslateCharsetInfo */
1683 BOOL translate_charset_info( DWORD *src, CHARSETINFO *cs, DWORD flags )
1685 unsigned int i;
1687 switch (flags)
1689 case TCI_SRCFONTSIG:
1690 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
1691 if (charset_info[i].fs.fsCsb[0] & src[0]) goto found;
1692 return FALSE;
1693 case TCI_SRCCODEPAGE:
1694 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
1695 if (PtrToUlong(src) == charset_info[i].ciACP) goto found;
1696 return FALSE;
1697 case TCI_SRCCHARSET:
1698 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
1699 if (PtrToUlong(src) == charset_info[i].ciCharset) goto found;
1700 return FALSE;
1701 default:
1702 return FALSE;
1704 found:
1705 *cs = charset_info[i];
1706 return TRUE;
1709 /* font matching */
1711 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
1713 struct gdi_font_link *font_link;
1715 if (!face->scalable && !can_use_bitmap) return FALSE;
1716 if (!fs.fsCsb[0]) return TRUE;
1717 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
1718 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
1719 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
1720 return FALSE;
1723 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
1724 const LOGFONTW *lf, FONTSIGNATURE fs,
1725 BOOL can_use_bitmap )
1727 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
1728 unsigned int best_score = 4;
1729 int best_diff = 0;
1730 int it = !!lf->lfItalic;
1731 int bd = lf->lfWeight > 550;
1732 int height = lf->lfHeight;
1734 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1736 int italic = !!(face->ntmFlags & NTM_ITALIC);
1737 int bold = !!(face->ntmFlags & NTM_BOLD);
1738 int score = (italic ^ it) + (bold ^ bd);
1740 if (!can_select_face( face, fs, can_use_bitmap )) continue;
1741 if (score > best_score) continue;
1742 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
1743 best_score = score;
1744 best = face;
1745 if (best->scalable && best_score == 0) break;
1746 if (!best->scalable)
1748 int diff;
1749 if (height > 0)
1750 diff = height - (signed int)best->size.height;
1751 else
1752 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
1753 if (!best_bitmap ||
1754 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
1755 (best_diff < 0 && diff > best_diff))
1757 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
1758 best_diff = diff;
1759 best_bitmap = best;
1760 if (best_score == 0 && best_diff == 0) break;
1764 if (!best) return NULL;
1765 return best->scalable ? best : best_bitmap;
1768 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
1769 const LOGFONTW *lf, FONTSIGNATURE fs,
1770 BOOL can_use_bitmap, const WCHAR **orig_name )
1772 struct gdi_font_family *family;
1773 struct gdi_font_face *face;
1775 family = find_family_from_any_name( name );
1776 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
1777 if (subst)
1779 family = find_family_from_any_name( subst );
1780 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
1783 /* search by full face name */
1784 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1785 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1786 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
1787 can_select_face( face, fs, can_use_bitmap ))
1788 return face;
1790 if ((family = find_family_from_font_links( name, subst, fs )))
1792 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1794 return NULL;
1796 found:
1797 if (orig_name && family != face->family)
1798 *orig_name = family->family_name;
1799 return face;
1802 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
1803 BOOL can_use_bitmap, BOOL want_vertical )
1805 struct gdi_font_family *family;
1806 struct gdi_font_face *face;
1807 WCHAR name[LF_FACESIZE + 1];
1808 int i = 0;
1810 /* first try the family fallbacks */
1811 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
1813 if (want_vertical)
1815 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
1816 name[0] = '@';
1819 if (!(family = find_family_from_any_name(name))) continue;
1820 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1822 /* otherwise try only scalable */
1823 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1825 if ((family->family_name[0] == '@') == !want_vertical) continue;
1826 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1828 if (!can_use_bitmap) return NULL;
1829 /* then also bitmap fonts */
1830 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1832 if ((family->family_name[0] == '@') == !want_vertical) continue;
1833 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1835 return NULL;
1838 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
1839 BOOL *substituted, const WCHAR **orig_name )
1841 BOOL want_vertical = (lf->lfFaceName[0] == '@');
1842 struct gdi_font_face *face;
1844 if (!translate_charset_info( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
1846 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
1847 csi->fs.fsCsb[0] = 0;
1850 if (lf->lfFaceName[0])
1852 int subst_charset;
1853 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
1855 if (subst)
1857 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
1858 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
1859 if (subst_charset != -1)
1860 translate_charset_info( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
1861 *substituted = TRUE;
1864 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap, orig_name )))
1865 return face;
1867 *substituted = FALSE; /* substitution is no longer relevant */
1869 /* If requested charset was DEFAULT_CHARSET then try using charset
1870 corresponding to the current ansi codepage */
1871 if (!csi->fs.fsCsb[0])
1873 if (!translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
1875 FIXME( "TCI failed on codepage %d\n", ansi_cp.CodePage );
1876 csi->fs.fsCsb[0] = 0;
1880 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1881 if (csi->fs.fsCsb[0])
1883 csi->fs.fsCsb[0] = 0;
1884 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1886 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
1887 return NULL;
1890 /* realized font objects */
1892 #define FIRST_FONT_HANDLE 1
1893 #define MAX_FONT_HANDLES 256
1895 struct font_handle_entry
1897 struct gdi_font *font;
1898 WORD generation; /* generation count for reusing handle values */
1901 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
1902 static struct font_handle_entry *next_free;
1903 static struct font_handle_entry *next_unused = font_handles;
1905 static struct font_handle_entry *handle_entry( DWORD handle )
1907 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
1909 if (idx < MAX_FONT_HANDLES)
1911 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
1912 return &font_handles[idx];
1914 if (handle) WARN( "invalid handle 0x%08x\n", handle );
1915 return NULL;
1918 static struct gdi_font *get_font_from_handle( DWORD handle )
1920 struct font_handle_entry *entry = handle_entry( handle );
1922 if (entry) return entry->font;
1923 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1924 return NULL;
1927 static DWORD alloc_font_handle( struct gdi_font *font )
1929 struct font_handle_entry *entry;
1931 entry = next_free;
1932 if (entry)
1933 next_free = (struct font_handle_entry *)entry->font;
1934 else if (next_unused < font_handles + MAX_FONT_HANDLES)
1935 entry = next_unused++;
1936 else
1938 ERR( "out of realized font handles\n" );
1939 return 0;
1941 entry->font = font;
1942 if (++entry->generation == 0xffff) entry->generation = 1;
1943 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
1946 static void free_font_handle( DWORD handle )
1948 struct font_handle_entry *entry;
1950 if ((entry = handle_entry( handle )))
1952 entry->font = (struct gdi_font *)next_free;
1953 next_free = entry;
1957 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
1959 UINT len = file ? lstrlenW(file) : 0;
1960 struct gdi_font *font = calloc( 1, offsetof( struct gdi_font, file[len + 1] ));
1962 font->refcount = 1;
1963 font->matrix.eM11 = font->matrix.eM22 = 1.0;
1964 font->scale_y = 1;
1965 font->kern_count = -1;
1966 list_init( &font->child_fonts );
1968 if (file)
1970 FILE_NETWORK_OPEN_INFORMATION info;
1971 UNICODE_STRING nt_name;
1972 OBJECT_ATTRIBUTES attr;
1974 nt_name.Buffer = (WCHAR *)file;
1975 nt_name.Length = nt_name.MaximumLength = len * sizeof(WCHAR);
1977 attr.Length = sizeof(attr);
1978 attr.RootDirectory = 0;
1979 attr.Attributes = OBJ_CASE_INSENSITIVE;
1980 attr.ObjectName = &nt_name;
1981 attr.SecurityDescriptor = NULL;
1982 attr.SecurityQualityOfService = NULL;
1984 if (!NtQueryFullAttributesFile( &attr, &info ))
1986 font->writetime.dwLowDateTime = info.LastWriteTime.LowPart;
1987 font->writetime.dwHighDateTime = info.LastWriteTime.HighPart;
1988 font->data_size = info.EndOfFile.QuadPart;
1989 memcpy( font->file, file, len * sizeof(WCHAR) );
1992 else
1994 font->data_ptr = data_ptr;
1995 font->data_size = data_size;
1998 font->handle = alloc_font_handle( font );
1999 return font;
2002 static void free_gdi_font( struct gdi_font *font )
2004 DWORD i;
2005 struct gdi_font *child, *child_next;
2007 if (font->private) font_funcs->destroy_font( font );
2008 free_font_handle( font->handle );
2009 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
2011 list_remove( &child->entry );
2012 free_gdi_font( child );
2014 for (i = 0; i < font->gm_size; i++) free( font->gm[i] );
2015 free( font->otm.otmpFamilyName );
2016 free( font->otm.otmpStyleName );
2017 free( font->otm.otmpFaceName );
2018 free( font->otm.otmpFullName );
2019 free( font->gm );
2020 free( font->kern_pairs );
2021 free( font->gsub_table );
2022 free( font );
2025 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
2027 return font->use_logfont_name ? font->lf.lfFaceName : (WCHAR *)font->otm.otmpFamilyName;
2030 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
2031 const LOGFONTW *lf )
2033 struct gdi_font *font;
2035 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
2036 font->fs = face->fs;
2037 font->lf = *lf;
2038 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
2039 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
2040 font->scalable = face->scalable;
2041 font->face_index = face->face_index;
2042 font->ntmFlags = face->ntmFlags;
2043 font->aa_flags = HIWORD( face->flags );
2044 if (!family_name) family_name = face->family->family_name;
2045 font->otm.otmpFamilyName = (char *)wcsdup( family_name );
2046 font->otm.otmpStyleName = (char *)wcsdup( face->style_name );
2047 font->otm.otmpFaceName = (char *)wcsdup( face->full_name );
2048 return font;
2051 struct glyph_metrics
2053 GLYPHMETRICS gm;
2054 ABC abc; /* metrics of the unrotated char */
2055 BOOL init;
2058 #define GM_BLOCK_SIZE 128
2060 /* TODO: GGO format support */
2061 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
2063 UINT block = index / GM_BLOCK_SIZE;
2064 UINT entry = index % GM_BLOCK_SIZE;
2066 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
2068 *gm = font->gm[block][entry].gm;
2069 *abc = font->gm[block][entry].abc;
2071 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2072 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
2073 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2074 return TRUE;
2077 return FALSE;
2080 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
2081 const GLYPHMETRICS *gm, const ABC *abc )
2083 UINT block = index / GM_BLOCK_SIZE;
2084 UINT entry = index % GM_BLOCK_SIZE;
2086 if (block >= font->gm_size)
2088 struct glyph_metrics **ptr;
2090 if (!(ptr = realloc( font->gm, (block + 1) * sizeof(*ptr) ))) return;
2091 memset( ptr + font->gm_size, 0, (block + 1 - font->gm_size) * sizeof(*ptr) );
2092 font->gm_size = block + 1;
2093 font->gm = ptr;
2095 if (!font->gm[block])
2097 font->gm[block] = calloc( sizeof(**font->gm), GM_BLOCK_SIZE );
2098 if (!font->gm[block]) return;
2100 font->gm[block][entry].gm = *gm;
2101 font->gm[block][entry].abc = *abc;
2102 font->gm[block][entry].init = TRUE;
2106 /* GSUB table support */
2108 typedef struct
2110 DWORD version;
2111 WORD ScriptList;
2112 WORD FeatureList;
2113 WORD LookupList;
2114 } GSUB_Header;
2116 typedef struct
2118 CHAR ScriptTag[4];
2119 WORD Script;
2120 } GSUB_ScriptRecord;
2122 typedef struct
2124 WORD ScriptCount;
2125 GSUB_ScriptRecord ScriptRecord[1];
2126 } GSUB_ScriptList;
2128 typedef struct
2130 CHAR LangSysTag[4];
2131 WORD LangSys;
2132 } GSUB_LangSysRecord;
2134 typedef struct
2136 WORD DefaultLangSys;
2137 WORD LangSysCount;
2138 GSUB_LangSysRecord LangSysRecord[1];
2139 } GSUB_Script;
2141 typedef struct
2143 WORD LookupOrder; /* Reserved */
2144 WORD ReqFeatureIndex;
2145 WORD FeatureCount;
2146 WORD FeatureIndex[1];
2147 } GSUB_LangSys;
2149 typedef struct
2151 CHAR FeatureTag[4];
2152 WORD Feature;
2153 } GSUB_FeatureRecord;
2155 typedef struct
2157 WORD FeatureCount;
2158 GSUB_FeatureRecord FeatureRecord[1];
2159 } GSUB_FeatureList;
2161 typedef struct
2163 WORD FeatureParams; /* Reserved */
2164 WORD LookupCount;
2165 WORD LookupListIndex[1];
2166 } GSUB_Feature;
2168 typedef struct
2170 WORD LookupCount;
2171 WORD Lookup[1];
2172 } GSUB_LookupList;
2174 typedef struct
2176 WORD LookupType;
2177 WORD LookupFlag;
2178 WORD SubTableCount;
2179 WORD SubTable[1];
2180 } GSUB_LookupTable;
2182 typedef struct
2184 WORD CoverageFormat;
2185 WORD GlyphCount;
2186 WORD GlyphArray[1];
2187 } GSUB_CoverageFormat1;
2189 typedef struct
2191 WORD Start;
2192 WORD End;
2193 WORD StartCoverageIndex;
2194 } GSUB_RangeRecord;
2196 typedef struct
2198 WORD CoverageFormat;
2199 WORD RangeCount;
2200 GSUB_RangeRecord RangeRecord[1];
2201 } GSUB_CoverageFormat2;
2203 typedef struct
2205 WORD SubstFormat; /* = 1 */
2206 WORD Coverage;
2207 WORD DeltaGlyphID;
2208 } GSUB_SingleSubstFormat1;
2210 typedef struct
2212 WORD SubstFormat; /* = 2 */
2213 WORD Coverage;
2214 WORD GlyphCount;
2215 WORD Substitute[1];
2216 } GSUB_SingleSubstFormat2;
2218 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
2220 GSUB_ScriptList *script;
2221 GSUB_Script *deflt = NULL;
2222 int i;
2224 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
2225 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
2226 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
2228 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
2229 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
2230 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
2231 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
2233 return deflt;
2236 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
2238 int i, offset;
2239 GSUB_LangSys *lang;
2241 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
2243 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
2245 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
2246 lang = (GSUB_LangSys *)((BYTE *)script + offset);
2247 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
2249 offset = GET_BE_WORD(script->DefaultLangSys);
2250 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
2251 return NULL;
2254 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
2256 int i;
2257 const GSUB_FeatureList *feature;
2259 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
2260 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
2261 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
2263 int index = GET_BE_WORD(lang->FeatureIndex[i]);
2264 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
2265 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
2267 return NULL;
2270 static const char *get_opentype_script( const struct gdi_font *font )
2273 * I am not sure if this is the correct way to generate our script tag
2275 switch (font->charset)
2277 case ANSI_CHARSET: return "latn";
2278 case BALTIC_CHARSET: return "latn"; /* ?? */
2279 case CHINESEBIG5_CHARSET: return "hani";
2280 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
2281 case GB2312_CHARSET: return "hani";
2282 case GREEK_CHARSET: return "grek";
2283 case HANGUL_CHARSET: return "hang";
2284 case RUSSIAN_CHARSET: return "cyrl";
2285 case SHIFTJIS_CHARSET: return "kana";
2286 case TURKISH_CHARSET: return "latn"; /* ?? */
2287 case VIETNAMESE_CHARSET: return "latn";
2288 case JOHAB_CHARSET: return "latn"; /* ?? */
2289 case ARABIC_CHARSET: return "arab";
2290 case HEBREW_CHARSET: return "hebr";
2291 case THAI_CHARSET: return "thai";
2292 default: return "latn";
2296 static void *get_GSUB_vert_feature( struct gdi_font *font )
2298 GSUB_Header *header;
2299 GSUB_Script *script;
2300 GSUB_LangSys *language;
2301 GSUB_Feature *feature;
2302 DWORD length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2304 if (length == GDI_ERROR) return NULL;
2306 header = malloc( length );
2307 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2308 TRACE( "Loaded GSUB table of %i bytes\n", length );
2310 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2312 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2314 feature = GSUB_get_feature( header, language, "vrt2" );
2315 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2316 if (feature)
2318 font->gsub_table = header;
2319 return feature;
2321 TRACE("vrt2/vert feature not found\n");
2323 else TRACE("Language not found\n");
2325 else TRACE("Script not found\n");
2327 free( header );
2328 return NULL;
2331 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2333 GSUB_CoverageFormat1 *cf1 = table;
2335 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2337 int i, count = GET_BE_WORD(cf1->GlyphCount);
2339 TRACE("Coverage Format 1, %i glyphs\n",count);
2340 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2341 return -1;
2343 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2345 int i, count;
2346 GSUB_CoverageFormat2 *cf2 = table;
2348 count = GET_BE_WORD(cf2->RangeCount);
2349 TRACE("Coverage Format 2, %i ranges\n",count);
2350 for (i = 0; i < count; i++)
2352 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2353 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2354 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2356 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2357 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2360 return -1;
2362 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2364 return -1;
2367 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2369 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2370 int i, j, offset;
2372 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2373 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2375 GSUB_LookupTable *look;
2376 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2377 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2378 TRACE("type %i, flag %x, subtables %i\n",
2379 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2380 if (GET_BE_WORD(look->LookupType) == 1)
2382 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2384 GSUB_SingleSubstFormat1 *ssf1;
2385 offset = GET_BE_WORD(look->SubTable[j]);
2386 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2387 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2389 int offset = GET_BE_WORD(ssf1->Coverage);
2390 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2391 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2393 TRACE(" Glyph 0x%x ->",glyph);
2394 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2395 TRACE(" 0x%x\n",glyph);
2398 else
2400 GSUB_SingleSubstFormat2 *ssf2;
2401 int index, offset;
2403 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2404 offset = GET_BE_WORD(ssf1->Coverage);
2405 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2406 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2407 TRACE(" Coverage index %i\n",index);
2408 if (index != -1)
2410 TRACE(" Glyph is 0x%x ->",glyph);
2411 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2412 TRACE("0x%x\n",glyph);
2417 else FIXME("We only handle SubType 1\n");
2419 return glyph;
2422 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2424 if (!glyph) return glyph;
2425 if (!font->gsub_table) return glyph;
2426 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2429 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2431 FONTSIGNATURE fs = {{0}};
2432 struct gdi_font *child;
2433 struct gdi_font_face *face;
2435 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE, NULL ))) return;
2437 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2438 child->matrix = font->matrix;
2439 child->can_use_bitmap = font->can_use_bitmap;
2440 child->scale_y = font->scale_y;
2441 child->aveWidth = font->aveWidth;
2442 child->charset = font->charset;
2443 child->codepage = font->codepage;
2444 child->base_font = font;
2445 list_add_tail( &font->child_fonts, &child->entry );
2446 TRACE( "created child font %p for base %p\n", child, font );
2449 static void create_child_font_list( struct gdi_font *font )
2451 struct gdi_font_link *font_link;
2452 struct gdi_font_link_entry *entry;
2453 const WCHAR* font_name = (WCHAR *)font->otm.otmpFaceName;
2455 if ((font_link = find_gdi_font_link( font_name )))
2457 TRACE("found entry in system list\n");
2458 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2459 add_child_font( font, entry->family_name );
2462 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2463 * Sans Serif. This is how asian windows get default fallbacks for fonts
2465 if (ansi_cp.MaximumCharacterSize == 2 && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2466 facename_compare( font_name, microsoft_sans_serifW, -1 ) != 0)
2468 if ((font_link = find_gdi_font_link( microsoft_sans_serifW )))
2470 TRACE("found entry in default fallback list\n");
2471 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2472 add_child_font( font, entry->family_name );
2477 /* font cache */
2479 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2480 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2481 static unsigned int unused_font_count;
2482 #define UNUSED_CACHE_SIZE 10
2484 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2485 const FMAT2 *matrix, BOOL can_use_bitmap )
2487 if (font->hash != hash) return TRUE;
2488 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2489 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2490 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2491 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2494 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2496 DWORD hash = 0, *ptr, two_chars;
2497 WORD *pwc;
2498 unsigned int i;
2500 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2501 hash ^= *ptr;
2502 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2503 hash ^= *ptr;
2504 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2506 two_chars = *ptr;
2507 pwc = (WCHAR *)&two_chars;
2508 if(!*pwc) break;
2509 *pwc = towupper(*pwc);
2510 pwc++;
2511 *pwc = towupper(*pwc);
2512 hash ^= two_chars;
2513 if(!*pwc) break;
2515 hash ^= !can_use_bitmap;
2516 return hash;
2519 static void cache_gdi_font( struct gdi_font *font )
2521 static DWORD cache_num = 1;
2523 font->cache_num = cache_num++;
2524 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2525 list_add_head( &gdi_font_list, &font->entry );
2526 TRACE( "font %p\n", font );
2529 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2531 struct gdi_font *font;
2532 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2534 /* try the in-use list */
2535 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2537 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2538 list_remove( &font->entry );
2539 list_add_head( &gdi_font_list, &font->entry );
2540 if (!font->refcount++)
2542 list_remove( &font->unused_entry );
2543 unused_font_count--;
2545 return font;
2547 return NULL;
2550 static void release_gdi_font( struct gdi_font *font )
2552 if (!font) return;
2554 TRACE( "font %p\n", font );
2556 /* add it to the unused list */
2557 pthread_mutex_lock( &font_lock );
2558 if (!--font->refcount)
2560 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2561 if (unused_font_count > UNUSED_CACHE_SIZE)
2563 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2564 TRACE( "freeing %p\n", font );
2565 list_remove( &font->entry );
2566 list_remove( &font->unused_entry );
2567 free_gdi_font( font );
2569 else unused_font_count++;
2571 pthread_mutex_unlock( &font_lock );
2574 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2576 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2578 set_reg_ascii_value( hkey, "Courier", fl->courier );
2579 set_reg_ascii_value( hkey, "MS Serif", fl->serif );
2580 set_reg_ascii_value( hkey, "MS Sans Serif", sserif );
2581 set_reg_ascii_value( hkey, "Small Fonts", fl->small );
2584 static void set_value_key(HKEY hkey, const char *name, const char *value)
2586 if (value)
2587 set_reg_ascii_value( hkey, name, value );
2588 else if (name)
2590 WCHAR nameW[64];
2591 asciiz_to_unicode( nameW, name );
2592 reg_delete_value( hkey, nameW );
2596 static void update_font_association_info(void)
2598 static const WCHAR associated_charsetW[] =
2599 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
2601 if (ansi_cp.MaximumCharacterSize == 2)
2603 HKEY hkey;
2604 if ((hkey = reg_create_key( NULL, font_assoc_keyW, sizeof(font_assoc_keyW), 0, NULL )))
2606 HKEY hsubkey;
2607 if ((hsubkey = reg_create_key( hkey, associated_charsetW, sizeof(associated_charsetW),
2608 0, NULL )))
2610 switch (ansi_cp.CodePage)
2612 case 932:
2613 set_value_key(hsubkey, "ANSI(00)", "NO");
2614 set_value_key(hsubkey, "OEM(FF)", "NO");
2615 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2616 break;
2617 case 936:
2618 case 949:
2619 case 950:
2620 set_value_key(hsubkey, "ANSI(00)", "YES");
2621 set_value_key(hsubkey, "OEM(FF)", "YES");
2622 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2623 break;
2625 NtClose( hsubkey );
2628 /* TODO: Associated DefaultFonts */
2630 NtClose( hkey );
2633 else
2634 reg_delete_tree( NULL, font_assoc_keyW, sizeof(font_assoc_keyW) );
2637 static void set_multi_value_key( HKEY hkey, const WCHAR *name, const char *value, DWORD len )
2639 WCHAR valueW[256];
2640 ascii_to_unicode( valueW, value, len );
2641 if (value)
2642 set_reg_value( hkey, name, REG_MULTI_SZ, valueW, len * sizeof(WCHAR) );
2643 else if (name)
2644 reg_delete_value( hkey, name );
2647 static void update_font_system_link_info(void)
2649 static const char system_link_simplified_chinese[] =
2650 "SIMSUN.TTC,SimSun\0"
2651 "MINGLIU.TTC,PMingLiu\0"
2652 "MSGOTHIC.TTC,MS UI Gothic\0"
2653 "BATANG.TTC,Batang\0";
2654 static const char system_link_traditional_chinese[] =
2655 "MINGLIU.TTC,PMingLiu\0"
2656 "SIMSUN.TTC,SimSun\0"
2657 "MSGOTHIC.TTC,MS UI Gothic\0"
2658 "BATANG.TTC,Batang\0";
2659 static const char system_link_japanese[] =
2660 "MSGOTHIC.TTC,MS UI Gothic\0"
2661 "MINGLIU.TTC,PMingLiU\0"
2662 "SIMSUN.TTC,SimSun\0"
2663 "GULIM.TTC,Gulim\0";
2664 static const char system_link_korean[] =
2665 "GULIM.TTC,Gulim\0"
2666 "MSGOTHIC.TTC,MS UI Gothic\0"
2667 "MINGLIU.TTC,PMingLiU\0"
2668 "SIMSUN.TTC,SimSun\0";
2669 static const char system_link_non_cjk[] =
2670 "MSGOTHIC.TTC,MS UI Gothic\0"
2671 "MINGLIU.TTC,PMingLiU\0"
2672 "SIMSUN.TTC,SimSun\0"
2673 "GULIM.TTC,Gulim\0";
2674 HKEY hkey;
2676 if ((hkey = reg_create_key( NULL, system_link_keyW, sizeof(system_link_keyW), 0, NULL )))
2678 const char *link;
2679 DWORD len;
2681 switch (ansi_cp.CodePage)
2683 case 932:
2684 link = system_link_japanese;
2685 len = sizeof(system_link_japanese);
2686 break;
2687 case 936:
2688 link = system_link_simplified_chinese;
2689 len = sizeof(system_link_simplified_chinese);
2690 break;
2691 case 949:
2692 link = system_link_korean;
2693 len = sizeof(system_link_korean);
2694 break;
2695 case 950:
2696 link = system_link_traditional_chinese;
2697 len = sizeof(system_link_traditional_chinese);
2698 break;
2699 default:
2700 link = system_link_non_cjk;
2701 len = sizeof(system_link_non_cjk);
2703 set_multi_value_key(hkey, lucida_sans_unicodeW, link, len);
2704 set_multi_value_key(hkey, microsoft_sans_serifW, link, len);
2705 set_multi_value_key(hkey, tahomaW, link, len);
2706 NtClose( hkey );
2710 static void update_codepage( UINT screen_dpi )
2712 USHORT utf8_hdr[2] = { 0, CP_UTF8 };
2713 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[40 * sizeof(WCHAR)])];
2714 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
2715 char cpbuf[40];
2716 WCHAR cpbufW[40];
2717 HKEY hkey;
2718 DWORD size;
2719 UINT i;
2720 DWORD font_dpi = 0;
2721 BOOL done = FALSE, cp_match = FALSE;
2723 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
2725 size = query_reg_value( wine_fonts_key, log_pixelsW, info, sizeof(value_buffer) );
2726 if (size == sizeof(DWORD) && info->Type == REG_DWORD)
2727 font_dpi = *(DWORD *)info->Data;
2729 RtlInitCodePageTable( utf8_hdr, &utf8_cp );
2730 if (NtCurrentTeb()->Peb->AnsiCodePageData)
2731 RtlInitCodePageTable( NtCurrentTeb()->Peb->AnsiCodePageData, &ansi_cp );
2732 else
2733 ansi_cp = utf8_cp;
2734 if (NtCurrentTeb()->Peb->OemCodePageData)
2735 RtlInitCodePageTable( NtCurrentTeb()->Peb->OemCodePageData, &oem_cp );
2736 else
2737 oem_cp = utf8_cp;
2738 sprintf( cpbuf, "%u,%u", ansi_cp.CodePage, oem_cp.CodePage );
2739 asciiz_to_unicode( cpbufW, cpbuf );
2741 if (query_reg_ascii_value( wine_fonts_key, "Codepages", info, sizeof(value_buffer) ))
2743 cp_match = !wcscmp( (const WCHAR *)info->Data, cpbufW );
2744 if (cp_match && screen_dpi == font_dpi) return; /* already set correctly */
2745 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2746 debugstr_w((const WCHAR *)info->Data), font_dpi, ansi_cp.CodePage, oem_cp.CodePage, screen_dpi );
2748 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2749 ansi_cp.CodePage, oem_cp.CodePage, screen_dpi);
2751 set_reg_ascii_value( wine_fonts_key, "Codepages", cpbuf );
2752 set_reg_value( wine_fonts_key, log_pixelsW, REG_DWORD, &screen_dpi, sizeof(screen_dpi) );
2754 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
2756 if (nls_update_font_list[i].ansi_cp == ansi_cp.CodePage &&
2757 nls_update_font_list[i].oem_cp == oem_cp.CodePage)
2759 HKEY software_hkey;
2760 if ((software_hkey = reg_create_key( NULL, software_config_keyW,
2761 sizeof(software_config_keyW), 0, NULL )))
2763 static const WCHAR fontsW[] = {'F','o','n','t','s'};
2764 hkey = reg_create_key( software_hkey, fontsW, sizeof(fontsW), 0, NULL );
2765 NtClose( software_hkey );
2766 if (hkey)
2768 set_reg_ascii_value( hkey, "OEMFONT.FON", nls_update_font_list[i].oem );
2769 set_reg_ascii_value( hkey, "FIXEDFON.FON", nls_update_font_list[i].fixed );
2770 set_reg_ascii_value( hkey, "FONTS.FON", nls_update_font_list[i].system );
2771 NtClose( hkey );
2774 if ((hkey = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW),
2775 0, NULL )))
2777 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2778 NtClose( hkey );
2780 if ((hkey = reg_create_key( NULL, fonts_win9x_config_keyW,
2781 sizeof(fonts_win9x_config_keyW), 0, NULL )))
2783 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2784 NtClose( hkey );
2786 /* Only update these if the Codepage changed. */
2787 if (!cp_match &&
2788 (hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
2789 0, NULL )))
2791 set_reg_ascii_value( hkey, "MS Shell Dlg", nls_update_font_list[i].shelldlg );
2792 set_reg_ascii_value( hkey, "Tms Rmn", nls_update_font_list[i].tmsrmn );
2794 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2795 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2796 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2797 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2798 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2799 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2800 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2801 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2803 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2804 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2805 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2807 NtClose( hkey );
2809 done = TRUE;
2811 else
2813 /* Delete the FontSubstitutes from other locales */
2814 if ((hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
2815 0, NULL )))
2817 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2818 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2819 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2820 NtClose( hkey );
2824 if (!done)
2825 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp.CodePage, oem_cp.CodePage);
2827 /* update locale dependent font association info and font system link info in registry.
2828 update only when codepages changed, not logpixels. */
2829 if (!cp_match)
2831 update_font_association_info();
2832 update_font_system_link_info();
2837 /*************************************************************
2838 * font_CreateDC
2840 static BOOL CDECL font_CreateDC( PHYSDEV *dev, LPCWSTR device, LPCWSTR output,
2841 const DEVMODEW *devmode )
2843 struct font_physdev *physdev;
2845 if (!font_funcs) return TRUE;
2846 if (!(physdev = calloc( 1, sizeof(*physdev) ))) return FALSE;
2847 push_dc_driver( dev, &physdev->dev, &font_driver );
2848 return TRUE;
2852 /*************************************************************
2853 * font_DeleteDC
2855 static BOOL CDECL font_DeleteDC( PHYSDEV dev )
2857 struct font_physdev *physdev = get_font_dev( dev );
2859 release_gdi_font( physdev->font );
2860 free( physdev );
2861 return TRUE;
2865 struct gdi_font_enum_data
2867 ENUMLOGFONTEXW elf;
2868 NEWTEXTMETRICEXW ntm;
2871 struct enum_charset
2873 DWORD mask;
2874 DWORD charset;
2875 DWORD script;
2878 static BOOL is_complex_script_ansi_cp(void)
2880 return (ansi_cp.CodePage == 874 /* Thai */
2881 || ansi_cp.CodePage == 1255 /* Hebrew */
2882 || ansi_cp.CodePage == 1256 /* Arabic */
2886 /***************************************************
2887 * create_enum_charset_list
2889 * This function creates charset enumeration list because in DEFAULT_CHARSET
2890 * case, the ANSI codepage's charset takes precedence over other charsets.
2891 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2892 * This function works as a filter other than DEFAULT_CHARSET case.
2894 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
2896 struct enum_charset *start = list;
2897 CHARSETINFO csi;
2898 int i;
2900 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && csi.fs.fsCsb[0] != 0)
2902 list->mask = csi.fs.fsCsb[0];
2903 list->charset = csi.ciCharset;
2904 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2905 list++;
2907 else /* charset is DEFAULT_CHARSET or invalid. */
2909 DWORD mask = 0;
2911 /* Set the current codepage's charset as the first element. */
2912 if (!is_complex_script_ansi_cp() &&
2913 translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, &csi, TCI_SRCCODEPAGE ) &&
2914 csi.fs.fsCsb[0] != 0)
2916 list->mask = csi.fs.fsCsb[0];
2917 list->charset = csi.ciCharset;
2918 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2919 mask |= csi.fs.fsCsb[0];
2920 list++;
2923 /* Fill out left elements. */
2924 for (i = 0; i < 32; i++)
2926 FONTSIGNATURE fs;
2927 fs.fsCsb[0] = 1u << i;
2928 fs.fsCsb[1] = 0;
2929 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
2930 if (!translate_charset_info( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
2931 continue; /* skip, this is an invalid fsCsb bit. */
2932 list->mask = fs.fsCsb[0];
2933 list->charset = csi.ciCharset;
2934 list->script = i;
2935 mask |= fs.fsCsb[0];
2936 list++;
2938 /* add catch all mask for remaining bits */
2939 if (~mask)
2941 list->mask = ~mask;
2942 list->charset = DEFAULT_CHARSET;
2943 list->script = 33; /* other */
2944 list++;
2947 return list - start;
2950 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
2952 UINT ret = 0;
2954 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
2955 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
2956 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
2957 return ret;
2960 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
2962 struct gdi_font *font;
2963 LOGFONTW lf = { .lfHeight = -4096 /* preferable EM Square size */ };
2965 if (!face->scalable) lf.lfHeight = 0;
2967 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2969 if (!font_funcs->load_font( font ))
2971 free_gdi_font( font );
2972 return FALSE;
2975 if (font->scalable && -lf.lfHeight % font->otm.otmEMSquare != 0)
2977 /* reload with the original EM Square size */
2978 lf.lfHeight = -font->otm.otmEMSquare;
2979 free_gdi_font( font );
2981 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2982 if (!font_funcs->load_font( font ))
2984 free_gdi_font( font );
2985 return FALSE;
2989 if (font_funcs->set_outline_text_metrics( font ))
2991 static const DWORD ntm_ppem = 32;
2992 UINT cell_height;
2994 #define TM font->otm.otmTextMetrics
2995 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
2996 cell_height = TM.tmHeight / ( -lf.lfHeight / font->otm.otmEMSquare );
2997 ntm->ntmTm.tmHeight = muldiv( ntm_ppem, cell_height, font->otm.otmEMSquare );
2998 ntm->ntmTm.tmAscent = SCALE_NTM( TM.tmAscent );
2999 ntm->ntmTm.tmDescent = ntm->ntmTm.tmHeight - ntm->ntmTm.tmAscent;
3000 ntm->ntmTm.tmInternalLeading = SCALE_NTM( TM.tmInternalLeading );
3001 ntm->ntmTm.tmExternalLeading = SCALE_NTM( TM.tmExternalLeading );
3002 ntm->ntmTm.tmAveCharWidth = SCALE_NTM( TM.tmAveCharWidth );
3003 ntm->ntmTm.tmMaxCharWidth = SCALE_NTM( TM.tmMaxCharWidth );
3005 memcpy((char *)&ntm->ntmTm + offsetof( TEXTMETRICW, tmWeight ),
3006 (const char *)&TM + offsetof( TEXTMETRICW, tmWeight ),
3007 sizeof(TEXTMETRICW) - offsetof( TEXTMETRICW, tmWeight ));
3008 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
3009 ntm->ntmTm.ntmCellHeight = cell_height;
3010 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
3011 #undef SCALE_NTM
3012 #undef TM
3014 else if (font_funcs->set_bitmap_text_metrics( font ))
3016 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
3017 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
3018 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
3019 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
3021 ntm->ntmTm.ntmFlags = font->ntmFlags;
3022 ntm->ntmFontSig = font->fs;
3024 elf->elfLogFont.lfEscapement = 0;
3025 elf->elfLogFont.lfOrientation = 0;
3026 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
3027 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
3028 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
3029 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
3030 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
3031 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
3032 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
3033 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3034 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3035 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
3036 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3037 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
3038 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
3039 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
3041 free_gdi_font( font );
3042 return TRUE;
3045 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
3047 struct gdi_font_face *face;
3049 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
3050 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3051 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
3052 return FALSE;
3055 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
3057 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
3058 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
3061 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
3062 struct enum_charset *list, DWORD count, FONTENUMPROCW proc, LPARAM lparam,
3063 const WCHAR *subst )
3065 ENUMLOGFONTEXW elf;
3066 NEWTEXTMETRICEXW ntm;
3067 DWORD type, i;
3069 if (!face->cached_enum_data)
3071 struct gdi_font_enum_data *data;
3073 if (!(data = calloc( 1, sizeof(*data) )) ||
3074 !get_face_enum_data( face, &data->elf, &data->ntm ))
3076 free( data );
3077 return TRUE;
3079 face->cached_enum_data = data;
3082 elf = face->cached_enum_data->elf;
3083 ntm = face->cached_enum_data->ntm;
3084 type = get_font_type( &ntm );
3086 /* font replacement */
3087 if (family != face->family)
3089 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
3090 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
3092 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
3094 for (i = 0; i < count; i++)
3096 if (face->fs.fsCsb[0] == 0) /* OEM */
3098 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3099 elf.elfScript[0] = 32;
3100 i = count; /* break out of loop after enumeration */
3102 else
3104 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
3105 /* use the DEFAULT_CHARSET case only if no other charset is present */
3106 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
3107 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
3108 /* caller may fill elfScript with the actual string, see load_script_name */
3109 elf.elfScript[0] = list[i].script;
3111 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3112 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3113 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
3114 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, ntm.ntmTm.ntmFlags );
3115 /* release section before callback (FIXME) */
3116 pthread_mutex_unlock( &font_lock );
3117 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
3118 pthread_mutex_lock( &font_lock );
3120 return TRUE;
3123 /*************************************************************
3124 * font_EnumFonts
3126 static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
3128 struct gdi_font_family *family;
3129 struct gdi_font_face *face;
3130 struct enum_charset enum_charsets[32];
3131 DWORD count, charset;
3133 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
3135 count = create_enum_charset_list( charset, enum_charsets );
3137 pthread_mutex_lock( &font_lock );
3139 if (lf && lf->lfFaceName[0])
3141 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
3142 const WCHAR *orig_name = NULL;
3144 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
3145 if (face_name)
3147 orig_name = lf->lfFaceName;
3148 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
3150 else face_name = lf->lfFaceName;
3152 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3154 if (!family_matches(family, face_name)) continue;
3155 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3157 if (!face_matches( family->family_name, face, face_name )) continue;
3158 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
3159 return FALSE;
3163 else
3165 TRACE( "charset %d\n", charset );
3166 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3168 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
3169 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
3170 return FALSE;
3173 pthread_mutex_unlock( &font_lock );
3174 return TRUE;
3178 static BOOL check_unicode_tategaki( WCHAR ch )
3180 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
3181 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
3183 /* We only reach this code if typographical substitution did not occur */
3184 /* Type: U or Type: Tu */
3185 return (orientation == 1 || orientation == 3);
3188 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
3190 UINT index;
3192 if (glyph < 0x100) glyph += 0xf000;
3193 /* there are a number of old pre-Unicode "broken" TTFs, which
3194 do have symbols at U+00XX instead of U+f0XX */
3195 index = glyph;
3196 font_funcs->get_glyph_index( font, &index, FALSE );
3197 if (!index)
3199 index = glyph - 0xf000;
3200 font_funcs->get_glyph_index( font, &index, FALSE );
3202 return index;
3205 CPTABLEINFO *get_cptable( WORD cp )
3207 static CPTABLEINFO tables[100];
3208 unsigned int i;
3209 USHORT *ptr;
3210 SIZE_T size;
3212 if (cp == CP_ACP) return &ansi_cp;
3213 if (cp == CP_UTF8) return &utf8_cp;
3215 for (i = 0; i < ARRAY_SIZE(tables) && tables[i].CodePage; i++)
3216 if (tables[i].CodePage == cp) return &tables[i];
3217 if (NtGetNlsSectionPtr( 11, cp, NULL, (void **)&ptr, &size )) return NULL;
3218 if (i == ARRAY_SIZE(tables))
3220 ERR( "too many code pages\n" );
3221 return NULL;
3223 RtlInitCodePageTable( ptr, &tables[i] );
3224 return &tables[i];
3227 DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, DWORD srclen )
3229 DWORD ret;
3231 if (info->CodePage == CP_UTF8)
3232 RtlUnicodeToUTF8N( dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3233 else
3234 RtlUnicodeToCustomCPN( info, dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3236 return ret;
3239 DWORD win32u_wctomb_size( CPTABLEINFO *info, const WCHAR *src, DWORD srclen )
3241 DWORD ret;
3243 if (info->CodePage == CP_UTF8)
3245 RtlUnicodeToUTF8N( NULL, 0, &ret, src, srclen * sizeof(WCHAR) );
3247 else if(info->DBCSCodePage)
3249 WCHAR *uni2cp = info->WideCharTable;
3250 for (ret = srclen; srclen; srclen--, src++)
3251 if (uni2cp[*src] & 0xff00) ret++;
3253 else
3255 ret = srclen;
3258 return ret;
3261 DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *src, DWORD srclen )
3263 DWORD ret;
3265 if (info->CodePage == CP_UTF8)
3266 RtlUTF8ToUnicodeN( dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3267 else
3268 RtlCustomCPToUnicodeN( info, dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3270 return ret / sizeof(WCHAR);
3273 static BOOL wc_to_index( UINT cp, WCHAR wc, unsigned char *dst, BOOL allow_default )
3275 const CPTABLEINFO *info;
3277 if (!(info = get_cptable( cp ))) return FALSE;
3279 if (info->CodePage == CP_UTF8)
3281 if (wc < 0x80)
3283 *dst = wc;
3284 return TRUE;
3286 if (!allow_default) return FALSE;
3287 *dst = info->DefaultChar;
3288 return TRUE;
3290 else if (info->DBCSCodePage)
3292 WCHAR *uni2cp = info->WideCharTable;
3293 if (uni2cp[wc] & 0xff00) return FALSE;
3294 *dst = uni2cp[wc];
3296 else
3298 char *uni2cp = info->WideCharTable;
3299 *dst = uni2cp[wc];
3302 if (info->MultiByteTable[*dst] != wc)
3304 if (!allow_default) return FALSE;
3305 *dst = info->DefaultChar;
3308 return TRUE;
3311 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
3313 WCHAR wc = glyph;
3314 unsigned char ch;
3316 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
3318 if (font->codepage == CP_SYMBOL)
3320 glyph = get_glyph_index_symbol( font, wc );
3321 if (!glyph)
3323 if (wc_to_index( CP_ACP, wc, &ch, TRUE ))
3324 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
3327 else if (wc_to_index( font->codepage, wc, &ch, FALSE ))
3329 glyph = (unsigned char)ch;
3330 font_funcs->get_glyph_index( font, &glyph, FALSE );
3332 else return 0;
3334 return glyph;
3337 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
3339 struct gdi_font *child;
3340 UINT res;
3342 if ((res = get_glyph_index( *font, glyph ))) return res;
3343 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
3345 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
3347 if (!child->private && !font_funcs->load_font( child )) continue;
3348 if ((res = get_glyph_index( child, glyph )))
3350 *font = child;
3351 return res;
3354 return 0;
3357 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3358 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
3359 const MAT2 *mat )
3361 GLYPHMETRICS gm;
3362 ABC abc;
3363 DWORD ret = 1;
3364 UINT index = glyph;
3365 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
3367 if (format & GGO_GLYPH_INDEX)
3369 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3370 as glyph index. "Treasure Adventure Game" depends on this. */
3371 font_funcs->get_glyph_index( font, &index, FALSE );
3372 format &= ~GGO_GLYPH_INDEX;
3373 /* TODO: Window also turns off tategaki for glyphs passed in by index
3374 if their unicode code points fall outside of the range that is
3375 rotated. */
3377 else
3379 index = get_glyph_index_linked( &font, glyph );
3380 if (tategaki)
3382 UINT orig = index;
3383 index = get_GSUB_vert_glyph( font, index );
3384 if (index == orig) tategaki = check_unicode_tategaki( glyph );
3388 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
3390 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
3391 goto done;
3393 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
3394 if (ret == GDI_ERROR) return ret;
3396 if (format == GGO_METRICS && !mat)
3397 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
3399 done:
3400 if (gm_ret) *gm_ret = gm;
3401 if (abc_ret) *abc_ret = abc;
3402 return ret;
3406 /*************************************************************
3407 * font_FontIsLinked
3409 static BOOL CDECL font_FontIsLinked( PHYSDEV dev )
3411 struct font_physdev *physdev = get_font_dev( dev );
3413 if (!physdev->font)
3415 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
3416 return dev->funcs->pFontIsLinked( dev );
3418 return !list_empty( &physdev->font->child_fonts );
3422 /*************************************************************
3423 * font_GetCharABCWidths
3425 static BOOL CDECL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT count,
3426 WCHAR *chars, ABC *buffer )
3428 struct font_physdev *physdev = get_font_dev( dev );
3429 UINT c, i;
3431 if (!physdev->font)
3433 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3434 return dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
3437 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3439 pthread_mutex_lock( &font_lock );
3440 for (i = 0; i < count; i++)
3442 c = chars ? chars[i] : first + i;
3443 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &buffer[i], 0, NULL, NULL );
3445 pthread_mutex_unlock( &font_lock );
3446 return TRUE;
3450 /*************************************************************
3451 * font_GetCharABCWidthsI
3453 static BOOL CDECL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3455 struct font_physdev *physdev = get_font_dev( dev );
3456 UINT c;
3458 if (!physdev->font)
3460 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3461 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3464 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3466 pthread_mutex_lock( &font_lock );
3467 for (c = 0; c < count; c++, buffer++)
3468 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3469 NULL, buffer, 0, NULL, NULL );
3470 pthread_mutex_unlock( &font_lock );
3471 return TRUE;
3475 /*************************************************************
3476 * font_GetCharWidth
3478 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT count,
3479 const WCHAR *chars, INT *buffer )
3481 struct font_physdev *physdev = get_font_dev( dev );
3482 UINT c, i;
3483 ABC abc;
3485 if (!physdev->font)
3487 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3488 return dev->funcs->pGetCharWidth( dev, first, count, chars, buffer );
3491 TRACE( "%p, %d, %d, %p\n", physdev->font, first, count, buffer );
3493 pthread_mutex_lock( &font_lock );
3494 for (i = 0; i < count; i++)
3496 c = chars ? chars[i] : i + first;
3497 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3498 buffer[i] = 0;
3499 else
3500 buffer[i] = abc.abcA + abc.abcB + abc.abcC;
3502 pthread_mutex_unlock( &font_lock );
3503 return TRUE;
3507 /*************************************************************
3508 * font_GetCharWidthInfo
3510 static BOOL CDECL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3512 struct font_physdev *physdev = get_font_dev( dev );
3513 struct char_width_info *info = ptr;
3515 if (!physdev->font)
3517 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3518 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3521 info->unk = 0;
3522 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3523 info->lsb = info->rsb = 0;
3525 return TRUE;
3529 /*************************************************************
3530 * font_GetFontData
3532 static DWORD CDECL font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
3534 struct font_physdev *physdev = get_font_dev( dev );
3536 if (!physdev->font)
3538 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
3539 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
3541 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
3545 /*************************************************************
3546 * font_GetFontRealizationInfo
3548 static BOOL CDECL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
3550 struct font_physdev *physdev = get_font_dev( dev );
3551 struct font_realization_info *info = ptr;
3553 if (!physdev->font)
3555 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
3556 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
3559 TRACE( "(%p, %p)\n", physdev->font, info);
3561 info->flags = 1;
3562 if (physdev->font->scalable) info->flags |= 2;
3564 info->cache_num = physdev->font->cache_num;
3565 info->instance_id = physdev->font->handle;
3566 if (info->size == sizeof(*info))
3568 info->file_count = 1;
3569 info->face_index = physdev->font->face_index;
3570 info->simulations = 0;
3571 if (physdev->font->fake_bold) info->simulations |= 0x1;
3572 if (physdev->font->fake_italic) info->simulations |= 0x2;
3574 return TRUE;
3578 /*************************************************************
3579 * font_GetFontUnicodeRanges
3581 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
3583 struct font_physdev *physdev = get_font_dev( dev );
3584 DWORD size, num_ranges;
3586 if (!physdev->font)
3588 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
3589 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
3592 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
3593 size = offsetof( GLYPHSET, ranges[num_ranges] );
3594 if (glyphset)
3596 glyphset->cbThis = size;
3597 glyphset->cRanges = num_ranges;
3598 glyphset->flAccel = 0;
3600 return size;
3604 /*************************************************************
3605 * font_GetGlyphIndices
3607 static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
3609 struct font_physdev *physdev = get_font_dev( dev );
3610 UINT default_char;
3611 unsigned char ch;
3612 BOOL got_default = FALSE;
3613 int i;
3615 if (!physdev->font)
3617 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
3618 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
3621 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3623 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
3624 got_default = TRUE;
3627 pthread_mutex_lock( &font_lock );
3629 for (i = 0; i < count; i++)
3631 UINT glyph = str[i];
3633 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
3635 glyph = 0;
3636 if (physdev->font->codepage == CP_SYMBOL)
3638 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
3639 else if (str[i] < 0x100) glyph = str[i];
3641 else if (wc_to_index( physdev->font->codepage, str[i], &ch, FALSE ))
3642 glyph = (unsigned char)ch;
3644 if (!glyph)
3646 if (!got_default)
3648 default_char = font_funcs->get_default_glyph( physdev->font );
3649 got_default = TRUE;
3651 gi[i] = default_char;
3653 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
3656 pthread_mutex_unlock( &font_lock );
3657 return count;
3661 /*************************************************************
3662 * font_GetGlyphOutline
3664 static DWORD CDECL font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
3665 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
3667 struct font_physdev *physdev = get_font_dev( dev );
3668 DWORD ret;
3670 if (!physdev->font)
3672 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
3673 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
3675 pthread_mutex_lock( &font_lock );
3676 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
3677 pthread_mutex_unlock( &font_lock );
3678 return ret;
3682 /*************************************************************
3683 * font_GetKerningPairs
3685 static DWORD CDECL font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
3687 struct font_physdev *physdev = get_font_dev( dev );
3689 if (!physdev->font)
3691 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
3692 return dev->funcs->pGetKerningPairs( dev, count, pairs );
3695 pthread_mutex_lock( &font_lock );
3696 if (physdev->font->kern_count == -1)
3697 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
3698 &physdev->font->kern_pairs );
3699 pthread_mutex_unlock( &font_lock );
3701 if (count && pairs)
3703 count = min( count, physdev->font->kern_count );
3704 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
3706 else count = physdev->font->kern_count;
3708 return count;
3712 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
3714 double scale_x, scale_y;
3716 if (font->aveWidth)
3718 scale_x = (double)font->aveWidth;
3719 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3721 else
3722 scale_x = font->scale_y;
3724 scale_x *= fabs(font->matrix.eM11);
3725 scale_y = font->scale_y * fabs(font->matrix.eM22);
3727 /* Windows scales these values as signed integers even if they are unsigned */
3728 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3729 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3731 SCALE_Y(otm->otmTextMetrics.tmHeight);
3732 SCALE_Y(otm->otmTextMetrics.tmAscent);
3733 SCALE_Y(otm->otmTextMetrics.tmDescent);
3734 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
3735 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
3737 SCALE_X(otm->otmTextMetrics.tmOverhang);
3738 if (font->fake_bold)
3740 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
3741 otm->otmTextMetrics.tmAveCharWidth++;
3742 otm->otmTextMetrics.tmMaxCharWidth++;
3744 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
3745 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
3747 SCALE_Y(otm->otmAscent);
3748 SCALE_Y(otm->otmDescent);
3749 SCALE_Y(otm->otmLineGap);
3750 SCALE_Y(otm->otmsCapEmHeight);
3751 SCALE_Y(otm->otmsXHeight);
3752 SCALE_Y(otm->otmrcFontBox.top);
3753 SCALE_Y(otm->otmrcFontBox.bottom);
3754 SCALE_X(otm->otmrcFontBox.left);
3755 SCALE_X(otm->otmrcFontBox.right);
3756 SCALE_Y(otm->otmMacAscent);
3757 SCALE_Y(otm->otmMacDescent);
3758 SCALE_Y(otm->otmMacLineGap);
3759 SCALE_X(otm->otmptSubscriptSize.x);
3760 SCALE_Y(otm->otmptSubscriptSize.y);
3761 SCALE_X(otm->otmptSubscriptOffset.x);
3762 SCALE_Y(otm->otmptSubscriptOffset.y);
3763 SCALE_X(otm->otmptSuperscriptSize.x);
3764 SCALE_Y(otm->otmptSuperscriptSize.y);
3765 SCALE_X(otm->otmptSuperscriptOffset.x);
3766 SCALE_Y(otm->otmptSuperscriptOffset.y);
3767 SCALE_Y(otm->otmsStrikeoutSize);
3768 SCALE_Y(otm->otmsStrikeoutPosition);
3769 SCALE_Y(otm->otmsUnderscoreSize);
3770 SCALE_Y(otm->otmsUnderscorePosition);
3772 #undef SCALE_X
3773 #undef SCALE_Y
3776 /*************************************************************
3777 * font_GetOutlineTextMetrics
3779 static UINT CDECL font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
3781 struct font_physdev *physdev = get_font_dev( dev );
3782 UINT ret = 0;
3784 if (!physdev->font)
3786 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
3787 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
3790 if (!physdev->font->scalable) return 0;
3792 pthread_mutex_lock( &font_lock );
3793 if (font_funcs->set_outline_text_metrics( physdev->font ))
3795 ret = physdev->font->otm.otmSize;
3796 if (metrics && size >= physdev->font->otm.otmSize)
3798 WCHAR *ptr = (WCHAR *)(metrics + 1);
3799 *metrics = physdev->font->otm;
3800 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
3801 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
3802 ptr += lstrlenW(ptr) + 1;
3803 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
3804 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
3805 ptr += lstrlenW(ptr) + 1;
3806 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
3807 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
3808 ptr += lstrlenW(ptr) + 1;
3809 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
3810 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
3811 scale_outline_font_metrics( physdev->font, metrics );
3814 pthread_mutex_unlock( &font_lock );
3815 return ret;
3819 /*************************************************************
3820 * font_GetTextCharsetInfo
3822 static UINT CDECL font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
3824 struct font_physdev *physdev = get_font_dev( dev );
3826 if (!physdev->font)
3828 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
3829 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3831 if (fs) *fs = physdev->font->fs;
3832 return physdev->font->charset;
3836 /*************************************************************
3837 * font_GetTextExtentExPoint
3839 static BOOL CDECL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
3841 struct font_physdev *physdev = get_font_dev( dev );
3842 INT i, pos;
3843 ABC abc;
3845 if (!physdev->font)
3847 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
3848 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
3851 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
3853 pthread_mutex_lock( &font_lock );
3854 for (i = pos = 0; i < count; i++)
3856 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
3857 pos += abc.abcA + abc.abcB + abc.abcC;
3858 dxs[i] = pos;
3860 pthread_mutex_unlock( &font_lock );
3861 return TRUE;
3865 /*************************************************************
3866 * font_GetTextExtentExPointI
3868 static BOOL CDECL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
3870 struct font_physdev *physdev = get_font_dev( dev );
3871 INT i, pos;
3872 ABC abc;
3874 if (!physdev->font)
3876 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
3877 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
3880 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
3882 pthread_mutex_lock( &font_lock );
3883 for (i = pos = 0; i < count; i++)
3885 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
3886 NULL, &abc, 0, NULL, NULL );
3887 pos += abc.abcA + abc.abcB + abc.abcC;
3888 dxs[i] = pos;
3890 pthread_mutex_unlock( &font_lock );
3891 return TRUE;
3895 /*************************************************************
3896 * font_GetTextFace
3898 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
3900 struct font_physdev *physdev = get_font_dev( dev );
3901 const WCHAR *font_name;
3902 INT len;
3904 if (!physdev->font)
3906 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
3907 return dev->funcs->pGetTextFace( dev, count, str );
3909 font_name = get_gdi_font_name( physdev->font );
3910 len = lstrlenW( font_name ) + 1;
3911 if (str)
3913 lstrcpynW( str, font_name, count );
3914 len = min( count, len );
3916 return len;
3920 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
3922 double scale_x, scale_y;
3924 /* Make sure that the font has sane width/height ratio */
3925 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
3927 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
3928 font->aveWidth = 0;
3931 if (font->aveWidth)
3933 scale_x = (double)font->aveWidth;
3934 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3936 else
3937 scale_x = font->scale_y;
3939 scale_x *= fabs(font->matrix.eM11);
3940 scale_y = font->scale_y * fabs(font->matrix.eM22);
3942 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3943 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3945 SCALE_Y(tm->tmHeight);
3946 SCALE_Y(tm->tmAscent);
3947 SCALE_Y(tm->tmDescent);
3948 SCALE_Y(tm->tmInternalLeading);
3949 SCALE_Y(tm->tmExternalLeading);
3951 SCALE_X(tm->tmOverhang);
3952 if (font->fake_bold)
3954 if (!font->scalable) tm->tmOverhang++;
3955 tm->tmAveCharWidth++;
3956 tm->tmMaxCharWidth++;
3958 SCALE_X(tm->tmAveCharWidth);
3959 SCALE_X(tm->tmMaxCharWidth);
3961 #undef SCALE_X
3962 #undef SCALE_Y
3965 /*************************************************************
3966 * font_GetTextMetrics
3968 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
3970 struct font_physdev *physdev = get_font_dev( dev );
3971 BOOL ret = FALSE;
3973 if (!physdev->font)
3975 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
3976 return dev->funcs->pGetTextMetrics( dev, metrics );
3979 pthread_mutex_lock( &font_lock );
3980 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
3981 font_funcs->set_bitmap_text_metrics( physdev->font ))
3983 *metrics = physdev->font->otm.otmTextMetrics;
3984 scale_font_metrics( physdev->font, metrics );
3985 ret = TRUE;
3987 pthread_mutex_unlock( &font_lock );
3988 return ret;
3992 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
3994 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3995 a single face with the requested charset. The idea is to check if
3996 the selected font supports the current ANSI codepage, if it does
3997 return the corresponding charset, else return the first charset */
3999 int i;
4001 if (translate_charset_info( (DWORD*)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
4003 const struct gdi_font_link *font_link;
4005 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
4006 font_link = find_gdi_font_link(family_name);
4007 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
4009 for (i = 0; i < 32; i++)
4011 DWORD fs0 = 1u << i;
4012 if (face->fs.fsCsb[0] & fs0)
4014 if (translate_charset_info(&fs0, csi, TCI_SRCFONTSIG)) return;
4015 FIXME("TCI failing on %x\n", fs0);
4019 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4020 face->fs.fsCsb[0], debugstr_w(face->file));
4021 csi->ciACP = ansi_cp.CodePage;
4022 csi->ciCharset = DEFAULT_CHARSET;
4025 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
4027 struct gdi_font *font;
4028 struct gdi_font_face *face;
4029 INT height;
4030 CHARSETINFO csi;
4031 const WCHAR *orig_name = NULL;
4032 BOOL substituted = FALSE;
4034 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
4036 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4037 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4038 original value lfCharSet. Note this is a special case for
4039 Symbol and doesn't happen at least for "Wingdings*" */
4040 if (!facename_compare( lf->lfFaceName, symbolW, -1 )) lf->lfCharSet = SYMBOL_CHARSET;
4042 /* check the cache first */
4043 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4045 TRACE( "returning cached gdiFont(%p)\n", font );
4046 return font;
4048 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &substituted, &orig_name )))
4050 FIXME( "can't find a single appropriate font - bailing\n" );
4051 return NULL;
4053 height = lf->lfHeight;
4055 font = create_gdi_font( face, orig_name, lf );
4056 font->use_logfont_name = substituted;
4057 font->matrix = dcmat;
4058 font->can_use_bitmap = can_use_bitmap;
4059 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
4060 font->charset = csi.ciCharset;
4061 font->codepage = csi.ciACP;
4063 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
4064 face->data_ptr, face->face_index );
4066 font->aveWidth = height ? lf->lfWidth : 0;
4067 if (!face->scalable)
4069 /* Windows uses integer scaling factors for bitmap fonts */
4070 INT scale, scaled_height, diff;
4071 struct gdi_font *cachedfont;
4073 if (height > 0)
4074 diff = height - (signed int)face->size.height;
4075 else
4076 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
4078 /* FIXME: rotation of bitmap fonts is ignored */
4079 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
4080 if (font->aveWidth)
4081 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
4082 font->matrix.eM11 = font->matrix.eM22 = 1.0;
4083 dcmat.eM11 = dcmat.eM22 = 1.0;
4084 /* As we changed the matrix, we need to search the cache for the font again,
4085 * otherwise we might explode the cache. */
4086 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4088 TRACE("Found cached font after non-scalable matrix rescale!\n");
4089 free_gdi_font( font );
4090 return cachedfont;
4093 if (height != 0) height = diff;
4094 height += face->size.height;
4096 scale = (height + face->size.height - 1) / face->size.height;
4097 scaled_height = scale * face->size.height;
4098 /* Only jump to the next height if the difference <= 25% original height */
4099 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4100 /* The jump between unscaled and doubled is delayed by 1 */
4101 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4102 font->scale_y = scale;
4103 TRACE("font scale y: %d\n", font->scale_y);
4106 if (!font_funcs->load_font( font ))
4108 free_gdi_font( font );
4109 return NULL;
4112 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
4113 font->vert_feature = get_GSUB_vert_feature( font );
4115 create_child_font_list( font );
4117 TRACE( "caching: gdiFont=%p\n", font );
4118 cache_gdi_font( font );
4119 return font;
4122 /*************************************************************
4123 * font_SelectFont
4125 static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4127 struct font_physdev *physdev = get_font_dev( dev );
4128 struct gdi_font *font = NULL, *prev = physdev->font;
4129 DC *dc = get_physdev_dc( dev );
4131 if (hfont)
4133 LOGFONTW lf;
4134 FMAT2 dcmat;
4135 BOOL can_use_bitmap = !!(NtGdiGetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
4137 NtGdiExtGetObjectW( hfont, sizeof(lf), &lf );
4138 switch (lf.lfQuality)
4140 case NONANTIALIASED_QUALITY:
4141 if (!*aa_flags) *aa_flags = GGO_BITMAP;
4142 break;
4143 case ANTIALIASED_QUALITY:
4144 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
4145 break;
4148 lf.lfWidth = abs(lf.lfWidth);
4150 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4151 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4152 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4153 lf.lfEscapement );
4155 if (dc->attr->graphics_mode == GM_ADVANCED)
4157 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
4158 /* try to avoid not necessary glyph transformations */
4159 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4161 lf.lfHeight *= fabs(dcmat.eM11);
4162 lf.lfWidth *= fabs(dcmat.eM11);
4163 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4166 else
4168 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4169 dcmat.eM11 = dcmat.eM22 = 1.0;
4170 dcmat.eM21 = dcmat.eM12 = 0;
4171 lf.lfOrientation = lf.lfEscapement;
4172 if (dc->vport2WorldValid)
4174 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4175 lf.lfOrientation = -lf.lfOrientation;
4176 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4177 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4180 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
4182 pthread_mutex_lock( &font_lock );
4184 font = select_font( &lf, dcmat, can_use_bitmap );
4186 if (font)
4188 if (!*aa_flags) *aa_flags = font->aa_flags;
4189 if (!*aa_flags)
4191 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
4192 *aa_flags = subpixel_orientation;
4193 else
4194 *aa_flags = font_smoothing;
4196 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
4198 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
4199 pthread_mutex_unlock( &font_lock );
4201 physdev->font = font;
4202 if (prev) release_gdi_font( prev );
4203 return font ? hfont : 0;
4207 const struct gdi_dc_funcs font_driver =
4209 NULL, /* pAbortDoc */
4210 NULL, /* pAbortPath */
4211 NULL, /* pAlphaBlend */
4212 NULL, /* pAngleArc */
4213 NULL, /* pArc */
4214 NULL, /* pArcTo */
4215 NULL, /* pBeginPath */
4216 NULL, /* pBlendImage */
4217 NULL, /* pChord */
4218 NULL, /* pCloseFigure */
4219 NULL, /* pCreateCompatibleDC */
4220 font_CreateDC, /* pCreateDC */
4221 font_DeleteDC, /* pDeleteDC */
4222 NULL, /* pDeleteObject */
4223 NULL, /* pEllipse */
4224 NULL, /* pEndDoc */
4225 NULL, /* pEndPage */
4226 NULL, /* pEndPath */
4227 font_EnumFonts, /* pEnumFonts */
4228 NULL, /* pExtEscape */
4229 NULL, /* pExtFloodFill */
4230 NULL, /* pExtTextOut */
4231 NULL, /* pFillPath */
4232 NULL, /* pFillRgn */
4233 font_FontIsLinked, /* pFontIsLinked */
4234 NULL, /* pFrameRgn */
4235 NULL, /* pGetBoundsRect */
4236 font_GetCharABCWidths, /* pGetCharABCWidths */
4237 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
4238 font_GetCharWidth, /* pGetCharWidth */
4239 font_GetCharWidthInfo, /* pGetCharWidthInfo */
4240 NULL, /* pGetDeviceCaps */
4241 NULL, /* pGetDeviceGammaRamp */
4242 font_GetFontData, /* pGetFontData */
4243 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
4244 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
4245 font_GetGlyphIndices, /* pGetGlyphIndices */
4246 font_GetGlyphOutline, /* pGetGlyphOutline */
4247 NULL, /* pGetICMProfile */
4248 NULL, /* pGetImage */
4249 font_GetKerningPairs, /* pGetKerningPairs */
4250 NULL, /* pGetNearestColor */
4251 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
4252 NULL, /* pGetPixel */
4253 NULL, /* pGetSystemPaletteEntries */
4254 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
4255 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
4256 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
4257 font_GetTextFace, /* pGetTextFace */
4258 font_GetTextMetrics, /* pGetTextMetrics */
4259 NULL, /* pGradientFill */
4260 NULL, /* pInvertRgn */
4261 NULL, /* pLineTo */
4262 NULL, /* pMoveTo */
4263 NULL, /* pPaintRgn */
4264 NULL, /* pPatBlt */
4265 NULL, /* pPie */
4266 NULL, /* pPolyBezier */
4267 NULL, /* pPolyBezierTo */
4268 NULL, /* pPolyDraw */
4269 NULL, /* pPolyPolygon */
4270 NULL, /* pPolyPolyline */
4271 NULL, /* pPolylineTo */
4272 NULL, /* pPutImage */
4273 NULL, /* pRealizeDefaultPalette */
4274 NULL, /* pRealizePalette */
4275 NULL, /* pRectangle */
4276 NULL, /* pResetDC */
4277 NULL, /* pRoundRect */
4278 NULL, /* pSelectBitmap */
4279 NULL, /* pSelectBrush */
4280 font_SelectFont, /* pSelectFont */
4281 NULL, /* pSelectPen */
4282 NULL, /* pSetBkColor */
4283 NULL, /* pSetBoundsRect */
4284 NULL, /* pSetDCBrushColor */
4285 NULL, /* pSetDCPenColor */
4286 NULL, /* pSetDIBitsToDevice */
4287 NULL, /* pSetDeviceClipping */
4288 NULL, /* pSetDeviceGammaRamp */
4289 NULL, /* pSetPixel */
4290 NULL, /* pSetTextColor */
4291 NULL, /* pStartDoc */
4292 NULL, /* pStartPage */
4293 NULL, /* pStretchBlt */
4294 NULL, /* pStretchDIBits */
4295 NULL, /* pStrokeAndFillPath */
4296 NULL, /* pStrokePath */
4297 NULL, /* pUnrealizePalette */
4298 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
4299 NULL, /* pD3DKMTCloseAdapter */
4300 NULL, /* pD3DKMTOpenAdapterFromLuid */
4301 NULL, /* pD3DKMTQueryVideoMemoryInfo */
4302 NULL, /* pD3DKMTSetVidPnSourceOwner */
4303 GDI_PRIORITY_FONT_DRV /* priority */
4306 static BOOL get_key_value( HKEY key, const char *name, DWORD *value )
4308 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[12 * sizeof(WCHAR)])];
4309 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4310 DWORD count;
4312 count = query_reg_ascii_value( key, name, info, sizeof(value_buffer) );
4313 if (count)
4315 if (info->Type == REG_DWORD) memcpy( value, info->Data, sizeof(*value) );
4316 else *value = wcstol( (const WCHAR *)info->Data, NULL, 10 );
4318 return !!count;
4321 static UINT init_font_options(void)
4323 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[20 * sizeof(WCHAR)])];
4324 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4325 HKEY key;
4326 DWORD i, val, gamma = 1400;
4327 UINT dpi = 0;
4329 if (query_reg_ascii_value( wine_fonts_key, "AntialiasFakeBoldOrItalic",
4330 info, sizeof(value_buffer) ) && info->Type == REG_SZ)
4332 static const WCHAR valsW[] = {'y','Y','t','T','1',0};
4333 antialias_fakes = (wcschr( valsW, *(const WCHAR *)info->Data ) != NULL);
4336 if ((key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
4338 /* FIXME: handle vertical orientations even though Windows doesn't */
4339 if (get_key_value( key, "FontSmoothingOrientation", &val ))
4341 switch (val)
4343 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4344 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
4345 break;
4346 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4347 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
4348 break;
4351 if (get_key_value( key, "FontSmoothing", &val ) && val /* enabled */)
4353 if (get_key_value( key, "FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4354 font_smoothing = subpixel_orientation;
4355 else
4356 font_smoothing = GGO_GRAY4_BITMAP;
4358 if (get_key_value( key, "FontSmoothingGamma", &val ) && val)
4360 gamma = min( max( val, 1000 ), 2200 );
4362 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4363 NtClose( key );
4366 /* Calibrating the difference between the registry value and the Wine gamma value.
4367 This looks roughly similar to Windows Native with the same registry value.
4368 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4369 gamma = 1000 * gamma / 1400;
4370 if (gamma != 1000)
4372 for (i = 0; i < 256; i++)
4374 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
4375 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
4379 if (!dpi && (key = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) )))
4381 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4382 NtClose( key );
4384 if (!dpi) dpi = 96;
4386 font_gamma_ramp.gamma = gamma;
4387 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp.gamma, dpi );
4388 return dpi;
4392 /* compute positions for text rendering, in device coords */
4393 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4395 TEXTMETRICW tm;
4396 PHYSDEV dev;
4398 size->cx = size->cy = 0;
4399 if (!count) return TRUE;
4401 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4402 dev->funcs->pGetTextMetrics( dev, &tm );
4404 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4405 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4407 if (dc->breakExtra || dc->breakRem)
4409 int i, space = 0, rem = dc->breakRem;
4411 for (i = 0; i < count; i++)
4413 if (str[i] == tm.tmBreakChar)
4415 space += dc->breakExtra;
4416 if (rem > 0)
4418 space++;
4419 rem--;
4422 dx[i] += space;
4425 size->cx = dx[count - 1];
4426 size->cy = tm.tmHeight;
4427 return TRUE;
4430 /* compute positions for text rendering, in device coords */
4431 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4433 TEXTMETRICW tm;
4434 PHYSDEV dev;
4436 size->cx = size->cy = 0;
4437 if (!count) return TRUE;
4439 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4440 dev->funcs->pGetTextMetrics( dev, &tm );
4442 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4443 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4445 if (dc->breakExtra || dc->breakRem)
4447 WORD space_index;
4448 int i, space = 0, rem = dc->breakRem;
4450 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4451 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4453 for (i = 0; i < count; i++)
4455 if (indices[i] == space_index)
4457 space += dc->breakExtra;
4458 if (rem > 0)
4460 space++;
4461 rem--;
4464 dx[i] += space;
4467 size->cx = dx[count - 1];
4468 size->cy = tm.tmHeight;
4469 return TRUE;
4472 /***********************************************************************
4473 * get_text_charset_info
4475 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4477 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4479 UINT ret = DEFAULT_CHARSET;
4480 PHYSDEV dev;
4482 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4483 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4485 if (ret == DEFAULT_CHARSET && fs)
4486 memset(fs, 0, sizeof(FONTSIGNATURE));
4487 return ret;
4490 /***********************************************************************
4491 * NtGdiGetTextCharsetInfo (win32u.@)
4493 UINT WINAPI NtGdiGetTextCharsetInfo( HDC hdc, FONTSIGNATURE *fs, DWORD flags )
4495 UINT ret = DEFAULT_CHARSET;
4496 DC *dc = get_dc_ptr(hdc);
4498 if (dc)
4500 ret = get_text_charset_info( dc, fs, flags );
4501 release_dc_ptr( dc );
4503 return ret;
4506 /***********************************************************************
4507 * NtGdiHfontCreate (win32u.@)
4509 HFONT WINAPI NtGdiHfontCreate( const void *logfont, ULONG size, ULONG type,
4510 ULONG flags, void *data )
4512 HFONT hFont;
4513 FONTOBJ *fontPtr;
4514 const LOGFONTW *plf;
4516 if (!logfont) return 0;
4518 if (size == sizeof(ENUMLOGFONTEXDVW) || size == sizeof(ENUMLOGFONTEXW))
4520 const ENUMLOGFONTEXW *lfex = logfont;
4522 if (lfex->elfFullName[0] || lfex->elfStyle[0] || lfex->elfScript[0])
4524 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
4525 debugstr_w( lfex->elfFullName ), debugstr_w( lfex->elfStyle ),
4526 debugstr_w( lfex->elfScript ));
4529 plf = &lfex->elfLogFont;
4531 else if (size != sizeof(LOGFONTW))
4533 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
4534 return 0;
4536 else plf = logfont;
4538 if (!(fontPtr = malloc( sizeof(*fontPtr) ))) return 0;
4540 fontPtr->logfont = *plf;
4542 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, NTGDI_OBJ_FONT, &fontobj_funcs )))
4544 free( fontPtr );
4545 return 0;
4548 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4549 plf->lfHeight, plf->lfWidth,
4550 plf->lfEscapement, plf->lfOrientation,
4551 plf->lfPitchAndFamily,
4552 plf->lfOutPrecision, plf->lfClipPrecision,
4553 plf->lfQuality, plf->lfCharSet,
4554 debugstr_w(plf->lfFaceName),
4555 plf->lfWeight > 400 ? "Bold" : "",
4556 plf->lfItalic ? "Italic" : "",
4557 plf->lfUnderline ? "Underline" : "", hFont);
4559 return hFont;
4562 #define ASSOC_CHARSET_OEM 1
4563 #define ASSOC_CHARSET_ANSI 2
4564 #define ASSOC_CHARSET_SYMBOL 4
4566 static DWORD get_associated_charset_info(void)
4568 static DWORD associated_charset = -1;
4570 if (associated_charset == -1)
4572 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[32 * sizeof(WCHAR)])];
4573 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4574 HKEY hkey;
4576 static const WCHAR yesW[] = {'y','e','s',0};
4578 associated_charset = 0;
4580 if (!(hkey = reg_open_key( NULL, associated_charset_keyW, sizeof(associated_charset_keyW) )))
4581 return 0;
4583 if (query_reg_ascii_value( hkey, "ANSI(00)", info, sizeof(value_buffer) ) &&
4584 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4585 associated_charset |= ASSOC_CHARSET_ANSI;
4587 if (query_reg_ascii_value( hkey, "OEM(FF)", info, sizeof(value_buffer) ) &&
4588 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4589 associated_charset |= ASSOC_CHARSET_OEM;
4591 if (query_reg_ascii_value( hkey, "SYMBOL(02)", info, sizeof(value_buffer) ) &&
4592 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4593 associated_charset |= ASSOC_CHARSET_SYMBOL;
4595 NtClose( hkey );
4597 TRACE("associated_charset = %d\n", associated_charset);
4600 return associated_charset;
4603 static void update_font_code_page( DC *dc, HANDLE font )
4605 CHARSETINFO csi;
4606 int charset = get_text_charset_info( dc, NULL, 0 );
4608 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
4610 LOGFONTW lf;
4612 NtGdiExtGetObjectW( font, sizeof(lf), &lf );
4613 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
4614 charset = DEFAULT_CHARSET;
4617 /* Hmm, nicely designed api this one! */
4618 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
4619 dc->attr->font_code_page = csi.ciACP;
4620 else {
4621 switch(charset) {
4622 case OEM_CHARSET:
4623 dc->attr->font_code_page = oem_cp.CodePage;
4624 break;
4625 case DEFAULT_CHARSET:
4626 dc->attr->font_code_page = ansi_cp.CodePage;
4627 break;
4629 case VISCII_CHARSET:
4630 case TCVN_CHARSET:
4631 case KOI8_CHARSET:
4632 case ISO3_CHARSET:
4633 case ISO4_CHARSET:
4634 case ISO10_CHARSET:
4635 case CELTIC_CHARSET:
4636 /* FIXME: These have no place here, but because x11drv
4637 enumerates fonts with these (made up) charsets some apps
4638 might use them and then the FIXME below would become
4639 annoying. Now we could pick the intended codepage for
4640 each of these, but since it's broken anyway we'll just
4641 use CP_ACP and hope it'll go away...
4643 dc->attr->font_code_page = CP_ACP;
4644 break;
4646 default:
4647 FIXME("Can't find codepage for charset %d\n", charset);
4648 dc->attr->font_code_page = CP_ACP;
4649 break;
4653 TRACE( "charset %d => cp %d\n", charset, dc->attr->font_code_page );
4656 /***********************************************************************
4657 * NtGdiSelectFont (win32u.@)
4659 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
4661 HGDIOBJ ret = 0;
4662 DC *dc = get_dc_ptr( hdc );
4663 PHYSDEV physdev;
4664 UINT aa_flags = 0;
4666 if (!dc) return 0;
4668 if (!GDI_inc_ref_count( handle ))
4670 release_dc_ptr( dc );
4671 return 0;
4674 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
4675 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
4677 ret = dc->hFont;
4678 dc->hFont = handle;
4679 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
4680 update_font_code_page( dc, handle );
4681 if (dc->font_gamma_ramp == NULL)
4682 dc->font_gamma_ramp = &font_gamma_ramp;
4683 GDI_dec_ref_count( ret );
4685 else GDI_dec_ref_count( handle );
4687 release_dc_ptr( dc );
4688 return ret;
4692 /***********************************************************************
4693 * FONT_GetObjectW
4695 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
4697 FONTOBJ *font = GDI_GetObjPtr( handle, NTGDI_OBJ_FONT );
4699 if (!font) return 0;
4700 if (buffer)
4702 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
4703 memcpy( buffer, &font->logfont, count );
4705 else count = sizeof(LOGFONTW);
4706 GDI_ReleaseObj( handle );
4707 return count;
4711 /***********************************************************************
4712 * FONT_DeleteObject
4714 static BOOL FONT_DeleteObject( HGDIOBJ handle )
4716 FONTOBJ *obj;
4718 if (!(obj = free_gdi_handle( handle ))) return FALSE;
4719 free( obj );
4720 return TRUE;
4724 struct font_enum
4726 HDC hdc;
4727 struct font_enum_entry *buf;
4728 ULONG size;
4729 ULONG count;
4730 ULONG charset;
4733 static INT WINAPI font_enum_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
4734 DWORD type, LPARAM lp )
4736 struct font_enum *fe = (struct font_enum *)lp;
4738 if (fe->charset != DEFAULT_CHARSET && lf->lfCharSet != fe->charset) return 1;
4739 if ((type & RASTER_FONTTYPE) && !(NtGdiGetDeviceCaps( fe->hdc, TEXTCAPS ) & TC_RA_ABLE))
4740 return 1;
4742 if (fe->buf && fe->count < fe->size)
4744 fe->buf[fe->count].type = type;
4745 fe->buf[fe->count].lf = *(const ENUMLOGFONTEXW *)lf;
4746 fe->buf[fe->count].tm = *(const NEWTEXTMETRICEXW *)tm;
4748 fe->count++;
4749 return 1;
4752 /***********************************************************************
4753 * NtGdiEnumFonts (win32u.@)
4755 BOOL WINAPI NtGdiEnumFonts( HDC hdc, ULONG type, ULONG win32_compat, ULONG face_name_len,
4756 const WCHAR *face_name, ULONG charset, ULONG *count, void *buf )
4758 struct font_enum fe;
4759 PHYSDEV physdev;
4760 LOGFONTW lf;
4761 BOOL ret;
4762 DC *dc;
4764 if (!(dc = get_dc_ptr( hdc ))) return 0;
4766 memset( &lf, 0, sizeof(lf) );
4767 lf.lfCharSet = charset;
4768 if (face_name_len) memcpy( lf.lfFaceName, face_name, face_name_len * sizeof(WCHAR) );
4770 fe.hdc = hdc;
4771 fe.buf = buf;
4772 fe.size = *count / sizeof(*fe.buf);
4773 fe.count = 0;
4774 fe.charset = charset;
4776 physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
4777 ret = physdev->funcs->pEnumFonts( physdev, &lf, font_enum_proc, (LPARAM)&fe );
4778 if (ret && buf) ret = fe.count <= fe.size;
4779 *count = fe.count * sizeof(*fe.buf);
4781 release_dc_ptr( dc );
4782 return ret;
4786 /***********************************************************************
4787 * NtGdiSetTextJustification (win32u.@)
4789 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
4791 DC *dc;
4793 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
4795 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
4796 dc->attr->wnd_ext.cx );
4797 if (!extra) breaks = 0;
4798 if (breaks)
4800 dc->breakExtra = extra / breaks;
4801 dc->breakRem = extra - (breaks * dc->breakExtra);
4803 else
4805 dc->breakExtra = 0;
4806 dc->breakRem = 0;
4809 release_dc_ptr( dc );
4810 return TRUE;
4814 /***********************************************************************
4815 * NtGdiGetTextFaceW (win32u.@)
4817 INT WINAPI NtGdiGetTextFaceW( HDC hdc, INT count, WCHAR *name, BOOL alias_name )
4819 PHYSDEV dev;
4820 INT ret;
4822 DC * dc = get_dc_ptr( hdc );
4823 if (!dc) return 0;
4825 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
4826 ret = dev->funcs->pGetTextFace( dev, count, name );
4827 release_dc_ptr( dc );
4828 return ret;
4832 /***********************************************************************
4833 * NtGdiGetTextExtentExW (win32u.@)
4835 * Return the size of the string as it would be if it was output properly by
4836 * e.g. TextOut.
4838 BOOL WINAPI NtGdiGetTextExtentExW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
4839 INT *nfit, INT *dxs, SIZE *size, UINT flags )
4841 DC *dc;
4842 int i;
4843 BOOL ret;
4844 INT buffer[256], *pos = dxs;
4846 if (count < 0) return FALSE;
4848 dc = get_dc_ptr(hdc);
4849 if (!dc) return FALSE;
4851 if (!dxs)
4853 pos = buffer;
4854 if (count > 256 && !(pos = malloc( count * sizeof(*pos) )))
4856 release_dc_ptr( dc );
4857 return FALSE;
4862 if (flags)
4863 ret = get_char_positions_indices( dc, str, count, pos, size );
4864 else
4865 ret = get_char_positions( dc, str, count, pos, size );
4866 if (ret)
4868 if (dxs || nfit)
4870 for (i = 0; i < count; i++)
4872 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
4873 (i + 1) * dc->attr->char_extra;
4874 if (nfit && dx > (unsigned int)max_ext) break;
4875 if (dxs) dxs[i] = dx;
4877 if (nfit) *nfit = i;
4880 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
4881 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
4884 if (pos != buffer && pos != dxs) free( pos );
4885 release_dc_ptr( dc );
4887 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
4888 return ret;
4891 /***********************************************************************
4892 * NtGdiGetTextMetricsW (win32u.@)
4894 BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags )
4896 PHYSDEV physdev;
4897 BOOL ret = FALSE;
4898 DC * dc = get_dc_ptr( hdc );
4899 if (!dc) return FALSE;
4901 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4902 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
4904 if (ret)
4906 /* device layer returns values in device units
4907 * therefore we have to convert them to logical */
4909 metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
4910 metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
4911 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
4912 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
4913 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
4914 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
4915 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
4916 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
4917 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
4918 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
4919 ret = TRUE;
4921 TRACE("text metrics:\n"
4922 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
4923 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
4924 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
4925 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
4926 " PitchAndFamily = %02x\n"
4927 " --------------------\n"
4928 " InternalLeading = %i\n"
4929 " Ascent = %i\n"
4930 " Descent = %i\n"
4931 " Height = %i\n",
4932 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
4933 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
4934 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
4935 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
4936 metrics->tmPitchAndFamily,
4937 metrics->tmInternalLeading,
4938 metrics->tmAscent,
4939 metrics->tmDescent,
4940 metrics->tmHeight );
4942 release_dc_ptr( dc );
4943 return ret;
4947 /***********************************************************************
4948 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
4950 UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData,
4951 OUTLINETEXTMETRICW *lpOTM, ULONG opts )
4953 DC *dc = get_dc_ptr( hdc );
4954 OUTLINETEXTMETRICW *output = lpOTM;
4955 PHYSDEV dev;
4956 UINT ret;
4958 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
4959 if(!dc) return 0;
4961 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
4962 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
4964 if (lpOTM && ret > cbData)
4966 output = malloc( ret );
4967 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
4970 if (lpOTM && ret)
4972 output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
4973 output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
4974 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
4975 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
4976 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
4977 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
4978 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
4979 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
4980 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
4981 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
4982 output->otmAscent = height_to_LP( dc, output->otmAscent);
4983 output->otmDescent = height_to_LP( dc, output->otmDescent);
4984 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
4985 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
4986 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
4987 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
4988 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
4989 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
4990 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
4991 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
4992 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
4993 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
4994 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
4995 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
4996 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
4997 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
4998 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
4999 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5000 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5001 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5002 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5003 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5004 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5005 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5007 if(output != lpOTM)
5009 memcpy(lpOTM, output, cbData);
5010 free( output );
5011 ret = cbData;
5014 release_dc_ptr(dc);
5015 return ret;
5018 /***********************************************************************
5019 * NtGdiGetCharWidthW (win32u.@)
5021 BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5022 ULONG flags, void *buf )
5024 UINT i, count = last;
5025 BOOL ret;
5026 PHYSDEV dev;
5027 DC *dc;
5029 if (flags & NTGDI_GETCHARWIDTH_INDICES)
5031 ABC *abc;
5032 unsigned int i;
5034 if (!(abc = malloc( count * sizeof(ABC) )))
5035 return FALSE;
5037 if (!NtGdiGetCharABCWidthsW( hdc, first, last, chars,
5038 NTGDI_GETCHARABCWIDTHS_INT | NTGDI_GETCHARABCWIDTHS_INDICES,
5039 abc ))
5041 free( abc );
5042 return FALSE;
5045 for (i = 0; i < count; i++)
5046 ((INT *)buf)[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5048 free( abc );
5049 return TRUE;
5052 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5054 if (!chars) count = last - first + 1;
5055 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5056 ret = dev->funcs->pGetCharWidth( dev, first, count, chars, buf );
5058 if (ret)
5060 if (flags & NTGDI_GETCHARWIDTH_INT)
5062 INT *buffer = buf;
5063 /* convert device units to logical */
5064 for (i = 0; i < count; i++)
5065 buffer[i] = width_to_LP( dc, buffer[i] );
5067 else
5069 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
5070 for (i = 0; i < count; i++)
5071 ((float *)buf)[i] = ((int *)buf)[i] * scale;
5074 release_dc_ptr( dc );
5075 return ret;
5079 /* helper for nulldrv_ExtTextOut */
5080 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5081 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5083 UINT indices[3] = {0, 0, 0x20};
5084 unsigned int i;
5085 DWORD ret, size;
5086 int stride;
5088 indices[0] = index;
5089 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5091 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5093 index = indices[i];
5094 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, 0, NULL, &identity, FALSE );
5095 if (ret != GDI_ERROR) break;
5098 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5099 if (!image) return ERROR_SUCCESS;
5101 image->ptr = NULL;
5102 image->free = NULL;
5103 if (!ret) /* empty glyph */
5105 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5106 return ERROR_SUCCESS;
5109 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5110 size = metrics->gmBlackBoxY * stride;
5112 if (!(image->ptr = malloc( size ))) return ERROR_OUTOFMEMORY;
5113 image->is_copy = TRUE;
5114 image->free = free_heap_bits;
5116 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, size, image->ptr,
5117 &identity, FALSE );
5118 if (ret == GDI_ERROR)
5120 free( image->ptr );
5121 return ERROR_NOT_FOUND;
5123 return ERROR_SUCCESS;
5126 /* helper for nulldrv_ExtTextOut */
5127 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5128 LPCWSTR str, UINT count, const INT *dx )
5130 UINT i;
5131 RECT rect, bounds;
5133 reset_bounds( &bounds );
5134 for (i = 0; i < count; i++)
5136 GLYPHMETRICS metrics;
5138 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5140 rect.left = x + metrics.gmptGlyphOrigin.x;
5141 rect.top = y - metrics.gmptGlyphOrigin.y;
5142 rect.right = rect.left + metrics.gmBlackBoxX;
5143 rect.bottom = rect.top + metrics.gmBlackBoxY;
5144 add_bounds_rect( &bounds, &rect );
5146 if (dx)
5148 if (flags & ETO_PDY)
5150 x += dx[ i * 2 ];
5151 y += dx[ i * 2 + 1];
5153 else x += dx[ i ];
5155 else
5157 x += metrics.gmCellIncX;
5158 y += metrics.gmCellIncY;
5161 return bounds;
5164 /* helper for nulldrv_ExtTextOut */
5165 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5166 const struct gdi_image_bits *image, const RECT *clip )
5168 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5169 UINT i, count, max_count;
5170 LONG x, y;
5171 BYTE *ptr = image->ptr;
5172 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5173 POINT *pts;
5174 RECT rect, clipped_rect;
5176 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5177 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5178 rect.right = rect.left + metrics->gmBlackBoxX;
5179 rect.bottom = rect.top + metrics->gmBlackBoxY;
5180 if (!clip) clipped_rect = rect;
5181 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5183 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5184 pts = malloc( max_count * sizeof(*pts) );
5185 if (!pts) return;
5187 count = 0;
5188 ptr += (clipped_rect.top - rect.top) * stride;
5189 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5191 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5193 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5194 pts[count].x = rect.left + x;
5195 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5196 pts[count + 1].x = rect.left + x;
5197 if (pts[count + 1].x > pts[count].x)
5199 pts[count].y = pts[count + 1].y = y;
5200 count += 2;
5204 assert( count <= max_count );
5205 dp_to_lp( dc, pts, count );
5206 for (i = 0; i < count; i += 2)
5208 const ULONG pts_count = 2;
5209 NtGdiPolyPolyDraw( dc->hSelf, pts + i, &pts_count, 1, NtGdiPolyPolyline );
5211 free( pts );
5214 /***********************************************************************
5215 * nulldrv_ExtTextOut
5217 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5218 LPCWSTR str, UINT count, const INT *dx )
5220 DC *dc = get_nulldrv_dc( dev );
5221 UINT i;
5222 DWORD err;
5223 HGDIOBJ orig;
5224 HPEN pen;
5226 if (flags & ETO_OPAQUE)
5228 RECT rc = *rect;
5229 COLORREF brush_color = NtGdiGetNearestColor( dev->hdc, dc->attr->background_color );
5230 HBRUSH brush = NtGdiCreateSolidBrush( brush_color, NULL);
5232 if (brush)
5234 orig = NtGdiSelectBrush( dev->hdc, brush );
5235 dp_to_lp( dc, (POINT *)&rc, 2 );
5236 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5237 NtGdiSelectBrush( dev->hdc, orig );
5238 NtGdiDeleteObjectApp( brush );
5242 if (!count) return TRUE;
5244 if (dc->aa_flags != GGO_BITMAP)
5246 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5247 BITMAPINFO *info = (BITMAPINFO *)buffer;
5248 struct gdi_image_bits bits;
5249 struct bitblt_coords src, dst;
5250 PHYSDEV dst_dev;
5251 /* FIXME Subpixel modes */
5252 UINT aa_flags = GGO_GRAY4_BITMAP;
5254 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5255 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5256 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5257 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5259 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5260 src.x = src.visrect.left;
5261 src.y = src.visrect.top;
5262 src.width = src.visrect.right - src.visrect.left;
5263 src.height = src.visrect.bottom - src.visrect.top;
5264 dst = src;
5265 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5266 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5268 /* we can avoid the GetImage, just query the needed format */
5269 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5270 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5271 info->bmiHeader.biWidth = src.width;
5272 info->bmiHeader.biHeight = -src.height;
5273 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5274 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5275 if (!err || err == ERROR_BAD_FORMAT)
5277 /* make the source rectangle relative to the source bits */
5278 src.x = src.y = 0;
5279 src.visrect.left = src.visrect.top = 0;
5280 src.visrect.right = src.width;
5281 src.visrect.bottom = src.height;
5283 bits.ptr = malloc( info->bmiHeader.biSizeImage );
5284 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5285 bits.is_copy = TRUE;
5286 bits.free = free_heap_bits;
5287 err = ERROR_SUCCESS;
5290 else
5292 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5293 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5294 if (!err && !bits.is_copy)
5296 void *ptr = malloc( info->bmiHeader.biSizeImage );
5297 if (!ptr)
5299 if (bits.free) bits.free( &bits );
5300 return ERROR_OUTOFMEMORY;
5302 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5303 if (bits.free) bits.free( &bits );
5304 bits.ptr = ptr;
5305 bits.is_copy = TRUE;
5306 bits.free = free_heap_bits;
5309 if (!err)
5311 /* make x,y relative to the image bits */
5312 x += src.visrect.left - dst.visrect.left;
5313 y += src.visrect.top - dst.visrect.top;
5314 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5315 aa_flags, str, count, dx );
5316 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5317 if (bits.free) bits.free( &bits );
5318 return !err;
5322 pen = NtGdiCreatePen( PS_SOLID, 1, dc->attr->text_color, NULL );
5323 orig = NtGdiSelectPen( dev->hdc, pen );
5325 for (i = 0; i < count; i++)
5327 GLYPHMETRICS metrics;
5328 struct gdi_image_bits image;
5330 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5331 if (err) continue;
5333 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5334 if (image.free) image.free( &image );
5336 if (dx)
5338 if (flags & ETO_PDY)
5340 x += dx[ i * 2 ];
5341 y += dx[ i * 2 + 1];
5343 else x += dx[ i ];
5345 else
5347 x += metrics.gmCellIncX;
5348 y += metrics.gmCellIncY;
5352 NtGdiSelectPen( dev->hdc, orig );
5353 NtGdiDeleteObjectApp( pen );
5354 return TRUE;
5357 /***********************************************************************
5358 * get_line_width
5360 * Scale the underline / strikeout line width.
5362 static inline int get_line_width( DC *dc, int metric_size )
5364 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5365 if (width == 0) width = 1;
5366 if (metric_size < 0) width = -width;
5367 return width;
5370 /***********************************************************************
5371 * NtGdiExtTextOutW (win32u.@)
5373 * Draws text using the currently selected font, background color, and text color.
5376 * PARAMS
5377 * x,y [I] coordinates of string
5378 * flags [I]
5379 * ETO_GRAYED - undocumented on MSDN
5380 * ETO_OPAQUE - use background color for fill the rectangle
5381 * ETO_CLIPPED - clipping text to the rectangle
5382 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5383 * than encoded characters. Implies ETO_IGNORELANGUAGE
5384 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5385 * Affects BiDi ordering
5386 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5387 * ETO_PDY - unimplemented
5388 * ETO_NUMERICSLATIN - unimplemented always assumed -
5389 * do not translate numbers into locale representations
5390 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5391 * lprect [I] dimensions for clipping or/and opaquing
5392 * str [I] text string
5393 * count [I] number of symbols in string
5394 * lpDx [I] optional parameter with distance between drawing characters
5396 * RETURNS
5397 * Success: TRUE
5398 * Failure: FALSE
5400 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5401 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5403 BOOL ret = FALSE;
5404 UINT align;
5405 DWORD layout;
5406 POINT pt;
5407 TEXTMETRICW tm;
5408 LOGFONTW lf;
5409 double cosEsc, sinEsc;
5410 INT char_extra;
5411 SIZE sz;
5412 RECT rc;
5413 POINT *deltas = NULL, width = {0, 0};
5414 DC * dc = get_dc_ptr( hdc );
5415 PHYSDEV physdev;
5416 INT breakRem;
5417 static int quietfixme = 0;
5419 if (!dc) return FALSE;
5420 if (count > INT_MAX) return FALSE;
5422 align = dc->attr->text_align;
5423 breakRem = dc->breakRem;
5424 layout = dc->attr->layout;
5426 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5428 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5429 quietfixme = 1;
5432 update_dc( dc );
5433 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5435 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5436 if (layout & LAYOUT_RTL)
5438 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5439 align ^= TA_RTLREADING;
5442 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5443 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5444 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5445 dc->attr->map_mode);
5447 if(align & TA_UPDATECP)
5449 pt = dc->attr->cur_pos;
5450 x = pt.x;
5451 y = pt.y;
5454 NtGdiGetTextMetricsW( hdc, &tm, 0 );
5455 NtGdiExtGetObjectW( dc->hFont, sizeof(lf), &lf );
5457 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5458 lf.lfEscapement = 0;
5460 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5461 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5463 lf.lfEscapement = -lf.lfEscapement;
5466 if(lf.lfEscapement != 0)
5468 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5469 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5471 else
5473 cosEsc = 1;
5474 sinEsc = 0;
5477 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5479 rc = *lprect;
5480 lp_to_dp(dc, (POINT*)&rc, 2);
5481 order_rect( &rc );
5482 if (flags & ETO_OPAQUE)
5483 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5485 else flags &= ~ETO_CLIPPED;
5487 if(count == 0)
5489 ret = TRUE;
5490 goto done;
5493 pt.x = x;
5494 pt.y = y;
5495 lp_to_dp(dc, &pt, 1);
5496 x = pt.x;
5497 y = pt.y;
5499 char_extra = dc->attr->char_extra;
5500 if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5501 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5503 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
5505 UINT i;
5506 POINT total = {0, 0}, desired[2];
5508 deltas = malloc( count * sizeof(*deltas) );
5509 if (lpDx)
5511 if (flags & ETO_PDY)
5513 for (i = 0; i < count; i++)
5515 deltas[i].x = lpDx[i * 2] + char_extra;
5516 deltas[i].y = -lpDx[i * 2 + 1];
5519 else
5521 for (i = 0; i < count; i++)
5523 deltas[i].x = lpDx[i] + char_extra;
5524 deltas[i].y = 0;
5528 else
5530 INT *dx = malloc( count * sizeof(*dx) );
5532 NtGdiGetTextExtentExW( hdc, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX) );
5534 deltas[0].x = dx[0];
5535 deltas[0].y = 0;
5536 for (i = 1; i < count; i++)
5538 deltas[i].x = dx[i] - dx[i - 1];
5539 deltas[i].y = 0;
5541 free( dx );
5544 for(i = 0; i < count; i++)
5546 total.x += deltas[i].x;
5547 total.y += deltas[i].y;
5549 desired[0].x = desired[0].y = 0;
5551 desired[1].x = cosEsc * total.x + sinEsc * total.y;
5552 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
5554 lp_to_dp(dc, desired, 2);
5555 desired[1].x -= desired[0].x;
5556 desired[1].y -= desired[0].y;
5558 if (dc->attr->graphics_mode == GM_COMPATIBLE)
5560 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
5561 desired[1].x = -desired[1].x;
5562 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
5563 desired[1].y = -desired[1].y;
5566 deltas[i].x = desired[1].x - width.x;
5567 deltas[i].y = desired[1].y - width.y;
5569 width = desired[1];
5571 flags |= ETO_PDY;
5573 else
5575 POINT desired[2];
5577 NtGdiGetTextExtentExW( hdc, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX) );
5578 desired[0].x = desired[0].y = 0;
5579 desired[1].x = sz.cx;
5580 desired[1].y = 0;
5581 lp_to_dp(dc, desired, 2);
5582 desired[1].x -= desired[0].x;
5583 desired[1].y -= desired[0].y;
5585 if (dc->attr->graphics_mode == GM_COMPATIBLE)
5587 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
5588 desired[1].x = -desired[1].x;
5589 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
5590 desired[1].y = -desired[1].y;
5592 width = desired[1];
5595 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
5596 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
5597 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
5599 case TA_LEFT:
5600 if (align & TA_UPDATECP)
5602 pt.x = x + width.x;
5603 pt.y = y + width.y;
5604 dp_to_lp(dc, &pt, 1);
5605 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
5607 break;
5609 case TA_CENTER:
5610 x -= width.x / 2;
5611 y -= width.y / 2;
5612 break;
5614 case TA_RIGHT:
5615 x -= width.x;
5616 y -= width.y;
5617 if (align & TA_UPDATECP)
5619 pt.x = x;
5620 pt.y = y;
5621 dp_to_lp(dc, &pt, 1);
5622 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
5624 break;
5627 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
5629 case TA_TOP:
5630 y += tm.tmAscent * cosEsc;
5631 x += tm.tmAscent * sinEsc;
5632 break;
5634 case TA_BOTTOM:
5635 y -= tm.tmDescent * cosEsc;
5636 x -= tm.tmDescent * sinEsc;
5637 break;
5639 case TA_BASELINE:
5640 break;
5643 if (dc->attr->background_mode != TRANSPARENT)
5645 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
5647 if(!(flags & ETO_OPAQUE) || !lprect ||
5648 x < rc.left || x + width.x >= rc.right ||
5649 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
5651 RECT text_box;
5652 text_box.left = x;
5653 text_box.right = x + width.x;
5654 text_box.top = y - tm.tmAscent;
5655 text_box.bottom = y + tm.tmDescent;
5657 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
5658 if (!IsRectEmpty( &text_box ))
5659 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
5664 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
5665 str, count, (INT*)deltas );
5667 done:
5668 free( deltas );
5670 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
5672 int underlinePos, strikeoutPos;
5673 int underlineWidth, strikeoutWidth;
5674 UINT size = NtGdiGetOutlineTextMetricsInternalW( hdc, 0, NULL, 0 );
5675 OUTLINETEXTMETRICW* otm = NULL;
5676 POINT pts[5];
5677 HPEN hpen = NtGdiSelectPen( hdc, GetStockObject(NULL_PEN) );
5678 HBRUSH hbrush = NtGdiCreateSolidBrush( dc->attr->text_color, NULL );
5680 hbrush = NtGdiSelectBrush(hdc, hbrush);
5682 if(!size)
5684 underlinePos = 0;
5685 underlineWidth = tm.tmAscent / 20 + 1;
5686 strikeoutPos = tm.tmAscent / 2;
5687 strikeoutWidth = underlineWidth;
5689 else
5691 otm = malloc( size );
5692 NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
5693 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
5694 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
5695 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
5696 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
5697 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
5698 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
5699 free( otm );
5703 if (lf.lfUnderline)
5705 const ULONG cnt = 5;
5706 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
5707 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
5708 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
5709 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
5710 pts[2].x = pts[1].x + underlineWidth * sinEsc;
5711 pts[2].y = pts[1].y + underlineWidth * cosEsc;
5712 pts[3].x = pts[0].x + underlineWidth * sinEsc;
5713 pts[3].y = pts[0].y + underlineWidth * cosEsc;
5714 pts[4].x = pts[0].x;
5715 pts[4].y = pts[0].y;
5716 dp_to_lp(dc, pts, 5);
5717 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
5720 if (lf.lfStrikeOut)
5722 const ULONG cnt = 5;
5723 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
5724 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
5725 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
5726 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
5727 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
5728 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
5729 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
5730 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
5731 pts[4].x = pts[0].x;
5732 pts[4].y = pts[0].y;
5733 dp_to_lp(dc, pts, 5);
5734 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
5737 NtGdiSelectPen(hdc, hpen);
5738 hbrush = NtGdiSelectBrush(hdc, hbrush);
5739 NtGdiDeleteObjectApp( hbrush );
5742 release_dc_ptr( dc );
5744 return ret;
5748 /******************************************************************************
5749 * NtGdiGetCharABCWidthsW (win32u.@)
5751 * Retrieves widths of characters in range.
5753 * PARAMS
5754 * hdc [I] Handle of device context
5755 * firstChar [I] First character in range to query
5756 * lastChar [I] Last character in range to query
5757 * abc [O] Address of character-width structure
5759 * NOTES
5760 * Only works with TrueType fonts
5762 BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5763 ULONG flags, void *buffer )
5765 DC *dc = get_dc_ptr(hdc);
5766 PHYSDEV dev;
5767 unsigned int i, count = last;
5768 BOOL ret;
5769 TEXTMETRICW tm;
5771 if (!dc) return FALSE;
5773 if (!buffer)
5775 release_dc_ptr( dc );
5776 return FALSE;
5779 if (flags & NTGDI_GETCHARABCWIDTHS_INDICES)
5781 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
5782 ret = dev->funcs->pGetCharABCWidthsI( dev, first, count, chars, buffer );
5784 else
5786 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
5788 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
5789 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5790 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
5792 release_dc_ptr( dc );
5793 return FALSE;
5797 if (!chars) count = last - first + 1;
5798 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
5799 ret = dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
5802 if (ret)
5804 ABC *abc = buffer;
5805 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
5807 /* convert device units to logical */
5808 for (i = 0; i < count; i++)
5810 abc[i].abcA = width_to_LP( dc, abc[i].abcA );
5811 abc[i].abcB = width_to_LP( dc, abc[i].abcB );
5812 abc[i].abcC = width_to_LP( dc, abc[i].abcC );
5815 else
5817 /* convert device units to logical */
5818 FLOAT scale = fabs( dc->xformVport2World.eM11 );
5819 ABCFLOAT *abcf = buffer;
5821 for (i = 0; i < count; i++)
5823 abcf[i].abcfA = abc[i].abcA * scale;
5824 abcf[i].abcfB = abc[i].abcB * scale;
5825 abcf[i].abcfC = abc[i].abcC * scale;
5830 release_dc_ptr( dc );
5831 return ret;
5835 /***********************************************************************
5836 * NtGdiGetGlyphOutline (win32u.@)
5838 DWORD WINAPI NtGdiGetGlyphOutline( HDC hdc, UINT ch, UINT format, GLYPHMETRICS *metrics,
5839 DWORD size, void *buffer, const MAT2 *mat2,
5840 BOOL ignore_rotation )
5842 DC *dc;
5843 DWORD ret;
5844 PHYSDEV dev;
5846 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc, ch, format, metrics, size, buffer, mat2 );
5848 if (!mat2) return GDI_ERROR;
5850 dc = get_dc_ptr(hdc);
5851 if(!dc) return GDI_ERROR;
5853 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
5854 ret = dev->funcs->pGetGlyphOutline( dev, ch & 0xffff, format, metrics, size, buffer, mat2 );
5855 release_dc_ptr( dc );
5856 return ret;
5860 /**********************************************************************
5861 * __wine_get_file_outline_text_metric (win32u.@)
5863 BOOL CDECL __wine_get_file_outline_text_metric( const WCHAR *path, OUTLINETEXTMETRICW *otm )
5865 struct gdi_font *font = NULL;
5867 if (!path || !font_funcs) return FALSE;
5869 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
5870 font->lf.lfHeight = 100;
5871 if (!font_funcs->load_font( font )) goto done;
5872 if (!font_funcs->set_outline_text_metrics( font )) goto done;
5873 *otm = font->otm;
5874 free_gdi_font( font );
5875 return TRUE;
5877 done:
5878 if (font) free_gdi_font( font );
5879 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
5880 return FALSE;
5883 /*************************************************************************
5884 * NtGdiGetKerningPairs (win32u.@)
5886 DWORD WINAPI NtGdiGetKerningPairs( HDC hdc, DWORD count, KERNINGPAIR *kern_pair )
5888 DC *dc;
5889 DWORD ret;
5890 PHYSDEV dev;
5892 TRACE( "(%p,%d,%p)\n", hdc, count, kern_pair );
5894 if (!count && kern_pair)
5896 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
5897 return 0;
5900 dc = get_dc_ptr( hdc );
5901 if (!dc) return 0;
5903 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
5904 ret = dev->funcs->pGetKerningPairs( dev, count, kern_pair );
5905 release_dc_ptr( dc );
5906 return ret;
5909 /*************************************************************************
5910 * NtGdiGetFontData (win32u.@)
5912 * Retrieve data for TrueType font.
5914 * RETURNS
5916 * success: Number of bytes returned
5917 * failure: GDI_ERROR
5919 * NOTES
5921 * Calls RtlSetLastWin32Error()
5924 DWORD WINAPI NtGdiGetFontData( HDC hdc, DWORD table, DWORD offset, void *buffer, DWORD length )
5926 DC *dc = get_dc_ptr(hdc);
5927 PHYSDEV dev;
5928 DWORD ret;
5930 if(!dc) return GDI_ERROR;
5932 dev = GET_DC_PHYSDEV( dc, pGetFontData );
5933 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
5934 release_dc_ptr( dc );
5935 return ret;
5938 /*************************************************************************
5939 * NtGdiGetGlyphIndicesW (win32u.@)
5941 DWORD WINAPI NtGdiGetGlyphIndicesW( HDC hdc, const WCHAR *str, INT count,
5942 WORD *indices, DWORD flags )
5944 DC *dc = get_dc_ptr(hdc);
5945 PHYSDEV dev;
5946 DWORD ret;
5948 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc, debugstr_wn(str, count), count, indices, flags );
5950 if(!dc) return GDI_ERROR;
5952 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
5953 ret = dev->funcs->pGetGlyphIndices( dev, str, count, indices, flags );
5954 release_dc_ptr( dc );
5955 return ret;
5958 /***********************************************************************
5960 * Font Resource API *
5962 ***********************************************************************/
5965 static int add_system_font_resource( const WCHAR *file, DWORD flags )
5967 WCHAR path[MAX_PATH];
5968 int ret;
5970 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
5971 get_fonts_win_dir_path( file, path );
5972 pthread_mutex_lock( &font_lock );
5973 ret = font_funcs->add_font( path, flags );
5974 pthread_mutex_unlock( &font_lock );
5975 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
5976 if (!ret)
5978 get_fonts_data_dir_path( file, path );
5979 pthread_mutex_lock( &font_lock );
5980 ret = font_funcs->add_font( path, flags );
5981 pthread_mutex_unlock( &font_lock );
5983 return ret;
5986 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
5988 WCHAR path[MAX_PATH];
5989 int ret;
5991 get_fonts_win_dir_path( file, path );
5992 if (!(ret = remove_font( path, flags )))
5994 get_fonts_data_dir_path( file, path );
5995 ret = remove_font( path, flags );
5997 return ret;
6000 static int add_font_resource( LPCWSTR file, DWORD flags )
6002 int ret = 0;
6004 if (*file == '\\')
6006 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6008 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6009 pthread_mutex_lock( &font_lock );
6010 ret = font_funcs->add_font( file, addfont_flags );
6011 pthread_mutex_unlock( &font_lock );
6013 else if (!wcschr( file, '\\' ))
6014 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6016 return ret;
6019 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
6021 BOOL ret = FALSE;
6023 if (*file == '\\')
6025 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6027 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6028 ret = remove_font( file, addfont_flags );
6030 else if (!wcschr( file, '\\' ))
6031 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6033 return ret;
6036 static void load_system_bitmap_fonts(void)
6038 static const char * const fonts[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6039 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6040 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6041 HKEY hkey;
6042 DWORD i;
6044 if (!(hkey = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) ))) return;
6045 for (i = 0; i < ARRAY_SIZE(fonts); i++)
6047 if (query_reg_ascii_value( hkey, fonts[i], info, sizeof(value_buffer) ) && info->Type == REG_SZ)
6048 add_system_font_resource( (const WCHAR *)info->Data, ADDFONT_ALLOW_BITMAP );
6050 NtClose( hkey );
6053 static void load_directory_fonts( WCHAR *path, UINT flags )
6055 OBJECT_ATTRIBUTES attr;
6056 UNICODE_STRING nt_name;
6057 IO_STATUS_BLOCK io;
6058 HANDLE handle;
6059 char buf[8192];
6060 size_t len;
6062 len = lstrlenW( path );
6063 while (len && path[len - 1] == '\\') len--;
6065 nt_name.Buffer = path;
6066 nt_name.MaximumLength = nt_name.Length = len * sizeof(WCHAR);
6068 attr.Length = sizeof(attr);
6069 attr.RootDirectory = 0;
6070 attr.Attributes = OBJ_CASE_INSENSITIVE;
6071 attr.ObjectName = &nt_name;
6072 attr.SecurityDescriptor = NULL;
6073 attr.SecurityQualityOfService = NULL;
6075 if (NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
6076 FILE_SHARE_READ | FILE_SHARE_WRITE,
6077 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ))
6078 return;
6080 path[len++] = '\\';
6082 while (!NtQueryDirectoryFile( handle, 0, NULL, NULL, &io, buf, sizeof(buf),
6083 FileBothDirectoryInformation, FALSE, NULL, FALSE ) &&
6084 io.Information)
6086 FILE_BOTH_DIR_INFORMATION *info = (FILE_BOTH_DIR_INFORMATION *)buf;
6087 for (;;)
6089 if (!(info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
6091 memcpy( path + len, info->FileName, info->FileNameLength );
6092 path[len + info->FileNameLength / sizeof(WCHAR)] = 0;
6093 font_funcs->add_font( path, flags );
6095 if (!info->NextEntryOffset) break;
6096 info = (FILE_BOTH_DIR_INFORMATION *)((char *)info + info->NextEntryOffset);
6100 NtClose( handle );
6103 static void load_file_system_fonts(void)
6105 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024 * sizeof(WCHAR)])];
6106 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6107 WCHAR *ptr, *next, path[MAX_PATH];
6109 /* Windows directory */
6110 get_fonts_win_dir_path( NULL, path );
6111 load_directory_fonts( path, 0 );
6113 /* Wine data directory */
6114 get_fonts_data_dir_path( NULL, path );
6115 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6117 /* custom paths */
6118 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6119 if (query_reg_ascii_value( wine_fonts_key, "Path", info, sizeof(value_buffer) ) &&
6120 info->Type == REG_SZ)
6122 for (ptr = (WCHAR *)info->Data; ptr; ptr = next)
6124 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
6125 if (next && next - ptr < 2) continue;
6126 lstrcpynW( path, ptr, MAX_PATH );
6127 if (path[1] == ':')
6129 memmove( path + ARRAYSIZE(nt_prefixW), path, (lstrlenW( path ) + 1) * sizeof(WCHAR) );
6130 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6132 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6137 struct external_key
6139 struct list entry;
6140 WCHAR value[LF_FULLFACESIZE + 12];
6143 static void update_external_font_keys(void)
6145 struct list external_keys = LIST_INIT(external_keys);
6146 HKEY winnt_key = 0, win9x_key = 0;
6147 struct gdi_font_family *family;
6148 struct external_key *key, *next;
6149 struct gdi_font_face *face;
6150 DWORD len, i = 0;
6151 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6152 char buffer[2048];
6153 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
6154 WCHAR *file;
6155 HKEY hkey;
6157 static const WCHAR external_fontsW[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6159 winnt_key = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW), 0, NULL );
6160 win9x_key = reg_create_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW), 0, NULL );
6162 /* enumerate the fonts and add external ones to the two keys */
6164 if (!(hkey = reg_create_key( wine_fonts_key, external_fontsW, sizeof(external_fontsW), 0, NULL )))
6165 return;
6167 while (reg_enum_value( hkey, i++, info, sizeof(buffer) - sizeof(nt_prefixW),
6168 value, LF_FULLFACESIZE * sizeof(WCHAR) ))
6170 if (info->Type != REG_SZ) continue;
6172 path = (WCHAR *)(buffer + info->DataOffset);
6173 if (path[0] && path[1] == ':')
6175 memmove( path + ARRAYSIZE(nt_prefixW), path, info->DataLength );
6176 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6179 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6180 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
6182 face->flags |= ADDFONT_EXTERNAL_FOUND;
6183 continue;
6185 if (tmp && !*tmp) *tmp = ' ';
6186 if (!(key = malloc( sizeof(*key) ))) break;
6187 lstrcpyW( key->value, value );
6188 list_add_tail( &external_keys, &key->entry );
6191 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
6193 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
6195 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
6196 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
6198 lstrcpyW( value, face->full_name );
6199 if (face->scalable) lstrcatW( value, true_type_suffixW );
6201 if (face->file[0] == '\\')
6203 file = face->file;
6204 if (file[5] == ':') file += ARRAYSIZE(nt_prefixW);
6206 else if ((file = wcsrchr( face->file, '\\' )))
6207 file++;
6208 else
6209 file = face->file;
6211 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
6212 set_reg_value( winnt_key, value, REG_SZ, file, len );
6213 set_reg_value( win9x_key, value, REG_SZ, file, len );
6214 set_reg_value( hkey, value, REG_SZ, file, len );
6217 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
6219 reg_delete_value( win9x_key, key->value );
6220 reg_delete_value( winnt_key, key->value );
6221 reg_delete_value( hkey, key->value );
6222 list_remove( &key->entry );
6223 free( key );
6225 NtClose( win9x_key );
6226 NtClose( winnt_key );
6227 NtClose( hkey );
6230 static void load_registry_fonts(void)
6232 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6233 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6234 KEY_VALUE_FULL_INFORMATION *enum_info = (KEY_VALUE_FULL_INFORMATION *)value_buffer;
6235 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6236 DWORD i = 0, dlen;
6237 HKEY hkey;
6239 static const WCHAR dot_fonW[] = {'.','f','o','n',0};
6241 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6242 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6243 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6244 will skip these. */
6245 if (is_win9x())
6246 hkey = reg_open_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW) );
6247 else
6248 hkey = reg_open_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW) );
6249 if (!hkey) return;
6251 while (reg_enum_value( hkey, i++, enum_info, sizeof(value_buffer), value, sizeof(value) ))
6253 if (enum_info->Type != REG_SZ) continue;
6254 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6255 if (find_face_from_full_name( value )) continue;
6256 if (tmp && !*tmp) *tmp = ' ';
6258 if (!(dlen = query_reg_value( hkey, value, info, sizeof(value_buffer) - sizeof(nt_prefixW) )) ||
6259 info->Type != REG_SZ)
6261 WARN( "Unable to get face path %s\n", debugstr_w(value) );
6262 continue;
6265 path = (WCHAR *)info->Data;
6266 if (path[0] && path[1] == ':')
6268 memmove( path + ARRAYSIZE(nt_prefixW), path, dlen );
6269 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6270 dlen += sizeof(nt_prefixW);
6273 dlen /= sizeof(WCHAR);
6274 if (*path == '\\')
6275 add_font_resource( path, ADDFONT_ALLOW_BITMAP );
6276 else if (dlen >= 6 && !wcsicmp( path + dlen - 5, dot_fonW ))
6277 add_system_font_resource( path, ADDFONT_ALLOW_BITMAP );
6279 NtClose( hkey );
6282 static HKEY open_hkcu(void)
6284 char buffer[256];
6285 WCHAR bufferW[256];
6286 DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
6287 DWORD i, len = sizeof(sid_data);
6288 SID *sid;
6290 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
6291 return 0;
6293 sid = ((TOKEN_USER *)sid_data)->User.Sid;
6294 len = sprintf( buffer, "\\Registry\\User\\S-%u-%u", sid->Revision,
6295 MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
6296 MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
6297 for (i = 0; i < sid->SubAuthorityCount; i++)
6298 len += sprintf( buffer + len, "-%u", sid->SubAuthority[i] );
6299 ascii_to_unicode( bufferW, buffer, len + 1 );
6301 return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
6304 /***********************************************************************
6305 * font_init
6307 UINT font_init(void)
6309 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
6310 UNICODE_STRING name;
6311 HANDLE mutex;
6312 DWORD disposition;
6313 UINT dpi = 0;
6315 static WCHAR wine_font_mutexW[] =
6316 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6317 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6318 static const WCHAR wine_fonts_keyW[] =
6319 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6320 static const WCHAR cacheW[] = {'C','a','c','h','e'};
6322 if (!(hkcu_key = open_hkcu())) return 0;
6323 wine_fonts_key = reg_create_key( hkcu_key, wine_fonts_keyW, sizeof(wine_fonts_keyW), 0, NULL );
6324 if (wine_fonts_key) dpi = init_font_options();
6325 if (!dpi) return 96;
6326 update_codepage( dpi );
6328 if (!(font_funcs = init_freetype_lib()))
6329 return dpi;
6331 load_system_bitmap_fonts();
6332 load_file_system_fonts();
6333 font_funcs->load_fonts();
6335 attr.Attributes = OBJ_OPENIF;
6336 attr.ObjectName = &name;
6337 name.Buffer = wine_font_mutexW;
6338 name.Length = name.MaximumLength = sizeof(wine_font_mutexW);
6340 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return dpi;
6341 NtWaitForSingleObject( mutex, FALSE, NULL );
6343 wine_fonts_cache_key = reg_create_key( wine_fonts_key, cacheW, sizeof(cacheW),
6344 REG_OPTION_VOLATILE, &disposition );
6346 if (disposition == REG_CREATED_NEW_KEY)
6348 load_registry_fonts();
6349 update_external_font_keys();
6352 NtReleaseMutant( mutex, NULL );
6354 if (disposition != REG_CREATED_NEW_KEY)
6356 load_registry_fonts();
6357 load_font_list_from_cache();
6360 reorder_font_list();
6361 load_gdi_font_subst();
6362 load_gdi_font_replacements();
6363 load_system_links();
6364 dump_gdi_font_list();
6365 dump_gdi_font_subst();
6366 return dpi;
6369 /***********************************************************************
6370 * NtGdiAddFontResourceW (win32u.@)
6372 INT WINAPI NtGdiAddFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6373 DWORD tid, void *dv )
6375 if (!font_funcs) return 1;
6376 return add_font_resource( str, flags );
6379 /***********************************************************************
6380 * NtGdiAddFontMemResourceEx (win32u.@)
6382 HANDLE WINAPI NtGdiAddFontMemResourceEx( void *ptr, DWORD size, void *dv, ULONG dv_size,
6383 DWORD *count )
6385 HANDLE ret;
6386 DWORD num_fonts;
6387 void *copy;
6389 if (!ptr || !size || !count)
6391 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER);
6392 return NULL;
6394 if (!font_funcs) return NULL;
6395 if (!(copy = malloc( size ))) return NULL;
6396 memcpy( copy, ptr, size );
6398 pthread_mutex_lock( &font_lock );
6399 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6400 pthread_mutex_unlock( &font_lock );
6402 if (!num_fonts)
6404 free( copy );
6405 return NULL;
6408 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6409 * For now return something unique but quite random
6411 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
6413 __TRY
6415 *count = num_fonts;
6417 __EXCEPT
6419 WARN( "page fault while writing to *count (%p)\n", count );
6420 NtGdiRemoveFontMemResourceEx( ret );
6421 ret = 0;
6423 __ENDTRY
6424 TRACE( "Returning handle %p\n", ret );
6425 return ret;
6428 /***********************************************************************
6429 * NtGdiRemoveFontMemResourceEx (win32u.@)
6431 BOOL WINAPI NtGdiRemoveFontMemResourceEx( HANDLE handle )
6433 FIXME( "(%p) stub\n", handle );
6434 return TRUE;
6437 /***********************************************************************
6438 * NtGdiRemoveFontResourceW (win32u.@)
6440 BOOL WINAPI NtGdiRemoveFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6441 DWORD tid, void *dv )
6443 if (!font_funcs) return TRUE;
6444 return remove_font_resource( str, flags );
6447 /***********************************************************************
6448 * NtGdiGetFontUnicodeRanges (win32u.@)
6450 * Retrieve a list of supported Unicode characters in a font.
6452 * PARAMS
6453 * hdc [I] Handle to a device context.
6454 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6456 * RETURNS
6457 * Success: Number of bytes written to the buffer pointed to by lpgs.
6458 * Failure: 0
6461 DWORD WINAPI NtGdiGetFontUnicodeRanges( HDC hdc, GLYPHSET *lpgs )
6463 DWORD ret;
6464 PHYSDEV dev;
6465 DC *dc = get_dc_ptr(hdc);
6467 TRACE("(%p, %p)\n", hdc, lpgs);
6469 if (!dc) return 0;
6471 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
6472 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
6473 release_dc_ptr(dc);
6474 return ret;
6478 /*************************************************************
6479 * NtGdiFontIsLinked (win32u.@)
6481 BOOL WINAPI NtGdiFontIsLinked( HDC hdc )
6483 DC *dc = get_dc_ptr(hdc);
6484 PHYSDEV dev;
6485 BOOL ret;
6487 if (!dc) return FALSE;
6488 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
6489 ret = dev->funcs->pFontIsLinked( dev );
6490 release_dc_ptr(dc);
6491 TRACE("returning %d\n", ret);
6492 return ret;
6495 /*************************************************************
6496 * NtGdiGetRealizationInfo (win32u.@)
6498 BOOL WINAPI NtGdiGetRealizationInfo( HDC hdc, struct font_realization_info *info )
6500 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, file_count);
6501 PHYSDEV dev;
6502 BOOL ret;
6503 DC *dc;
6505 if (info->size != sizeof(*info) && !is_v0)
6506 return FALSE;
6508 dc = get_dc_ptr(hdc);
6509 if (!dc) return FALSE;
6510 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
6511 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
6512 release_dc_ptr(dc);
6513 return ret;
6516 /*************************************************************************
6517 * NtGdiGetRasterizerCaps (win32u.@)
6519 BOOL WINAPI NtGdiGetRasterizerCaps( RASTERIZER_STATUS *status, UINT size )
6521 status->nSize = sizeof(RASTERIZER_STATUS);
6522 status->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
6523 status->nLanguageID = 0;
6524 return TRUE;
6527 /*************************************************************************
6528 * NtGdiGetFontFileData (win32u.@)
6530 BOOL WINAPI NtGdiGetFontFileData( DWORD instance_id, DWORD file_index, UINT64 *offset,
6531 void *buff, DWORD buff_size )
6533 struct gdi_font *font;
6534 DWORD tag = 0, size;
6535 BOOL ret = FALSE;
6537 if (!font_funcs) return FALSE;
6538 pthread_mutex_lock( &font_lock );
6539 if ((font = get_font_from_handle( instance_id )))
6541 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
6542 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
6543 if (size != GDI_ERROR && size >= buff_size && *offset <= size - buff_size)
6544 ret = font_funcs->get_font_data( font, tag, *offset, buff, buff_size ) != GDI_ERROR;
6545 else
6546 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6548 pthread_mutex_unlock( &font_lock );
6549 return ret;
6552 /*************************************************************************
6553 * NtGdiGetFontFileInfo (win32u.@)
6555 BOOL WINAPI NtGdiGetFontFileInfo( DWORD instance_id, DWORD file_index, struct font_fileinfo *info,
6556 SIZE_T size, SIZE_T *needed )
6558 SIZE_T required_size = 0;
6559 struct gdi_font *font;
6560 BOOL ret = FALSE;
6562 pthread_mutex_lock( &font_lock );
6564 if ((font = get_font_from_handle( instance_id )))
6566 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
6567 if (required_size <= size)
6569 info->writetime = font->writetime;
6570 info->size.QuadPart = font->data_size;
6571 lstrcpyW( info->path, font->file );
6572 ret = TRUE;
6574 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
6577 pthread_mutex_unlock( &font_lock );
6578 if (needed) *needed = required_size;
6579 return ret;
6582 /*************************************************************
6583 * NtGdiGetCharWidthInfo (win32u.@)
6585 BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info )
6587 PHYSDEV dev;
6588 BOOL ret;
6589 DC *dc;
6591 dc = get_dc_ptr(hdc);
6592 if (!dc) return FALSE;
6593 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
6594 ret = dev->funcs->pGetCharWidthInfo( dev, info );
6596 if (ret)
6598 info->lsb = width_to_LP( dc, info->lsb );
6599 info->rsb = width_to_LP( dc, info->rsb );
6601 release_dc_ptr(dc);
6602 return ret;
6605 /***********************************************************************
6606 * DrawTextW (win32u.so)
6608 INT WINAPI DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags )
6610 struct draw_text_params *params;
6611 ULONG ret_len, size;
6612 void *ret_ptr;
6613 int ret;
6615 if (count == -1) count = wcslen( str );
6616 size = FIELD_OFFSET( struct draw_text_params, str[count] );
6617 if (!(params = malloc( size ))) return 0;
6618 params->hdc = hdc;
6619 params->rect = *rect;
6620 params->ret_rect = rect;
6621 params->flags = flags;
6622 if (count) memcpy( params->str, str, count * sizeof(WCHAR) );
6623 ret = KeUserModeCallback( NtUserDrawText, params, size, &ret_ptr, &ret_len );
6624 if (ret_len == sizeof(*rect)) *rect = *(const RECT *)ret_ptr;
6625 free( params );
6626 return ret;