win32u: Support UTF-8 as the default Ansi codepage.
[wine.git] / dlls / win32u / font.c
blobc5a5a5806bab87c37dc98541489f17d83d0789db
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[] = {
292 /* ANSI */
293 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
294 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
295 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
296 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
297 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
298 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
299 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
300 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
301 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
302 /* reserved by ANSI */
303 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
304 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
305 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
306 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
307 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
308 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
309 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
310 /* ANSI and OEM */
311 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
312 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
313 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
314 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
315 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
316 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
317 /* reserved for alternate ANSI and OEM */
318 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
319 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
320 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
321 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
322 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
323 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
324 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
325 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
326 /* reserved for system */
327 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
328 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
331 static const char * const default_serif_list[3] =
333 "Times New Roman",
334 "Liberation Serif",
335 "Bitstream Vera Serif"
337 static const char * const default_fixed_list[3] =
339 "Courier New",
340 "Liberation Mono",
341 "Bitstream Vera Sans Mono"
343 static const char * const default_sans_list[3] =
345 "Arial",
346 "Liberation Sans",
347 "Bitstream Vera Sans"
349 static WCHAR ff_roman_default[LF_FACESIZE];
350 static WCHAR ff_modern_default[LF_FACESIZE];
351 static WCHAR ff_swiss_default[LF_FACESIZE];
353 static const struct nls_update_font_list
355 UINT ansi_cp, oem_cp;
356 const char *oem, *fixed, *system;
357 const char *courier, *serif, *small, *sserif_96, *sserif_120;
358 /* these are for font substitutes */
359 const char *shelldlg, *tmsrmn;
360 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0, *helv_0, *tmsrmn_0;
361 struct subst { const char *from, *to; } arial_0, courier_new_0, times_new_roman_0;
362 } nls_update_font_list[] =
364 /* Latin 1 (United States) */
365 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
366 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
367 "Tahoma","Times New Roman"
369 /* Latin 1 (Multilingual) */
370 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
371 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
372 "Tahoma","Times New Roman" /* FIXME unverified */
374 /* UTF-8 */
375 { CP_UTF8, CP_UTF8, "vga850.fon", "vgafix.fon", "vgasys.fon",
376 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
377 "Tahoma", "Times New Roman" /* FIXME unverified */
379 /* Eastern Europe */
380 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
381 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
382 "Tahoma","Times New Roman", /* FIXME unverified */
383 "Fixedsys,238", "System,238",
384 "Courier New,238", "MS Serif,238", "Small Fonts,238",
385 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
386 { "Arial CE,0", "Arial,238" },
387 { "Courier New CE,0", "Courier New,238" },
388 { "Times New Roman CE,0", "Times New Roman,238" }
390 /* Cyrillic */
391 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
392 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
393 "Tahoma","Times New Roman", /* FIXME unverified */
394 "Fixedsys,204", "System,204",
395 "Courier New,204", "MS Serif,204", "Small Fonts,204",
396 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
397 { "Arial Cyr,0", "Arial,204" },
398 { "Courier New Cyr,0", "Courier New,204" },
399 { "Times New Roman Cyr,0", "Times New Roman,204" }
401 /* Greek */
402 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
403 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
404 "Tahoma","Times New Roman", /* FIXME unverified */
405 "Fixedsys,161", "System,161",
406 "Courier New,161", "MS Serif,161", "Small Fonts,161",
407 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
408 { "Arial Greek,0", "Arial,161" },
409 { "Courier New Greek,0", "Courier New,161" },
410 { "Times New Roman Greek,0", "Times New Roman,161" }
412 /* Turkish */
413 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
414 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
415 "Tahoma","Times New Roman", /* FIXME unverified */
416 "Fixedsys,162", "System,162",
417 "Courier New,162", "MS Serif,162", "Small Fonts,162",
418 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
419 { "Arial Tur,0", "Arial,162" },
420 { "Courier New Tur,0", "Courier New,162" },
421 { "Times New Roman Tur,0", "Times New Roman,162" }
423 /* Hebrew */
424 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
425 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
426 "Tahoma","Times New Roman", /* FIXME unverified */
427 "Fixedsys,177", "System,177",
428 "Courier New,177", "MS Serif,177", "Small Fonts,177",
429 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
431 /* Arabic */
432 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
433 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
434 "Microsoft Sans Serif","Times New Roman",
435 "Fixedsys,178", "System,178",
436 "Courier New,178", "MS Serif,178", "Small Fonts,178",
437 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
439 /* Baltic */
440 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
441 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
442 "Tahoma","Times New Roman", /* FIXME unverified */
443 "Fixedsys,186", "System,186",
444 "Courier New,186", "MS Serif,186", "Small Fonts,186",
445 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
446 { "Arial Baltic,0", "Arial,186" },
447 { "Courier New Baltic,0", "Courier New,186" },
448 { "Times New Roman Baltic,0", "Times New Roman,186" }
450 /* Vietnamese */
451 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
452 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
453 "Tahoma","Times New Roman" /* FIXME unverified */
455 /* Thai */
456 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
457 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
458 "Tahoma","Times New Roman" /* FIXME unverified */
460 /* Japanese */
461 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
462 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
463 "MS UI Gothic","MS Serif"
465 /* Chinese Simplified */
466 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
467 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
468 "SimSun", "NSimSun"
470 /* Korean */
471 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
472 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
473 "Gulim", "Batang"
475 /* Chinese Traditional */
476 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
477 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
478 "PMingLiU", "MingLiU"
482 static pthread_mutex_t font_lock = PTHREAD_MUTEX_INITIALIZER;
484 #ifndef WINE_FONT_DIR
485 #define WINE_FONT_DIR "fonts"
486 #endif
488 #ifdef WORDS_BIGENDIAN
489 #define GET_BE_WORD(x) (x)
490 #define GET_BE_DWORD(x) (x)
491 #else
492 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
493 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
494 #endif
496 static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
498 const char *dir;
499 ULONG len = MAX_PATH;
501 if ((dir = ntdll_get_data_dir()))
503 wine_unix_to_nt_file_name( dir, path, &len );
504 asciiz_to_unicode( path + len - 1, "\\" WINE_FONT_DIR "\\" );
506 else if ((dir = ntdll_get_build_dir()))
508 wine_unix_to_nt_file_name( dir, path, &len );
509 asciiz_to_unicode( path + len - 1, "\\fonts\\" );
512 if (file) lstrcatW( path, file );
515 static void get_fonts_win_dir_path( const WCHAR *file, WCHAR *path )
517 asciiz_to_unicode( path, "\\??\\C:\\windows\\fonts\\" );
518 if (file) lstrcatW( path, file );
521 HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len )
523 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
524 OBJECT_ATTRIBUTES attr;
525 HANDLE ret;
527 attr.Length = sizeof(attr);
528 attr.RootDirectory = root;
529 attr.ObjectName = &nameW;
530 attr.Attributes = 0;
531 attr.SecurityDescriptor = NULL;
532 attr.SecurityQualityOfService = NULL;
534 if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0;
535 return ret;
538 /* wrapper for NtCreateKey that creates the key recursively if necessary */
539 HKEY reg_create_key( HKEY root, const WCHAR *name, ULONG name_len,
540 DWORD options, DWORD *disposition )
542 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
543 OBJECT_ATTRIBUTES attr;
544 NTSTATUS status;
545 HANDLE ret;
547 attr.Length = sizeof(attr);
548 attr.RootDirectory = root;
549 attr.ObjectName = &nameW;
550 attr.Attributes = 0;
551 attr.SecurityDescriptor = NULL;
552 attr.SecurityQualityOfService = NULL;
554 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, options, disposition );
555 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
557 static const WCHAR registry_rootW[] = { '\\','R','e','g','i','s','t','r','y','\\' };
558 DWORD pos = 0, i = 0, len = name_len / sizeof(WCHAR);
560 /* don't try to create registry root */
561 if (!root && len > ARRAY_SIZE(registry_rootW) &&
562 !memcmp( name, registry_rootW, sizeof(registry_rootW) ))
563 i += ARRAY_SIZE(registry_rootW);
565 while (i < len && name[i] != '\\') i++;
566 if (i == len) return 0;
567 for (;;)
569 unsigned int subkey_options = options;
570 if (i < len) subkey_options &= ~(REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK);
571 nameW.Buffer = (WCHAR *)name + pos;
572 nameW.Length = (i - pos) * sizeof(WCHAR);
573 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, subkey_options, disposition );
575 if (attr.RootDirectory != root) NtClose( attr.RootDirectory );
576 if (!NT_SUCCESS(status)) return 0;
577 if (i == len) break;
578 attr.RootDirectory = ret;
579 while (i < len && name[i] == '\\') i++;
580 pos = i;
581 while (i < len && name[i] != '\\') i++;
584 return ret;
587 HKEY reg_open_hkcu_key( const char *name )
589 WCHAR nameW[128];
590 return reg_open_key( hkcu_key, nameW, asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) );
593 BOOL set_reg_value( HKEY hkey, const WCHAR *name, UINT type, const void *value, DWORD count )
595 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
596 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
597 return !NtSetValueKey( hkey, &nameW, 0, type, value, count );
600 void set_reg_ascii_value( HKEY hkey, const char *name, const char *value )
602 WCHAR nameW[64], valueW[128];
603 asciiz_to_unicode( nameW, name );
604 set_reg_value( hkey, nameW, REG_SZ, valueW, asciiz_to_unicode( valueW, value ));
607 ULONG query_reg_value( HKEY hkey, const WCHAR *name,
608 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
610 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
611 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
613 if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
614 info, size, &size ))
615 return 0;
617 return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
620 ULONG query_reg_ascii_value( HKEY hkey, const char *name,
621 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
623 WCHAR nameW[64];
624 asciiz_to_unicode( nameW, name );
625 return query_reg_value( hkey, nameW, info, size );
628 static BOOL reg_enum_value( HKEY hkey, unsigned int index, KEY_VALUE_FULL_INFORMATION *info,
629 ULONG size, WCHAR *name, ULONG name_size )
631 ULONG full_size;
633 if (NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
634 info, size, &full_size ))
635 return FALSE;
637 if (name_size)
639 if (name_size < info->NameLength + sizeof(WCHAR)) return FALSE;
640 memcpy( name, info->Name, info->NameLength );
641 name[info->NameLength / sizeof(WCHAR)] = 0;
643 return TRUE;
646 void reg_delete_value( HKEY hkey, const WCHAR *name )
648 unsigned int name_size = lstrlenW( name ) * sizeof(WCHAR);
649 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
650 NtDeleteValueKey( hkey, &nameW );
653 BOOL reg_delete_tree( HKEY parent, const WCHAR *name, ULONG name_len )
655 char buffer[4096];
656 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
657 DWORD size;
658 HKEY key;
659 BOOL ret = TRUE;
661 if (!(key = reg_open_key( parent, name, name_len ))) return FALSE;
663 while (ret && !NtEnumerateKey( key, 0, KeyNodeInformation, key_info, sizeof(buffer), &size ))
664 ret = reg_delete_tree( key, key_info->Name, key_info->NameLength );
666 if (ret) ret = !NtDeleteKey( key );
667 NtClose( key );
668 return ret;
671 /* font substitutions */
673 struct gdi_font_subst
675 struct list entry;
676 int from_charset;
677 int to_charset;
678 WCHAR names[1];
681 static struct list font_subst_list = LIST_INIT(font_subst_list);
683 static inline WCHAR *get_subst_to_name( struct gdi_font_subst *subst )
685 return subst->names + lstrlenW( subst->names ) + 1;
688 static void dump_gdi_font_subst(void)
690 struct gdi_font_subst *subst;
692 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
694 if (subst->from_charset != -1 || subst->to_charset != -1)
695 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst->names),
696 subst->from_charset, debugstr_w(get_subst_to_name(subst)), subst->to_charset);
697 else
698 TRACE("%s -> %s\n", debugstr_w(subst->names), debugstr_w(get_subst_to_name(subst)));
702 static const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset )
704 struct gdi_font_subst *subst;
706 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
708 if (!facename_compare( subst->names, from_name, -1 ) &&
709 (subst->from_charset == from_charset || subst->from_charset == -1))
711 if (to_charset) *to_charset = subst->to_charset;
712 return get_subst_to_name( subst );
715 return NULL;
718 static BOOL add_gdi_font_subst( const WCHAR *from_name, int from_charset, const WCHAR *to_name, int to_charset )
720 struct gdi_font_subst *subst;
721 int len = lstrlenW( from_name ) + lstrlenW( to_name ) + 2;
723 if (get_gdi_font_subst( from_name, from_charset, NULL )) return FALSE; /* already exists */
725 if (!(subst = malloc( offsetof( struct gdi_font_subst, names[len] ) )))
726 return FALSE;
727 lstrcpyW( subst->names, from_name );
728 lstrcpyW( get_subst_to_name(subst), to_name );
729 subst->from_charset = from_charset;
730 subst->to_charset = to_charset;
731 list_add_tail( &font_subst_list, &subst->entry );
732 return TRUE;
735 static void load_gdi_font_subst(void)
737 char buffer[512];
738 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
739 HKEY hkey;
740 DWORD i = 0;
741 WCHAR *data, *p, value[64];
743 if (!(hkey = reg_open_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW) )))
744 return;
746 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
748 int from_charset = -1, to_charset = -1;
750 if (info->Type != REG_SZ) continue;
751 data = (WCHAR *)((char *)info + info->DataOffset);
753 TRACE( "Got %s=%s\n", debugstr_w(value), debugstr_w(data) );
754 if ((p = wcsrchr( value, ',' )) && p[1])
756 *p++ = 0;
757 from_charset = wcstol( p, NULL, 10 );
759 if ((p = wcsrchr( data, ',' )) && p[1])
761 *p++ = 0;
762 to_charset = wcstol( p, NULL, 10 );
765 /* Win 2000 doesn't allow mapping between different charsets
766 or mapping of DEFAULT_CHARSET */
767 if ((!from_charset || to_charset == from_charset) && to_charset != DEFAULT_CHARSET)
768 add_gdi_font_subst( value, from_charset, data, to_charset );
770 NtClose( hkey );
773 /* font families */
775 static int family_namecmp( const WCHAR *str1, const WCHAR *str2 )
777 int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0);
779 if (!facename_compare( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0;
780 else if (!facename_compare( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1;
781 else if (!facename_compare( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2;
782 else prio1 = 3;
784 if (!facename_compare( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0;
785 else if (!facename_compare( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1;
786 else if (!facename_compare( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2;
787 else prio2 = 3;
789 if (prio1 != prio2) return prio1 - prio2;
790 if (vert1 != vert2) return vert1 - vert2;
791 return facename_compare( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 );
794 static int family_name_compare( const void *key, const struct wine_rb_entry *entry )
796 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, name_entry );
797 return family_namecmp( (const WCHAR *)key, family->family_name );
800 static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry )
802 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, second_name_entry );
803 return family_namecmp( (const WCHAR *)key, family->second_name );
806 static int face_full_name_compare( const void *key, const struct wine_rb_entry *entry )
808 const struct gdi_font_face *face = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_face, full_name_entry );
809 return facename_compare( (const WCHAR *)key, face->full_name, LF_FULLFACESIZE - 1 );
812 static struct wine_rb_tree family_name_tree = { family_name_compare };
813 static struct wine_rb_tree family_second_name_tree = { family_second_name_compare };
814 static struct wine_rb_tree face_full_name_tree = { face_full_name_compare };
816 static int face_is_in_full_name_tree( const struct gdi_font_face *face )
818 return face->full_name_entry.parent || face_full_name_tree.root == &face->full_name_entry;
821 static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name )
823 struct gdi_font_family *family = malloc( sizeof(*family) );
825 family->refcount = 1;
826 lstrcpynW( family->family_name, name, LF_FACESIZE );
827 if (second_name && second_name[0] && wcsicmp( name, second_name ))
829 lstrcpynW( family->second_name, second_name, LF_FACESIZE );
830 add_gdi_font_subst( second_name, -1, name, -1 );
832 else family->second_name[0] = 0;
833 list_init( &family->faces );
834 family->replacement = NULL;
835 wine_rb_put( &family_name_tree, family->family_name, &family->name_entry );
836 if (family->second_name[0]) wine_rb_put( &family_second_name_tree, family->second_name, &family->second_name_entry );
837 return family;
840 static void release_family( struct gdi_font_family *family )
842 if (--family->refcount) return;
843 assert( list_empty( &family->faces ));
844 wine_rb_remove( &family_name_tree, &family->name_entry );
845 if (family->second_name[0]) wine_rb_remove( &family_second_name_tree, &family->second_name_entry );
846 if (family->replacement) release_family( family->replacement );
847 free( family );
850 static struct gdi_font_family *find_family_from_name( const WCHAR *name )
852 struct wine_rb_entry *entry;
853 if (!(entry = wine_rb_get( &family_name_tree, name ))) return NULL;
854 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, name_entry );
857 static struct gdi_font_family *find_family_from_any_name( const WCHAR *name )
859 struct wine_rb_entry *entry;
860 struct gdi_font_family *family;
861 if ((family = find_family_from_name( name ))) return family;
862 if (!(entry = wine_rb_get( &family_second_name_tree, name ))) return NULL;
863 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, second_name_entry );
866 static struct gdi_font_face *find_face_from_full_name( const WCHAR *full_name )
868 struct wine_rb_entry *entry;
869 if (!(entry = wine_rb_get( &face_full_name_tree, full_name ))) return NULL;
870 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_face, full_name_entry );
873 static const struct list *get_family_face_list( const struct gdi_font_family *family )
875 return family->replacement ? &family->replacement->faces : &family->faces;
878 static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name )
880 struct gdi_font_face *face;
881 const WCHAR *file;
882 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
884 if (!face->file) continue;
885 file = wcsrchr(face->file, '\\');
886 if (!file) file = face->file;
887 else file++;
888 if (wcsicmp( file, file_name )) continue;
889 face->refcount++;
890 return face;
892 return NULL;
895 static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name )
897 struct gdi_font_family *family;
898 struct gdi_font_face *face;
900 TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
902 if (!family_name)
904 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
905 if ((face = family_find_face_from_filename( family, file_name ))) return face;
906 return NULL;
909 if (!(family = find_family_from_name( family_name ))) return NULL;
910 return family_find_face_from_filename( family, file_name );
913 static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
915 struct gdi_font_family *new_family, *family;
916 struct gdi_font_face *face;
917 WCHAR new_name_vert[LF_FACESIZE], replace_vert[LF_FACESIZE];
919 if (!(family = find_family_from_any_name( replace )))
921 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace) );
922 return FALSE;
925 if (!(new_family = create_family( new_name, NULL ))) return FALSE;
926 new_family->replacement = family;
927 family->refcount++;
928 TRACE( "mapping %s to %s\n", debugstr_w(replace), debugstr_w(new_name) );
930 /* also add replacement for vertical font if necessary */
931 if (replace[0] == '@') return TRUE;
932 if (list_empty( &family->faces )) return TRUE;
933 face = LIST_ENTRY( list_head(&family->faces), struct gdi_font_face, entry );
934 if (!(face->fs.fsCsb[0] & FS_DBCS_MASK)) return TRUE;
936 new_name_vert[0] = '@';
937 lstrcpynW( new_name_vert + 1, new_name, LF_FACESIZE - 1 );
938 if (find_family_from_any_name( new_name_vert )) return TRUE; /* already exists */
940 replace_vert[0] = '@';
941 lstrcpynW( replace_vert + 1, replace, LF_FACESIZE - 1 );
942 add_family_replacement( new_name_vert, replace_vert );
943 return TRUE;
947 * The replacement list is a way to map an entire font
948 * family onto another family. For example adding
950 * [HKCU\Software\Wine\Fonts\Replacements]
951 * "Wingdings"="Winedings"
953 * would enumerate the Winedings font both as Winedings and
954 * Wingdings. However if a real Wingdings font is present the
955 * replacement does not take place.
957 static void load_gdi_font_replacements(void)
959 char buffer[2048];
960 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
961 HKEY hkey;
962 DWORD i = 0;
963 WCHAR value[LF_FACESIZE];
965 static const WCHAR replacementsW[] = {'R','e','p','l','a','c','e','m','e','n','t','s'};
967 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
968 if (!(hkey = reg_open_key( wine_fonts_key, replacementsW, sizeof(replacementsW) ))) return;
970 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
972 WCHAR *data = (WCHAR *)((char *)info + info->DataOffset);
973 /* "NewName"="Oldname" */
974 if (!find_family_from_any_name( value ))
976 if (info->Type == REG_MULTI_SZ)
978 WCHAR *replace = data;
979 while (*replace)
981 if (add_family_replacement( value, replace )) break;
982 replace += lstrlenW(replace) + 1;
985 else if (info->Type == REG_SZ) add_family_replacement( value, data );
987 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
989 NtClose( hkey );
992 static void dump_gdi_font_list(void)
994 struct gdi_font_family *family;
995 struct gdi_font_face *face;
997 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
999 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
1000 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
1002 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
1003 face->fs.fsCsb[0] );
1004 if (!face->scalable) TRACE(" %d", face->size.height );
1005 TRACE("\n");
1010 static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
1012 if (index < 3)
1014 const char * const *defaults;
1016 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
1017 defaults = default_fixed_list;
1018 else if ((pitch_and_family & 0xf0) == FF_ROMAN)
1019 defaults = default_serif_list;
1020 else
1021 defaults = default_sans_list;
1022 asciiz_to_unicode( buffer, defaults[index] );
1023 return TRUE;
1025 return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
1028 static void set_default_family( DWORD pitch_and_family, WCHAR *default_name )
1030 struct wine_rb_entry *entry;
1031 WCHAR name[LF_FACESIZE];
1032 int i = 0;
1034 while (enum_fallbacks( pitch_and_family, i++, name ))
1036 if (!(entry = wine_rb_get( &family_name_tree, name ))) continue;
1037 wine_rb_remove( &family_name_tree, entry );
1038 lstrcpynW( default_name, name, LF_FACESIZE - 1 );
1039 wine_rb_put( &family_name_tree, name, entry );
1040 return;
1044 static void reorder_font_list(void)
1046 set_default_family( FF_ROMAN, ff_roman_default );
1047 set_default_family( FF_MODERN, ff_modern_default );
1048 set_default_family( FF_SWISS, ff_swiss_default );
1051 static void release_face( struct gdi_font_face *face )
1053 if (--face->refcount) return;
1054 if (face->family)
1056 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1057 list_remove( &face->entry );
1058 release_family( face->family );
1060 if (face_is_in_full_name_tree( face )) wine_rb_remove( &face_full_name_tree, &face->full_name_entry );
1061 free( face->file );
1062 free( face->style_name );
1063 free( face->full_name );
1064 free( face->cached_enum_data );
1065 free( face );
1068 static int remove_font( const WCHAR *file, DWORD flags )
1070 struct gdi_font_family *family, *family_next;
1071 struct gdi_font_face *face, *face_next;
1072 int count = 0;
1074 pthread_mutex_lock( &font_lock );
1075 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_name_tree, struct gdi_font_family, name_entry )
1077 family->refcount++;
1078 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry )
1080 if (!face->file) continue;
1081 if (LOWORD(face->flags) != LOWORD(flags)) continue;
1082 if (!wcsicmp( face->file, file ))
1084 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
1085 release_face( face );
1086 count++;
1089 release_family( family );
1091 pthread_mutex_unlock( &font_lock );
1092 return count;
1095 static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
1097 if (facename_compare( f1->full_name, f2->full_name, -1 )) return FALSE;
1098 if (f1->scalable) return TRUE;
1099 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1100 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1103 static inline int style_order( const struct gdi_font_face *face )
1105 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1107 case NTM_REGULAR:
1108 return 0;
1109 case NTM_BOLD:
1110 return 1;
1111 case NTM_ITALIC:
1112 return 2;
1113 case NTM_BOLD | NTM_ITALIC:
1114 return 3;
1115 default:
1116 WARN( "Don't know how to order face %s with flags 0x%08x\n",
1117 debugstr_w(face->full_name), face->ntmFlags );
1118 return 9999;
1122 static BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
1124 struct gdi_font_face *cursor;
1126 LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
1128 if (faces_equal( face, cursor ))
1130 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
1131 debugstr_w(face->full_name), debugstr_w(family->family_name),
1132 cursor->version, face->version );
1134 if (face->file && cursor->file && !wcsicmp( face->file, cursor->file ))
1136 cursor->refcount++;
1137 TRACE("Font %s already in list, refcount now %d\n",
1138 debugstr_w(face->file), cursor->refcount);
1139 return FALSE;
1141 if (face->version <= cursor->version)
1143 TRACE("Original font %s is newer so skipping %s\n",
1144 debugstr_w(cursor->file), debugstr_w(face->file));
1145 return FALSE;
1147 else
1149 TRACE("Replacing original %s with %s\n",
1150 debugstr_w(cursor->file), debugstr_w(face->file));
1151 list_add_before( &cursor->entry, &face->entry );
1152 face->family = family;
1153 family->refcount++;
1154 face->refcount++;
1155 if (face_is_in_full_name_tree( cursor ))
1157 wine_rb_replace( &face_full_name_tree, &cursor->full_name_entry, &face->full_name_entry );
1158 memset( &cursor->full_name_entry, 0, sizeof(cursor->full_name_entry) );
1160 release_face( cursor );
1161 return TRUE;
1164 if (style_order( face ) < style_order( cursor )) break;
1167 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
1168 debugstr_w(family->family_name), debugstr_w(face->file) );
1169 list_add_before( &cursor->entry, &face->entry );
1170 if (face->scalable) wine_rb_put( &face_full_name_tree, face->full_name, &face->full_name_entry );
1171 face->family = family;
1172 family->refcount++;
1173 face->refcount++;
1174 return TRUE;
1177 static struct gdi_font_face *create_face( struct gdi_font_family *family, const WCHAR *style,
1178 const WCHAR *fullname, const WCHAR *file,
1179 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1180 DWORD ntmflags, DWORD version, DWORD flags,
1181 const struct bitmap_font_size *size )
1183 struct gdi_font_face *face = calloc( 1, sizeof(*face) );
1185 face->refcount = 1;
1186 face->style_name = wcsdup( style );
1187 face->full_name = wcsdup( fullname );
1188 face->face_index = index;
1189 face->fs = fs;
1190 face->ntmFlags = ntmflags;
1191 face->version = version;
1192 face->flags = flags;
1193 face->data_ptr = data_ptr;
1194 face->data_size = data_size;
1195 if (file) face->file = wcsdup( file );
1196 if (size) face->size = *size;
1197 else face->scalable = TRUE;
1198 if (insert_face_in_family_list( face, family )) return face;
1199 release_face( face );
1200 return NULL;
1203 int add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
1204 const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
1205 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1206 DWORD ntmflags, DWORD version, DWORD flags,
1207 const struct bitmap_font_size *size )
1209 struct gdi_font_face *face;
1210 struct gdi_font_family *family;
1211 int ret = 0;
1213 if ((family = find_family_from_name( family_name ))) family->refcount++;
1214 else if (!(family = create_family( family_name, second_name ))) return ret;
1216 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1217 index, fs, ntmflags, version, flags, size )))
1219 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1220 release_face( face );
1222 release_family( family );
1223 ret++;
1225 if (fs.fsCsb[0] & FS_DBCS_MASK)
1227 WCHAR vert_family[LF_FACESIZE], vert_second[LF_FACESIZE], vert_full[LF_FULLFACESIZE];
1229 vert_family[0] = '@';
1230 lstrcpynW( vert_family + 1, family_name, LF_FACESIZE - 1 );
1232 if (second_name && second_name[0])
1234 vert_second[0] = '@';
1235 lstrcpynW( vert_second + 1, second_name, LF_FACESIZE - 1 );
1237 else vert_second[0] = 0;
1239 if (fullname)
1241 vert_full[0] = '@';
1242 lstrcpynW( vert_full + 1, fullname, LF_FULLFACESIZE - 1 );
1243 fullname = vert_full;
1246 if ((family = find_family_from_name( vert_family ))) family->refcount++;
1247 else if (!(family = create_family( vert_family, vert_second ))) return ret;
1249 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1250 index, fs, ntmflags, version, flags | ADDFONT_VERTICAL_FONT, size )))
1252 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1253 release_face( face );
1255 release_family( family );
1256 ret++;
1258 return ret;
1261 /* font cache */
1263 struct cached_face
1265 DWORD index;
1266 DWORD flags;
1267 DWORD ntmflags;
1268 DWORD version;
1269 struct bitmap_font_size size;
1270 FONTSIGNATURE fs;
1271 WCHAR full_name[1];
1272 /* WCHAR file_name[]; */
1275 static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
1276 void *buffer, DWORD buffer_size, BOOL scalable )
1278 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1279 KEY_NODE_INFORMATION *node_info = (KEY_NODE_INFORMATION *)buffer;
1280 DWORD index = 0, total_size;
1281 struct gdi_font_face *face;
1282 HKEY hkey_strike;
1283 WCHAR name[256];
1284 struct cached_face *cached;
1286 while (reg_enum_value( hkey_family, index++, info,
1287 buffer_size - sizeof(DWORD), name, sizeof(name) ))
1289 cached = (struct cached_face *)((char *)info + info->DataOffset);
1290 if (info->Type == REG_BINARY && info->DataLength > sizeof(*cached))
1292 ((DWORD *)cached)[info->DataLength / sizeof(DWORD)] = 0;
1293 if ((face = create_face( family, name, cached->full_name,
1294 cached->full_name + lstrlenW(cached->full_name) + 1,
1295 NULL, 0, cached->index, cached->fs, cached->ntmflags, cached->version,
1296 cached->flags, scalable ? NULL : &cached->size )))
1298 if (!scalable)
1299 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1300 face->size.height, face->size.width, face->size.size >> 6,
1301 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1303 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1304 face->fs.fsCsb[0], face->fs.fsCsb[1],
1305 face->fs.fsUsb[0], face->fs.fsUsb[1],
1306 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1308 release_face( face );
1313 /* load bitmap strikes */
1315 index = 0;
1316 while (!NtEnumerateKey( hkey_family, index++, KeyNodeInformation, node_info,
1317 buffer_size, &total_size ))
1319 if ((hkey_strike = reg_open_key( hkey_family, node_info->Name, node_info->NameLength )))
1321 load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
1322 NtClose( hkey_strike );
1327 static void load_font_list_from_cache(void)
1329 WCHAR buffer[4096];
1330 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer;
1331 KEY_NODE_INFORMATION *enum_info = (KEY_NODE_INFORMATION *)buffer;
1332 DWORD family_index = 0, total_size;
1333 struct gdi_font_family *family;
1334 HKEY hkey_family;
1335 WCHAR *second_name = (WCHAR *)info->Data;
1337 while (!NtEnumerateKey( wine_fonts_cache_key, family_index++, KeyNodeInformation, enum_info,
1338 sizeof(buffer), &total_size ))
1340 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, enum_info->Name,
1341 enum_info->NameLength )))
1342 continue;
1343 TRACE( "opened family key %s\n", debugstr_wn(enum_info->Name, enum_info->NameLength / sizeof(WCHAR)) );
1344 if (!query_reg_value( hkey_family, NULL, info, sizeof(buffer) ))
1345 second_name[0] = 0;
1347 family = create_family( buffer, second_name );
1349 load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
1351 NtClose( hkey_family );
1352 release_family( family );
1356 static void add_face_to_cache( struct gdi_font_face *face )
1358 HKEY hkey_family, hkey_face;
1359 DWORD len, buffer[1024];
1360 struct cached_face *cached = (struct cached_face *)buffer;
1362 if (!(hkey_family = reg_create_key( wine_fonts_cache_key, face->family->family_name,
1363 lstrlenW( face->family->family_name ) * sizeof(WCHAR),
1364 REG_OPTION_VOLATILE, NULL )))
1365 return;
1367 if (face->family->second_name[0])
1368 set_reg_value( hkey_family, NULL, REG_SZ, face->family->second_name,
1369 (lstrlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1371 if (!face->scalable)
1373 WCHAR nameW[10];
1374 char name[10];
1376 sprintf( name, "%d", face->size.y_ppem );
1377 hkey_face = reg_create_key( hkey_family, nameW,
1378 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR),
1379 REG_OPTION_VOLATILE, NULL );
1381 else hkey_face = hkey_family;
1383 memset( cached, 0, sizeof(*cached) );
1384 cached->index = face->face_index;
1385 cached->flags = face->flags;
1386 cached->ntmflags = face->ntmFlags;
1387 cached->version = face->version;
1388 cached->fs = face->fs;
1389 if (!face->scalable) cached->size = face->size;
1390 lstrcpyW( cached->full_name, face->full_name );
1391 len = lstrlenW( face->full_name ) + 1;
1392 lstrcpyW( cached->full_name + len, face->file );
1393 len += lstrlenW( face->file ) + 1;
1395 set_reg_value( hkey_face, face->style_name, REG_BINARY, cached,
1396 offsetof( struct cached_face, full_name[len] ));
1398 if (hkey_face != hkey_family) NtClose( hkey_face );
1399 NtClose( hkey_family );
1402 static void remove_face_from_cache( struct gdi_font_face *face )
1404 HKEY hkey_family, hkey;
1406 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, face->family->family_name,
1407 lstrlenW( face->family->family_name ) * sizeof(WCHAR) )))
1408 return;
1410 if (!face->scalable)
1412 WCHAR nameW[10];
1413 char name[10];
1414 sprintf( name, "%d", face->size.y_ppem );
1415 if ((hkey = reg_open_key( hkey_family, nameW,
1416 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) )))
1418 NtDeleteKey( hkey );
1419 NtClose( hkey );
1422 else reg_delete_value( hkey_family, face->style_name );
1424 NtClose( hkey_family );
1427 /* font links */
1429 struct gdi_font_link
1431 struct list entry;
1432 struct list links;
1433 WCHAR name[LF_FACESIZE];
1434 FONTSIGNATURE fs;
1437 struct gdi_font_link_entry
1439 struct list entry;
1440 FONTSIGNATURE fs;
1441 WCHAR family_name[LF_FACESIZE];
1444 static struct list font_links = LIST_INIT(font_links);
1446 static struct gdi_font_link *find_gdi_font_link( const WCHAR *name )
1448 struct gdi_font_link *link;
1450 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1451 if (!facename_compare( link->name, name, LF_FACESIZE - 1 )) return link;
1452 return NULL;
1455 static struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
1456 FONTSIGNATURE fs )
1458 struct gdi_font_link *link;
1459 struct gdi_font_link_entry *entry;
1460 struct gdi_font_family *family;
1462 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1464 if (!facename_compare( link->name, name, LF_FACESIZE - 1 ) ||
1465 (subst && !facename_compare( link->name, subst, LF_FACESIZE - 1 )))
1467 TRACE("found entry in system list\n");
1468 LIST_FOR_EACH_ENTRY( entry, &link->links, struct gdi_font_link_entry, entry )
1470 const struct gdi_font_link *links;
1472 family = find_family_from_name( entry->family_name );
1473 if (!fs.fsCsb[0]) return family;
1474 if (fs.fsCsb[0] & entry->fs.fsCsb[0]) return family;
1475 if ((links = find_gdi_font_link( family->family_name )) && fs.fsCsb[0] & links->fs.fsCsb[0])
1476 return family;
1480 return NULL;
1483 static struct gdi_font_link *add_gdi_font_link( const WCHAR *name )
1485 struct gdi_font_link *link = find_gdi_font_link( name );
1487 if (link) return link;
1488 if ((link = malloc( sizeof(*link) )))
1490 lstrcpynW( link->name, name, LF_FACESIZE );
1491 memset( &link->fs, 0, sizeof(link->fs) );
1492 list_init( &link->links );
1493 list_add_tail( &font_links, &link->entry );
1495 return link;
1498 static void add_gdi_font_link_entry( struct gdi_font_link *link, const WCHAR *family_name, FONTSIGNATURE fs )
1500 struct gdi_font_link_entry *entry;
1502 entry = malloc( sizeof(*entry) );
1503 lstrcpynW( entry->family_name, family_name, LF_FACESIZE );
1504 entry->fs = fs;
1505 link->fs.fsCsb[0] |= fs.fsCsb[0];
1506 link->fs.fsCsb[1] |= fs.fsCsb[1];
1507 list_add_tail( &link->links, &entry->entry );
1510 static const WCHAR lucida_sans_unicodeW[] =
1511 {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
1512 static const WCHAR microsoft_sans_serifW[] =
1513 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1514 static const WCHAR tahomaW[] =
1515 {'T','a','h','o','m','a',0};
1516 static const WCHAR ms_ui_gothicW[] =
1517 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1518 static const WCHAR sim_sunW[] =
1519 {'S','i','m','S','u','n',0};
1520 static const WCHAR gulimW[] =
1521 {'G','u','l','i','m',0};
1522 static const WCHAR p_ming_li_uW[] =
1523 {'P','M','i','n','g','L','i','U',0};
1524 static const WCHAR batangW[] =
1525 {'B','a','t','a','n','g',0};
1527 static const WCHAR * const font_links_list[] =
1529 lucida_sans_unicodeW,
1530 microsoft_sans_serifW,
1531 tahomaW
1534 static const struct font_links_defaults_list
1536 /* Keyed off substitution for "MS Shell Dlg" */
1537 const WCHAR *shelldlg;
1538 /* Maximum of four substitutes, plus terminating NULL pointer */
1539 const WCHAR *substitutes[5];
1540 } font_links_defaults_list[] =
1542 /* Non East-Asian */
1543 { tahomaW, /* FIXME unverified ordering */
1544 { ms_ui_gothicW, sim_sunW, gulimW, p_ming_li_uW, NULL }
1546 /* Below lists are courtesy of
1547 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1549 /* Japanese */
1550 { ms_ui_gothicW,
1551 { ms_ui_gothicW, p_ming_li_uW, sim_sunW, gulimW, NULL }
1553 /* Chinese Simplified */
1554 { sim_sunW,
1555 { sim_sunW, p_ming_li_uW, ms_ui_gothicW, batangW, NULL }
1557 /* Korean */
1558 { gulimW,
1559 { gulimW, p_ming_li_uW, ms_ui_gothicW, sim_sunW, NULL }
1561 /* Chinese Traditional */
1562 { p_ming_li_uW,
1563 { p_ming_li_uW, sim_sunW, ms_ui_gothicW, batangW, NULL }
1567 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1569 struct gdi_font_family *family;
1570 struct gdi_font_face *face;
1571 struct gdi_font_link *font_link;
1572 const WCHAR *file, *value;
1574 /* Don't store fonts that are only substitutes for other fonts */
1575 if (get_gdi_font_subst( name, -1, NULL ))
1577 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1578 return;
1580 font_link = add_gdi_font_link( name );
1581 for ( ; *values; values++)
1583 if (!facename_compare( name, *values, -1 )) continue;
1584 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1585 if (!(family = find_family_from_name( value ))) continue;
1586 /* use first extant filename for this Family */
1587 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1589 if (!face->file) continue;
1590 file = wcsrchr(face->file, '\\');
1591 if (!file) file = face->file;
1592 else file++;
1593 if ((face = find_face_from_filename( file, value )))
1595 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1596 TRACE( "added internal SystemLink for %s to %s in %s\n",
1597 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1599 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1600 break;
1605 static void load_system_links(void)
1607 HKEY hkey;
1608 DWORD i, j;
1609 const WCHAR *shelldlg_name;
1610 struct gdi_font_link *font_link, *system_font_link;
1611 struct gdi_font_face *face;
1613 static const WCHAR ms_shell_dlgW[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
1614 static const WCHAR systemW[] = {'S','y','s','t','e','m',0};
1615 static const WCHAR tahoma_ttfW[] = {'t','a','h','o','m','a','.','t','t','f',0};
1617 if ((hkey = reg_open_key( NULL, system_link_keyW, sizeof(system_link_keyW) )))
1619 char buffer[4096];
1620 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1621 WCHAR value[MAX_PATH];
1622 WCHAR *entry, *next;
1624 i = 0;
1625 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
1627 /* Don't store fonts that are only substitutes for other fonts */
1628 if (!get_gdi_font_subst( value, -1, NULL ))
1630 char *data = (char *)info + info->DataOffset;
1631 font_link = add_gdi_font_link( value );
1632 for (entry = (WCHAR *)data; (char *)entry < data + info->DataLength && *entry; entry = next)
1634 const WCHAR *family_name = NULL;
1635 WCHAR *p;
1637 TRACE( "%s: %s\n", debugstr_w(value), debugstr_w(entry) );
1639 next = entry + lstrlenW(entry) + 1;
1640 if ((p = wcschr( entry, ',' )))
1642 *p++ = 0;
1643 while (*p == ' ' || *p == '\t') p++;
1644 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
1646 if ((face = find_face_from_filename( entry, family_name )))
1648 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1649 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
1651 else TRACE( "Unable to find file %s family %s\n",
1652 debugstr_w(entry), debugstr_w(family_name) );
1655 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1657 NtClose( hkey );
1660 if ((shelldlg_name = get_gdi_font_subst( ms_shell_dlgW, -1, NULL )))
1662 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
1664 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
1666 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
1667 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
1669 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
1670 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
1671 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
1672 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
1676 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1678 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1679 that Tahoma has */
1681 system_font_link = add_gdi_font_link( systemW );
1682 if ((face = find_face_from_filename( tahoma_ttfW, tahomaW )))
1684 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
1685 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
1687 if ((font_link = find_gdi_font_link( tahomaW )))
1689 struct gdi_font_link_entry *entry;
1690 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
1691 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
1695 /* see TranslateCharsetInfo */
1696 BOOL translate_charset_info( DWORD *src, CHARSETINFO *cs, DWORD flags )
1698 int index = 0;
1700 switch (flags)
1702 case TCI_SRCFONTSIG:
1703 while (index < ARRAY_SIZE(charset_info) && !(*src>>index & 0x0001)) index++;
1704 break;
1705 case TCI_SRCCODEPAGE:
1706 while (index < ARRAY_SIZE(charset_info) && PtrToUlong(src) != charset_info[index].ciACP)
1707 index++;
1708 break;
1709 case TCI_SRCCHARSET:
1710 while (index < ARRAY_SIZE(charset_info) &&
1711 PtrToUlong(src) != charset_info[index].ciCharset)
1712 index++;
1713 break;
1714 default:
1715 return FALSE;
1718 if (index >= ARRAY_SIZE(charset_info) || charset_info[index].ciCharset == DEFAULT_CHARSET) return FALSE;
1719 *cs = charset_info[index];
1720 return TRUE;
1723 /* font matching */
1725 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
1727 struct gdi_font_link *font_link;
1729 if (!face->scalable && !can_use_bitmap) return FALSE;
1730 if (!fs.fsCsb[0]) return TRUE;
1731 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
1732 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
1733 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
1734 return FALSE;
1737 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
1738 const LOGFONTW *lf, FONTSIGNATURE fs,
1739 BOOL can_use_bitmap )
1741 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
1742 unsigned int best_score = 4;
1743 int best_diff = 0;
1744 int it = !!lf->lfItalic;
1745 int bd = lf->lfWeight > 550;
1746 int height = lf->lfHeight;
1748 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1750 int italic = !!(face->ntmFlags & NTM_ITALIC);
1751 int bold = !!(face->ntmFlags & NTM_BOLD);
1752 int score = (italic ^ it) + (bold ^ bd);
1754 if (!can_select_face( face, fs, can_use_bitmap )) continue;
1755 if (score > best_score) continue;
1756 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
1757 best_score = score;
1758 best = face;
1759 if (best->scalable && best_score == 0) break;
1760 if (!best->scalable)
1762 int diff;
1763 if (height > 0)
1764 diff = height - (signed int)best->size.height;
1765 else
1766 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
1767 if (!best_bitmap ||
1768 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
1769 (best_diff < 0 && diff > best_diff))
1771 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
1772 best_diff = diff;
1773 best_bitmap = best;
1774 if (best_score == 0 && best_diff == 0) break;
1778 if (!best) return NULL;
1779 return best->scalable ? best : best_bitmap;
1782 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
1783 const LOGFONTW *lf, FONTSIGNATURE fs,
1784 BOOL can_use_bitmap, const WCHAR **orig_name )
1786 struct gdi_font_family *family;
1787 struct gdi_font_face *face;
1789 family = find_family_from_any_name( name );
1790 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
1791 if (subst)
1793 family = find_family_from_any_name( subst );
1794 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
1797 /* search by full face name */
1798 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1799 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1800 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
1801 can_select_face( face, fs, can_use_bitmap ))
1802 return face;
1804 if ((family = find_family_from_font_links( name, subst, fs )))
1806 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1808 return NULL;
1810 found:
1811 if (orig_name && family != face->family)
1812 *orig_name = family->family_name;
1813 return face;
1816 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
1817 BOOL can_use_bitmap, BOOL want_vertical )
1819 struct gdi_font_family *family;
1820 struct gdi_font_face *face;
1821 WCHAR name[LF_FACESIZE + 1];
1822 int i = 0;
1824 /* first try the family fallbacks */
1825 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
1827 if (want_vertical)
1829 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
1830 name[0] = '@';
1833 if (!(family = find_family_from_any_name(name))) continue;
1834 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1836 /* otherwise try only scalable */
1837 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1839 if ((family->family_name[0] == '@') == !want_vertical) continue;
1840 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1842 if (!can_use_bitmap) return NULL;
1843 /* then also bitmap fonts */
1844 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1846 if ((family->family_name[0] == '@') == !want_vertical) continue;
1847 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1849 return NULL;
1852 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
1853 BOOL *substituted, const WCHAR **orig_name )
1855 BOOL want_vertical = (lf->lfFaceName[0] == '@');
1856 struct gdi_font_face *face;
1858 if (!translate_charset_info( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
1860 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
1861 csi->fs.fsCsb[0] = 0;
1864 if (lf->lfFaceName[0])
1866 int subst_charset;
1867 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
1869 if (subst)
1871 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
1872 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
1873 if (subst_charset != -1)
1874 translate_charset_info( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
1875 *substituted = TRUE;
1878 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap, orig_name )))
1879 return face;
1881 *substituted = FALSE; /* substitution is no longer relevant */
1883 /* If requested charset was DEFAULT_CHARSET then try using charset
1884 corresponding to the current ansi codepage */
1885 if (!csi->fs.fsCsb[0])
1887 if (!translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
1889 FIXME( "TCI failed on codepage %d\n", ansi_cp.CodePage );
1890 csi->fs.fsCsb[0] = 0;
1894 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1895 if (csi->fs.fsCsb[0])
1897 csi->fs.fsCsb[0] = 0;
1898 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1900 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
1901 return NULL;
1904 /* realized font objects */
1906 #define FIRST_FONT_HANDLE 1
1907 #define MAX_FONT_HANDLES 256
1909 struct font_handle_entry
1911 struct gdi_font *font;
1912 WORD generation; /* generation count for reusing handle values */
1915 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
1916 static struct font_handle_entry *next_free;
1917 static struct font_handle_entry *next_unused = font_handles;
1919 static struct font_handle_entry *handle_entry( DWORD handle )
1921 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
1923 if (idx < MAX_FONT_HANDLES)
1925 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
1926 return &font_handles[idx];
1928 if (handle) WARN( "invalid handle 0x%08x\n", handle );
1929 return NULL;
1932 static struct gdi_font *get_font_from_handle( DWORD handle )
1934 struct font_handle_entry *entry = handle_entry( handle );
1936 if (entry) return entry->font;
1937 SetLastError( ERROR_INVALID_PARAMETER );
1938 return NULL;
1941 static DWORD alloc_font_handle( struct gdi_font *font )
1943 struct font_handle_entry *entry;
1945 entry = next_free;
1946 if (entry)
1947 next_free = (struct font_handle_entry *)entry->font;
1948 else if (next_unused < font_handles + MAX_FONT_HANDLES)
1949 entry = next_unused++;
1950 else
1952 ERR( "out of realized font handles\n" );
1953 return 0;
1955 entry->font = font;
1956 if (++entry->generation == 0xffff) entry->generation = 1;
1957 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
1960 static void free_font_handle( DWORD handle )
1962 struct font_handle_entry *entry;
1964 if ((entry = handle_entry( handle )))
1966 entry->font = (struct gdi_font *)next_free;
1967 next_free = entry;
1971 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
1973 UINT len = file ? lstrlenW(file) : 0;
1974 struct gdi_font *font = calloc( 1, offsetof( struct gdi_font, file[len + 1] ));
1976 font->refcount = 1;
1977 font->matrix.eM11 = font->matrix.eM22 = 1.0;
1978 font->scale_y = 1;
1979 font->kern_count = -1;
1980 list_init( &font->child_fonts );
1982 if (file)
1984 FILE_NETWORK_OPEN_INFORMATION info;
1985 UNICODE_STRING nt_name;
1986 OBJECT_ATTRIBUTES attr;
1988 nt_name.Buffer = (WCHAR *)file;
1989 nt_name.Length = nt_name.MaximumLength = len * sizeof(WCHAR);
1991 attr.Length = sizeof(attr);
1992 attr.RootDirectory = 0;
1993 attr.Attributes = OBJ_CASE_INSENSITIVE;
1994 attr.ObjectName = &nt_name;
1995 attr.SecurityDescriptor = NULL;
1996 attr.SecurityQualityOfService = NULL;
1998 if (!NtQueryFullAttributesFile( &attr, &info ))
2000 font->writetime.dwLowDateTime = info.LastWriteTime.LowPart;
2001 font->writetime.dwHighDateTime = info.LastWriteTime.HighPart;
2002 font->data_size = info.EndOfFile.QuadPart;
2003 memcpy( font->file, file, len * sizeof(WCHAR) );
2006 else
2008 font->data_ptr = data_ptr;
2009 font->data_size = data_size;
2012 font->handle = alloc_font_handle( font );
2013 return font;
2016 static void free_gdi_font( struct gdi_font *font )
2018 DWORD i;
2019 struct gdi_font *child, *child_next;
2021 if (font->private) font_funcs->destroy_font( font );
2022 free_font_handle( font->handle );
2023 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
2025 list_remove( &child->entry );
2026 free_gdi_font( child );
2028 for (i = 0; i < font->gm_size; i++) free( font->gm[i] );
2029 free( font->otm.otmpFamilyName );
2030 free( font->otm.otmpStyleName );
2031 free( font->otm.otmpFaceName );
2032 free( font->otm.otmpFullName );
2033 free( font->gm );
2034 free( font->kern_pairs );
2035 free( font->gsub_table );
2036 free( font );
2039 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
2041 return font->use_logfont_name ? font->lf.lfFaceName : (WCHAR *)font->otm.otmpFamilyName;
2044 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
2045 const LOGFONTW *lf )
2047 struct gdi_font *font;
2049 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
2050 font->fs = face->fs;
2051 font->lf = *lf;
2052 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
2053 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
2054 font->scalable = face->scalable;
2055 font->face_index = face->face_index;
2056 font->ntmFlags = face->ntmFlags;
2057 font->aa_flags = HIWORD( face->flags );
2058 if (!family_name) family_name = face->family->family_name;
2059 font->otm.otmpFamilyName = (char *)wcsdup( family_name );
2060 font->otm.otmpStyleName = (char *)wcsdup( face->style_name );
2061 font->otm.otmpFaceName = (char *)wcsdup( face->full_name );
2062 return font;
2065 struct glyph_metrics
2067 GLYPHMETRICS gm;
2068 ABC abc; /* metrics of the unrotated char */
2069 BOOL init;
2072 #define GM_BLOCK_SIZE 128
2074 /* TODO: GGO format support */
2075 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
2077 UINT block = index / GM_BLOCK_SIZE;
2078 UINT entry = index % GM_BLOCK_SIZE;
2080 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
2082 *gm = font->gm[block][entry].gm;
2083 *abc = font->gm[block][entry].abc;
2085 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2086 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
2087 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2088 return TRUE;
2091 return FALSE;
2094 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
2095 const GLYPHMETRICS *gm, const ABC *abc )
2097 UINT block = index / GM_BLOCK_SIZE;
2098 UINT entry = index % GM_BLOCK_SIZE;
2100 if (block >= font->gm_size)
2102 struct glyph_metrics **ptr;
2104 if (!(ptr = realloc( font->gm, (block + 1) * sizeof(*ptr) ))) return;
2105 memset( ptr + font->gm_size, 0, (block + 1 - font->gm_size) * sizeof(*ptr) );
2106 font->gm_size = block + 1;
2107 font->gm = ptr;
2109 if (!font->gm[block])
2111 font->gm[block] = calloc( sizeof(**font->gm), GM_BLOCK_SIZE );
2112 if (!font->gm[block]) return;
2114 font->gm[block][entry].gm = *gm;
2115 font->gm[block][entry].abc = *abc;
2116 font->gm[block][entry].init = TRUE;
2120 /* GSUB table support */
2122 typedef struct
2124 DWORD version;
2125 WORD ScriptList;
2126 WORD FeatureList;
2127 WORD LookupList;
2128 } GSUB_Header;
2130 typedef struct
2132 CHAR ScriptTag[4];
2133 WORD Script;
2134 } GSUB_ScriptRecord;
2136 typedef struct
2138 WORD ScriptCount;
2139 GSUB_ScriptRecord ScriptRecord[1];
2140 } GSUB_ScriptList;
2142 typedef struct
2144 CHAR LangSysTag[4];
2145 WORD LangSys;
2146 } GSUB_LangSysRecord;
2148 typedef struct
2150 WORD DefaultLangSys;
2151 WORD LangSysCount;
2152 GSUB_LangSysRecord LangSysRecord[1];
2153 } GSUB_Script;
2155 typedef struct
2157 WORD LookupOrder; /* Reserved */
2158 WORD ReqFeatureIndex;
2159 WORD FeatureCount;
2160 WORD FeatureIndex[1];
2161 } GSUB_LangSys;
2163 typedef struct
2165 CHAR FeatureTag[4];
2166 WORD Feature;
2167 } GSUB_FeatureRecord;
2169 typedef struct
2171 WORD FeatureCount;
2172 GSUB_FeatureRecord FeatureRecord[1];
2173 } GSUB_FeatureList;
2175 typedef struct
2177 WORD FeatureParams; /* Reserved */
2178 WORD LookupCount;
2179 WORD LookupListIndex[1];
2180 } GSUB_Feature;
2182 typedef struct
2184 WORD LookupCount;
2185 WORD Lookup[1];
2186 } GSUB_LookupList;
2188 typedef struct
2190 WORD LookupType;
2191 WORD LookupFlag;
2192 WORD SubTableCount;
2193 WORD SubTable[1];
2194 } GSUB_LookupTable;
2196 typedef struct
2198 WORD CoverageFormat;
2199 WORD GlyphCount;
2200 WORD GlyphArray[1];
2201 } GSUB_CoverageFormat1;
2203 typedef struct
2205 WORD Start;
2206 WORD End;
2207 WORD StartCoverageIndex;
2208 } GSUB_RangeRecord;
2210 typedef struct
2212 WORD CoverageFormat;
2213 WORD RangeCount;
2214 GSUB_RangeRecord RangeRecord[1];
2215 } GSUB_CoverageFormat2;
2217 typedef struct
2219 WORD SubstFormat; /* = 1 */
2220 WORD Coverage;
2221 WORD DeltaGlyphID;
2222 } GSUB_SingleSubstFormat1;
2224 typedef struct
2226 WORD SubstFormat; /* = 2 */
2227 WORD Coverage;
2228 WORD GlyphCount;
2229 WORD Substitute[1];
2230 } GSUB_SingleSubstFormat2;
2232 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
2234 GSUB_ScriptList *script;
2235 GSUB_Script *deflt = NULL;
2236 int i;
2238 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
2239 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
2240 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
2242 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
2243 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
2244 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
2245 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
2247 return deflt;
2250 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
2252 int i, offset;
2253 GSUB_LangSys *lang;
2255 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
2257 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
2259 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
2260 lang = (GSUB_LangSys *)((BYTE *)script + offset);
2261 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
2263 offset = GET_BE_WORD(script->DefaultLangSys);
2264 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
2265 return NULL;
2268 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
2270 int i;
2271 const GSUB_FeatureList *feature;
2273 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
2274 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
2275 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
2277 int index = GET_BE_WORD(lang->FeatureIndex[i]);
2278 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
2279 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
2281 return NULL;
2284 static const char *get_opentype_script( const struct gdi_font *font )
2287 * I am not sure if this is the correct way to generate our script tag
2289 switch (font->charset)
2291 case ANSI_CHARSET: return "latn";
2292 case BALTIC_CHARSET: return "latn"; /* ?? */
2293 case CHINESEBIG5_CHARSET: return "hani";
2294 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
2295 case GB2312_CHARSET: return "hani";
2296 case GREEK_CHARSET: return "grek";
2297 case HANGUL_CHARSET: return "hang";
2298 case RUSSIAN_CHARSET: return "cyrl";
2299 case SHIFTJIS_CHARSET: return "kana";
2300 case TURKISH_CHARSET: return "latn"; /* ?? */
2301 case VIETNAMESE_CHARSET: return "latn";
2302 case JOHAB_CHARSET: return "latn"; /* ?? */
2303 case ARABIC_CHARSET: return "arab";
2304 case HEBREW_CHARSET: return "hebr";
2305 case THAI_CHARSET: return "thai";
2306 default: return "latn";
2310 static void *get_GSUB_vert_feature( struct gdi_font *font )
2312 GSUB_Header *header;
2313 GSUB_Script *script;
2314 GSUB_LangSys *language;
2315 GSUB_Feature *feature;
2316 DWORD length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2318 if (length == GDI_ERROR) return NULL;
2320 header = malloc( length );
2321 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2322 TRACE( "Loaded GSUB table of %i bytes\n", length );
2324 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2326 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2328 feature = GSUB_get_feature( header, language, "vrt2" );
2329 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2330 if (feature)
2332 font->gsub_table = header;
2333 return feature;
2335 TRACE("vrt2/vert feature not found\n");
2337 else TRACE("Language not found\n");
2339 else TRACE("Script not found\n");
2341 free( header );
2342 return NULL;
2345 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2347 GSUB_CoverageFormat1 *cf1 = table;
2349 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2351 int i, count = GET_BE_WORD(cf1->GlyphCount);
2353 TRACE("Coverage Format 1, %i glyphs\n",count);
2354 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2355 return -1;
2357 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2359 int i, count;
2360 GSUB_CoverageFormat2 *cf2 = table;
2362 count = GET_BE_WORD(cf2->RangeCount);
2363 TRACE("Coverage Format 2, %i ranges\n",count);
2364 for (i = 0; i < count; i++)
2366 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2367 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2368 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2370 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2371 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2374 return -1;
2376 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2378 return -1;
2381 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2383 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2384 int i, j, offset;
2386 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2387 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2389 GSUB_LookupTable *look;
2390 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2391 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2392 TRACE("type %i, flag %x, subtables %i\n",
2393 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2394 if (GET_BE_WORD(look->LookupType) == 1)
2396 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2398 GSUB_SingleSubstFormat1 *ssf1;
2399 offset = GET_BE_WORD(look->SubTable[j]);
2400 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2401 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2403 int offset = GET_BE_WORD(ssf1->Coverage);
2404 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2405 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2407 TRACE(" Glyph 0x%x ->",glyph);
2408 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2409 TRACE(" 0x%x\n",glyph);
2412 else
2414 GSUB_SingleSubstFormat2 *ssf2;
2415 int index, offset;
2417 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2418 offset = GET_BE_WORD(ssf1->Coverage);
2419 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2420 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2421 TRACE(" Coverage index %i\n",index);
2422 if (index != -1)
2424 TRACE(" Glyph is 0x%x ->",glyph);
2425 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2426 TRACE("0x%x\n",glyph);
2431 else FIXME("We only handle SubType 1\n");
2433 return glyph;
2436 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2438 if (!glyph) return glyph;
2439 if (!font->gsub_table) return glyph;
2440 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2443 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2445 FONTSIGNATURE fs = {{0}};
2446 struct gdi_font *child;
2447 struct gdi_font_face *face;
2449 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE, NULL ))) return;
2451 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2452 child->matrix = font->matrix;
2453 child->can_use_bitmap = font->can_use_bitmap;
2454 child->scale_y = font->scale_y;
2455 child->aveWidth = font->aveWidth;
2456 child->charset = font->charset;
2457 child->codepage = font->codepage;
2458 child->base_font = font;
2459 list_add_tail( &font->child_fonts, &child->entry );
2460 TRACE( "created child font %p for base %p\n", child, font );
2463 static void create_child_font_list( struct gdi_font *font )
2465 struct gdi_font_link *font_link;
2466 struct gdi_font_link_entry *entry;
2467 const WCHAR* font_name = (WCHAR *)font->otm.otmpFaceName;
2469 if ((font_link = find_gdi_font_link( font_name )))
2471 TRACE("found entry in system list\n");
2472 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2473 add_child_font( font, entry->family_name );
2476 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2477 * Sans Serif. This is how asian windows get default fallbacks for fonts
2479 if (ansi_cp.MaximumCharacterSize == 2 && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2480 facename_compare( font_name, microsoft_sans_serifW, -1 ) != 0)
2482 if ((font_link = find_gdi_font_link( microsoft_sans_serifW )))
2484 TRACE("found entry in default fallback list\n");
2485 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2486 add_child_font( font, entry->family_name );
2491 /* font cache */
2493 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2494 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2495 static unsigned int unused_font_count;
2496 #define UNUSED_CACHE_SIZE 10
2498 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2499 const FMAT2 *matrix, BOOL can_use_bitmap )
2501 if (font->hash != hash) return TRUE;
2502 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2503 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2504 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2505 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2508 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2510 DWORD hash = 0, *ptr, two_chars;
2511 WORD *pwc;
2512 unsigned int i;
2514 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2515 hash ^= *ptr;
2516 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2517 hash ^= *ptr;
2518 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2520 two_chars = *ptr;
2521 pwc = (WCHAR *)&two_chars;
2522 if(!*pwc) break;
2523 *pwc = towupper(*pwc);
2524 pwc++;
2525 *pwc = towupper(*pwc);
2526 hash ^= two_chars;
2527 if(!*pwc) break;
2529 hash ^= !can_use_bitmap;
2530 return hash;
2533 static void cache_gdi_font( struct gdi_font *font )
2535 static DWORD cache_num = 1;
2537 font->cache_num = cache_num++;
2538 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2539 list_add_head( &gdi_font_list, &font->entry );
2540 TRACE( "font %p\n", font );
2543 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2545 struct gdi_font *font;
2546 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2548 /* try the in-use list */
2549 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2551 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2552 list_remove( &font->entry );
2553 list_add_head( &gdi_font_list, &font->entry );
2554 if (!font->refcount++)
2556 list_remove( &font->unused_entry );
2557 unused_font_count--;
2559 return font;
2561 return NULL;
2564 static void release_gdi_font( struct gdi_font *font )
2566 if (!font) return;
2568 TRACE( "font %p\n", font );
2570 /* add it to the unused list */
2571 pthread_mutex_lock( &font_lock );
2572 if (!--font->refcount)
2574 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2575 if (unused_font_count > UNUSED_CACHE_SIZE)
2577 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2578 TRACE( "freeing %p\n", font );
2579 list_remove( &font->entry );
2580 list_remove( &font->unused_entry );
2581 free_gdi_font( font );
2583 else unused_font_count++;
2585 pthread_mutex_unlock( &font_lock );
2588 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2590 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2592 set_reg_ascii_value( hkey, "Courier", fl->courier );
2593 set_reg_ascii_value( hkey, "MS Serif", fl->serif );
2594 set_reg_ascii_value( hkey, "MS Sans Serif", sserif );
2595 set_reg_ascii_value( hkey, "Small Fonts", fl->small );
2598 static void set_value_key(HKEY hkey, const char *name, const char *value)
2600 if (value)
2601 set_reg_ascii_value( hkey, name, value );
2602 else if (name)
2604 WCHAR nameW[64];
2605 asciiz_to_unicode( nameW, name );
2606 reg_delete_value( hkey, nameW );
2610 static void update_font_association_info(void)
2612 static const WCHAR associated_charsetW[] =
2613 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
2615 if (ansi_cp.MaximumCharacterSize == 2)
2617 HKEY hkey;
2618 if ((hkey = reg_create_key( NULL, font_assoc_keyW, sizeof(font_assoc_keyW), 0, NULL )))
2620 HKEY hsubkey;
2621 if ((hsubkey = reg_create_key( hkey, associated_charsetW, sizeof(associated_charsetW),
2622 0, NULL )))
2624 switch (ansi_cp.CodePage)
2626 case 932:
2627 set_value_key(hsubkey, "ANSI(00)", "NO");
2628 set_value_key(hsubkey, "OEM(FF)", "NO");
2629 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2630 break;
2631 case 936:
2632 case 949:
2633 case 950:
2634 set_value_key(hsubkey, "ANSI(00)", "YES");
2635 set_value_key(hsubkey, "OEM(FF)", "YES");
2636 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2637 break;
2639 NtClose( hsubkey );
2642 /* TODO: Associated DefaultFonts */
2644 NtClose( hkey );
2647 else
2648 reg_delete_tree( NULL, font_assoc_keyW, sizeof(font_assoc_keyW) );
2651 static void set_multi_value_key( HKEY hkey, const WCHAR *name, const char *value, DWORD len )
2653 WCHAR valueW[256];
2654 ascii_to_unicode( valueW, value, len );
2655 if (value)
2656 set_reg_value( hkey, name, REG_MULTI_SZ, valueW, len * sizeof(WCHAR) );
2657 else if (name)
2658 reg_delete_value( hkey, name );
2661 static void update_font_system_link_info(void)
2663 static const char system_link_simplified_chinese[] =
2664 "SIMSUN.TTC,SimSun\0"
2665 "MINGLIU.TTC,PMingLiu\0"
2666 "MSGOTHIC.TTC,MS UI Gothic\0"
2667 "BATANG.TTC,Batang\0";
2668 static const char system_link_traditional_chinese[] =
2669 "MINGLIU.TTC,PMingLiu\0"
2670 "SIMSUN.TTC,SimSun\0"
2671 "MSGOTHIC.TTC,MS UI Gothic\0"
2672 "BATANG.TTC,Batang\0";
2673 static const char system_link_japanese[] =
2674 "MSGOTHIC.TTC,MS UI Gothic\0"
2675 "MINGLIU.TTC,PMingLiU\0"
2676 "SIMSUN.TTC,SimSun\0"
2677 "GULIM.TTC,Gulim\0";
2678 static const char system_link_korean[] =
2679 "GULIM.TTC,Gulim\0"
2680 "MSGOTHIC.TTC,MS UI Gothic\0"
2681 "MINGLIU.TTC,PMingLiU\0"
2682 "SIMSUN.TTC,SimSun\0";
2683 static const char system_link_non_cjk[] =
2684 "MSGOTHIC.TTC,MS UI Gothic\0"
2685 "MINGLIU.TTC,PMingLiU\0"
2686 "SIMSUN.TTC,SimSun\0"
2687 "GULIM.TTC,Gulim\0";
2688 HKEY hkey;
2690 if ((hkey = reg_create_key( NULL, system_link_keyW, sizeof(system_link_keyW), 0, NULL )))
2692 const char *link;
2693 DWORD len;
2695 switch (ansi_cp.CodePage)
2697 case 932:
2698 link = system_link_japanese;
2699 len = sizeof(system_link_japanese);
2700 break;
2701 case 936:
2702 link = system_link_simplified_chinese;
2703 len = sizeof(system_link_simplified_chinese);
2704 break;
2705 case 949:
2706 link = system_link_korean;
2707 len = sizeof(system_link_korean);
2708 break;
2709 case 950:
2710 link = system_link_traditional_chinese;
2711 len = sizeof(system_link_traditional_chinese);
2712 break;
2713 default:
2714 link = system_link_non_cjk;
2715 len = sizeof(system_link_non_cjk);
2717 set_multi_value_key(hkey, lucida_sans_unicodeW, link, len);
2718 set_multi_value_key(hkey, microsoft_sans_serifW, link, len);
2719 set_multi_value_key(hkey, tahomaW, link, len);
2720 NtClose( hkey );
2724 static void update_codepage( UINT screen_dpi )
2726 USHORT utf8_hdr[2] = { 0, CP_UTF8 };
2727 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[40 * sizeof(WCHAR)])];
2728 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
2729 char cpbuf[40];
2730 WCHAR cpbufW[40];
2731 HKEY hkey;
2732 DWORD size;
2733 UINT i;
2734 DWORD font_dpi = 0;
2735 BOOL done = FALSE, cp_match = FALSE;
2737 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
2739 size = query_reg_value( wine_fonts_key, log_pixelsW, info, sizeof(value_buffer) );
2740 if (size == sizeof(DWORD) && info->Type == REG_DWORD)
2741 font_dpi = *(DWORD *)info->Data;
2743 RtlInitCodePageTable( utf8_hdr, &utf8_cp );
2744 if (NtCurrentTeb()->Peb->AnsiCodePageData)
2745 RtlInitCodePageTable( NtCurrentTeb()->Peb->AnsiCodePageData, &ansi_cp );
2746 else
2747 ansi_cp = utf8_cp;
2748 if (NtCurrentTeb()->Peb->OemCodePageData)
2749 RtlInitCodePageTable( NtCurrentTeb()->Peb->OemCodePageData, &oem_cp );
2750 else
2751 oem_cp = utf8_cp;
2752 sprintf( cpbuf, "%u,%u", ansi_cp.CodePage, oem_cp.CodePage );
2753 asciiz_to_unicode( cpbufW, cpbuf );
2755 if (query_reg_ascii_value( wine_fonts_key, "Codepages", info, sizeof(value_buffer) ))
2757 cp_match = !wcscmp( (const WCHAR *)info->Data, cpbufW );
2758 if (cp_match && screen_dpi == font_dpi) return; /* already set correctly */
2759 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2760 debugstr_w((const WCHAR *)info->Data), font_dpi, ansi_cp.CodePage, oem_cp.CodePage, screen_dpi );
2762 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2763 ansi_cp.CodePage, oem_cp.CodePage, screen_dpi);
2765 set_reg_ascii_value( wine_fonts_key, "Codepages", cpbuf );
2766 set_reg_value( wine_fonts_key, log_pixelsW, REG_DWORD, &screen_dpi, sizeof(screen_dpi) );
2768 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
2770 if (nls_update_font_list[i].ansi_cp == ansi_cp.CodePage &&
2771 nls_update_font_list[i].oem_cp == oem_cp.CodePage)
2773 HKEY software_hkey;
2774 if ((software_hkey = reg_create_key( NULL, software_config_keyW,
2775 sizeof(software_config_keyW), 0, NULL )))
2777 static const WCHAR fontsW[] = {'F','o','n','t','s'};
2778 hkey = reg_create_key( software_hkey, fontsW, sizeof(fontsW), 0, NULL );
2779 NtClose( software_hkey );
2780 if (hkey)
2782 set_reg_ascii_value( hkey, "OEMFONT.FON", nls_update_font_list[i].oem );
2783 set_reg_ascii_value( hkey, "FIXEDFON.FON", nls_update_font_list[i].fixed );
2784 set_reg_ascii_value( hkey, "FONTS.FON", nls_update_font_list[i].system );
2785 NtClose( hkey );
2788 if ((hkey = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW),
2789 0, NULL )))
2791 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2792 NtClose( hkey );
2794 if ((hkey = reg_create_key( NULL, fonts_win9x_config_keyW,
2795 sizeof(fonts_win9x_config_keyW), 0, NULL )))
2797 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2798 NtClose( hkey );
2800 /* Only update these if the Codepage changed. */
2801 if (!cp_match &&
2802 (hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
2803 0, NULL )))
2805 set_reg_ascii_value( hkey, "MS Shell Dlg", nls_update_font_list[i].shelldlg );
2806 set_reg_ascii_value( hkey, "Tms Rmn", nls_update_font_list[i].tmsrmn );
2808 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2809 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2810 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2811 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2812 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2813 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2814 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2815 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2817 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2818 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2819 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2821 NtClose( hkey );
2823 done = TRUE;
2825 else
2827 /* Delete the FontSubstitutes from other locales */
2828 if ((hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
2829 0, NULL )))
2831 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2832 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2833 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2834 NtClose( hkey );
2838 if (!done)
2839 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp.CodePage, oem_cp.CodePage);
2841 /* update locale dependent font association info and font system link info in registry.
2842 update only when codepages changed, not logpixels. */
2843 if (!cp_match)
2845 update_font_association_info();
2846 update_font_system_link_info();
2851 /*************************************************************
2852 * font_CreateDC
2854 static BOOL CDECL font_CreateDC( PHYSDEV *dev, LPCWSTR device, LPCWSTR output,
2855 const DEVMODEW *devmode )
2857 struct font_physdev *physdev;
2859 if (!font_funcs) return TRUE;
2860 if (!(physdev = calloc( 1, sizeof(*physdev) ))) return FALSE;
2861 push_dc_driver( dev, &physdev->dev, &font_driver );
2862 return TRUE;
2866 /*************************************************************
2867 * font_DeleteDC
2869 static BOOL CDECL font_DeleteDC( PHYSDEV dev )
2871 struct font_physdev *physdev = get_font_dev( dev );
2873 release_gdi_font( physdev->font );
2874 free( physdev );
2875 return TRUE;
2879 struct gdi_font_enum_data
2881 ENUMLOGFONTEXW elf;
2882 NEWTEXTMETRICEXW ntm;
2885 struct enum_charset
2887 DWORD mask;
2888 DWORD charset;
2889 DWORD script;
2892 static BOOL is_complex_script_ansi_cp(void)
2894 return (ansi_cp.CodePage == 874 /* Thai */
2895 || ansi_cp.CodePage == 1255 /* Hebrew */
2896 || ansi_cp.CodePage == 1256 /* Arabic */
2900 /***************************************************
2901 * create_enum_charset_list
2903 * This function creates charset enumeration list because in DEFAULT_CHARSET
2904 * case, the ANSI codepage's charset takes precedence over other charsets.
2905 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2906 * This function works as a filter other than DEFAULT_CHARSET case.
2908 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
2910 struct enum_charset *start = list;
2911 CHARSETINFO csi;
2912 int i;
2914 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && 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 list++;
2921 else /* charset is DEFAULT_CHARSET or invalid. */
2923 DWORD mask = 0;
2925 /* Set the current codepage's charset as the first element. */
2926 if (!is_complex_script_ansi_cp() &&
2927 translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, &csi, TCI_SRCCODEPAGE ) &&
2928 csi.fs.fsCsb[0] != 0)
2930 list->mask = csi.fs.fsCsb[0];
2931 list->charset = csi.ciCharset;
2932 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2933 mask |= csi.fs.fsCsb[0];
2934 list++;
2937 /* Fill out left elements. */
2938 for (i = 0; i < 32; i++)
2940 FONTSIGNATURE fs;
2941 fs.fsCsb[0] = 1u << i;
2942 fs.fsCsb[1] = 0;
2943 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
2944 if (!translate_charset_info( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
2945 continue; /* skip, this is an invalid fsCsb bit. */
2946 list->mask = fs.fsCsb[0];
2947 list->charset = csi.ciCharset;
2948 list->script = i;
2949 mask |= fs.fsCsb[0];
2950 list++;
2952 /* add catch all mask for remaining bits */
2953 if (~mask)
2955 list->mask = ~mask;
2956 list->charset = DEFAULT_CHARSET;
2957 list->script = 33; /* other */
2958 list++;
2961 return list - start;
2964 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
2966 UINT ret = 0;
2968 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
2969 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
2970 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
2971 return ret;
2974 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
2976 struct gdi_font *font;
2977 LOGFONTW lf = { .lfHeight = -4096 /* preferable EM Square size */ };
2979 if (!face->scalable) lf.lfHeight = 0;
2981 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2983 if (!font_funcs->load_font( font ))
2985 free_gdi_font( font );
2986 return FALSE;
2989 if (font->scalable && -lf.lfHeight % font->otm.otmEMSquare != 0)
2991 /* reload with the original EM Square size */
2992 lf.lfHeight = -font->otm.otmEMSquare;
2993 free_gdi_font( font );
2995 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2996 if (!font_funcs->load_font( font ))
2998 free_gdi_font( font );
2999 return FALSE;
3003 if (font_funcs->set_outline_text_metrics( font ))
3005 static const DWORD ntm_ppem = 32;
3006 UINT cell_height;
3008 #define TM font->otm.otmTextMetrics
3009 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
3010 cell_height = TM.tmHeight / ( -lf.lfHeight / font->otm.otmEMSquare );
3011 ntm->ntmTm.tmHeight = muldiv( ntm_ppem, cell_height, font->otm.otmEMSquare );
3012 ntm->ntmTm.tmAscent = SCALE_NTM( TM.tmAscent );
3013 ntm->ntmTm.tmDescent = ntm->ntmTm.tmHeight - ntm->ntmTm.tmAscent;
3014 ntm->ntmTm.tmInternalLeading = SCALE_NTM( TM.tmInternalLeading );
3015 ntm->ntmTm.tmExternalLeading = SCALE_NTM( TM.tmExternalLeading );
3016 ntm->ntmTm.tmAveCharWidth = SCALE_NTM( TM.tmAveCharWidth );
3017 ntm->ntmTm.tmMaxCharWidth = SCALE_NTM( TM.tmMaxCharWidth );
3019 memcpy((char *)&ntm->ntmTm + offsetof( TEXTMETRICW, tmWeight ),
3020 (const char *)&TM + offsetof( TEXTMETRICW, tmWeight ),
3021 sizeof(TEXTMETRICW) - offsetof( TEXTMETRICW, tmWeight ));
3022 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
3023 ntm->ntmTm.ntmCellHeight = cell_height;
3024 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
3025 #undef SCALE_NTM
3026 #undef TM
3028 else if (font_funcs->set_bitmap_text_metrics( font ))
3030 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
3031 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
3032 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
3033 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
3035 ntm->ntmTm.ntmFlags = font->ntmFlags;
3036 ntm->ntmFontSig = font->fs;
3038 elf->elfLogFont.lfEscapement = 0;
3039 elf->elfLogFont.lfOrientation = 0;
3040 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
3041 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
3042 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
3043 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
3044 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
3045 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
3046 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
3047 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3048 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3049 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
3050 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3051 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
3052 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
3053 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
3055 free_gdi_font( font );
3056 return TRUE;
3059 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
3061 struct gdi_font_face *face;
3063 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
3064 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3065 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
3066 return FALSE;
3069 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
3071 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
3072 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
3075 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
3076 struct enum_charset *list, DWORD count, FONTENUMPROCW proc, LPARAM lparam,
3077 const WCHAR *subst )
3079 ENUMLOGFONTEXW elf;
3080 NEWTEXTMETRICEXW ntm;
3081 DWORD type, i;
3083 if (!face->cached_enum_data)
3085 struct gdi_font_enum_data *data;
3087 if (!(data = calloc( 1, sizeof(*data) )) ||
3088 !get_face_enum_data( face, &data->elf, &data->ntm ))
3090 free( data );
3091 return TRUE;
3093 face->cached_enum_data = data;
3096 elf = face->cached_enum_data->elf;
3097 ntm = face->cached_enum_data->ntm;
3098 type = get_font_type( &ntm );
3100 /* font replacement */
3101 if (family != face->family)
3103 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
3104 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
3106 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
3108 for (i = 0; i < count; i++)
3110 if (face->fs.fsCsb[0] == 0) /* OEM */
3112 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3113 elf.elfScript[0] = 32;
3114 i = count; /* break out of loop after enumeration */
3116 else
3118 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
3119 /* use the DEFAULT_CHARSET case only if no other charset is present */
3120 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
3121 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
3122 /* caller may fill elfScript with the actual string, see load_script_name */
3123 elf.elfScript[0] = list[i].script;
3125 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3126 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3127 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
3128 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, ntm.ntmTm.ntmFlags );
3129 /* release section before callback (FIXME) */
3130 pthread_mutex_unlock( &font_lock );
3131 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
3132 pthread_mutex_lock( &font_lock );
3134 return TRUE;
3137 /*************************************************************
3138 * font_EnumFonts
3140 static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
3142 struct gdi_font_family *family;
3143 struct gdi_font_face *face;
3144 struct enum_charset enum_charsets[32];
3145 DWORD count, charset;
3147 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
3149 count = create_enum_charset_list( charset, enum_charsets );
3151 pthread_mutex_lock( &font_lock );
3153 if (lf && lf->lfFaceName[0])
3155 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
3156 const WCHAR *orig_name = NULL;
3158 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
3159 if (face_name)
3161 orig_name = lf->lfFaceName;
3162 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
3164 else face_name = lf->lfFaceName;
3166 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3168 if (!family_matches(family, face_name)) continue;
3169 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3171 if (!face_matches( family->family_name, face, face_name )) continue;
3172 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
3173 return FALSE;
3177 else
3179 TRACE( "charset %d\n", charset );
3180 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3182 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
3183 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
3184 return FALSE;
3187 pthread_mutex_unlock( &font_lock );
3188 return TRUE;
3192 static BOOL check_unicode_tategaki( WCHAR ch )
3194 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
3195 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
3197 /* We only reach this code if typographical substitution did not occur */
3198 /* Type: U or Type: Tu */
3199 return (orientation == 1 || orientation == 3);
3202 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
3204 UINT index;
3206 if (glyph < 0x100) glyph += 0xf000;
3207 /* there are a number of old pre-Unicode "broken" TTFs, which
3208 do have symbols at U+00XX instead of U+f0XX */
3209 index = glyph;
3210 font_funcs->get_glyph_index( font, &index, FALSE );
3211 if (!index)
3213 index = glyph - 0xf000;
3214 font_funcs->get_glyph_index( font, &index, FALSE );
3216 return index;
3219 CPTABLEINFO *get_cptable( WORD cp )
3221 static CPTABLEINFO tables[100];
3222 unsigned int i;
3223 USHORT *ptr;
3224 SIZE_T size;
3226 if (cp == CP_ACP) return &ansi_cp;
3227 if (cp == CP_UTF8) return &utf8_cp;
3229 for (i = 0; i < ARRAY_SIZE(tables) && tables[i].CodePage; i++)
3230 if (tables[i].CodePage == cp) return &tables[i];
3231 if (NtGetNlsSectionPtr( 11, cp, NULL, (void **)&ptr, &size )) return NULL;
3232 if (i == ARRAY_SIZE(tables))
3234 ERR( "too many code pages\n" );
3235 return NULL;
3237 RtlInitCodePageTable( ptr, &tables[i] );
3238 return &tables[i];
3241 DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, DWORD srclen )
3243 DWORD ret;
3245 if (info->CodePage == CP_UTF8)
3246 RtlUnicodeToUTF8N( dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3247 else
3248 RtlUnicodeToCustomCPN( info, dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3250 return ret;
3253 DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *src, DWORD srclen )
3255 DWORD ret;
3257 if (info->CodePage == CP_UTF8)
3258 RtlUTF8ToUnicodeN( dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3259 else
3260 RtlCustomCPToUnicodeN( info, dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3262 return ret / sizeof(WCHAR);
3265 static BOOL wc_to_index( UINT cp, WCHAR wc, unsigned char *dst, BOOL allow_default )
3267 const CPTABLEINFO *info;
3269 if (!(info = get_cptable( cp ))) return FALSE;
3271 if (info->CodePage == CP_UTF8)
3273 if (wc < 0x80)
3275 *dst = wc;
3276 return TRUE;
3278 if (!allow_default) return FALSE;
3279 *dst = info->DefaultChar;
3280 return TRUE;
3282 else if (info->DBCSCodePage)
3284 WCHAR *uni2cp = info->WideCharTable;
3285 if (uni2cp[wc] & 0xff00) return FALSE;
3286 *dst = uni2cp[wc];
3288 else
3290 char *uni2cp = info->WideCharTable;
3291 *dst = uni2cp[wc];
3294 if (info->MultiByteTable[*dst] != wc)
3296 if (!allow_default) return FALSE;
3297 *dst = info->DefaultChar;
3300 return TRUE;
3303 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
3305 WCHAR wc = glyph;
3306 unsigned char ch;
3308 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
3310 if (font->codepage == CP_SYMBOL)
3312 glyph = get_glyph_index_symbol( font, wc );
3313 if (!glyph)
3315 if (wc_to_index( CP_ACP, wc, &ch, TRUE ))
3316 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
3319 else if (wc_to_index( font->codepage, wc, &ch, FALSE ))
3321 glyph = (unsigned char)ch;
3322 font_funcs->get_glyph_index( font, &glyph, FALSE );
3324 else return 0;
3326 return glyph;
3329 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
3331 struct gdi_font *child;
3332 UINT res;
3334 if ((res = get_glyph_index( *font, glyph ))) return res;
3335 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
3337 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
3339 if (!child->private && !font_funcs->load_font( child )) continue;
3340 if ((res = get_glyph_index( child, glyph )))
3342 *font = child;
3343 return res;
3346 return 0;
3349 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3350 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
3351 const MAT2 *mat )
3353 GLYPHMETRICS gm;
3354 ABC abc;
3355 DWORD ret = 1;
3356 UINT index = glyph;
3357 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
3359 if (format & GGO_GLYPH_INDEX)
3361 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3362 as glyph index. "Treasure Adventure Game" depends on this. */
3363 font_funcs->get_glyph_index( font, &index, FALSE );
3364 format &= ~GGO_GLYPH_INDEX;
3365 /* TODO: Window also turns off tategaki for glyphs passed in by index
3366 if their unicode code points fall outside of the range that is
3367 rotated. */
3369 else
3371 index = get_glyph_index_linked( &font, glyph );
3372 if (tategaki)
3374 UINT orig = index;
3375 index = get_GSUB_vert_glyph( font, index );
3376 if (index == orig) tategaki = check_unicode_tategaki( glyph );
3380 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
3382 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
3383 goto done;
3385 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
3386 if (ret == GDI_ERROR) return ret;
3388 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && !mat)
3389 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
3391 done:
3392 if (gm_ret) *gm_ret = gm;
3393 if (abc_ret) *abc_ret = abc;
3394 return ret;
3398 /*************************************************************
3399 * font_FontIsLinked
3401 static BOOL CDECL font_FontIsLinked( PHYSDEV dev )
3403 struct font_physdev *physdev = get_font_dev( dev );
3405 if (!physdev->font)
3407 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
3408 return dev->funcs->pFontIsLinked( dev );
3410 return !list_empty( &physdev->font->child_fonts );
3414 /*************************************************************
3415 * font_GetCharABCWidths
3417 static BOOL CDECL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT count,
3418 WCHAR *chars, ABC *buffer )
3420 struct font_physdev *physdev = get_font_dev( dev );
3421 UINT c, i;
3423 if (!physdev->font)
3425 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3426 return dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
3429 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3431 pthread_mutex_lock( &font_lock );
3432 for (i = 0; i < count; i++)
3434 c = chars ? chars[i] : first + i;
3435 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &buffer[i], 0, NULL, NULL );
3437 pthread_mutex_unlock( &font_lock );
3438 return TRUE;
3442 /*************************************************************
3443 * font_GetCharABCWidthsI
3445 static BOOL CDECL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3447 struct font_physdev *physdev = get_font_dev( dev );
3448 UINT c;
3450 if (!physdev->font)
3452 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3453 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3456 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3458 pthread_mutex_lock( &font_lock );
3459 for (c = 0; c < count; c++, buffer++)
3460 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3461 NULL, buffer, 0, NULL, NULL );
3462 pthread_mutex_unlock( &font_lock );
3463 return TRUE;
3467 /*************************************************************
3468 * font_GetCharWidth
3470 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT count,
3471 const WCHAR *chars, INT *buffer )
3473 struct font_physdev *physdev = get_font_dev( dev );
3474 UINT c, i;
3475 ABC abc;
3477 if (!physdev->font)
3479 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3480 return dev->funcs->pGetCharWidth( dev, first, count, chars, buffer );
3483 TRACE( "%p, %d, %d, %p\n", physdev->font, first, count, buffer );
3485 pthread_mutex_lock( &font_lock );
3486 for (i = 0; i < count; i++)
3488 c = chars ? chars[i] : i + first;
3489 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3490 buffer[i] = 0;
3491 else
3492 buffer[i] = abc.abcA + abc.abcB + abc.abcC;
3494 pthread_mutex_unlock( &font_lock );
3495 return TRUE;
3499 /*************************************************************
3500 * font_GetCharWidthInfo
3502 static BOOL CDECL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3504 struct font_physdev *physdev = get_font_dev( dev );
3505 struct char_width_info *info = ptr;
3507 if (!physdev->font)
3509 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3510 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3513 info->unk = 0;
3514 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3515 info->lsb = info->rsb = 0;
3517 return TRUE;
3521 /*************************************************************
3522 * font_GetFontData
3524 static DWORD CDECL font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
3526 struct font_physdev *physdev = get_font_dev( dev );
3528 if (!physdev->font)
3530 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
3531 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
3533 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
3537 /*************************************************************
3538 * font_GetFontRealizationInfo
3540 static BOOL CDECL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
3542 struct font_physdev *physdev = get_font_dev( dev );
3543 struct font_realization_info *info = ptr;
3545 if (!physdev->font)
3547 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
3548 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
3551 TRACE( "(%p, %p)\n", physdev->font, info);
3553 info->flags = 1;
3554 if (physdev->font->scalable) info->flags |= 2;
3556 info->cache_num = physdev->font->cache_num;
3557 info->instance_id = physdev->font->handle;
3558 if (info->size == sizeof(*info))
3560 info->file_count = 1;
3561 info->face_index = physdev->font->face_index;
3562 info->simulations = 0;
3563 if (physdev->font->fake_bold) info->simulations |= 0x1;
3564 if (physdev->font->fake_italic) info->simulations |= 0x2;
3566 return TRUE;
3570 /*************************************************************
3571 * font_GetFontUnicodeRanges
3573 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
3575 struct font_physdev *physdev = get_font_dev( dev );
3576 DWORD size, num_ranges;
3578 if (!physdev->font)
3580 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
3581 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
3584 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
3585 size = offsetof( GLYPHSET, ranges[num_ranges] );
3586 if (glyphset)
3588 glyphset->cbThis = size;
3589 glyphset->cRanges = num_ranges;
3590 glyphset->flAccel = 0;
3592 return size;
3596 /*************************************************************
3597 * font_GetGlyphIndices
3599 static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
3601 struct font_physdev *physdev = get_font_dev( dev );
3602 UINT default_char;
3603 unsigned char ch;
3604 BOOL got_default = FALSE;
3605 int i;
3607 if (!physdev->font)
3609 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
3610 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
3613 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3615 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
3616 got_default = TRUE;
3619 pthread_mutex_lock( &font_lock );
3621 for (i = 0; i < count; i++)
3623 UINT glyph = str[i];
3625 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
3627 glyph = 0;
3628 if (physdev->font->codepage == CP_SYMBOL)
3630 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
3631 else if (str[i] < 0x100) glyph = str[i];
3633 else if (wc_to_index( physdev->font->codepage, str[i], &ch, FALSE ))
3634 glyph = (unsigned char)ch;
3636 if (!glyph)
3638 if (!got_default)
3640 default_char = font_funcs->get_default_glyph( physdev->font );
3641 got_default = TRUE;
3643 gi[i] = default_char;
3645 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
3648 pthread_mutex_unlock( &font_lock );
3649 return count;
3653 /*************************************************************
3654 * font_GetGlyphOutline
3656 static DWORD CDECL font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
3657 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
3659 struct font_physdev *physdev = get_font_dev( dev );
3660 DWORD ret;
3662 if (!physdev->font)
3664 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
3665 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
3667 pthread_mutex_lock( &font_lock );
3668 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
3669 pthread_mutex_unlock( &font_lock );
3670 return ret;
3674 /*************************************************************
3675 * font_GetKerningPairs
3677 static DWORD CDECL font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
3679 struct font_physdev *physdev = get_font_dev( dev );
3681 if (!physdev->font)
3683 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
3684 return dev->funcs->pGetKerningPairs( dev, count, pairs );
3687 pthread_mutex_lock( &font_lock );
3688 if (physdev->font->kern_count == -1)
3689 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
3690 &physdev->font->kern_pairs );
3691 pthread_mutex_unlock( &font_lock );
3693 if (count && pairs)
3695 count = min( count, physdev->font->kern_count );
3696 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
3698 else count = physdev->font->kern_count;
3700 return count;
3704 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
3706 double scale_x, scale_y;
3708 if (font->aveWidth)
3710 scale_x = (double)font->aveWidth;
3711 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3713 else
3714 scale_x = font->scale_y;
3716 scale_x *= fabs(font->matrix.eM11);
3717 scale_y = font->scale_y * fabs(font->matrix.eM22);
3719 /* Windows scales these values as signed integers even if they are unsigned */
3720 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3721 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3723 SCALE_Y(otm->otmTextMetrics.tmHeight);
3724 SCALE_Y(otm->otmTextMetrics.tmAscent);
3725 SCALE_Y(otm->otmTextMetrics.tmDescent);
3726 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
3727 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
3729 SCALE_X(otm->otmTextMetrics.tmOverhang);
3730 if (font->fake_bold)
3732 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
3733 otm->otmTextMetrics.tmAveCharWidth++;
3734 otm->otmTextMetrics.tmMaxCharWidth++;
3736 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
3737 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
3739 SCALE_Y(otm->otmAscent);
3740 SCALE_Y(otm->otmDescent);
3741 SCALE_Y(otm->otmLineGap);
3742 SCALE_Y(otm->otmsCapEmHeight);
3743 SCALE_Y(otm->otmsXHeight);
3744 SCALE_Y(otm->otmrcFontBox.top);
3745 SCALE_Y(otm->otmrcFontBox.bottom);
3746 SCALE_X(otm->otmrcFontBox.left);
3747 SCALE_X(otm->otmrcFontBox.right);
3748 SCALE_Y(otm->otmMacAscent);
3749 SCALE_Y(otm->otmMacDescent);
3750 SCALE_Y(otm->otmMacLineGap);
3751 SCALE_X(otm->otmptSubscriptSize.x);
3752 SCALE_Y(otm->otmptSubscriptSize.y);
3753 SCALE_X(otm->otmptSubscriptOffset.x);
3754 SCALE_Y(otm->otmptSubscriptOffset.y);
3755 SCALE_X(otm->otmptSuperscriptSize.x);
3756 SCALE_Y(otm->otmptSuperscriptSize.y);
3757 SCALE_X(otm->otmptSuperscriptOffset.x);
3758 SCALE_Y(otm->otmptSuperscriptOffset.y);
3759 SCALE_Y(otm->otmsStrikeoutSize);
3760 SCALE_Y(otm->otmsStrikeoutPosition);
3761 SCALE_Y(otm->otmsUnderscoreSize);
3762 SCALE_Y(otm->otmsUnderscorePosition);
3764 #undef SCALE_X
3765 #undef SCALE_Y
3768 /*************************************************************
3769 * font_GetOutlineTextMetrics
3771 static UINT CDECL font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
3773 struct font_physdev *physdev = get_font_dev( dev );
3774 UINT ret = 0;
3776 if (!physdev->font)
3778 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
3779 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
3782 if (!physdev->font->scalable) return 0;
3784 pthread_mutex_lock( &font_lock );
3785 if (font_funcs->set_outline_text_metrics( physdev->font ))
3787 ret = physdev->font->otm.otmSize;
3788 if (metrics && size >= physdev->font->otm.otmSize)
3790 WCHAR *ptr = (WCHAR *)(metrics + 1);
3791 *metrics = physdev->font->otm;
3792 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
3793 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
3794 ptr += lstrlenW(ptr) + 1;
3795 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
3796 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
3797 ptr += lstrlenW(ptr) + 1;
3798 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
3799 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
3800 ptr += lstrlenW(ptr) + 1;
3801 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
3802 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
3803 scale_outline_font_metrics( physdev->font, metrics );
3806 pthread_mutex_unlock( &font_lock );
3807 return ret;
3811 /*************************************************************
3812 * font_GetTextCharsetInfo
3814 static UINT CDECL font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
3816 struct font_physdev *physdev = get_font_dev( dev );
3818 if (!physdev->font)
3820 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
3821 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3823 if (fs) *fs = physdev->font->fs;
3824 return physdev->font->charset;
3828 /*************************************************************
3829 * font_GetTextExtentExPoint
3831 static BOOL CDECL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
3833 struct font_physdev *physdev = get_font_dev( dev );
3834 INT i, pos;
3835 ABC abc;
3837 if (!physdev->font)
3839 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
3840 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
3843 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
3845 pthread_mutex_lock( &font_lock );
3846 for (i = pos = 0; i < count; i++)
3848 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
3849 pos += abc.abcA + abc.abcB + abc.abcC;
3850 dxs[i] = pos;
3852 pthread_mutex_unlock( &font_lock );
3853 return TRUE;
3857 /*************************************************************
3858 * font_GetTextExtentExPointI
3860 static BOOL CDECL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
3862 struct font_physdev *physdev = get_font_dev( dev );
3863 INT i, pos;
3864 ABC abc;
3866 if (!physdev->font)
3868 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
3869 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
3872 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
3874 pthread_mutex_lock( &font_lock );
3875 for (i = pos = 0; i < count; i++)
3877 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
3878 NULL, &abc, 0, NULL, NULL );
3879 pos += abc.abcA + abc.abcB + abc.abcC;
3880 dxs[i] = pos;
3882 pthread_mutex_unlock( &font_lock );
3883 return TRUE;
3887 /*************************************************************
3888 * font_GetTextFace
3890 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
3892 struct font_physdev *physdev = get_font_dev( dev );
3893 const WCHAR *font_name;
3894 INT len;
3896 if (!physdev->font)
3898 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
3899 return dev->funcs->pGetTextFace( dev, count, str );
3901 font_name = get_gdi_font_name( physdev->font );
3902 len = lstrlenW( font_name ) + 1;
3903 if (str)
3905 lstrcpynW( str, font_name, count );
3906 len = min( count, len );
3908 return len;
3912 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
3914 double scale_x, scale_y;
3916 /* Make sure that the font has sane width/height ratio */
3917 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
3919 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
3920 font->aveWidth = 0;
3923 if (font->aveWidth)
3925 scale_x = (double)font->aveWidth;
3926 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3928 else
3929 scale_x = font->scale_y;
3931 scale_x *= fabs(font->matrix.eM11);
3932 scale_y = font->scale_y * fabs(font->matrix.eM22);
3934 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3935 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3937 SCALE_Y(tm->tmHeight);
3938 SCALE_Y(tm->tmAscent);
3939 SCALE_Y(tm->tmDescent);
3940 SCALE_Y(tm->tmInternalLeading);
3941 SCALE_Y(tm->tmExternalLeading);
3943 SCALE_X(tm->tmOverhang);
3944 if (font->fake_bold)
3946 if (!font->scalable) tm->tmOverhang++;
3947 tm->tmAveCharWidth++;
3948 tm->tmMaxCharWidth++;
3950 SCALE_X(tm->tmAveCharWidth);
3951 SCALE_X(tm->tmMaxCharWidth);
3953 #undef SCALE_X
3954 #undef SCALE_Y
3957 /*************************************************************
3958 * font_GetTextMetrics
3960 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
3962 struct font_physdev *physdev = get_font_dev( dev );
3963 BOOL ret = FALSE;
3965 if (!physdev->font)
3967 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
3968 return dev->funcs->pGetTextMetrics( dev, metrics );
3971 pthread_mutex_lock( &font_lock );
3972 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
3973 font_funcs->set_bitmap_text_metrics( physdev->font ))
3975 *metrics = physdev->font->otm.otmTextMetrics;
3976 scale_font_metrics( physdev->font, metrics );
3977 ret = TRUE;
3979 pthread_mutex_unlock( &font_lock );
3980 return ret;
3984 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
3986 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3987 a single face with the requested charset. The idea is to check if
3988 the selected font supports the current ANSI codepage, if it does
3989 return the corresponding charset, else return the first charset */
3991 int i;
3993 if (translate_charset_info( (DWORD*)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
3995 const struct gdi_font_link *font_link;
3997 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
3998 font_link = find_gdi_font_link(family_name);
3999 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
4001 for (i = 0; i < 32; i++)
4003 DWORD fs0 = 1u << i;
4004 if (face->fs.fsCsb[0] & fs0)
4006 if (translate_charset_info(&fs0, csi, TCI_SRCFONTSIG)) return;
4007 FIXME("TCI failing on %x\n", fs0);
4011 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4012 face->fs.fsCsb[0], debugstr_w(face->file));
4013 csi->ciACP = ansi_cp.CodePage;
4014 csi->ciCharset = DEFAULT_CHARSET;
4017 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
4019 struct gdi_font *font;
4020 struct gdi_font_face *face;
4021 INT height;
4022 CHARSETINFO csi;
4023 const WCHAR *orig_name = NULL;
4024 BOOL substituted = FALSE;
4026 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
4028 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4029 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4030 original value lfCharSet. Note this is a special case for
4031 Symbol and doesn't happen at least for "Wingdings*" */
4032 if (!facename_compare( lf->lfFaceName, symbolW, -1 )) lf->lfCharSet = SYMBOL_CHARSET;
4034 /* check the cache first */
4035 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4037 TRACE( "returning cached gdiFont(%p)\n", font );
4038 return font;
4040 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &substituted, &orig_name )))
4042 FIXME( "can't find a single appropriate font - bailing\n" );
4043 return NULL;
4045 height = lf->lfHeight;
4047 font = create_gdi_font( face, orig_name, lf );
4048 font->use_logfont_name = substituted;
4049 font->matrix = dcmat;
4050 font->can_use_bitmap = can_use_bitmap;
4051 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
4052 font->charset = csi.ciCharset;
4053 font->codepage = csi.ciACP;
4055 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
4056 face->data_ptr, face->face_index );
4058 font->aveWidth = height ? lf->lfWidth : 0;
4059 if (!face->scalable)
4061 /* Windows uses integer scaling factors for bitmap fonts */
4062 INT scale, scaled_height, diff;
4063 struct gdi_font *cachedfont;
4065 if (height > 0)
4066 diff = height - (signed int)face->size.height;
4067 else
4068 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
4070 /* FIXME: rotation of bitmap fonts is ignored */
4071 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
4072 if (font->aveWidth)
4073 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
4074 font->matrix.eM11 = font->matrix.eM22 = 1.0;
4075 dcmat.eM11 = dcmat.eM22 = 1.0;
4076 /* As we changed the matrix, we need to search the cache for the font again,
4077 * otherwise we might explode the cache. */
4078 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4080 TRACE("Found cached font after non-scalable matrix rescale!\n");
4081 free_gdi_font( font );
4082 return cachedfont;
4085 if (height != 0) height = diff;
4086 height += face->size.height;
4088 scale = (height + face->size.height - 1) / face->size.height;
4089 scaled_height = scale * face->size.height;
4090 /* Only jump to the next height if the difference <= 25% original height */
4091 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4092 /* The jump between unscaled and doubled is delayed by 1 */
4093 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4094 font->scale_y = scale;
4095 TRACE("font scale y: %d\n", font->scale_y);
4098 if (!font_funcs->load_font( font ))
4100 free_gdi_font( font );
4101 return NULL;
4104 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
4105 font->vert_feature = get_GSUB_vert_feature( font );
4107 create_child_font_list( font );
4109 TRACE( "caching: gdiFont=%p\n", font );
4110 cache_gdi_font( font );
4111 return font;
4114 /*************************************************************
4115 * font_SelectFont
4117 static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4119 struct font_physdev *physdev = get_font_dev( dev );
4120 struct gdi_font *font = NULL, *prev = physdev->font;
4121 DC *dc = get_physdev_dc( dev );
4123 if (hfont)
4125 LOGFONTW lf;
4126 FMAT2 dcmat;
4127 BOOL can_use_bitmap = !!(NtGdiGetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
4129 NtGdiExtGetObjectW( hfont, sizeof(lf), &lf );
4130 switch (lf.lfQuality)
4132 case NONANTIALIASED_QUALITY:
4133 if (!*aa_flags) *aa_flags = GGO_BITMAP;
4134 break;
4135 case ANTIALIASED_QUALITY:
4136 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
4137 break;
4140 lf.lfWidth = abs(lf.lfWidth);
4142 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4143 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4144 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4145 lf.lfEscapement );
4147 if (dc->attr->graphics_mode == GM_ADVANCED)
4149 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
4150 /* try to avoid not necessary glyph transformations */
4151 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4153 lf.lfHeight *= fabs(dcmat.eM11);
4154 lf.lfWidth *= fabs(dcmat.eM11);
4155 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4158 else
4160 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4161 dcmat.eM11 = dcmat.eM22 = 1.0;
4162 dcmat.eM21 = dcmat.eM12 = 0;
4163 lf.lfOrientation = lf.lfEscapement;
4164 if (dc->vport2WorldValid)
4166 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4167 lf.lfOrientation = -lf.lfOrientation;
4168 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4169 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4172 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
4174 pthread_mutex_lock( &font_lock );
4176 font = select_font( &lf, dcmat, can_use_bitmap );
4178 if (font)
4180 if (!*aa_flags) *aa_flags = font->aa_flags;
4181 if (!*aa_flags)
4183 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
4184 *aa_flags = subpixel_orientation;
4185 else
4186 *aa_flags = font_smoothing;
4188 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
4190 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
4191 pthread_mutex_unlock( &font_lock );
4193 physdev->font = font;
4194 if (prev) release_gdi_font( prev );
4195 return font ? hfont : 0;
4199 const struct gdi_dc_funcs font_driver =
4201 NULL, /* pAbortDoc */
4202 NULL, /* pAbortPath */
4203 NULL, /* pAlphaBlend */
4204 NULL, /* pAngleArc */
4205 NULL, /* pArc */
4206 NULL, /* pArcTo */
4207 NULL, /* pBeginPath */
4208 NULL, /* pBlendImage */
4209 NULL, /* pChord */
4210 NULL, /* pCloseFigure */
4211 NULL, /* pCreateCompatibleDC */
4212 font_CreateDC, /* pCreateDC */
4213 font_DeleteDC, /* pDeleteDC */
4214 NULL, /* pDeleteObject */
4215 NULL, /* pEllipse */
4216 NULL, /* pEndDoc */
4217 NULL, /* pEndPage */
4218 NULL, /* pEndPath */
4219 font_EnumFonts, /* pEnumFonts */
4220 NULL, /* pExtEscape */
4221 NULL, /* pExtFloodFill */
4222 NULL, /* pExtTextOut */
4223 NULL, /* pFillPath */
4224 NULL, /* pFillRgn */
4225 font_FontIsLinked, /* pFontIsLinked */
4226 NULL, /* pFrameRgn */
4227 NULL, /* pGetBoundsRect */
4228 font_GetCharABCWidths, /* pGetCharABCWidths */
4229 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
4230 font_GetCharWidth, /* pGetCharWidth */
4231 font_GetCharWidthInfo, /* pGetCharWidthInfo */
4232 NULL, /* pGetDeviceCaps */
4233 NULL, /* pGetDeviceGammaRamp */
4234 font_GetFontData, /* pGetFontData */
4235 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
4236 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
4237 font_GetGlyphIndices, /* pGetGlyphIndices */
4238 font_GetGlyphOutline, /* pGetGlyphOutline */
4239 NULL, /* pGetICMProfile */
4240 NULL, /* pGetImage */
4241 font_GetKerningPairs, /* pGetKerningPairs */
4242 NULL, /* pGetNearestColor */
4243 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
4244 NULL, /* pGetPixel */
4245 NULL, /* pGetSystemPaletteEntries */
4246 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
4247 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
4248 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
4249 font_GetTextFace, /* pGetTextFace */
4250 font_GetTextMetrics, /* pGetTextMetrics */
4251 NULL, /* pGradientFill */
4252 NULL, /* pInvertRgn */
4253 NULL, /* pLineTo */
4254 NULL, /* pMoveTo */
4255 NULL, /* pPaintRgn */
4256 NULL, /* pPatBlt */
4257 NULL, /* pPie */
4258 NULL, /* pPolyBezier */
4259 NULL, /* pPolyBezierTo */
4260 NULL, /* pPolyDraw */
4261 NULL, /* pPolyPolygon */
4262 NULL, /* pPolyPolyline */
4263 NULL, /* pPolylineTo */
4264 NULL, /* pPutImage */
4265 NULL, /* pRealizeDefaultPalette */
4266 NULL, /* pRealizePalette */
4267 NULL, /* pRectangle */
4268 NULL, /* pResetDC */
4269 NULL, /* pRoundRect */
4270 NULL, /* pSelectBitmap */
4271 NULL, /* pSelectBrush */
4272 font_SelectFont, /* pSelectFont */
4273 NULL, /* pSelectPen */
4274 NULL, /* pSetBkColor */
4275 NULL, /* pSetBoundsRect */
4276 NULL, /* pSetDCBrushColor */
4277 NULL, /* pSetDCPenColor */
4278 NULL, /* pSetDIBitsToDevice */
4279 NULL, /* pSetDeviceClipping */
4280 NULL, /* pSetDeviceGammaRamp */
4281 NULL, /* pSetPixel */
4282 NULL, /* pSetTextColor */
4283 NULL, /* pStartDoc */
4284 NULL, /* pStartPage */
4285 NULL, /* pStretchBlt */
4286 NULL, /* pStretchDIBits */
4287 NULL, /* pStrokeAndFillPath */
4288 NULL, /* pStrokePath */
4289 NULL, /* pUnrealizePalette */
4290 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
4291 NULL, /* pD3DKMTSetVidPnSourceOwner */
4292 GDI_PRIORITY_FONT_DRV /* priority */
4295 static BOOL get_key_value( HKEY key, const char *name, DWORD *value )
4297 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[12 * sizeof(WCHAR)])];
4298 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4299 DWORD count;
4301 count = query_reg_ascii_value( key, name, info, sizeof(value_buffer) );
4302 if (count)
4304 if (info->Type == REG_DWORD) memcpy( value, info->Data, sizeof(*value) );
4305 else *value = wcstol( (const WCHAR *)info->Data, NULL, 10 );
4307 return !!count;
4310 static UINT init_font_options(void)
4312 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[20 * sizeof(WCHAR)])];
4313 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4314 HKEY key;
4315 DWORD i, val, gamma = 1400;
4316 UINT dpi = 0;
4318 if (query_reg_ascii_value( wine_fonts_key, "AntialiasFakeBoldOrItalic",
4319 info, sizeof(value_buffer) ) && info->Type == REG_SZ)
4321 static const WCHAR valsW[] = {'y','Y','t','T','1',0};
4322 antialias_fakes = (wcschr( valsW, *(const WCHAR *)info->Data ) != NULL);
4325 if ((key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
4327 /* FIXME: handle vertical orientations even though Windows doesn't */
4328 if (get_key_value( key, "FontSmoothingOrientation", &val ))
4330 switch (val)
4332 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4333 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
4334 break;
4335 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4336 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
4337 break;
4340 if (get_key_value( key, "FontSmoothing", &val ) && val /* enabled */)
4342 if (get_key_value( key, "FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4343 font_smoothing = subpixel_orientation;
4344 else
4345 font_smoothing = GGO_GRAY4_BITMAP;
4347 if (get_key_value( key, "FontSmoothingGamma", &val ) && val)
4349 gamma = min( max( val, 1000 ), 2200 );
4351 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4352 NtClose( key );
4355 /* Calibrating the difference between the registry value and the Wine gamma value.
4356 This looks roughly similar to Windows Native with the same registry value.
4357 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4358 gamma = 1000 * gamma / 1400;
4359 if (gamma != 1000)
4361 for (i = 0; i < 256; i++)
4363 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
4364 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
4368 if (!dpi && (key = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) )))
4370 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4371 NtClose( key );
4373 if (!dpi) dpi = 96;
4375 font_gamma_ramp.gamma = gamma;
4376 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp.gamma, dpi );
4377 return dpi;
4381 /* compute positions for text rendering, in device coords */
4382 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4384 TEXTMETRICW tm;
4385 PHYSDEV dev;
4387 size->cx = size->cy = 0;
4388 if (!count) return TRUE;
4390 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4391 dev->funcs->pGetTextMetrics( dev, &tm );
4393 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4394 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4396 if (dc->breakExtra || dc->breakRem)
4398 int i, space = 0, rem = dc->breakRem;
4400 for (i = 0; i < count; i++)
4402 if (str[i] == tm.tmBreakChar)
4404 space += dc->breakExtra;
4405 if (rem > 0)
4407 space++;
4408 rem--;
4411 dx[i] += space;
4414 size->cx = dx[count - 1];
4415 size->cy = tm.tmHeight;
4416 return TRUE;
4419 /* compute positions for text rendering, in device coords */
4420 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4422 TEXTMETRICW tm;
4423 PHYSDEV dev;
4425 size->cx = size->cy = 0;
4426 if (!count) return TRUE;
4428 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4429 dev->funcs->pGetTextMetrics( dev, &tm );
4431 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4432 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4434 if (dc->breakExtra || dc->breakRem)
4436 WORD space_index;
4437 int i, space = 0, rem = dc->breakRem;
4439 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4440 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4442 for (i = 0; i < count; i++)
4444 if (indices[i] == space_index)
4446 space += dc->breakExtra;
4447 if (rem > 0)
4449 space++;
4450 rem--;
4453 dx[i] += space;
4456 size->cx = dx[count - 1];
4457 size->cy = tm.tmHeight;
4458 return TRUE;
4461 /***********************************************************************
4462 * get_text_charset_info
4464 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4466 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4468 UINT ret = DEFAULT_CHARSET;
4469 PHYSDEV dev;
4471 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4472 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4474 if (ret == DEFAULT_CHARSET && fs)
4475 memset(fs, 0, sizeof(FONTSIGNATURE));
4476 return ret;
4479 /***********************************************************************
4480 * NtGdiGetTextCharsetInfo (win32u.@)
4482 UINT WINAPI NtGdiGetTextCharsetInfo( HDC hdc, FONTSIGNATURE *fs, DWORD flags )
4484 UINT ret = DEFAULT_CHARSET;
4485 DC *dc = get_dc_ptr(hdc);
4487 if (dc)
4489 ret = get_text_charset_info( dc, fs, flags );
4490 release_dc_ptr( dc );
4492 return ret;
4495 /***********************************************************************
4496 * NtGdiHfontCreate (win32u.@)
4498 HFONT WINAPI NtGdiHfontCreate( const ENUMLOGFONTEXDVW *penumex, ULONG size, ULONG type,
4499 ULONG flags, void *data )
4501 HFONT hFont;
4502 FONTOBJ *fontPtr;
4503 const LOGFONTW *plf;
4505 if (!penumex) return 0;
4507 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
4508 penumex->elfEnumLogfontEx.elfStyle[0] ||
4509 penumex->elfEnumLogfontEx.elfScript[0])
4511 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4512 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
4513 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
4514 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
4517 plf = &penumex->elfEnumLogfontEx.elfLogFont;
4518 if (!(fontPtr = malloc( sizeof(*fontPtr) ))) return 0;
4520 fontPtr->logfont = *plf;
4522 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, NTGDI_OBJ_FONT, &fontobj_funcs )))
4524 free( fontPtr );
4525 return 0;
4528 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4529 plf->lfHeight, plf->lfWidth,
4530 plf->lfEscapement, plf->lfOrientation,
4531 plf->lfPitchAndFamily,
4532 plf->lfOutPrecision, plf->lfClipPrecision,
4533 plf->lfQuality, plf->lfCharSet,
4534 debugstr_w(plf->lfFaceName),
4535 plf->lfWeight > 400 ? "Bold" : "",
4536 plf->lfItalic ? "Italic" : "",
4537 plf->lfUnderline ? "Underline" : "", hFont);
4539 return hFont;
4542 #define ASSOC_CHARSET_OEM 1
4543 #define ASSOC_CHARSET_ANSI 2
4544 #define ASSOC_CHARSET_SYMBOL 4
4546 static DWORD get_associated_charset_info(void)
4548 static DWORD associated_charset = -1;
4550 if (associated_charset == -1)
4552 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[32 * sizeof(WCHAR)])];
4553 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4554 HKEY hkey;
4556 static const WCHAR yesW[] = {'y','e','s',0};
4558 associated_charset = 0;
4560 if (!(hkey = reg_open_key( NULL, associated_charset_keyW, sizeof(associated_charset_keyW) )))
4561 return 0;
4563 if (query_reg_ascii_value( hkey, "ANSI(00)", info, sizeof(value_buffer) ) &&
4564 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4565 associated_charset |= ASSOC_CHARSET_ANSI;
4567 if (query_reg_ascii_value( hkey, "OEM(FF)", info, sizeof(value_buffer) ) &&
4568 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4569 associated_charset |= ASSOC_CHARSET_OEM;
4571 if (query_reg_ascii_value( hkey, "SYMBOL(02)", info, sizeof(value_buffer) ) &&
4572 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4573 associated_charset |= ASSOC_CHARSET_SYMBOL;
4575 NtClose( hkey );
4577 TRACE("associated_charset = %d\n", associated_charset);
4580 return associated_charset;
4583 static void update_font_code_page( DC *dc, HANDLE font )
4585 CHARSETINFO csi;
4586 int charset = get_text_charset_info( dc, NULL, 0 );
4588 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
4590 LOGFONTW lf;
4592 NtGdiExtGetObjectW( font, sizeof(lf), &lf );
4593 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
4594 charset = DEFAULT_CHARSET;
4597 /* Hmm, nicely designed api this one! */
4598 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
4599 dc->attr->font_code_page = csi.ciACP;
4600 else {
4601 switch(charset) {
4602 case OEM_CHARSET:
4603 dc->attr->font_code_page = oem_cp.CodePage;
4604 break;
4605 case DEFAULT_CHARSET:
4606 dc->attr->font_code_page = ansi_cp.CodePage;
4607 break;
4609 case VISCII_CHARSET:
4610 case TCVN_CHARSET:
4611 case KOI8_CHARSET:
4612 case ISO3_CHARSET:
4613 case ISO4_CHARSET:
4614 case ISO10_CHARSET:
4615 case CELTIC_CHARSET:
4616 /* FIXME: These have no place here, but because x11drv
4617 enumerates fonts with these (made up) charsets some apps
4618 might use them and then the FIXME below would become
4619 annoying. Now we could pick the intended codepage for
4620 each of these, but since it's broken anyway we'll just
4621 use CP_ACP and hope it'll go away...
4623 dc->attr->font_code_page = CP_ACP;
4624 break;
4626 default:
4627 FIXME("Can't find codepage for charset %d\n", charset);
4628 dc->attr->font_code_page = CP_ACP;
4629 break;
4633 TRACE( "charset %d => cp %d\n", charset, dc->attr->font_code_page );
4636 /***********************************************************************
4637 * NtGdiSelectFont (win32u.@)
4639 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
4641 HGDIOBJ ret = 0;
4642 DC *dc = get_dc_ptr( hdc );
4643 PHYSDEV physdev;
4644 UINT aa_flags = 0;
4646 if (!dc) return 0;
4648 if (!GDI_inc_ref_count( handle ))
4650 release_dc_ptr( dc );
4651 return 0;
4654 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
4655 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
4657 ret = dc->hFont;
4658 dc->hFont = handle;
4659 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
4660 update_font_code_page( dc, handle );
4661 if (dc->font_gamma_ramp == NULL)
4662 dc->font_gamma_ramp = &font_gamma_ramp;
4663 GDI_dec_ref_count( ret );
4665 else GDI_dec_ref_count( handle );
4667 release_dc_ptr( dc );
4668 return ret;
4672 /***********************************************************************
4673 * FONT_GetObjectW
4675 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
4677 FONTOBJ *font = GDI_GetObjPtr( handle, NTGDI_OBJ_FONT );
4679 if (!font) return 0;
4680 if (buffer)
4682 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
4683 memcpy( buffer, &font->logfont, count );
4685 else count = sizeof(LOGFONTW);
4686 GDI_ReleaseObj( handle );
4687 return count;
4691 /***********************************************************************
4692 * FONT_DeleteObject
4694 static BOOL FONT_DeleteObject( HGDIOBJ handle )
4696 FONTOBJ *obj;
4698 if (!(obj = free_gdi_handle( handle ))) return FALSE;
4699 free( obj );
4700 return TRUE;
4704 struct font_enum
4706 HDC hdc;
4707 struct font_enum_entry *buf;
4708 ULONG size;
4709 ULONG count;
4710 ULONG charset;
4713 static INT WINAPI font_enum_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
4714 DWORD type, LPARAM lp )
4716 struct font_enum *fe = (struct font_enum *)lp;
4718 if (fe->charset != DEFAULT_CHARSET && lf->lfCharSet != fe->charset) return 1;
4719 if ((type & RASTER_FONTTYPE) && !(NtGdiGetDeviceCaps( fe->hdc, TEXTCAPS ) & TC_RA_ABLE))
4720 return 1;
4722 if (fe->buf && fe->count < fe->size)
4724 fe->buf[fe->count].type = type;
4725 fe->buf[fe->count].lf = *(const ENUMLOGFONTEXW *)lf;
4726 fe->buf[fe->count].tm = *(const NEWTEXTMETRICEXW *)tm;
4728 fe->count++;
4729 return 1;
4732 /***********************************************************************
4733 * NtGdiEnumFonts (win32u.@)
4735 BOOL WINAPI NtGdiEnumFonts( HDC hdc, ULONG type, ULONG win32_compat, ULONG face_name_len,
4736 const WCHAR *face_name, ULONG charset, ULONG *count, void *buf )
4738 struct font_enum fe;
4739 PHYSDEV physdev;
4740 LOGFONTW lf;
4741 BOOL ret;
4742 DC *dc;
4744 if (!(dc = get_dc_ptr( hdc ))) return 0;
4746 memset( &lf, 0, sizeof(lf) );
4747 lf.lfCharSet = charset;
4748 if (face_name_len) memcpy( lf.lfFaceName, face_name, face_name_len * sizeof(WCHAR) );
4750 fe.hdc = hdc;
4751 fe.buf = buf;
4752 fe.size = *count / sizeof(*fe.buf);
4753 fe.count = 0;
4754 fe.charset = charset;
4756 physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
4757 ret = physdev->funcs->pEnumFonts( physdev, &lf, font_enum_proc, (LPARAM)&fe );
4758 if (ret && buf) ret = fe.count <= fe.size;
4759 *count = fe.count * sizeof(*fe.buf);
4761 release_dc_ptr( dc );
4762 return ret;
4766 /***********************************************************************
4767 * NtGdiSetTextJustification (win32u.@)
4769 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
4771 DC *dc;
4773 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
4775 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
4776 dc->attr->wnd_ext.cx );
4777 if (!extra) breaks = 0;
4778 if (breaks)
4780 dc->breakExtra = extra / breaks;
4781 dc->breakRem = extra - (breaks * dc->breakExtra);
4783 else
4785 dc->breakExtra = 0;
4786 dc->breakRem = 0;
4789 release_dc_ptr( dc );
4790 return TRUE;
4794 /***********************************************************************
4795 * NtGdiGetTextFaceW (win32u.@)
4797 INT WINAPI NtGdiGetTextFaceW( HDC hdc, INT count, WCHAR *name, BOOL alias_name )
4799 PHYSDEV dev;
4800 INT ret;
4802 DC * dc = get_dc_ptr( hdc );
4803 if (!dc) return 0;
4805 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
4806 ret = dev->funcs->pGetTextFace( dev, count, name );
4807 release_dc_ptr( dc );
4808 return ret;
4812 /***********************************************************************
4813 * NtGdiGetTextExtentExW (win32u.@)
4815 * Return the size of the string as it would be if it was output properly by
4816 * e.g. TextOut.
4818 BOOL WINAPI NtGdiGetTextExtentExW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
4819 INT *nfit, INT *dxs, SIZE *size, UINT flags )
4821 DC *dc;
4822 int i;
4823 BOOL ret;
4824 INT buffer[256], *pos = dxs;
4826 if (count < 0) return FALSE;
4828 dc = get_dc_ptr(hdc);
4829 if (!dc) return FALSE;
4831 if (!dxs)
4833 pos = buffer;
4834 if (count > 256 && !(pos = malloc( count * sizeof(*pos) )))
4836 release_dc_ptr( dc );
4837 return FALSE;
4842 if (flags)
4843 ret = get_char_positions_indices( dc, str, count, pos, size );
4844 else
4845 ret = get_char_positions( dc, str, count, pos, size );
4846 if (ret)
4848 if (dxs || nfit)
4850 for (i = 0; i < count; i++)
4852 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
4853 (i + 1) * dc->attr->char_extra;
4854 if (nfit && dx > (unsigned int)max_ext) break;
4855 if (dxs) dxs[i] = dx;
4857 if (nfit) *nfit = i;
4860 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
4861 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
4864 if (pos != buffer && pos != dxs) free( pos );
4865 release_dc_ptr( dc );
4867 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
4868 return ret;
4871 /***********************************************************************
4872 * NtGdiGetTextMetricsW (win32u.@)
4874 BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags )
4876 PHYSDEV physdev;
4877 BOOL ret = FALSE;
4878 DC * dc = get_dc_ptr( hdc );
4879 if (!dc) return FALSE;
4881 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4882 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
4884 if (ret)
4886 /* device layer returns values in device units
4887 * therefore we have to convert them to logical */
4889 metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
4890 metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
4891 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
4892 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
4893 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
4894 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
4895 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
4896 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
4897 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
4898 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
4899 ret = TRUE;
4901 TRACE("text metrics:\n"
4902 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
4903 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
4904 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
4905 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
4906 " PitchAndFamily = %02x\n"
4907 " --------------------\n"
4908 " InternalLeading = %i\n"
4909 " Ascent = %i\n"
4910 " Descent = %i\n"
4911 " Height = %i\n",
4912 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
4913 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
4914 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
4915 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
4916 metrics->tmPitchAndFamily,
4917 metrics->tmInternalLeading,
4918 metrics->tmAscent,
4919 metrics->tmDescent,
4920 metrics->tmHeight );
4922 release_dc_ptr( dc );
4923 return ret;
4927 /***********************************************************************
4928 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
4930 UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData,
4931 OUTLINETEXTMETRICW *lpOTM, ULONG opts )
4933 DC *dc = get_dc_ptr( hdc );
4934 OUTLINETEXTMETRICW *output = lpOTM;
4935 PHYSDEV dev;
4936 UINT ret;
4938 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
4939 if(!dc) return 0;
4941 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
4942 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
4944 if (lpOTM && ret > cbData)
4946 output = malloc( ret );
4947 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
4950 if (lpOTM && ret)
4952 output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
4953 output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
4954 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
4955 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
4956 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
4957 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
4958 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
4959 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
4960 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
4961 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
4962 output->otmAscent = height_to_LP( dc, output->otmAscent);
4963 output->otmDescent = height_to_LP( dc, output->otmDescent);
4964 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
4965 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
4966 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
4967 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
4968 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
4969 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
4970 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
4971 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
4972 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
4973 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
4974 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
4975 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
4976 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
4977 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
4978 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
4979 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
4980 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
4981 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
4982 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
4983 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
4984 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
4985 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
4987 if(output != lpOTM)
4989 memcpy(lpOTM, output, cbData);
4990 free( output );
4991 ret = cbData;
4994 release_dc_ptr(dc);
4995 return ret;
4998 /***********************************************************************
4999 * NtGdiGetCharWidthW (win32u.@)
5001 BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5002 ULONG flags, void *buf )
5004 UINT i, count = last;
5005 BOOL ret;
5006 PHYSDEV dev;
5007 DC *dc;
5009 if (flags & NTGDI_GETCHARWIDTH_INDICES)
5011 ABC *abc;
5012 unsigned int i;
5014 if (!(abc = malloc( count * sizeof(ABC) )))
5015 return FALSE;
5017 if (!NtGdiGetCharABCWidthsW( hdc, first, last, chars,
5018 NTGDI_GETCHARABCWIDTHS_INT | NTGDI_GETCHARABCWIDTHS_INDICES,
5019 abc ))
5021 free( abc );
5022 return FALSE;
5025 for (i = 0; i < count; i++)
5026 ((INT *)buf)[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5028 free( abc );
5029 return TRUE;
5032 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5034 if (!chars) count = last - first + 1;
5035 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5036 ret = dev->funcs->pGetCharWidth( dev, first, count, chars, buf );
5038 if (ret)
5040 if (flags & NTGDI_GETCHARWIDTH_INT)
5042 INT *buffer = buf;
5043 /* convert device units to logical */
5044 for (i = 0; i < count; i++)
5045 buffer[i] = width_to_LP( dc, buffer[i] );
5047 else
5049 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
5050 for (i = 0; i < count; i++)
5051 ((float *)buf)[i] = ((int *)buf)[i] * scale;
5054 release_dc_ptr( dc );
5055 return ret;
5059 /* helper for nulldrv_ExtTextOut */
5060 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5061 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5063 UINT indices[3] = {0, 0, 0x20};
5064 unsigned int i;
5065 DWORD ret, size;
5066 int stride;
5068 indices[0] = index;
5069 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5071 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5073 index = indices[i];
5074 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, 0, NULL, &identity, FALSE );
5075 if (ret != GDI_ERROR) break;
5078 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5079 if (!image) return ERROR_SUCCESS;
5081 image->ptr = NULL;
5082 image->free = NULL;
5083 if (!ret) /* empty glyph */
5085 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5086 return ERROR_SUCCESS;
5089 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5090 size = metrics->gmBlackBoxY * stride;
5092 if (!(image->ptr = malloc( size ))) return ERROR_OUTOFMEMORY;
5093 image->is_copy = TRUE;
5094 image->free = free_heap_bits;
5096 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, size, image->ptr,
5097 &identity, FALSE );
5098 if (ret == GDI_ERROR)
5100 free( image->ptr );
5101 return ERROR_NOT_FOUND;
5103 return ERROR_SUCCESS;
5106 /* helper for nulldrv_ExtTextOut */
5107 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5108 LPCWSTR str, UINT count, const INT *dx )
5110 UINT i;
5111 RECT rect, bounds;
5113 reset_bounds( &bounds );
5114 for (i = 0; i < count; i++)
5116 GLYPHMETRICS metrics;
5118 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5120 rect.left = x + metrics.gmptGlyphOrigin.x;
5121 rect.top = y - metrics.gmptGlyphOrigin.y;
5122 rect.right = rect.left + metrics.gmBlackBoxX;
5123 rect.bottom = rect.top + metrics.gmBlackBoxY;
5124 add_bounds_rect( &bounds, &rect );
5126 if (dx)
5128 if (flags & ETO_PDY)
5130 x += dx[ i * 2 ];
5131 y += dx[ i * 2 + 1];
5133 else x += dx[ i ];
5135 else
5137 x += metrics.gmCellIncX;
5138 y += metrics.gmCellIncY;
5141 return bounds;
5144 /* helper for nulldrv_ExtTextOut */
5145 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5146 const struct gdi_image_bits *image, const RECT *clip )
5148 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5149 UINT i, count, max_count;
5150 LONG x, y;
5151 BYTE *ptr = image->ptr;
5152 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5153 POINT *pts;
5154 RECT rect, clipped_rect;
5156 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5157 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5158 rect.right = rect.left + metrics->gmBlackBoxX;
5159 rect.bottom = rect.top + metrics->gmBlackBoxY;
5160 if (!clip) clipped_rect = rect;
5161 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5163 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5164 pts = malloc( max_count * sizeof(*pts) );
5165 if (!pts) return;
5167 count = 0;
5168 ptr += (clipped_rect.top - rect.top) * stride;
5169 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5171 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5173 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5174 pts[count].x = rect.left + x;
5175 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5176 pts[count + 1].x = rect.left + x;
5177 if (pts[count + 1].x > pts[count].x)
5179 pts[count].y = pts[count + 1].y = y;
5180 count += 2;
5184 assert( count <= max_count );
5185 dp_to_lp( dc, pts, count );
5186 for (i = 0; i < count; i += 2)
5188 const ULONG pts_count = 2;
5189 NtGdiPolyPolyDraw( dc->hSelf, pts + i, &pts_count, 1, NtGdiPolyPolyline );
5191 free( pts );
5194 /***********************************************************************
5195 * nulldrv_ExtTextOut
5197 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5198 LPCWSTR str, UINT count, const INT *dx )
5200 DC *dc = get_nulldrv_dc( dev );
5201 UINT i;
5202 DWORD err;
5203 HGDIOBJ orig;
5204 HPEN pen;
5206 if (flags & ETO_OPAQUE)
5208 RECT rc = *rect;
5209 COLORREF brush_color = NtGdiGetNearestColor( dev->hdc, dc->attr->background_color );
5210 HBRUSH brush = NtGdiCreateSolidBrush( brush_color, NULL);
5212 if (brush)
5214 orig = NtGdiSelectBrush( dev->hdc, brush );
5215 dp_to_lp( dc, (POINT *)&rc, 2 );
5216 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5217 NtGdiSelectBrush( dev->hdc, orig );
5218 NtGdiDeleteObjectApp( brush );
5222 if (!count) return TRUE;
5224 if (dc->aa_flags != GGO_BITMAP)
5226 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5227 BITMAPINFO *info = (BITMAPINFO *)buffer;
5228 struct gdi_image_bits bits;
5229 struct bitblt_coords src, dst;
5230 PHYSDEV dst_dev;
5231 /* FIXME Subpixel modes */
5232 UINT aa_flags = GGO_GRAY4_BITMAP;
5234 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5235 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5236 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5237 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5239 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5240 src.x = src.visrect.left;
5241 src.y = src.visrect.top;
5242 src.width = src.visrect.right - src.visrect.left;
5243 src.height = src.visrect.bottom - src.visrect.top;
5244 dst = src;
5245 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5246 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5248 /* we can avoid the GetImage, just query the needed format */
5249 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5250 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5251 info->bmiHeader.biWidth = src.width;
5252 info->bmiHeader.biHeight = -src.height;
5253 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5254 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5255 if (!err || err == ERROR_BAD_FORMAT)
5257 /* make the source rectangle relative to the source bits */
5258 src.x = src.y = 0;
5259 src.visrect.left = src.visrect.top = 0;
5260 src.visrect.right = src.width;
5261 src.visrect.bottom = src.height;
5263 bits.ptr = malloc( info->bmiHeader.biSizeImage );
5264 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5265 bits.is_copy = TRUE;
5266 bits.free = free_heap_bits;
5267 err = ERROR_SUCCESS;
5270 else
5272 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5273 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5274 if (!err && !bits.is_copy)
5276 void *ptr = malloc( info->bmiHeader.biSizeImage );
5277 if (!ptr)
5279 if (bits.free) bits.free( &bits );
5280 return ERROR_OUTOFMEMORY;
5282 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5283 if (bits.free) bits.free( &bits );
5284 bits.ptr = ptr;
5285 bits.is_copy = TRUE;
5286 bits.free = free_heap_bits;
5289 if (!err)
5291 /* make x,y relative to the image bits */
5292 x += src.visrect.left - dst.visrect.left;
5293 y += src.visrect.top - dst.visrect.top;
5294 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5295 aa_flags, str, count, dx );
5296 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5297 if (bits.free) bits.free( &bits );
5298 return !err;
5302 pen = NtGdiCreatePen( PS_SOLID, 1, dc->attr->text_color, NULL );
5303 orig = NtGdiSelectPen( dev->hdc, pen );
5305 for (i = 0; i < count; i++)
5307 GLYPHMETRICS metrics;
5308 struct gdi_image_bits image;
5310 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5311 if (err) continue;
5313 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5314 if (image.free) image.free( &image );
5316 if (dx)
5318 if (flags & ETO_PDY)
5320 x += dx[ i * 2 ];
5321 y += dx[ i * 2 + 1];
5323 else x += dx[ i ];
5325 else
5327 x += metrics.gmCellIncX;
5328 y += metrics.gmCellIncY;
5332 NtGdiSelectPen( dev->hdc, orig );
5333 NtGdiDeleteObjectApp( pen );
5334 return TRUE;
5337 /***********************************************************************
5338 * get_line_width
5340 * Scale the underline / strikeout line width.
5342 static inline int get_line_width( DC *dc, int metric_size )
5344 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5345 if (width == 0) width = 1;
5346 if (metric_size < 0) width = -width;
5347 return width;
5350 /***********************************************************************
5351 * NtGdiExtTextOutW (win32u.@)
5353 * Draws text using the currently selected font, background color, and text color.
5356 * PARAMS
5357 * x,y [I] coordinates of string
5358 * flags [I]
5359 * ETO_GRAYED - undocumented on MSDN
5360 * ETO_OPAQUE - use background color for fill the rectangle
5361 * ETO_CLIPPED - clipping text to the rectangle
5362 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5363 * than encoded characters. Implies ETO_IGNORELANGUAGE
5364 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5365 * Affects BiDi ordering
5366 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5367 * ETO_PDY - unimplemented
5368 * ETO_NUMERICSLATIN - unimplemented always assumed -
5369 * do not translate numbers into locale representations
5370 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5371 * lprect [I] dimensions for clipping or/and opaquing
5372 * str [I] text string
5373 * count [I] number of symbols in string
5374 * lpDx [I] optional parameter with distance between drawing characters
5376 * RETURNS
5377 * Success: TRUE
5378 * Failure: FALSE
5380 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5381 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5383 BOOL ret = FALSE;
5384 UINT align;
5385 DWORD layout;
5386 POINT pt;
5387 TEXTMETRICW tm;
5388 LOGFONTW lf;
5389 double cosEsc, sinEsc;
5390 INT char_extra;
5391 SIZE sz;
5392 RECT rc;
5393 POINT *deltas = NULL, width = {0, 0};
5394 DC * dc = get_dc_ptr( hdc );
5395 PHYSDEV physdev;
5396 INT breakRem;
5397 static int quietfixme = 0;
5399 if (!dc) return FALSE;
5400 if (count > INT_MAX) return FALSE;
5402 align = dc->attr->text_align;
5403 breakRem = dc->breakRem;
5404 layout = dc->attr->layout;
5406 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5408 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5409 quietfixme = 1;
5412 update_dc( dc );
5413 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5415 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5416 if (layout & LAYOUT_RTL)
5418 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5419 align ^= TA_RTLREADING;
5422 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5423 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5424 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5425 dc->attr->map_mode);
5427 if(align & TA_UPDATECP)
5429 pt = dc->attr->cur_pos;
5430 x = pt.x;
5431 y = pt.y;
5434 NtGdiGetTextMetricsW( hdc, &tm, 0 );
5435 NtGdiExtGetObjectW( dc->hFont, sizeof(lf), &lf );
5437 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5438 lf.lfEscapement = 0;
5440 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5441 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5443 lf.lfEscapement = -lf.lfEscapement;
5446 if(lf.lfEscapement != 0)
5448 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5449 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5451 else
5453 cosEsc = 1;
5454 sinEsc = 0;
5457 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5459 rc = *lprect;
5460 lp_to_dp(dc, (POINT*)&rc, 2);
5461 order_rect( &rc );
5462 if (flags & ETO_OPAQUE)
5463 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5465 else flags &= ~ETO_CLIPPED;
5467 if(count == 0)
5469 ret = TRUE;
5470 goto done;
5473 pt.x = x;
5474 pt.y = y;
5475 lp_to_dp(dc, &pt, 1);
5476 x = pt.x;
5477 y = pt.y;
5479 char_extra = dc->attr->char_extra;
5480 if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5481 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5483 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
5485 UINT i;
5486 POINT total = {0, 0}, desired[2];
5488 deltas = malloc( count * sizeof(*deltas) );
5489 if (lpDx)
5491 if (flags & ETO_PDY)
5493 for (i = 0; i < count; i++)
5495 deltas[i].x = lpDx[i * 2] + char_extra;
5496 deltas[i].y = -lpDx[i * 2 + 1];
5499 else
5501 for (i = 0; i < count; i++)
5503 deltas[i].x = lpDx[i] + char_extra;
5504 deltas[i].y = 0;
5508 else
5510 INT *dx = malloc( count * sizeof(*dx) );
5512 NtGdiGetTextExtentExW( hdc, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX) );
5514 deltas[0].x = dx[0];
5515 deltas[0].y = 0;
5516 for (i = 1; i < count; i++)
5518 deltas[i].x = dx[i] - dx[i - 1];
5519 deltas[i].y = 0;
5521 free( dx );
5524 for(i = 0; i < count; i++)
5526 total.x += deltas[i].x;
5527 total.y += deltas[i].y;
5529 desired[0].x = desired[0].y = 0;
5531 desired[1].x = cosEsc * total.x + sinEsc * total.y;
5532 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
5534 lp_to_dp(dc, desired, 2);
5535 desired[1].x -= desired[0].x;
5536 desired[1].y -= desired[0].y;
5538 if (dc->attr->graphics_mode == GM_COMPATIBLE)
5540 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
5541 desired[1].x = -desired[1].x;
5542 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
5543 desired[1].y = -desired[1].y;
5546 deltas[i].x = desired[1].x - width.x;
5547 deltas[i].y = desired[1].y - width.y;
5549 width = desired[1];
5551 flags |= ETO_PDY;
5553 else
5555 POINT desired[2];
5557 NtGdiGetTextExtentExW( hdc, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX) );
5558 desired[0].x = desired[0].y = 0;
5559 desired[1].x = sz.cx;
5560 desired[1].y = 0;
5561 lp_to_dp(dc, desired, 2);
5562 desired[1].x -= desired[0].x;
5563 desired[1].y -= desired[0].y;
5565 if (dc->attr->graphics_mode == GM_COMPATIBLE)
5567 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
5568 desired[1].x = -desired[1].x;
5569 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
5570 desired[1].y = -desired[1].y;
5572 width = desired[1];
5575 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
5576 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
5577 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
5579 case TA_LEFT:
5580 if (align & TA_UPDATECP)
5582 pt.x = x + width.x;
5583 pt.y = y + width.y;
5584 dp_to_lp(dc, &pt, 1);
5585 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
5587 break;
5589 case TA_CENTER:
5590 x -= width.x / 2;
5591 y -= width.y / 2;
5592 break;
5594 case TA_RIGHT:
5595 x -= width.x;
5596 y -= width.y;
5597 if (align & TA_UPDATECP)
5599 pt.x = x;
5600 pt.y = y;
5601 dp_to_lp(dc, &pt, 1);
5602 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
5604 break;
5607 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
5609 case TA_TOP:
5610 y += tm.tmAscent * cosEsc;
5611 x += tm.tmAscent * sinEsc;
5612 break;
5614 case TA_BOTTOM:
5615 y -= tm.tmDescent * cosEsc;
5616 x -= tm.tmDescent * sinEsc;
5617 break;
5619 case TA_BASELINE:
5620 break;
5623 if (dc->attr->background_mode != TRANSPARENT)
5625 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
5627 if(!(flags & ETO_OPAQUE) || !lprect ||
5628 x < rc.left || x + width.x >= rc.right ||
5629 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
5631 RECT text_box;
5632 text_box.left = x;
5633 text_box.right = x + width.x;
5634 text_box.top = y - tm.tmAscent;
5635 text_box.bottom = y + tm.tmDescent;
5637 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
5638 if (!is_rect_empty( &text_box ))
5639 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
5644 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
5645 str, count, (INT*)deltas );
5647 done:
5648 free( deltas );
5650 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
5652 int underlinePos, strikeoutPos;
5653 int underlineWidth, strikeoutWidth;
5654 UINT size = NtGdiGetOutlineTextMetricsInternalW( hdc, 0, NULL, 0 );
5655 OUTLINETEXTMETRICW* otm = NULL;
5656 POINT pts[5];
5657 HPEN hpen = NtGdiSelectPen( hdc, get_stock_object(NULL_PEN) );
5658 HBRUSH hbrush = NtGdiCreateSolidBrush( dc->attr->text_color, NULL );
5660 hbrush = NtGdiSelectBrush(hdc, hbrush);
5662 if(!size)
5664 underlinePos = 0;
5665 underlineWidth = tm.tmAscent / 20 + 1;
5666 strikeoutPos = tm.tmAscent / 2;
5667 strikeoutWidth = underlineWidth;
5669 else
5671 otm = malloc( size );
5672 NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
5673 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
5674 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
5675 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
5676 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
5677 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
5678 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
5679 free( otm );
5683 if (lf.lfUnderline)
5685 const ULONG cnt = 5;
5686 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
5687 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
5688 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
5689 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
5690 pts[2].x = pts[1].x + underlineWidth * sinEsc;
5691 pts[2].y = pts[1].y + underlineWidth * cosEsc;
5692 pts[3].x = pts[0].x + underlineWidth * sinEsc;
5693 pts[3].y = pts[0].y + underlineWidth * cosEsc;
5694 pts[4].x = pts[0].x;
5695 pts[4].y = pts[0].y;
5696 dp_to_lp(dc, pts, 5);
5697 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
5700 if (lf.lfStrikeOut)
5702 const ULONG cnt = 5;
5703 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
5704 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
5705 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
5706 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
5707 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
5708 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
5709 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
5710 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
5711 pts[4].x = pts[0].x;
5712 pts[4].y = pts[0].y;
5713 dp_to_lp(dc, pts, 5);
5714 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
5717 NtGdiSelectPen(hdc, hpen);
5718 hbrush = NtGdiSelectBrush(hdc, hbrush);
5719 NtGdiDeleteObjectApp( hbrush );
5722 release_dc_ptr( dc );
5724 return ret;
5728 /******************************************************************************
5729 * NtGdiGetCharABCWidthsW (win32u.@)
5731 * Retrieves widths of characters in range.
5733 * PARAMS
5734 * hdc [I] Handle of device context
5735 * firstChar [I] First character in range to query
5736 * lastChar [I] Last character in range to query
5737 * abc [O] Address of character-width structure
5739 * NOTES
5740 * Only works with TrueType fonts
5742 BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5743 ULONG flags, void *buffer )
5745 DC *dc = get_dc_ptr(hdc);
5746 PHYSDEV dev;
5747 unsigned int i, count = last;
5748 BOOL ret;
5749 TEXTMETRICW tm;
5751 if (!dc) return FALSE;
5753 if (!buffer)
5755 release_dc_ptr( dc );
5756 return FALSE;
5759 if (flags & NTGDI_GETCHARABCWIDTHS_INDICES)
5761 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
5762 ret = dev->funcs->pGetCharABCWidthsI( dev, first, count, chars, buffer );
5764 else
5766 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
5768 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
5769 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5770 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
5772 release_dc_ptr( dc );
5773 return FALSE;
5777 if (!chars) count = last - first + 1;
5778 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
5779 ret = dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
5782 if (ret)
5784 ABC *abc = buffer;
5785 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
5787 /* convert device units to logical */
5788 for (i = 0; i < count; i++)
5790 abc[i].abcA = width_to_LP( dc, abc[i].abcA );
5791 abc[i].abcB = width_to_LP( dc, abc[i].abcB );
5792 abc[i].abcC = width_to_LP( dc, abc[i].abcC );
5795 else
5797 /* convert device units to logical */
5798 FLOAT scale = fabs( dc->xformVport2World.eM11 );
5799 ABCFLOAT *abcf = buffer;
5801 for (i = 0; i < count; i++)
5803 abcf[i].abcfA = abc[i].abcA * scale;
5804 abcf[i].abcfB = abc[i].abcB * scale;
5805 abcf[i].abcfC = abc[i].abcC * scale;
5810 release_dc_ptr( dc );
5811 return ret;
5815 /***********************************************************************
5816 * NtGdiGetGlyphOutline (win32u.@)
5818 DWORD WINAPI NtGdiGetGlyphOutline( HDC hdc, UINT ch, UINT format, GLYPHMETRICS *metrics,
5819 DWORD size, void *buffer, const MAT2 *mat2,
5820 BOOL ignore_rotation )
5822 DC *dc;
5823 DWORD ret;
5824 PHYSDEV dev;
5826 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc, ch, format, metrics, size, buffer, mat2 );
5828 if (!mat2) return GDI_ERROR;
5830 dc = get_dc_ptr(hdc);
5831 if(!dc) return GDI_ERROR;
5833 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
5834 ret = dev->funcs->pGetGlyphOutline( dev, ch & 0xffff, format, metrics, size, buffer, mat2 );
5835 release_dc_ptr( dc );
5836 return ret;
5840 /**********************************************************************
5841 * __wine_get_file_outline_text_metric (win32u.@)
5843 BOOL CDECL __wine_get_file_outline_text_metric( const WCHAR *path, OUTLINETEXTMETRICW *otm )
5845 struct gdi_font *font = NULL;
5847 if (!path || !font_funcs) return FALSE;
5849 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
5850 font->lf.lfHeight = 100;
5851 if (!font_funcs->load_font( font )) goto done;
5852 if (!font_funcs->set_outline_text_metrics( font )) goto done;
5853 *otm = font->otm;
5854 free_gdi_font( font );
5855 return TRUE;
5857 done:
5858 if (font) free_gdi_font( font );
5859 SetLastError( ERROR_INVALID_PARAMETER );
5860 return FALSE;
5863 /*************************************************************************
5864 * NtGdiGetKerningPairs (win32u.@)
5866 DWORD WINAPI NtGdiGetKerningPairs( HDC hdc, DWORD count, KERNINGPAIR *kern_pair )
5868 DC *dc;
5869 DWORD ret;
5870 PHYSDEV dev;
5872 TRACE( "(%p,%d,%p)\n", hdc, count, kern_pair );
5874 if (!count && kern_pair)
5876 SetLastError( ERROR_INVALID_PARAMETER );
5877 return 0;
5880 dc = get_dc_ptr( hdc );
5881 if (!dc) return 0;
5883 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
5884 ret = dev->funcs->pGetKerningPairs( dev, count, kern_pair );
5885 release_dc_ptr( dc );
5886 return ret;
5889 /*************************************************************************
5890 * NtGdiGetFontData (win32u.@)
5892 * Retrieve data for TrueType font.
5894 * RETURNS
5896 * success: Number of bytes returned
5897 * failure: GDI_ERROR
5899 * NOTES
5901 * Calls SetLastError()
5904 DWORD WINAPI NtGdiGetFontData( HDC hdc, DWORD table, DWORD offset, void *buffer, DWORD length )
5906 DC *dc = get_dc_ptr(hdc);
5907 PHYSDEV dev;
5908 DWORD ret;
5910 if(!dc) return GDI_ERROR;
5912 dev = GET_DC_PHYSDEV( dc, pGetFontData );
5913 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
5914 release_dc_ptr( dc );
5915 return ret;
5918 /*************************************************************************
5919 * NtGdiGetGlyphIndicesW (win32u.@)
5921 DWORD WINAPI NtGdiGetGlyphIndicesW( HDC hdc, const WCHAR *str, INT count,
5922 WORD *indices, DWORD flags )
5924 DC *dc = get_dc_ptr(hdc);
5925 PHYSDEV dev;
5926 DWORD ret;
5928 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc, debugstr_wn(str, count), count, indices, flags );
5930 if(!dc) return GDI_ERROR;
5932 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
5933 ret = dev->funcs->pGetGlyphIndices( dev, str, count, indices, flags );
5934 release_dc_ptr( dc );
5935 return ret;
5938 /***********************************************************************
5940 * Font Resource API *
5942 ***********************************************************************/
5945 static int add_system_font_resource( const WCHAR *file, DWORD flags )
5947 WCHAR path[MAX_PATH];
5948 int ret;
5950 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
5951 get_fonts_win_dir_path( file, path );
5952 pthread_mutex_lock( &font_lock );
5953 ret = font_funcs->add_font( path, flags );
5954 pthread_mutex_unlock( &font_lock );
5955 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
5956 if (!ret)
5958 get_fonts_data_dir_path( file, path );
5959 pthread_mutex_lock( &font_lock );
5960 ret = font_funcs->add_font( path, flags );
5961 pthread_mutex_unlock( &font_lock );
5963 return ret;
5966 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
5968 WCHAR path[MAX_PATH];
5969 int ret;
5971 get_fonts_win_dir_path( file, path );
5972 if (!(ret = remove_font( path, flags )))
5974 get_fonts_data_dir_path( file, path );
5975 ret = remove_font( path, flags );
5977 return ret;
5980 static int add_font_resource( LPCWSTR file, DWORD flags )
5982 int ret = 0;
5984 if (*file == '\\')
5986 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
5988 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
5989 pthread_mutex_lock( &font_lock );
5990 ret = font_funcs->add_font( file, addfont_flags );
5991 pthread_mutex_unlock( &font_lock );
5993 else if (!wcschr( file, '\\' ))
5994 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
5996 return ret;
5999 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
6001 BOOL ret = FALSE;
6003 if (*file == '\\')
6005 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6007 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6008 ret = remove_font( file, addfont_flags );
6010 else if (!wcschr( file, '\\' ))
6011 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6013 return ret;
6016 static void load_system_bitmap_fonts(void)
6018 static const char * const fonts[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6019 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6020 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6021 HKEY hkey;
6022 DWORD i;
6024 if (!(hkey = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) ))) return;
6025 for (i = 0; i < ARRAY_SIZE(fonts); i++)
6027 if (query_reg_ascii_value( hkey, fonts[i], info, sizeof(value_buffer) ) && info->Type == REG_SZ)
6028 add_system_font_resource( (const WCHAR *)info->Data, ADDFONT_ALLOW_BITMAP );
6030 NtClose( hkey );
6033 static void load_directory_fonts( WCHAR *path, UINT flags )
6035 OBJECT_ATTRIBUTES attr;
6036 UNICODE_STRING nt_name;
6037 IO_STATUS_BLOCK io;
6038 HANDLE handle;
6039 char buf[8192];
6040 size_t len;
6042 len = lstrlenW( path );
6043 while (len && path[len - 1] == '\\') len--;
6045 nt_name.Buffer = path;
6046 nt_name.MaximumLength = nt_name.Length = len * sizeof(WCHAR);
6048 attr.Length = sizeof(attr);
6049 attr.RootDirectory = 0;
6050 attr.Attributes = OBJ_CASE_INSENSITIVE;
6051 attr.ObjectName = &nt_name;
6052 attr.SecurityDescriptor = NULL;
6053 attr.SecurityQualityOfService = NULL;
6055 if (NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
6056 FILE_SHARE_READ | FILE_SHARE_WRITE,
6057 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ))
6058 return;
6060 path[len++] = '\\';
6062 while (!NtQueryDirectoryFile( handle, 0, NULL, NULL, &io, buf, sizeof(buf),
6063 FileBothDirectoryInformation, FALSE, NULL, FALSE ) &&
6064 io.Information)
6066 FILE_BOTH_DIR_INFORMATION *info = (FILE_BOTH_DIR_INFORMATION *)buf;
6067 for (;;)
6069 if (!(info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
6071 memcpy( path + len, info->FileName, info->FileNameLength );
6072 path[len + info->FileNameLength / sizeof(WCHAR)] = 0;
6073 font_funcs->add_font( path, flags );
6075 if (!info->NextEntryOffset) break;
6076 info = (FILE_BOTH_DIR_INFORMATION *)((char *)info + info->NextEntryOffset);
6080 NtClose( handle );
6083 static void load_file_system_fonts(void)
6085 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024 * sizeof(WCHAR)])];
6086 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6087 WCHAR *ptr, *next, path[MAX_PATH];
6089 /* Windows directory */
6090 get_fonts_win_dir_path( NULL, path );
6091 load_directory_fonts( path, 0 );
6093 /* Wine data directory */
6094 get_fonts_data_dir_path( NULL, path );
6095 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6097 /* custom paths */
6098 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6099 if (query_reg_ascii_value( wine_fonts_key, "Path", info, sizeof(value_buffer) ) &&
6100 info->Type == REG_SZ)
6102 for (ptr = (WCHAR *)info->Data; ptr; ptr = next)
6104 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
6105 if (next && next - ptr < 2) continue;
6106 lstrcpynW( path, ptr, MAX_PATH );
6107 if (path[1] == ':')
6109 memmove( path + ARRAYSIZE(nt_prefixW), path, (lstrlenW( path ) + 1) * sizeof(WCHAR) );
6110 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6112 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6117 struct external_key
6119 struct list entry;
6120 WCHAR value[LF_FULLFACESIZE + 12];
6123 static void update_external_font_keys(void)
6125 struct list external_keys = LIST_INIT(external_keys);
6126 HKEY winnt_key = 0, win9x_key = 0;
6127 struct gdi_font_family *family;
6128 struct external_key *key, *next;
6129 struct gdi_font_face *face;
6130 DWORD len, i = 0;
6131 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6132 char buffer[2048];
6133 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
6134 WCHAR *file;
6135 HKEY hkey;
6137 static const WCHAR external_fontsW[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6139 winnt_key = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW), 0, NULL );
6140 win9x_key = reg_create_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW), 0, NULL );
6142 /* enumerate the fonts and add external ones to the two keys */
6144 if (!(hkey = reg_create_key( wine_fonts_key, external_fontsW, sizeof(external_fontsW), 0, NULL )))
6145 return;
6147 while (reg_enum_value( hkey, i++, info, sizeof(buffer) - sizeof(nt_prefixW),
6148 value, LF_FULLFACESIZE * sizeof(WCHAR) ))
6150 if (info->Type != REG_SZ) continue;
6152 path = (WCHAR *)(buffer + info->DataOffset);
6153 if (path[0] && path[1] == ':')
6155 memmove( path + ARRAYSIZE(nt_prefixW), path, info->DataLength );
6156 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6159 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6160 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
6162 face->flags |= ADDFONT_EXTERNAL_FOUND;
6163 continue;
6165 if (tmp && !*tmp) *tmp = ' ';
6166 if (!(key = malloc( sizeof(*key) ))) break;
6167 lstrcpyW( key->value, value );
6168 list_add_tail( &external_keys, &key->entry );
6171 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
6173 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
6175 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
6176 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
6178 lstrcpyW( value, face->full_name );
6179 if (face->scalable) lstrcatW( value, true_type_suffixW );
6181 if (face->file[0] == '\\')
6183 file = face->file;
6184 if (file[5] == ':') file += ARRAYSIZE(nt_prefixW);
6186 else if ((file = wcsrchr( face->file, '\\' )))
6187 file++;
6188 else
6189 file = face->file;
6191 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
6192 set_reg_value( winnt_key, value, REG_SZ, file, len );
6193 set_reg_value( win9x_key, value, REG_SZ, file, len );
6194 set_reg_value( hkey, value, REG_SZ, file, len );
6197 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
6199 reg_delete_value( win9x_key, key->value );
6200 reg_delete_value( winnt_key, key->value );
6201 reg_delete_value( hkey, key->value );
6202 list_remove( &key->entry );
6203 free( key );
6205 NtClose( win9x_key );
6206 NtClose( winnt_key );
6207 NtClose( hkey );
6210 static void load_registry_fonts(void)
6212 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6213 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6214 KEY_VALUE_FULL_INFORMATION *enum_info = (KEY_VALUE_FULL_INFORMATION *)value_buffer;
6215 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6216 DWORD i = 0, dlen;
6217 HKEY hkey;
6219 static const WCHAR dot_fonW[] = {'.','f','o','n',0};
6221 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6222 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6223 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6224 will skip these. */
6225 if (is_win9x())
6226 hkey = reg_open_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW) );
6227 else
6228 hkey = reg_open_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW) );
6229 if (!hkey) return;
6231 while (reg_enum_value( hkey, i++, enum_info, sizeof(value_buffer), value, sizeof(value) ))
6233 if (enum_info->Type != REG_SZ) continue;
6234 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6235 if (find_face_from_full_name( value )) continue;
6236 if (tmp && !*tmp) *tmp = ' ';
6238 if (!(dlen = query_reg_value( hkey, value, info, sizeof(value_buffer) - sizeof(nt_prefixW) )) ||
6239 info->Type != REG_SZ)
6241 WARN( "Unable to get face path %s\n", debugstr_w(value) );
6242 continue;
6245 path = (WCHAR *)info->Data;
6246 if (path[0] && path[1] == ':')
6248 memmove( path + ARRAYSIZE(nt_prefixW), path, dlen );
6249 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6250 dlen += sizeof(nt_prefixW);
6253 dlen /= sizeof(WCHAR);
6254 if (*path == '\\')
6255 add_font_resource( path, ADDFONT_ALLOW_BITMAP );
6256 else if (dlen >= 6 && !wcsicmp( path + dlen - 5, dot_fonW ))
6257 add_system_font_resource( path, ADDFONT_ALLOW_BITMAP );
6259 NtClose( hkey );
6262 static HKEY open_hkcu(void)
6264 char buffer[256];
6265 WCHAR bufferW[256];
6266 DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
6267 DWORD i, len = sizeof(sid_data);
6268 SID *sid;
6270 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
6271 return 0;
6273 sid = ((TOKEN_USER *)sid_data)->User.Sid;
6274 len = sprintf( buffer, "\\Registry\\User\\S-%u-%u", sid->Revision,
6275 MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
6276 MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
6277 for (i = 0; i < sid->SubAuthorityCount; i++)
6278 len += sprintf( buffer + len, "-%u", sid->SubAuthority[i] );
6279 ascii_to_unicode( bufferW, buffer, len + 1 );
6281 return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
6284 /***********************************************************************
6285 * font_init
6287 UINT font_init(void)
6289 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
6290 UNICODE_STRING name;
6291 HANDLE mutex;
6292 DWORD disposition;
6293 UINT dpi = 0;
6295 static WCHAR wine_font_mutexW[] =
6296 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6297 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6298 static const WCHAR wine_fonts_keyW[] =
6299 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6300 static const WCHAR cacheW[] = {'C','a','c','h','e'};
6302 if (!(hkcu_key = open_hkcu())) return 0;
6303 wine_fonts_key = reg_create_key( hkcu_key, wine_fonts_keyW, sizeof(wine_fonts_keyW), 0, NULL );
6304 if (wine_fonts_key) dpi = init_font_options();
6305 if (!dpi) return 96;
6306 update_codepage( dpi );
6308 if (!(font_funcs = init_freetype_lib()))
6309 return dpi;
6311 load_system_bitmap_fonts();
6312 load_file_system_fonts();
6313 font_funcs->load_fonts();
6315 attr.Attributes = OBJ_OPENIF;
6316 attr.ObjectName = &name;
6317 name.Buffer = wine_font_mutexW;
6318 name.Length = name.MaximumLength = sizeof(wine_font_mutexW);
6320 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return dpi;
6321 NtWaitForSingleObject( mutex, FALSE, NULL );
6323 wine_fonts_cache_key = reg_create_key( wine_fonts_key, cacheW, sizeof(cacheW),
6324 REG_OPTION_VOLATILE, &disposition );
6326 if (disposition == REG_CREATED_NEW_KEY)
6328 load_registry_fonts();
6329 update_external_font_keys();
6332 NtReleaseMutant( mutex, NULL );
6334 if (disposition != REG_CREATED_NEW_KEY)
6336 load_registry_fonts();
6337 load_font_list_from_cache();
6340 reorder_font_list();
6341 load_gdi_font_subst();
6342 load_gdi_font_replacements();
6343 load_system_links();
6344 dump_gdi_font_list();
6345 dump_gdi_font_subst();
6346 return dpi;
6349 /***********************************************************************
6350 * NtGdiAddFontResourceW (win32u.@)
6352 INT WINAPI NtGdiAddFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6353 DWORD tid, void *dv )
6355 if (!font_funcs) return 1;
6356 return add_font_resource( str, flags );
6359 /***********************************************************************
6360 * NtGdiAddFontMemResourceEx (win32u.@)
6362 HANDLE WINAPI NtGdiAddFontMemResourceEx( void *ptr, DWORD size, void *dv, ULONG dv_size,
6363 DWORD *count )
6365 HANDLE ret;
6366 DWORD num_fonts;
6367 void *copy;
6369 if (!ptr || !size || !count)
6371 SetLastError(ERROR_INVALID_PARAMETER);
6372 return NULL;
6374 if (!font_funcs) return NULL;
6375 if (!(copy = malloc( size ))) return NULL;
6376 memcpy( copy, ptr, size );
6378 pthread_mutex_lock( &font_lock );
6379 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6380 pthread_mutex_unlock( &font_lock );
6382 if (!num_fonts)
6384 free( copy );
6385 return NULL;
6388 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6389 * For now return something unique but quite random
6391 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
6393 __TRY
6395 *count = num_fonts;
6397 __EXCEPT
6399 WARN( "page fault while writing to *count (%p)\n", count );
6400 NtGdiRemoveFontMemResourceEx( ret );
6401 ret = 0;
6403 __ENDTRY
6404 TRACE( "Returning handle %p\n", ret );
6405 return ret;
6408 /***********************************************************************
6409 * NtGdiRemoveFontMemResourceEx (win32u.@)
6411 BOOL WINAPI NtGdiRemoveFontMemResourceEx( HANDLE handle )
6413 FIXME( "(%p) stub\n", handle );
6414 return TRUE;
6417 /***********************************************************************
6418 * NtGdiRemoveFontResourceW (win32u.@)
6420 BOOL WINAPI NtGdiRemoveFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6421 DWORD tid, void *dv )
6423 if (!font_funcs) return TRUE;
6424 return remove_font_resource( str, flags );
6427 /***********************************************************************
6428 * NtGdiGetFontUnicodeRanges (win32u.@)
6430 * Retrieve a list of supported Unicode characters in a font.
6432 * PARAMS
6433 * hdc [I] Handle to a device context.
6434 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6436 * RETURNS
6437 * Success: Number of bytes written to the buffer pointed to by lpgs.
6438 * Failure: 0
6441 DWORD WINAPI NtGdiGetFontUnicodeRanges( HDC hdc, GLYPHSET *lpgs )
6443 DWORD ret;
6444 PHYSDEV dev;
6445 DC *dc = get_dc_ptr(hdc);
6447 TRACE("(%p, %p)\n", hdc, lpgs);
6449 if (!dc) return 0;
6451 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
6452 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
6453 release_dc_ptr(dc);
6454 return ret;
6458 /*************************************************************
6459 * NtGdiFontIsLinked (win32u.@)
6461 BOOL WINAPI NtGdiFontIsLinked( HDC hdc )
6463 DC *dc = get_dc_ptr(hdc);
6464 PHYSDEV dev;
6465 BOOL ret;
6467 if (!dc) return FALSE;
6468 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
6469 ret = dev->funcs->pFontIsLinked( dev );
6470 release_dc_ptr(dc);
6471 TRACE("returning %d\n", ret);
6472 return ret;
6475 /*************************************************************
6476 * NtGdiGetRealizationInfo (win32u.@)
6478 BOOL WINAPI NtGdiGetRealizationInfo( HDC hdc, struct font_realization_info *info )
6480 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, file_count);
6481 PHYSDEV dev;
6482 BOOL ret;
6483 DC *dc;
6485 if (info->size != sizeof(*info) && !is_v0)
6486 return FALSE;
6488 dc = get_dc_ptr(hdc);
6489 if (!dc) return FALSE;
6490 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
6491 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
6492 release_dc_ptr(dc);
6493 return ret;
6496 /*************************************************************************
6497 * NtGdiGetRasterizerCaps (win32u.@)
6499 BOOL WINAPI NtGdiGetRasterizerCaps( RASTERIZER_STATUS *status, UINT size )
6501 status->nSize = sizeof(RASTERIZER_STATUS);
6502 status->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
6503 status->nLanguageID = 0;
6504 return TRUE;
6507 /*************************************************************************
6508 * NtGdiGetFontFileData (win32u.@)
6510 BOOL WINAPI NtGdiGetFontFileData( DWORD instance_id, DWORD file_index, UINT64 *offset,
6511 void *buff, DWORD buff_size )
6513 struct gdi_font *font;
6514 DWORD tag = 0, size;
6515 BOOL ret = FALSE;
6517 if (!font_funcs) return FALSE;
6518 pthread_mutex_lock( &font_lock );
6519 if ((font = get_font_from_handle( instance_id )))
6521 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
6522 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
6523 if (size != GDI_ERROR && size >= buff_size && *offset <= size - buff_size)
6524 ret = font_funcs->get_font_data( font, tag, *offset, buff, buff_size ) != GDI_ERROR;
6525 else
6526 SetLastError( ERROR_INVALID_PARAMETER );
6528 pthread_mutex_unlock( &font_lock );
6529 return ret;
6532 /*************************************************************************
6533 * NtGdiGetFontFileInfo (win32u.@)
6535 BOOL WINAPI NtGdiGetFontFileInfo( DWORD instance_id, DWORD file_index, struct font_fileinfo *info,
6536 SIZE_T size, SIZE_T *needed )
6538 SIZE_T required_size = 0;
6539 struct gdi_font *font;
6540 BOOL ret = FALSE;
6542 pthread_mutex_lock( &font_lock );
6544 if ((font = get_font_from_handle( instance_id )))
6546 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
6547 if (required_size <= size)
6549 info->writetime = font->writetime;
6550 info->size.QuadPart = font->data_size;
6551 lstrcpyW( info->path, font->file );
6552 ret = TRUE;
6554 else SetLastError( ERROR_INSUFFICIENT_BUFFER );
6557 pthread_mutex_unlock( &font_lock );
6558 if (needed) *needed = required_size;
6559 return ret;
6562 /*************************************************************
6563 * NtGdiGetCharWidthInfo (win32u.@)
6565 BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info )
6567 PHYSDEV dev;
6568 BOOL ret;
6569 DC *dc;
6571 dc = get_dc_ptr(hdc);
6572 if (!dc) return FALSE;
6573 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
6574 ret = dev->funcs->pGetCharWidthInfo( dev, info );
6576 if (ret)
6578 info->lsb = width_to_LP( dc, info->lsb );
6579 info->rsb = width_to_LP( dc, info->rsb );
6581 release_dc_ptr(dc);
6582 return ret;