win32u: Add font links for MS Gothic.
[wine.git] / dlls / win32u / font.c
blob9ead47e1983133b067475dbbe4a14c78ea783b2b
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include <limits.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <pthread.h>
34 #include "ntstatus.h"
35 #define WIN32_NO_STATUS
36 #include "winerror.h"
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winternl.h"
41 #include "winreg.h"
42 #include "ntgdi_private.h"
44 #include "wine/unixlib.h"
45 #include "wine/rbtree.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(font);
50 static HKEY wine_fonts_key;
51 static HKEY wine_fonts_cache_key;
52 HKEY hkcu_key;
54 struct font_physdev
56 struct gdi_physdev dev;
57 struct gdi_font *font;
60 static inline struct font_physdev *get_font_dev( PHYSDEV dev )
62 return (struct font_physdev *)dev;
65 struct gdi_font_family
67 struct wine_rb_entry name_entry;
68 struct wine_rb_entry second_name_entry;
69 unsigned int refcount;
70 WCHAR family_name[LF_FACESIZE];
71 WCHAR second_name[LF_FACESIZE];
72 struct list faces;
73 struct gdi_font_family *replacement;
76 struct gdi_font_face
78 struct list entry;
79 unsigned int refcount;
80 WCHAR *style_name;
81 WCHAR *full_name;
82 WCHAR *file;
83 void *data_ptr;
84 SIZE_T data_size;
85 UINT face_index;
86 FONTSIGNATURE fs;
87 DWORD ntmFlags;
88 DWORD version;
89 DWORD flags; /* ADDFONT flags */
90 BOOL scalable;
91 struct bitmap_font_size size; /* set if face is a bitmap */
92 struct gdi_font_family *family;
93 struct gdi_font_enum_data *cached_enum_data;
94 struct wine_rb_entry full_name_entry;
97 static const struct font_backend_funcs *font_funcs;
99 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
101 static const WCHAR nt_prefixW[] = {'\\','?','?','\\'};
103 static const WCHAR true_type_suffixW[] = {' ','(','T','r','u','e','T','y','p','e',')',0};
105 static const WCHAR system_link_keyW[] =
107 '\\','R','e','g','i','s','t','r','y',
108 '\\','M','a','c','h','i','n','e',
109 '\\','S','o','f','t','w','a','r','e',
110 '\\','M','i','c','r','o','s','o','f','t',
111 '\\','W','i','n','d','o','w','s',' ','N','T',
112 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
113 '\\','F','o','n','t','L','i','n','k',
114 '\\','S','y','s','t','e','m','L','i','n','k'
117 static const WCHAR associated_charset_keyW[] =
119 '\\','R','e','g','i','s','t','r','y',
120 '\\','M','a','c','h','i','n','e',
121 '\\','S','y','s','t','e','m',
122 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
123 '\\','C','o','n','t','r','o','l',
124 '\\','F','o','n','t','A','s','s','o','c',
125 '\\','A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t'
128 static const WCHAR software_config_keyW[] =
130 '\\','R','e','g','i','s','t','r','y',
131 '\\','M','a','c','h','i','n','e',
132 '\\','S','y','s','t','e','m',
133 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
134 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
135 '\\','C','u','r','r','e','n','t',
136 '\\','S','o','f','t','w','a','r','e',
139 static const WCHAR fonts_config_keyW[] =
141 '\\','R','e','g','i','s','t','r','y',
142 '\\','M','a','c','h','i','n','e',
143 '\\','S','y','s','t','e','m',
144 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
145 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
146 '\\','C','u','r','r','e','n','t',
147 '\\','S','o','f','t','w','a','r','e',
148 '\\','F','o','n','t','s'
151 static const WCHAR fonts_win9x_config_keyW[] =
153 '\\','R','e','g','i','s','t','r','y',
154 '\\','M','a','c','h','i','n','e',
155 '\\','S','o','f','t','w','a','r','e',
156 '\\','M','i','c','r','o','s','o','f','t',
157 '\\','W','i','n','d','o','w','s',
158 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
159 '\\','F','o','n','t','s'
162 static const WCHAR fonts_winnt_config_keyW[] =
164 '\\','R','e','g','i','s','t','r','y',
165 '\\','M','a','c','h','i','n','e',
166 '\\','S','o','f','t','w','a','r','e',
167 '\\','M','i','c','r','o','s','o','f','t',
168 '\\','W','i','n','d','o','w','s',' ','N','T',
169 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
170 '\\','F','o','n','t','s'
173 static const WCHAR font_substitutes_keyW[] =
175 '\\','R','e','g','i','s','t','r','y',
176 '\\','M','a','c','h','i','n','e',
177 '\\','S','o','f','t','w','a','r','e',
178 '\\','M','i','c','r','o','s','o','f','t',
179 '\\','W','i','n','d','o','w','s',' ','N','T',
180 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
181 '\\','F','o','n','t','S','u','b','s','t','i','t','u','t','e','s'
184 static const WCHAR font_assoc_keyW[] =
186 '\\','R','e','g','i','s','t','r','y',
187 '\\','M','a','c','h','i','n','e',
188 '\\','S','y','s','t','e','m',
189 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
190 '\\','C','o','n','t','r','o','l',
191 '\\','F','o','n','t','A','s','s','o','c'
194 static UINT font_smoothing = GGO_BITMAP;
195 static UINT subpixel_orientation = GGO_GRAY4_BITMAP;
196 static BOOL antialias_fakes = TRUE;
197 static struct font_gamma_ramp font_gamma_ramp;
199 static void add_face_to_cache( struct gdi_font_face *face );
200 static void remove_face_from_cache( struct gdi_font_face *face );
202 static CPTABLEINFO utf8_cp;
203 static CPTABLEINFO oem_cp;
204 CPTABLEINFO ansi_cp = { 0 };
206 static inline WCHAR facename_tolower( WCHAR c )
208 if (c >= 'A' && c <= 'Z') return c - 'A' + 'a';
209 else if (c > 127) return RtlDowncaseUnicodeChar( c );
210 else return c;
213 static inline int facename_compare( const WCHAR *str1, const WCHAR *str2, SIZE_T len )
215 while (len--)
217 WCHAR c1 = facename_tolower( *str1++ ), c2 = facename_tolower( *str2++ );
218 if (c1 != c2) return c1 - c2;
219 else if (!c1) return 0;
221 return 0;
224 /* Device -> World size conversion */
226 /* Performs a device to world transformation on the specified width (which
227 * is in integer format).
229 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
231 double floatWidth;
233 /* Perform operation with floating point */
234 floatWidth = (double)width * dc->xformVport2World.eM11;
235 /* Round to integers */
236 return GDI_ROUND(floatWidth);
239 /* Performs a device to world transformation on the specified size (which
240 * is in integer format).
242 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
244 double floatHeight;
246 /* Perform operation with floating point */
247 floatHeight = (double)height * dc->xformVport2World.eM22;
248 /* Round to integers */
249 return GDI_ROUND(floatHeight);
252 /* scale width and height but don't mirror them */
254 static inline INT width_to_LP( DC *dc, INT width )
256 return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
259 static inline INT height_to_LP( DC *dc, INT height )
261 return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
264 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
266 POINT pt[2];
267 pt[0].x = pt[0].y = 0;
268 pt[1].x = 0;
269 pt[1].y = height;
270 lp_to_dp(dc, pt, 2);
271 return pt[1].y - pt[0].y;
274 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
275 static BOOL FONT_DeleteObject( HGDIOBJ handle );
277 static const struct gdi_obj_funcs fontobj_funcs =
279 FONT_GetObjectW, /* pGetObjectW */
280 NULL, /* pUnrealizeObject */
281 FONT_DeleteObject /* pDeleteObject */
284 typedef struct
286 struct gdi_obj_header obj;
287 LOGFONTW logfont;
288 } FONTOBJ;
290 /* for translate_charset_info */
291 static const CHARSETINFO charset_info[] =
293 { ANSI_CHARSET, 1252, { {0}, { FS_LATIN1 }}},
294 { EASTEUROPE_CHARSET, 1250, { {0}, { FS_LATIN2 }}},
295 { RUSSIAN_CHARSET, 1251, { {0}, { FS_CYRILLIC }}},
296 { GREEK_CHARSET, 1253, { {0}, { FS_GREEK }}},
297 { TURKISH_CHARSET, 1254, { {0}, { FS_TURKISH }}},
298 { HEBREW_CHARSET, 1255, { {0}, { FS_HEBREW }}},
299 { ARABIC_CHARSET, 1256, { {0}, { FS_ARABIC }}},
300 { BALTIC_CHARSET, 1257, { {0}, { FS_BALTIC }}},
301 { VIETNAMESE_CHARSET, 1258, { {0}, { FS_VIETNAMESE }}},
302 { THAI_CHARSET, 874, { {0}, { FS_THAI }}},
303 { SHIFTJIS_CHARSET, 932, { {0}, { FS_JISJAPAN }}},
304 { GB2312_CHARSET, 936, { {0}, { FS_CHINESESIMP }}},
305 { HANGEUL_CHARSET, 949, { {0}, { FS_WANSUNG }}},
306 { CHINESEBIG5_CHARSET, 950, { {0}, { FS_CHINESETRAD }}},
307 { JOHAB_CHARSET, 1361, { {0}, { FS_JOHAB }}},
308 { 254, CP_UTF8, { {0}, { 0x04000000 }}},
309 { SYMBOL_CHARSET, CP_SYMBOL, { {0}, { FS_SYMBOL }}}
312 static const char * const default_serif_list[3] =
314 "Times New Roman",
315 "Liberation Serif",
316 "Bitstream Vera Serif"
318 static const char * const default_fixed_list[3] =
320 "Courier New",
321 "Liberation Mono",
322 "Bitstream Vera Sans Mono"
324 static const char * const default_sans_list[3] =
326 "Arial",
327 "Liberation Sans",
328 "Bitstream Vera Sans"
330 static WCHAR ff_roman_default[LF_FACESIZE];
331 static WCHAR ff_modern_default[LF_FACESIZE];
332 static WCHAR ff_swiss_default[LF_FACESIZE];
334 static const struct nls_update_font_list
336 UINT ansi_cp, oem_cp;
337 const char *oem, *fixed, *system;
338 const char *courier, *serif, *small, *sserif_96, *sserif_120;
339 /* these are for font substitutes */
340 const char *shelldlg, *tmsrmn;
341 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0, *helv_0, *tmsrmn_0;
342 struct subst { const char *from, *to; } arial_0, courier_new_0, times_new_roman_0;
343 } nls_update_font_list[] =
345 /* Latin 1 (United States) */
346 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
347 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
348 "Tahoma","Times New Roman"
350 /* Latin 1 (Multilingual) */
351 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
352 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
353 "Tahoma","Times New Roman" /* FIXME unverified */
355 /* UTF-8 */
356 { CP_UTF8, CP_UTF8, "vga850.fon", "vgafix.fon", "vgasys.fon",
357 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
358 "Tahoma", "Times New Roman" /* FIXME unverified */
360 /* Eastern Europe */
361 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
362 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
363 "Tahoma","Times New Roman", /* FIXME unverified */
364 "Fixedsys,238", "System,238",
365 "Courier New,238", "MS Serif,238", "Small Fonts,238",
366 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
367 { "Arial CE,0", "Arial,238" },
368 { "Courier New CE,0", "Courier New,238" },
369 { "Times New Roman CE,0", "Times New Roman,238" }
371 /* Cyrillic */
372 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
373 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
374 "Tahoma","Times New Roman", /* FIXME unverified */
375 "Fixedsys,204", "System,204",
376 "Courier New,204", "MS Serif,204", "Small Fonts,204",
377 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
378 { "Arial Cyr,0", "Arial,204" },
379 { "Courier New Cyr,0", "Courier New,204" },
380 { "Times New Roman Cyr,0", "Times New Roman,204" }
382 /* Greek */
383 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
384 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
385 "Tahoma","Times New Roman", /* FIXME unverified */
386 "Fixedsys,161", "System,161",
387 "Courier New,161", "MS Serif,161", "Small Fonts,161",
388 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
389 { "Arial Greek,0", "Arial,161" },
390 { "Courier New Greek,0", "Courier New,161" },
391 { "Times New Roman Greek,0", "Times New Roman,161" }
393 /* Turkish */
394 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
395 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
396 "Tahoma","Times New Roman", /* FIXME unverified */
397 "Fixedsys,162", "System,162",
398 "Courier New,162", "MS Serif,162", "Small Fonts,162",
399 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
400 { "Arial Tur,0", "Arial,162" },
401 { "Courier New Tur,0", "Courier New,162" },
402 { "Times New Roman Tur,0", "Times New Roman,162" }
404 /* Hebrew */
405 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
406 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
407 "Tahoma","Times New Roman", /* FIXME unverified */
408 "Fixedsys,177", "System,177",
409 "Courier New,177", "MS Serif,177", "Small Fonts,177",
410 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
412 /* Arabic */
413 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
414 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
415 "Microsoft Sans Serif","Times New Roman",
416 "Fixedsys,178", "System,178",
417 "Courier New,178", "MS Serif,178", "Small Fonts,178",
418 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
420 /* Baltic */
421 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
422 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
423 "Tahoma","Times New Roman", /* FIXME unverified */
424 "Fixedsys,186", "System,186",
425 "Courier New,186", "MS Serif,186", "Small Fonts,186",
426 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
427 { "Arial Baltic,0", "Arial,186" },
428 { "Courier New Baltic,0", "Courier New,186" },
429 { "Times New Roman Baltic,0", "Times New Roman,186" }
431 /* Vietnamese */
432 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
433 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
434 "Tahoma","Times New Roman" /* FIXME unverified */
436 /* Thai */
437 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
438 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
439 "Tahoma","Times New Roman" /* FIXME unverified */
441 /* Japanese */
442 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
443 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
444 "MS UI Gothic","MS Serif"
446 /* Chinese Simplified */
447 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
449 "SimSun", "NSimSun"
451 /* Korean */
452 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
453 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
454 "Gulim", "Batang"
456 /* Chinese Traditional */
457 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
458 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
459 "PMingLiU", "MingLiU"
463 static pthread_mutex_t font_lock = PTHREAD_MUTEX_INITIALIZER;
465 #ifndef WINE_FONT_DIR
466 #define WINE_FONT_DIR "fonts"
467 #endif
469 #ifdef WORDS_BIGENDIAN
470 #define GET_BE_WORD(x) (x)
471 #define GET_BE_DWORD(x) (x)
472 #else
473 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
474 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
475 #endif
477 static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
479 const char *dir;
480 ULONG len = MAX_PATH;
482 if ((dir = ntdll_get_data_dir()))
484 wine_unix_to_nt_file_name( dir, path, &len );
485 asciiz_to_unicode( path + len - 1, "\\" WINE_FONT_DIR "\\" );
487 else if ((dir = ntdll_get_build_dir()))
489 wine_unix_to_nt_file_name( dir, path, &len );
490 asciiz_to_unicode( path + len - 1, "\\fonts\\" );
493 if (file) lstrcatW( path, file );
496 static void get_fonts_win_dir_path( const WCHAR *file, WCHAR *path )
498 asciiz_to_unicode( path, "\\??\\C:\\windows\\fonts\\" );
499 if (file) lstrcatW( path, file );
502 HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len )
504 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
505 OBJECT_ATTRIBUTES attr;
506 HANDLE ret;
508 attr.Length = sizeof(attr);
509 attr.RootDirectory = root;
510 attr.ObjectName = &nameW;
511 attr.Attributes = 0;
512 attr.SecurityDescriptor = NULL;
513 attr.SecurityQualityOfService = NULL;
515 if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0;
516 return ret;
519 /* wrapper for NtCreateKey that creates the key recursively if necessary */
520 HKEY reg_create_key( HKEY root, const WCHAR *name, ULONG name_len,
521 DWORD options, DWORD *disposition )
523 UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
524 OBJECT_ATTRIBUTES attr;
525 NTSTATUS status;
526 HANDLE ret;
528 attr.Length = sizeof(attr);
529 attr.RootDirectory = root;
530 attr.ObjectName = &nameW;
531 attr.Attributes = 0;
532 attr.SecurityDescriptor = NULL;
533 attr.SecurityQualityOfService = NULL;
535 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, options, disposition );
536 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
538 static const WCHAR registry_rootW[] = { '\\','R','e','g','i','s','t','r','y','\\' };
539 DWORD pos = 0, i = 0, len = name_len / sizeof(WCHAR);
541 /* don't try to create registry root */
542 if (!root && len > ARRAY_SIZE(registry_rootW) &&
543 !memcmp( name, registry_rootW, sizeof(registry_rootW) ))
544 i += ARRAY_SIZE(registry_rootW);
546 while (i < len && name[i] != '\\') i++;
547 if (i == len) return 0;
548 for (;;)
550 unsigned int subkey_options = options;
551 if (i < len) subkey_options &= ~(REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK);
552 nameW.Buffer = (WCHAR *)name + pos;
553 nameW.Length = (i - pos) * sizeof(WCHAR);
554 status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, subkey_options, disposition );
556 if (attr.RootDirectory != root) NtClose( attr.RootDirectory );
557 if (!NT_SUCCESS(status)) return 0;
558 if (i == len) break;
559 attr.RootDirectory = ret;
560 while (i < len && name[i] == '\\') i++;
561 pos = i;
562 while (i < len && name[i] != '\\') i++;
565 return ret;
568 HKEY reg_open_hkcu_key( const char *name )
570 WCHAR nameW[128];
571 return reg_open_key( hkcu_key, nameW, asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) );
574 BOOL set_reg_value( HKEY hkey, const WCHAR *name, UINT type, const void *value, DWORD count )
576 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
577 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
578 return !NtSetValueKey( hkey, &nameW, 0, type, value, count );
581 void set_reg_ascii_value( HKEY hkey, const char *name, const char *value )
583 WCHAR nameW[64], valueW[128];
584 asciiz_to_unicode( nameW, name );
585 set_reg_value( hkey, nameW, REG_SZ, valueW, asciiz_to_unicode( valueW, value ));
588 ULONG query_reg_value( HKEY hkey, const WCHAR *name,
589 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
591 unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
592 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
594 if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
595 info, size, &size ))
596 return 0;
598 return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
601 ULONG query_reg_ascii_value( HKEY hkey, const char *name,
602 KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
604 WCHAR nameW[64];
605 asciiz_to_unicode( nameW, name );
606 return query_reg_value( hkey, nameW, info, size );
609 static BOOL reg_enum_value( HKEY hkey, unsigned int index, KEY_VALUE_FULL_INFORMATION *info,
610 ULONG size, WCHAR *name, ULONG name_size )
612 ULONG full_size;
614 if (NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
615 info, size, &full_size ))
616 return FALSE;
618 if (name_size)
620 if (name_size < info->NameLength + sizeof(WCHAR)) return FALSE;
621 memcpy( name, info->Name, info->NameLength );
622 name[info->NameLength / sizeof(WCHAR)] = 0;
624 return TRUE;
627 void reg_delete_value( HKEY hkey, const WCHAR *name )
629 unsigned int name_size = lstrlenW( name ) * sizeof(WCHAR);
630 UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
631 NtDeleteValueKey( hkey, &nameW );
634 BOOL reg_delete_tree( HKEY parent, const WCHAR *name, ULONG name_len )
636 char buffer[4096];
637 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
638 DWORD size;
639 HKEY key;
640 BOOL ret = TRUE;
642 if (!(key = reg_open_key( parent, name, name_len ))) return FALSE;
644 while (ret && !NtEnumerateKey( key, 0, KeyNodeInformation, key_info, sizeof(buffer), &size ))
645 ret = reg_delete_tree( key, key_info->Name, key_info->NameLength );
647 if (ret) ret = !NtDeleteKey( key );
648 NtClose( key );
649 return ret;
652 /* font substitutions */
654 struct gdi_font_subst
656 struct list entry;
657 int from_charset;
658 int to_charset;
659 WCHAR names[1];
662 static struct list font_subst_list = LIST_INIT(font_subst_list);
664 static inline WCHAR *get_subst_to_name( struct gdi_font_subst *subst )
666 return subst->names + lstrlenW( subst->names ) + 1;
669 static void dump_gdi_font_subst(void)
671 struct gdi_font_subst *subst;
673 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
675 if (subst->from_charset != -1 || subst->to_charset != -1)
676 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst->names),
677 subst->from_charset, debugstr_w(get_subst_to_name(subst)), subst->to_charset);
678 else
679 TRACE("%s -> %s\n", debugstr_w(subst->names), debugstr_w(get_subst_to_name(subst)));
683 static const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset )
685 struct gdi_font_subst *subst;
687 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
689 if (!facename_compare( subst->names, from_name, -1 ) &&
690 (subst->from_charset == from_charset || subst->from_charset == -1))
692 if (to_charset) *to_charset = subst->to_charset;
693 return get_subst_to_name( subst );
696 return NULL;
699 static BOOL add_gdi_font_subst( const WCHAR *from_name, int from_charset, const WCHAR *to_name, int to_charset )
701 struct gdi_font_subst *subst;
702 int len = lstrlenW( from_name ) + lstrlenW( to_name ) + 2;
704 if (get_gdi_font_subst( from_name, from_charset, NULL )) return FALSE; /* already exists */
706 if (!(subst = malloc( offsetof( struct gdi_font_subst, names[len] ) )))
707 return FALSE;
708 lstrcpyW( subst->names, from_name );
709 lstrcpyW( get_subst_to_name(subst), to_name );
710 subst->from_charset = from_charset;
711 subst->to_charset = to_charset;
712 list_add_tail( &font_subst_list, &subst->entry );
713 return TRUE;
716 static void load_gdi_font_subst(void)
718 char buffer[512];
719 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
720 HKEY hkey;
721 DWORD i = 0;
722 WCHAR *data, *p, value[64];
724 if (!(hkey = reg_open_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW) )))
725 return;
727 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
729 int from_charset = -1, to_charset = -1;
731 if (info->Type != REG_SZ) continue;
732 data = (WCHAR *)((char *)info + info->DataOffset);
734 TRACE( "Got %s=%s\n", debugstr_w(value), debugstr_w(data) );
735 if ((p = wcsrchr( value, ',' )) && p[1])
737 *p++ = 0;
738 from_charset = wcstol( p, NULL, 10 );
740 if ((p = wcsrchr( data, ',' )) && p[1])
742 *p++ = 0;
743 to_charset = wcstol( p, NULL, 10 );
746 /* Win 2000 doesn't allow mapping between different charsets
747 or mapping of DEFAULT_CHARSET */
748 if ((!from_charset || to_charset == from_charset) && to_charset != DEFAULT_CHARSET)
749 add_gdi_font_subst( value, from_charset, data, to_charset );
751 NtClose( hkey );
754 /* font families */
756 static int family_namecmp( const WCHAR *str1, const WCHAR *str2 )
758 int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0);
760 if (!facename_compare( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0;
761 else if (!facename_compare( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1;
762 else if (!facename_compare( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2;
763 else prio1 = 3;
765 if (!facename_compare( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0;
766 else if (!facename_compare( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1;
767 else if (!facename_compare( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2;
768 else prio2 = 3;
770 if (prio1 != prio2) return prio1 - prio2;
771 if (vert1 != vert2) return vert1 - vert2;
772 return facename_compare( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 );
775 static int family_name_compare( const void *key, const struct wine_rb_entry *entry )
777 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, name_entry );
778 return family_namecmp( (const WCHAR *)key, family->family_name );
781 static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry )
783 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, second_name_entry );
784 return family_namecmp( (const WCHAR *)key, family->second_name );
787 static int face_full_name_compare( const void *key, const struct wine_rb_entry *entry )
789 const struct gdi_font_face *face = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_face, full_name_entry );
790 return facename_compare( (const WCHAR *)key, face->full_name, LF_FULLFACESIZE - 1 );
793 static struct wine_rb_tree family_name_tree = { family_name_compare };
794 static struct wine_rb_tree family_second_name_tree = { family_second_name_compare };
795 static struct wine_rb_tree face_full_name_tree = { face_full_name_compare };
797 static int face_is_in_full_name_tree( const struct gdi_font_face *face )
799 return face->full_name_entry.parent || face_full_name_tree.root == &face->full_name_entry;
802 static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name )
804 struct gdi_font_family *family = malloc( sizeof(*family) );
806 family->refcount = 1;
807 lstrcpynW( family->family_name, name, LF_FACESIZE );
808 if (second_name && second_name[0] && wcsicmp( name, second_name ))
810 lstrcpynW( family->second_name, second_name, LF_FACESIZE );
811 add_gdi_font_subst( second_name, -1, name, -1 );
813 else family->second_name[0] = 0;
814 list_init( &family->faces );
815 family->replacement = NULL;
816 wine_rb_put( &family_name_tree, family->family_name, &family->name_entry );
817 if (family->second_name[0]) wine_rb_put( &family_second_name_tree, family->second_name, &family->second_name_entry );
818 return family;
821 static void release_family( struct gdi_font_family *family )
823 if (--family->refcount) return;
824 assert( list_empty( &family->faces ));
825 wine_rb_remove( &family_name_tree, &family->name_entry );
826 if (family->second_name[0]) wine_rb_remove( &family_second_name_tree, &family->second_name_entry );
827 if (family->replacement) release_family( family->replacement );
828 free( family );
831 static struct gdi_font_family *find_family_from_name( const WCHAR *name )
833 struct wine_rb_entry *entry;
834 if (!(entry = wine_rb_get( &family_name_tree, name ))) return NULL;
835 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, name_entry );
838 static struct gdi_font_family *find_family_from_any_name( const WCHAR *name )
840 struct wine_rb_entry *entry;
841 struct gdi_font_family *family;
842 if ((family = find_family_from_name( name ))) return family;
843 if (!(entry = wine_rb_get( &family_second_name_tree, name ))) return NULL;
844 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, second_name_entry );
847 static struct gdi_font_face *find_face_from_full_name( const WCHAR *full_name )
849 struct wine_rb_entry *entry;
850 if (!(entry = wine_rb_get( &face_full_name_tree, full_name ))) return NULL;
851 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_face, full_name_entry );
854 static const struct list *get_family_face_list( const struct gdi_font_family *family )
856 return family->replacement ? &family->replacement->faces : &family->faces;
859 static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name )
861 struct gdi_font_face *face;
862 const WCHAR *file;
863 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
865 if (!face->file) continue;
866 file = wcsrchr(face->file, '\\');
867 if (!file) file = face->file;
868 else file++;
869 if (wcsicmp( file, file_name )) continue;
870 face->refcount++;
871 return face;
873 return NULL;
876 static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name )
878 struct gdi_font_family *family;
879 struct gdi_font_face *face;
881 TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
883 if (!family_name)
885 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
886 if ((face = family_find_face_from_filename( family, file_name ))) return face;
887 return NULL;
890 if (!(family = find_family_from_name( family_name ))) return NULL;
891 return family_find_face_from_filename( family, file_name );
894 static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
896 struct gdi_font_family *new_family, *family;
897 struct gdi_font_face *face;
898 WCHAR new_name_vert[LF_FACESIZE], replace_vert[LF_FACESIZE];
900 if (!(family = find_family_from_any_name( replace )))
902 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace) );
903 return FALSE;
906 if (family->replacement)
908 TRACE( "%s is replaced by another font, skipping.\n", debugstr_w(replace) );
909 return FALSE;
912 if (!(new_family = create_family( new_name, NULL ))) return FALSE;
913 new_family->replacement = family;
914 family->refcount++;
915 TRACE( "mapping %s to %s\n", debugstr_w(replace), debugstr_w(new_name) );
917 /* also add replacement for vertical font if necessary */
918 if (replace[0] == '@') return TRUE;
919 if (list_empty( &family->faces )) return TRUE;
920 face = LIST_ENTRY( list_head(&family->faces), struct gdi_font_face, entry );
921 if (!(face->fs.fsCsb[0] & FS_DBCS_MASK)) return TRUE;
923 new_name_vert[0] = '@';
924 lstrcpynW( new_name_vert + 1, new_name, LF_FACESIZE - 1 );
925 if (find_family_from_any_name( new_name_vert )) return TRUE; /* already exists */
927 replace_vert[0] = '@';
928 lstrcpynW( replace_vert + 1, replace, LF_FACESIZE - 1 );
929 add_family_replacement( new_name_vert, replace_vert );
930 return TRUE;
934 * The replacement list is a way to map an entire font
935 * family onto another family. For example adding
937 * [HKCU\Software\Wine\Fonts\Replacements]
938 * "Wingdings"="Winedings"
940 * would enumerate the Winedings font both as Winedings and
941 * Wingdings. However if a real Wingdings font is present the
942 * replacement does not take place.
944 static void load_gdi_font_replacements(void)
946 char buffer[2048];
947 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
948 HKEY hkey;
949 DWORD i = 0;
950 WCHAR value[LF_FACESIZE];
952 static const WCHAR replacementsW[] = {'R','e','p','l','a','c','e','m','e','n','t','s'};
954 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
955 if (!(hkey = reg_open_key( wine_fonts_key, replacementsW, sizeof(replacementsW) ))) return;
957 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
959 WCHAR *data = (WCHAR *)((char *)info + info->DataOffset);
960 /* "NewName"="Oldname" */
961 if (!find_family_from_any_name( value ))
963 if (info->Type == REG_MULTI_SZ)
965 WCHAR *replace = data;
966 while (*replace)
968 if (add_family_replacement( value, replace )) break;
969 replace += lstrlenW(replace) + 1;
972 else if (info->Type == REG_SZ) add_family_replacement( value, data );
974 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
976 NtClose( hkey );
979 static void dump_gdi_font_list(void)
981 struct gdi_font_family *family;
982 struct gdi_font_face *face;
984 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
986 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
987 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
989 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
990 face->fs.fsCsb[0] );
991 if (!face->scalable) TRACE(" %d", face->size.height );
992 TRACE("\n");
997 static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
999 if (index < 3)
1001 const char * const *defaults;
1003 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
1004 defaults = default_fixed_list;
1005 else if ((pitch_and_family & 0xf0) == FF_ROMAN)
1006 defaults = default_serif_list;
1007 else
1008 defaults = default_sans_list;
1009 asciiz_to_unicode( buffer, defaults[index] );
1010 return TRUE;
1012 return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
1015 static void set_default_family( DWORD pitch_and_family, WCHAR *default_name )
1017 struct wine_rb_entry *entry;
1018 WCHAR name[LF_FACESIZE];
1019 int i = 0;
1021 while (enum_fallbacks( pitch_and_family, i++, name ))
1023 if (!(entry = wine_rb_get( &family_name_tree, name ))) continue;
1024 wine_rb_remove( &family_name_tree, entry );
1025 lstrcpynW( default_name, name, LF_FACESIZE - 1 );
1026 wine_rb_put( &family_name_tree, name, entry );
1027 return;
1031 static void reorder_font_list(void)
1033 set_default_family( FF_ROMAN, ff_roman_default );
1034 set_default_family( FF_MODERN, ff_modern_default );
1035 set_default_family( FF_SWISS, ff_swiss_default );
1038 static void release_face( struct gdi_font_face *face )
1040 if (--face->refcount) return;
1041 if (face->family)
1043 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1044 list_remove( &face->entry );
1045 release_family( face->family );
1047 if (face_is_in_full_name_tree( face )) wine_rb_remove( &face_full_name_tree, &face->full_name_entry );
1048 free( face->file );
1049 free( face->style_name );
1050 free( face->full_name );
1051 free( face->cached_enum_data );
1052 free( face );
1055 static int remove_font( const WCHAR *file, DWORD flags )
1057 struct gdi_font_family *family, *family_next;
1058 struct gdi_font_face *face, *face_next;
1059 int count = 0;
1061 pthread_mutex_lock( &font_lock );
1062 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_name_tree, struct gdi_font_family, name_entry )
1064 family->refcount++;
1065 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry )
1067 if (!face->file) continue;
1068 if (LOWORD(face->flags) != LOWORD(flags)) continue;
1069 if (!wcsicmp( face->file, file ))
1071 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
1072 release_face( face );
1073 count++;
1076 release_family( family );
1078 pthread_mutex_unlock( &font_lock );
1079 return count;
1082 static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
1084 if (facename_compare( f1->full_name, f2->full_name, -1 )) return FALSE;
1085 if (f1->scalable) return TRUE;
1086 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1087 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1090 static inline int style_order( const struct gdi_font_face *face )
1092 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1094 case NTM_REGULAR:
1095 return 0;
1096 case NTM_BOLD:
1097 return 1;
1098 case NTM_ITALIC:
1099 return 2;
1100 case NTM_BOLD | NTM_ITALIC:
1101 return 3;
1102 default:
1103 WARN( "Don't know how to order face %s with flags 0x%08x\n",
1104 debugstr_w(face->full_name), face->ntmFlags );
1105 return 9999;
1109 static BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
1111 struct gdi_font_face *cursor;
1113 LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
1115 if (faces_equal( face, cursor ))
1117 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
1118 debugstr_w(face->full_name), debugstr_w(family->family_name),
1119 cursor->version, face->version );
1121 if (face->file && cursor->file && !wcsicmp( face->file, cursor->file ))
1123 cursor->refcount++;
1124 TRACE("Font %s already in list, refcount now %d\n",
1125 debugstr_w(face->file), cursor->refcount);
1126 return FALSE;
1128 if (face->version <= cursor->version)
1130 TRACE("Original font %s is newer so skipping %s\n",
1131 debugstr_w(cursor->file), debugstr_w(face->file));
1132 return FALSE;
1134 else
1136 TRACE("Replacing original %s with %s\n",
1137 debugstr_w(cursor->file), debugstr_w(face->file));
1138 list_add_before( &cursor->entry, &face->entry );
1139 face->family = family;
1140 family->refcount++;
1141 face->refcount++;
1142 if (face_is_in_full_name_tree( cursor ))
1144 wine_rb_replace( &face_full_name_tree, &cursor->full_name_entry, &face->full_name_entry );
1145 memset( &cursor->full_name_entry, 0, sizeof(cursor->full_name_entry) );
1147 release_face( cursor );
1148 return TRUE;
1151 if (style_order( face ) < style_order( cursor )) break;
1154 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
1155 debugstr_w(family->family_name), debugstr_w(face->file) );
1156 list_add_before( &cursor->entry, &face->entry );
1157 if (face->scalable) wine_rb_put( &face_full_name_tree, face->full_name, &face->full_name_entry );
1158 face->family = family;
1159 family->refcount++;
1160 face->refcount++;
1161 return TRUE;
1164 static struct gdi_font_face *create_face( struct gdi_font_family *family, const WCHAR *style,
1165 const WCHAR *fullname, const WCHAR *file,
1166 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1167 DWORD ntmflags, DWORD version, DWORD flags,
1168 const struct bitmap_font_size *size )
1170 struct gdi_font_face *face = calloc( 1, sizeof(*face) );
1172 face->refcount = 1;
1173 face->style_name = wcsdup( style );
1174 face->full_name = wcsdup( fullname );
1175 face->face_index = index;
1176 face->fs = fs;
1177 face->ntmFlags = ntmflags;
1178 face->version = version;
1179 face->flags = flags;
1180 face->data_ptr = data_ptr;
1181 face->data_size = data_size;
1182 if (file) face->file = wcsdup( file );
1183 if (size) face->size = *size;
1184 else face->scalable = TRUE;
1185 if (insert_face_in_family_list( face, family )) return face;
1186 release_face( face );
1187 return NULL;
1190 int add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
1191 const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
1192 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
1193 DWORD ntmflags, DWORD version, DWORD flags,
1194 const struct bitmap_font_size *size )
1196 struct gdi_font_face *face;
1197 struct gdi_font_family *family;
1198 int ret = 0;
1200 if ((family = find_family_from_name( family_name ))) family->refcount++;
1201 else if (!(family = create_family( family_name, second_name ))) return ret;
1203 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1204 index, fs, ntmflags, version, flags, size )))
1206 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1207 release_face( face );
1209 release_family( family );
1210 ret++;
1212 if (fs.fsCsb[0] & FS_DBCS_MASK)
1214 WCHAR vert_family[LF_FACESIZE], vert_second[LF_FACESIZE], vert_full[LF_FULLFACESIZE];
1216 vert_family[0] = '@';
1217 lstrcpynW( vert_family + 1, family_name, LF_FACESIZE - 1 );
1219 if (second_name && second_name[0])
1221 vert_second[0] = '@';
1222 lstrcpynW( vert_second + 1, second_name, LF_FACESIZE - 1 );
1224 else vert_second[0] = 0;
1226 if (fullname)
1228 vert_full[0] = '@';
1229 lstrcpynW( vert_full + 1, fullname, LF_FULLFACESIZE - 1 );
1230 fullname = vert_full;
1233 if ((family = find_family_from_name( vert_family ))) family->refcount++;
1234 else if (!(family = create_family( vert_family, vert_second ))) return ret;
1236 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1237 index, fs, ntmflags, version, flags | ADDFONT_VERTICAL_FONT, size )))
1239 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1240 release_face( face );
1242 release_family( family );
1243 ret++;
1245 return ret;
1248 /* font cache */
1250 struct cached_face
1252 DWORD index;
1253 DWORD flags;
1254 DWORD ntmflags;
1255 DWORD version;
1256 struct bitmap_font_size size;
1257 FONTSIGNATURE fs;
1258 WCHAR full_name[1];
1259 /* WCHAR file_name[]; */
1262 static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
1263 void *buffer, DWORD buffer_size, BOOL scalable )
1265 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1266 KEY_NODE_INFORMATION *node_info = (KEY_NODE_INFORMATION *)buffer;
1267 DWORD index = 0, total_size;
1268 struct gdi_font_face *face;
1269 HKEY hkey_strike;
1270 WCHAR name[256];
1271 struct cached_face *cached;
1273 while (reg_enum_value( hkey_family, index++, info,
1274 buffer_size - sizeof(DWORD), name, sizeof(name) ))
1276 cached = (struct cached_face *)((char *)info + info->DataOffset);
1277 if (info->Type == REG_BINARY && info->DataLength > sizeof(*cached))
1279 ((DWORD *)cached)[info->DataLength / sizeof(DWORD)] = 0;
1280 if ((face = create_face( family, name, cached->full_name,
1281 cached->full_name + lstrlenW(cached->full_name) + 1,
1282 NULL, 0, cached->index, cached->fs, cached->ntmflags, cached->version,
1283 cached->flags, scalable ? NULL : &cached->size )))
1285 if (!scalable)
1286 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1287 face->size.height, face->size.width, face->size.size >> 6,
1288 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1290 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1291 face->fs.fsCsb[0], face->fs.fsCsb[1],
1292 face->fs.fsUsb[0], face->fs.fsUsb[1],
1293 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1295 release_face( face );
1300 /* load bitmap strikes */
1302 index = 0;
1303 while (!NtEnumerateKey( hkey_family, index++, KeyNodeInformation, node_info,
1304 buffer_size, &total_size ))
1306 if ((hkey_strike = reg_open_key( hkey_family, node_info->Name, node_info->NameLength )))
1308 load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
1309 NtClose( hkey_strike );
1314 static void load_font_list_from_cache(void)
1316 WCHAR buffer[4096];
1317 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer;
1318 KEY_NODE_INFORMATION *enum_info = (KEY_NODE_INFORMATION *)buffer;
1319 DWORD family_index = 0, total_size;
1320 struct gdi_font_family *family;
1321 HKEY hkey_family;
1322 WCHAR *second_name = (WCHAR *)info->Data;
1324 while (!NtEnumerateKey( wine_fonts_cache_key, family_index++, KeyNodeInformation, enum_info,
1325 sizeof(buffer), &total_size ))
1327 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, enum_info->Name,
1328 enum_info->NameLength )))
1329 continue;
1330 TRACE( "opened family key %s\n", debugstr_wn(enum_info->Name, enum_info->NameLength / sizeof(WCHAR)) );
1331 if (!query_reg_value( hkey_family, NULL, info, sizeof(buffer) ))
1332 second_name[0] = 0;
1334 family = create_family( buffer, second_name );
1336 load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
1338 NtClose( hkey_family );
1339 release_family( family );
1343 static void add_face_to_cache( struct gdi_font_face *face )
1345 HKEY hkey_family, hkey_face;
1346 DWORD len, buffer[1024];
1347 struct cached_face *cached = (struct cached_face *)buffer;
1349 if (!(hkey_family = reg_create_key( wine_fonts_cache_key, face->family->family_name,
1350 lstrlenW( face->family->family_name ) * sizeof(WCHAR),
1351 REG_OPTION_VOLATILE, NULL )))
1352 return;
1354 if (face->family->second_name[0])
1355 set_reg_value( hkey_family, NULL, REG_SZ, face->family->second_name,
1356 (lstrlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1358 if (!face->scalable)
1360 WCHAR nameW[10];
1361 char name[10];
1363 sprintf( name, "%d", face->size.y_ppem );
1364 hkey_face = reg_create_key( hkey_family, nameW,
1365 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR),
1366 REG_OPTION_VOLATILE, NULL );
1368 else hkey_face = hkey_family;
1370 memset( cached, 0, sizeof(*cached) );
1371 cached->index = face->face_index;
1372 cached->flags = face->flags;
1373 cached->ntmflags = face->ntmFlags;
1374 cached->version = face->version;
1375 cached->fs = face->fs;
1376 if (!face->scalable) cached->size = face->size;
1377 lstrcpyW( cached->full_name, face->full_name );
1378 len = lstrlenW( face->full_name ) + 1;
1379 lstrcpyW( cached->full_name + len, face->file );
1380 len += lstrlenW( face->file ) + 1;
1382 set_reg_value( hkey_face, face->style_name, REG_BINARY, cached,
1383 offsetof( struct cached_face, full_name[len] ));
1385 if (hkey_face != hkey_family) NtClose( hkey_face );
1386 NtClose( hkey_family );
1389 static void remove_face_from_cache( struct gdi_font_face *face )
1391 HKEY hkey_family, hkey;
1393 if (!(hkey_family = reg_open_key( wine_fonts_cache_key, face->family->family_name,
1394 lstrlenW( face->family->family_name ) * sizeof(WCHAR) )))
1395 return;
1397 if (!face->scalable)
1399 WCHAR nameW[10];
1400 char name[10];
1401 sprintf( name, "%d", face->size.y_ppem );
1402 if ((hkey = reg_open_key( hkey_family, nameW,
1403 asciiz_to_unicode( nameW, name ) - sizeof(WCHAR) )))
1405 NtDeleteKey( hkey );
1406 NtClose( hkey );
1409 else reg_delete_value( hkey_family, face->style_name );
1411 NtClose( hkey_family );
1414 /* font links */
1416 struct gdi_font_link
1418 struct list entry;
1419 struct list links;
1420 WCHAR name[LF_FACESIZE];
1421 FONTSIGNATURE fs;
1424 struct gdi_font_link_entry
1426 struct list entry;
1427 FONTSIGNATURE fs;
1428 WCHAR family_name[LF_FACESIZE];
1431 static struct list font_links = LIST_INIT(font_links);
1433 static struct gdi_font_link *find_gdi_font_link( const WCHAR *name )
1435 struct gdi_font_link *link;
1437 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1438 if (!facename_compare( link->name, name, LF_FACESIZE - 1 )) return link;
1439 return NULL;
1442 static struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
1443 FONTSIGNATURE fs )
1445 struct gdi_font_link *link;
1446 struct gdi_font_link_entry *entry;
1447 struct gdi_font_family *family;
1449 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1451 if (!facename_compare( link->name, name, LF_FACESIZE - 1 ) ||
1452 (subst && !facename_compare( link->name, subst, LF_FACESIZE - 1 )))
1454 TRACE("found entry in system list\n");
1455 LIST_FOR_EACH_ENTRY( entry, &link->links, struct gdi_font_link_entry, entry )
1457 const struct gdi_font_link *links;
1459 family = find_family_from_name( entry->family_name );
1460 if (!fs.fsCsb[0]) return family;
1461 if (fs.fsCsb[0] & entry->fs.fsCsb[0]) return family;
1462 if ((links = find_gdi_font_link( family->family_name )) && fs.fsCsb[0] & links->fs.fsCsb[0])
1463 return family;
1467 return NULL;
1470 static struct gdi_font_link *add_gdi_font_link( const WCHAR *name )
1472 struct gdi_font_link *link = find_gdi_font_link( name );
1474 if (link) return link;
1475 if ((link = malloc( sizeof(*link) )))
1477 lstrcpynW( link->name, name, LF_FACESIZE );
1478 memset( &link->fs, 0, sizeof(link->fs) );
1479 list_init( &link->links );
1480 list_add_tail( &font_links, &link->entry );
1482 return link;
1485 static void add_gdi_font_link_entry( struct gdi_font_link *link, const WCHAR *family_name, FONTSIGNATURE fs )
1487 struct gdi_font_link_entry *entry;
1489 entry = malloc( sizeof(*entry) );
1490 lstrcpynW( entry->family_name, family_name, LF_FACESIZE );
1491 entry->fs = fs;
1492 link->fs.fsCsb[0] |= fs.fsCsb[0];
1493 link->fs.fsCsb[1] |= fs.fsCsb[1];
1494 list_add_tail( &link->links, &entry->entry );
1497 static const WCHAR lucida_sans_unicodeW[] =
1498 {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
1499 static const WCHAR microsoft_sans_serifW[] =
1500 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1501 static const WCHAR tahomaW[] =
1502 {'T','a','h','o','m','a',0};
1503 static const WCHAR ms_gothicW[] =
1504 {'M','S',' ','G','o','t','h','i','c',0};
1505 static const WCHAR ms_p_gothicW[] =
1506 {'M','S',' ','P','G','o','t','h','i','c',0};
1507 static const WCHAR ms_ui_gothicW[] =
1508 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1509 static const WCHAR sim_sunW[] =
1510 {'S','i','m','S','u','n',0};
1511 static const WCHAR gulimW[] =
1512 {'G','u','l','i','m',0};
1513 static const WCHAR ming_li_uW[] =
1514 {'M','i','n','g','L','i','U',0};
1515 static const WCHAR p_ming_li_uW[] =
1516 {'P','M','i','n','g','L','i','U',0};
1517 static const WCHAR ming_li_u_hkscsW[] =
1518 {'M','i','n','g','L','i','U','_','H','K','S','C','S',0};
1519 static const WCHAR ming_li_u_ext_bW[] =
1520 {'M','i','n','g','L','i','U','-','E','x','t','B',0};
1521 static const WCHAR p_ming_li_u_ext_bW[] =
1522 {'P','M','i','n','g','L','i','U','-','E','x','t','B',0};
1523 static const WCHAR ming_li_u_hkscs_ext_bW[] =
1524 {'M','i','n','g','L','i','U','_','H','K','S','C','S','-','E','x','t','B',0};
1525 static const WCHAR batangW[] =
1526 {'B','a','t','a','n','g',0};
1527 static const WCHAR microsoft_jheng_heiW[] =
1528 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',0};
1529 static const WCHAR microsoft_jheng_hei_boldW[] =
1530 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','B','o','l','d',0};
1531 static const WCHAR microsoft_jheng_hei_uiW[] =
1532 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',0};
1533 static const WCHAR microsoft_jheng_hei_ui_boldW[] =
1534 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','B','o','l','d',0};
1535 static const WCHAR microsoft_jheng_hei_ui_lightW[] =
1536 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','L','i','g','h','t',0};
1538 static const WCHAR * const font_links_list[] =
1540 lucida_sans_unicodeW,
1541 microsoft_sans_serifW,
1542 tahomaW
1545 static const struct font_links_defaults_list
1547 /* Keyed off substitution for "MS Shell Dlg" */
1548 const WCHAR *shelldlg;
1549 /* Maximum of four substitutes, plus terminating NULL pointer */
1550 const WCHAR *substitutes[5];
1551 } font_links_defaults_list[] =
1553 /* Non East-Asian */
1554 { tahomaW, /* FIXME unverified ordering */
1555 { ms_ui_gothicW, sim_sunW, gulimW, p_ming_li_uW, NULL }
1557 /* Below lists are courtesy of
1558 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1560 /* Japanese */
1561 { ms_ui_gothicW,
1562 { ms_ui_gothicW, p_ming_li_uW, sim_sunW, gulimW, NULL }
1564 /* Chinese Simplified */
1565 { sim_sunW,
1566 { sim_sunW, p_ming_li_uW, ms_ui_gothicW, batangW, NULL }
1568 /* Korean */
1569 { gulimW,
1570 { gulimW, p_ming_li_uW, ms_ui_gothicW, sim_sunW, NULL }
1572 /* Chinese Traditional */
1573 { p_ming_li_uW,
1574 { p_ming_li_uW, sim_sunW, ms_ui_gothicW, batangW, NULL }
1578 static const char system_link_tahoma_sc[] =
1579 "SIMSUN.TTC,SimSun\0"
1580 "MINGLIU.TTC,PMingLiu\0"
1581 "MSGOTHIC.TTC,MS UI Gothic\0"
1582 "BATANG.TTC,Batang\0"
1583 "MSYH.TTC,Microsoft YaHei UI\0"
1584 "MSJH.TTC,Microsoft JhengHei UI\0"
1585 "YUGOTHM.TTC,Yu Gothic UI\0"
1586 "MALGUN.TTF,Malgun Gothic\0"
1587 "SEGUISYM.TTF,Segoe UI Symbol\0";
1589 static const char system_link_tahoma_tc[] =
1590 "MINGLIU.TTC,PMingLiu\0"
1591 "SIMSUN.TTC,SimSun\0"
1592 "MSGOTHIC.TTC,MS UI Gothic\0"
1593 "BATANG.TTC,Batang\0"
1594 "MSJH.TTC,Microsoft JhengHei UI\0"
1595 "MSYH.TTC,Microsoft YaHei UI\0"
1596 "YUGOTHM.TTC,Yu Gothic UI\0"
1597 "MALGUN.TTF,Malgun Gothic\0"
1598 "SEGUISYM.TTF,Segoe UI Symbol\0";
1600 static const char system_link_tahoma_jp[] =
1601 "MSGOTHIC.TTC,MS UI Gothic\0"
1602 "MINGLIU.TTC,PMingLiU\0"
1603 "SIMSUN.TTC,SimSun\0"
1604 "GULIM.TTC,Gulim\0"
1605 "YUGOTHM.TTC,Yu Gothic UI\0"
1606 "MSJH.TTC,Microsoft JhengHei UI\0"
1607 "MSYH.TTC,Microsoft YaHei UI\0"
1608 "MALGUN.TTF,Malgun Gothic\0"
1609 "SEGUISYM.TTF,Segoe UI Symbol\0";
1611 static const char system_link_tahoma_kr[] =
1612 "GULIM.TTC,Gulim\0"
1613 "MSGOTHIC.TTC,MS UI Gothic\0"
1614 "MINGLIU.TTC,PMingLiU\0"
1615 "SIMSUN.TTC,SimSun\0"
1616 "MALGUN.TTF,Malgun Gothic\0"
1617 "YUGOTHM.TTC,Yu Gothic UI\0"
1618 "MSJH.TTC,Microsoft JhengHei UI\0"
1619 "MSYH.TTC,Microsoft YaHei UI\0"
1620 "SEGUISYM.TTF,Segoe UI Symbol\0";
1622 static const char system_link_tahoma_non_cjk[] =
1623 "MSGOTHIC.TTC,MS UI Gothic\0"
1624 "MINGLIU.TTC,PMingLiU\0"
1625 "SIMSUN.TTC,SimSun\0"
1626 "GULIM.TTC,Gulim\0"
1627 "YUGOTHM.TTC,Yu Gothic UI\0"
1628 "MSJH.TTC,Microsoft JhengHei UI\0"
1629 "MSYH.TTC,Microsoft YaHei UI\0"
1630 "MALGUN.TTF,Malgun Gothic\0"
1631 "SEGUISYM.TTF,Segoe UI Symbol\0";
1633 static const char system_link_ms_gothic[] =
1634 "MINGLIU.TTC,MingLiU\0"
1635 "SIMSUN.TTC,SimSun\0"
1636 "GULIM.TTC,GulimChe\0"
1637 "YUGOTHM.TTC,Yu Gothic UI\0"
1638 "MSJH.TTC,Microsoft JhengHei UI\0"
1639 "MSYH.TTC,Microsoft YaHei UI\0"
1640 "MALGUN.TTF,Malgun Gothic\0"
1641 "SEGUISYM.TTF,Segoe UI Symbol\0";
1643 static const char system_link_ms_p_gothic[] =
1644 "MINGLIU.TTC,PMingLiU\0"
1645 "SIMSUN.TTC,SimSun\0"
1646 "GULIM.TTC,Gulim\0"
1647 "YUGOTHM.TTC,Yu Gothic UI\0"
1648 "MSJH.TTC,Microsoft JhengHei UI\0"
1649 "MSYH.TTC,Microsoft YaHei UI\0"
1650 "MALGUN.TTF,Malgun Gothic\0"
1651 "SEGUISYM.TTF,Segoe UI Symbol\0";
1653 static const char system_link_ms_ui_gothic[] =
1654 "MICROSS.TTF,Microsoft Sans Serif\0"
1655 "MINGLIU.TTC,PMingLiU\0"
1656 "SIMSUN.TTC,SimSun\0"
1657 "GULIM.TTC,Gulim\0"
1658 "YUGOTHM.TTC,Yu Gothic UI\0"
1659 "MSJH.TTC,Microsoft JhengHei UI\0"
1660 "MSYH.TTC,Microsoft YaHei UI\0"
1661 "MALGUN.TTF,Malgun Gothic\0"
1662 "SEGUISYM.TTF,Segoe UI Symbol\0";
1664 static const char system_link_microsoft_jheng_hei[] =
1665 "SEGOEUI.TTF,Segoe UI\0"
1666 "MINGLIU.TTC,MingLiU\0"
1667 "MSYH.TTC,Microsoft YaHei\0"
1668 "MEIRYO.TTC,Meiryo\0"
1669 "MALGUN.TTF,Malgun Gothic\0"
1670 "YUGOTHM.TTC,Yu Gothic UI\0"
1671 "SEGUISYM.TTF,Segoe UI Symbol\0";
1673 static const char system_link_microsoft_jheng_hei_bold[] =
1674 "SEGOEUIB.TTF,Segoe UI Bold\0"
1675 "MINGLIU.TTC,MingLiU\0"
1676 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1677 "MEIRYOB.TTC,Meiryo Bold\0"
1678 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1679 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1680 "SEGUISYM.TTF,Segoe UI Symbol\0";
1682 static const char system_link_microsoft_jheng_hei_ui[] =
1683 "SEGOEUI.TTF,Segoe UI\0"
1684 "MINGLIU.TTC,MingLiU\0"
1685 "MSYH.TTC,Microsoft YaHei UI\0"
1686 "MEIRYO.TTC,Meiryo UI\0"
1687 "MALGUN.TTF,Malgun Gothic\0"
1688 "YUGOTHM.TTC,Yu Gothic UI\0"
1689 "SEGUISYM.TTF,Segoe UI Symbol\0";
1691 static const char system_link_microsoft_jheng_hei_ui_bold[] =
1692 "SEGOEUIB.TTF,Segoe UI Bold\0"
1693 "MINGLIU.TTC,MingLiU\0"
1694 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1695 "MEIRYOB.TTC,Meiryo UI Bold\0"
1696 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1697 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1698 "SEGUISYM.TTF,Segoe UI Symbol\0";
1700 static const char system_link_microsoft_jheng_hei_ui_light[] =
1701 "SEGOEUIL.TTF,Segoe UI Light\0"
1702 "MINGLIU.TTC,MingLiU\0"
1703 "MSYHL.TTC,Microsoft YaHei UI Light\0"
1704 "MEIRYO.TTC,Meiryo UI\0"
1705 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1706 "YUGOTHL.TTC,Yu Gothic UI Light\0"
1707 "SEGUISYM.TTF,Segoe UI Symbol\0";
1709 static const char system_link_ming_li_u[] =
1710 "MICROSS.TTF,Microsoft Sans Serif\0"
1711 "SIMSUN.TTC,SimSun\0"
1712 "MSMINCHO.TTC,MS Mincho\0"
1713 "BATANG.TTC,BatangChe\0"
1714 "MSJH.TTC,Microsoft JhengHei UI\0"
1715 "MSYH.TTC,Microsoft YaHei UI\0"
1716 "YUGOTHM.TTC,Yu Gothic UI\0"
1717 "MALGUN.TTF,Malgun Gothic\0"
1718 "SEGUISYM.TTF,Segoe UI Symbol\0";
1720 static const char system_link_p_ming_li_u[] =
1721 "MICROSS.TTF,Microsoft Sans Serif\0"
1722 "SIMSUN.TTC,SimSun\0"
1723 "MSMINCHO.TTC,MS PMincho\0"
1724 "BATANG.TTC,Batang\0"
1725 "MSJH.TTC,Microsoft JhengHei UI\0"
1726 "MSYH.TTC,Microsoft YaHei UI\0"
1727 "YUGOTHM.TTC,Yu Gothic UI\0"
1728 "MALGUN.TTF,Malgun Gothic\0"
1729 "SEGUISYM.TTF,Segoe UI Symbol\0";
1731 static const char system_link_ming_li_u_hkscs[] =
1732 "MICROSS.TTF,Microsoft Sans Serif\0"
1733 "MINGLIU.TTC,MingLiU\0"
1734 "SIMSUN.TTC,SimSun\0"
1735 "MSMINCHO.TTC,MS Mincho\0"
1736 "BATANG.TTC,BatangChe\0"
1737 "MSJH.TTC,Microsoft JhengHei UI\0"
1738 "MSYH.TTC,Microsoft YaHei UI\0"
1739 "YUGOTHM.TTC,Yu Gothic UI\0"
1740 "MALGUN.TTF,Malgun Gothic\0"
1741 "SEGUISYM.TTF,Segoe UI Symbol\0";
1743 static const char system_link_ming_li_u_ext_b[] =
1744 "MICROSS.TTF,Microsoft Sans Serif\0"
1745 "MINGLIU.TTC,MingLiU\0"
1746 "SIMSUN.TTC,SimSun\0"
1747 "MSMINCHO.TTC,MS Mincho\0"
1748 "BATANG.TTC,BatangChe\0"
1749 "MSJH.TTC,Microsoft JhengHei UI\0"
1750 "MSYH.TTC,Microsoft YaHei UI\0"
1751 "YUGOTHM.TTC,Yu Gothic UI\0"
1752 "MALGUN.TTF,Malgun Gothic\0"
1753 "SEGUISYM.TTF,Segoe UI Symbol\0";
1755 static const char system_link_p_ming_li_u_ext_b[] =
1756 "MICROSS.TTF,Microsoft Sans Serif\0"
1757 "MINGLIU.TTC,PMingLiU\0"
1758 "SIMSUN.TTC,SimSun\0"
1759 "MSMINCHO.TTC,MS PMincho\0"
1760 "BATANG.TTC,Batang\0"
1761 "MSJH.TTC,Microsoft JhengHei UI\0"
1762 "MSYH.TTC,Microsoft YaHei UI\0"
1763 "YUGOTHM.TTC,Yu Gothic UI\0"
1764 "MALGUN.TTF,Malgun Gothic\0"
1765 "SEGUISYM.TTF,Segoe UI Symbol\0";
1767 static const char system_link_ming_li_u_hkscs_ext_b[] =
1768 "MICROSS.TTF,Microsoft Sans Serif\0"
1769 "MINGLIU.TTC,MingLiU_HKSCS\0"
1770 "MINGLIU.TTC,MingLiU\0"
1771 "SIMSUN.TTC,SimSun\0"
1772 "MSMINCHO.TTC,MS Mincho\0"
1773 "BATANG.TTC,BatangChe\0"
1774 "MSJH.TTC,Microsoft JhengHei UI\0"
1775 "MSYH.TTC,Microsoft YaHei UI\0"
1776 "YUGOTHM.TTC,Yu Gothic UI\0"
1777 "MALGUN.TTF,Malgun Gothic\0"
1778 "SEGUISYM.TTF,Segoe UI Symbol\0";
1780 static const struct system_link_reg
1782 const WCHAR *font_name;
1783 BOOL locale_dependent;
1784 const char *link_non_cjk;
1785 DWORD link_non_cjk_len;
1786 const char *link_sc;
1787 DWORD link_sc_len;
1788 const char *link_tc;
1789 DWORD link_tc_len;
1790 const char *link_jp;
1791 DWORD link_jp_len;
1792 const char *link_kr;
1793 DWORD link_kr_len;
1795 default_system_link[] =
1798 tahomaW, TRUE,
1799 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1800 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1801 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1802 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1803 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1806 microsoft_sans_serifW, TRUE,
1807 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1808 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1809 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1810 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1811 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1814 lucida_sans_unicodeW, TRUE,
1815 system_link_tahoma_non_cjk, sizeof(system_link_tahoma_non_cjk),
1816 system_link_tahoma_sc, sizeof(system_link_tahoma_sc),
1817 system_link_tahoma_tc, sizeof(system_link_tahoma_tc),
1818 system_link_tahoma_jp, sizeof(system_link_tahoma_jp),
1819 system_link_tahoma_kr, sizeof(system_link_tahoma_kr),
1821 { ms_gothicW, FALSE, system_link_ms_gothic, sizeof(system_link_ms_gothic) },
1822 { ms_p_gothicW, FALSE, system_link_ms_p_gothic, sizeof(system_link_ms_p_gothic) },
1823 { ms_ui_gothicW, FALSE, system_link_ms_ui_gothic, sizeof(system_link_ms_ui_gothic) },
1824 { microsoft_jheng_heiW, FALSE, system_link_microsoft_jheng_hei, sizeof(system_link_microsoft_jheng_hei) },
1825 { microsoft_jheng_hei_boldW, FALSE, system_link_microsoft_jheng_hei_bold, sizeof(system_link_microsoft_jheng_hei_bold) },
1826 { microsoft_jheng_hei_uiW, FALSE, system_link_microsoft_jheng_hei_ui, sizeof(system_link_microsoft_jheng_hei_ui) },
1827 { microsoft_jheng_hei_ui_boldW, FALSE, system_link_microsoft_jheng_hei_ui_bold, sizeof(system_link_microsoft_jheng_hei_ui_bold) },
1828 { microsoft_jheng_hei_ui_lightW, FALSE, system_link_microsoft_jheng_hei_ui_light, sizeof(system_link_microsoft_jheng_hei_ui_light) },
1829 { ming_li_uW, FALSE, system_link_ming_li_u, sizeof(system_link_ming_li_u) },
1830 { p_ming_li_uW, FALSE, system_link_p_ming_li_u, sizeof(system_link_p_ming_li_u) },
1831 { ming_li_u_hkscsW, FALSE, system_link_ming_li_u_hkscs, sizeof(system_link_ming_li_u_hkscs) },
1832 { ming_li_u_ext_bW, FALSE, system_link_ming_li_u_ext_b, sizeof(system_link_ming_li_u_ext_b) },
1833 { p_ming_li_u_ext_bW, FALSE, system_link_p_ming_li_u_ext_b, sizeof(system_link_p_ming_li_u_ext_b) },
1834 { ming_li_u_hkscs_ext_bW, FALSE, system_link_ming_li_u_hkscs_ext_b, sizeof(system_link_ming_li_u_hkscs_ext_b) },
1837 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1839 struct gdi_font_family *family;
1840 struct gdi_font_face *face;
1841 struct gdi_font_link *font_link;
1842 const WCHAR *file, *value;
1844 /* Don't store fonts that are only substitutes for other fonts */
1845 if (get_gdi_font_subst( name, -1, NULL ))
1847 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1848 return;
1850 font_link = add_gdi_font_link( name );
1851 for ( ; *values; values++)
1853 if (!facename_compare( name, *values, -1 )) continue;
1854 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1855 if (!(family = find_family_from_name( value ))) continue;
1856 /* use first extant filename for this Family */
1857 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1859 if (!face->file) continue;
1860 file = wcsrchr(face->file, '\\');
1861 if (!file) file = face->file;
1862 else file++;
1863 if ((face = find_face_from_filename( file, value )))
1865 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1866 TRACE( "added internal SystemLink for %s to %s in %s\n",
1867 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1869 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1870 break;
1875 static void load_system_links(void)
1877 HKEY hkey;
1878 DWORD i, j;
1879 const WCHAR *shelldlg_name;
1880 struct gdi_font_link *font_link, *system_font_link;
1881 struct gdi_font_face *face;
1883 static const WCHAR ms_shell_dlgW[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
1884 static const WCHAR systemW[] = {'S','y','s','t','e','m',0};
1885 static const WCHAR tahoma_ttfW[] = {'t','a','h','o','m','a','.','t','t','f',0};
1887 if ((hkey = reg_open_key( NULL, system_link_keyW, sizeof(system_link_keyW) )))
1889 char buffer[4096];
1890 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1891 WCHAR value[MAX_PATH];
1892 WCHAR *entry, *next;
1894 i = 0;
1895 while (reg_enum_value( hkey, i++, info, sizeof(buffer), value, sizeof(value) ))
1897 /* Don't store fonts that are only substitutes for other fonts */
1898 if (!get_gdi_font_subst( value, -1, NULL ))
1900 char *data = (char *)info + info->DataOffset;
1901 font_link = add_gdi_font_link( value );
1902 for (entry = (WCHAR *)data; (char *)entry < data + info->DataLength && *entry; entry = next)
1904 const WCHAR *family_name = NULL;
1905 WCHAR *p;
1907 TRACE( "%s: %s\n", debugstr_w(value), debugstr_w(entry) );
1909 next = entry + lstrlenW(entry) + 1;
1910 if ((p = wcschr( entry, ',' )))
1912 *p++ = 0;
1913 while (*p == ' ' || *p == '\t') p++;
1914 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
1916 if ((face = find_face_from_filename( entry, family_name )))
1918 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1919 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
1921 else TRACE( "Unable to find file %s family %s\n",
1922 debugstr_w(entry), debugstr_w(family_name) );
1925 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1927 NtClose( hkey );
1930 if ((shelldlg_name = get_gdi_font_subst( ms_shell_dlgW, -1, NULL )))
1932 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
1934 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
1936 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
1937 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
1939 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
1940 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
1941 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
1942 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
1946 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1948 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1949 that Tahoma has */
1951 system_font_link = add_gdi_font_link( systemW );
1952 if ((face = find_face_from_filename( tahoma_ttfW, tahomaW )))
1954 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
1955 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
1957 if ((font_link = find_gdi_font_link( tahomaW )))
1959 struct gdi_font_link_entry *entry;
1960 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
1961 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
1965 /* see TranslateCharsetInfo */
1966 BOOL translate_charset_info( DWORD *src, CHARSETINFO *cs, DWORD flags )
1968 unsigned int i;
1970 switch (flags)
1972 case TCI_SRCFONTSIG:
1973 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
1974 if (charset_info[i].fs.fsCsb[0] & src[0]) goto found;
1975 return FALSE;
1976 case TCI_SRCCODEPAGE:
1977 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
1978 if (PtrToUlong(src) == charset_info[i].ciACP) goto found;
1979 return FALSE;
1980 case TCI_SRCCHARSET:
1981 for (i = 0; i < ARRAY_SIZE(charset_info); i++)
1982 if (PtrToUlong(src) == charset_info[i].ciCharset) goto found;
1983 return FALSE;
1984 default:
1985 return FALSE;
1987 found:
1988 *cs = charset_info[i];
1989 return TRUE;
1992 /* font matching */
1994 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
1996 struct gdi_font_link *font_link;
1998 if (!face->scalable && !can_use_bitmap) return FALSE;
1999 if (!fs.fsCsb[0]) return TRUE;
2000 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
2001 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
2002 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
2003 return FALSE;
2006 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
2007 const LOGFONTW *lf, FONTSIGNATURE fs,
2008 BOOL can_use_bitmap )
2010 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
2011 unsigned int best_score = 4;
2012 int best_diff = 0;
2013 int it = !!lf->lfItalic;
2014 int bd = lf->lfWeight > 550;
2015 int height = lf->lfHeight;
2017 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2019 int italic = !!(face->ntmFlags & NTM_ITALIC);
2020 int bold = !!(face->ntmFlags & NTM_BOLD);
2021 int score = (italic ^ it) + (bold ^ bd);
2023 if (!can_select_face( face, fs, can_use_bitmap )) continue;
2024 if (score > best_score) continue;
2025 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
2026 best_score = score;
2027 best = face;
2028 if (best->scalable && best_score == 0) break;
2029 if (!best->scalable)
2031 int diff;
2032 if (height > 0)
2033 diff = height - (signed int)best->size.height;
2034 else
2035 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
2036 if (!best_bitmap ||
2037 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
2038 (best_diff < 0 && diff > best_diff))
2040 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
2041 best_diff = diff;
2042 best_bitmap = best;
2043 if (best_score == 0 && best_diff == 0) break;
2047 if (!best) return NULL;
2048 return best->scalable ? best : best_bitmap;
2051 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
2052 const LOGFONTW *lf, FONTSIGNATURE fs,
2053 BOOL can_use_bitmap, const WCHAR **orig_name )
2055 struct gdi_font_family *family;
2056 struct gdi_font_face *face;
2058 family = find_family_from_any_name( name );
2059 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
2060 if (subst)
2062 family = find_family_from_any_name( subst );
2063 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) goto found;
2066 /* search by full face name */
2067 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2068 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2069 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
2070 can_select_face( face, fs, can_use_bitmap ))
2071 return face;
2073 if ((family = find_family_from_font_links( name, subst, fs )))
2075 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
2077 return NULL;
2079 found:
2080 if (orig_name && family != face->family)
2081 *orig_name = family->family_name;
2082 return face;
2085 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
2086 BOOL can_use_bitmap, BOOL want_vertical )
2088 struct gdi_font_family *family;
2089 struct gdi_font_face *face;
2090 WCHAR name[LF_FACESIZE + 1];
2091 int i = 0;
2093 /* first try the family fallbacks */
2094 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
2096 if (want_vertical)
2098 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
2099 name[0] = '@';
2102 if (!(family = find_family_from_any_name(name))) continue;
2103 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
2105 /* otherwise try only scalable */
2106 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2108 if ((family->family_name[0] == '@') == !want_vertical) continue;
2109 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
2111 if (!can_use_bitmap) return NULL;
2112 /* then also bitmap fonts */
2113 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2115 if ((family->family_name[0] == '@') == !want_vertical) continue;
2116 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
2118 return NULL;
2121 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
2122 BOOL *substituted, const WCHAR **orig_name )
2124 BOOL want_vertical = (lf->lfFaceName[0] == '@');
2125 struct gdi_font_face *face;
2127 if (!translate_charset_info( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
2129 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
2130 csi->fs.fsCsb[0] = 0;
2133 if (lf->lfFaceName[0])
2135 int subst_charset;
2136 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
2138 if (subst)
2140 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
2141 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
2142 if (subst_charset != -1)
2143 translate_charset_info( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
2144 *substituted = TRUE;
2147 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap, orig_name )))
2148 return face;
2150 *substituted = FALSE; /* substitution is no longer relevant */
2152 /* If requested charset was DEFAULT_CHARSET then try using charset
2153 corresponding to the current ansi codepage */
2154 if (!csi->fs.fsCsb[0])
2156 if (!translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
2158 FIXME( "TCI failed on codepage %d\n", ansi_cp.CodePage );
2159 csi->fs.fsCsb[0] = 0;
2163 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
2164 if (csi->fs.fsCsb[0])
2166 csi->fs.fsCsb[0] = 0;
2167 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
2169 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
2170 return NULL;
2173 /* realized font objects */
2175 #define FIRST_FONT_HANDLE 1
2176 #define MAX_FONT_HANDLES 256
2178 struct font_handle_entry
2180 struct gdi_font *font;
2181 WORD generation; /* generation count for reusing handle values */
2184 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
2185 static struct font_handle_entry *next_free;
2186 static struct font_handle_entry *next_unused = font_handles;
2188 static struct font_handle_entry *handle_entry( DWORD handle )
2190 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
2192 if (idx < MAX_FONT_HANDLES)
2194 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
2195 return &font_handles[idx];
2197 if (handle) WARN( "invalid handle 0x%08x\n", handle );
2198 return NULL;
2201 static struct gdi_font *get_font_from_handle( DWORD handle )
2203 struct font_handle_entry *entry = handle_entry( handle );
2205 if (entry) return entry->font;
2206 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
2207 return NULL;
2210 static DWORD alloc_font_handle( struct gdi_font *font )
2212 struct font_handle_entry *entry;
2214 entry = next_free;
2215 if (entry)
2216 next_free = (struct font_handle_entry *)entry->font;
2217 else if (next_unused < font_handles + MAX_FONT_HANDLES)
2218 entry = next_unused++;
2219 else
2221 ERR( "out of realized font handles\n" );
2222 return 0;
2224 entry->font = font;
2225 if (++entry->generation == 0xffff) entry->generation = 1;
2226 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
2229 static void free_font_handle( DWORD handle )
2231 struct font_handle_entry *entry;
2233 if ((entry = handle_entry( handle )))
2235 entry->font = (struct gdi_font *)next_free;
2236 next_free = entry;
2240 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
2242 UINT len = file ? lstrlenW(file) : 0;
2243 struct gdi_font *font = calloc( 1, offsetof( struct gdi_font, file[len + 1] ));
2245 font->refcount = 1;
2246 font->matrix.eM11 = font->matrix.eM22 = 1.0;
2247 font->scale_y = 1;
2248 font->kern_count = -1;
2249 list_init( &font->child_fonts );
2251 if (file)
2253 FILE_NETWORK_OPEN_INFORMATION info;
2254 UNICODE_STRING nt_name;
2255 OBJECT_ATTRIBUTES attr;
2257 nt_name.Buffer = (WCHAR *)file;
2258 nt_name.Length = nt_name.MaximumLength = len * sizeof(WCHAR);
2260 attr.Length = sizeof(attr);
2261 attr.RootDirectory = 0;
2262 attr.Attributes = OBJ_CASE_INSENSITIVE;
2263 attr.ObjectName = &nt_name;
2264 attr.SecurityDescriptor = NULL;
2265 attr.SecurityQualityOfService = NULL;
2267 if (!NtQueryFullAttributesFile( &attr, &info ))
2269 font->writetime.dwLowDateTime = info.LastWriteTime.LowPart;
2270 font->writetime.dwHighDateTime = info.LastWriteTime.HighPart;
2271 font->data_size = info.EndOfFile.QuadPart;
2272 memcpy( font->file, file, len * sizeof(WCHAR) );
2275 else
2277 font->data_ptr = data_ptr;
2278 font->data_size = data_size;
2281 font->handle = alloc_font_handle( font );
2282 return font;
2285 static void free_gdi_font( struct gdi_font *font )
2287 DWORD i;
2288 struct gdi_font *child, *child_next;
2290 if (font->private) font_funcs->destroy_font( font );
2291 free_font_handle( font->handle );
2292 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
2294 list_remove( &child->entry );
2295 free_gdi_font( child );
2297 for (i = 0; i < font->gm_size; i++) free( font->gm[i] );
2298 free( font->otm.otmpFamilyName );
2299 free( font->otm.otmpStyleName );
2300 free( font->otm.otmpFaceName );
2301 free( font->otm.otmpFullName );
2302 free( font->gm );
2303 free( font->kern_pairs );
2304 free( font->gsub_table );
2305 free( font );
2308 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
2310 return font->use_logfont_name ? font->lf.lfFaceName : (WCHAR *)font->otm.otmpFamilyName;
2313 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
2314 const LOGFONTW *lf )
2316 struct gdi_font *font;
2318 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
2319 font->fs = face->fs;
2320 font->lf = *lf;
2321 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
2322 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
2323 font->scalable = face->scalable;
2324 font->face_index = face->face_index;
2325 font->ntmFlags = face->ntmFlags;
2326 font->aa_flags = HIWORD( face->flags );
2327 if (!family_name) family_name = face->family->family_name;
2328 font->otm.otmpFamilyName = (char *)wcsdup( family_name );
2329 font->otm.otmpStyleName = (char *)wcsdup( face->style_name );
2330 font->otm.otmpFaceName = (char *)wcsdup( face->full_name );
2331 return font;
2334 struct glyph_metrics
2336 GLYPHMETRICS gm;
2337 ABC abc; /* metrics of the unrotated char */
2338 BOOL init;
2341 #define GM_BLOCK_SIZE 128
2343 /* TODO: GGO format support */
2344 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
2346 UINT block = index / GM_BLOCK_SIZE;
2347 UINT entry = index % GM_BLOCK_SIZE;
2349 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
2351 *gm = font->gm[block][entry].gm;
2352 *abc = font->gm[block][entry].abc;
2354 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2355 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
2356 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2357 return TRUE;
2360 return FALSE;
2363 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
2364 const GLYPHMETRICS *gm, const ABC *abc )
2366 UINT block = index / GM_BLOCK_SIZE;
2367 UINT entry = index % GM_BLOCK_SIZE;
2369 if (block >= font->gm_size)
2371 struct glyph_metrics **ptr;
2373 if (!(ptr = realloc( font->gm, (block + 1) * sizeof(*ptr) ))) return;
2374 memset( ptr + font->gm_size, 0, (block + 1 - font->gm_size) * sizeof(*ptr) );
2375 font->gm_size = block + 1;
2376 font->gm = ptr;
2378 if (!font->gm[block])
2380 font->gm[block] = calloc( sizeof(**font->gm), GM_BLOCK_SIZE );
2381 if (!font->gm[block]) return;
2383 font->gm[block][entry].gm = *gm;
2384 font->gm[block][entry].abc = *abc;
2385 font->gm[block][entry].init = TRUE;
2389 /* GSUB table support */
2391 typedef struct
2393 DWORD version;
2394 WORD ScriptList;
2395 WORD FeatureList;
2396 WORD LookupList;
2397 } GSUB_Header;
2399 typedef struct
2401 CHAR ScriptTag[4];
2402 WORD Script;
2403 } GSUB_ScriptRecord;
2405 typedef struct
2407 WORD ScriptCount;
2408 GSUB_ScriptRecord ScriptRecord[1];
2409 } GSUB_ScriptList;
2411 typedef struct
2413 CHAR LangSysTag[4];
2414 WORD LangSys;
2415 } GSUB_LangSysRecord;
2417 typedef struct
2419 WORD DefaultLangSys;
2420 WORD LangSysCount;
2421 GSUB_LangSysRecord LangSysRecord[1];
2422 } GSUB_Script;
2424 typedef struct
2426 WORD LookupOrder; /* Reserved */
2427 WORD ReqFeatureIndex;
2428 WORD FeatureCount;
2429 WORD FeatureIndex[1];
2430 } GSUB_LangSys;
2432 typedef struct
2434 CHAR FeatureTag[4];
2435 WORD Feature;
2436 } GSUB_FeatureRecord;
2438 typedef struct
2440 WORD FeatureCount;
2441 GSUB_FeatureRecord FeatureRecord[1];
2442 } GSUB_FeatureList;
2444 typedef struct
2446 WORD FeatureParams; /* Reserved */
2447 WORD LookupCount;
2448 WORD LookupListIndex[1];
2449 } GSUB_Feature;
2451 typedef struct
2453 WORD LookupCount;
2454 WORD Lookup[1];
2455 } GSUB_LookupList;
2457 typedef struct
2459 WORD LookupType;
2460 WORD LookupFlag;
2461 WORD SubTableCount;
2462 WORD SubTable[1];
2463 } GSUB_LookupTable;
2465 typedef struct
2467 WORD CoverageFormat;
2468 WORD GlyphCount;
2469 WORD GlyphArray[1];
2470 } GSUB_CoverageFormat1;
2472 typedef struct
2474 WORD Start;
2475 WORD End;
2476 WORD StartCoverageIndex;
2477 } GSUB_RangeRecord;
2479 typedef struct
2481 WORD CoverageFormat;
2482 WORD RangeCount;
2483 GSUB_RangeRecord RangeRecord[1];
2484 } GSUB_CoverageFormat2;
2486 typedef struct
2488 WORD SubstFormat; /* = 1 */
2489 WORD Coverage;
2490 WORD DeltaGlyphID;
2491 } GSUB_SingleSubstFormat1;
2493 typedef struct
2495 WORD SubstFormat; /* = 2 */
2496 WORD Coverage;
2497 WORD GlyphCount;
2498 WORD Substitute[1];
2499 } GSUB_SingleSubstFormat2;
2501 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
2503 GSUB_ScriptList *script;
2504 GSUB_Script *deflt = NULL;
2505 int i;
2507 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
2508 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
2509 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
2511 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
2512 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
2513 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
2514 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
2516 return deflt;
2519 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
2521 int i, offset;
2522 GSUB_LangSys *lang;
2524 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
2526 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
2528 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
2529 lang = (GSUB_LangSys *)((BYTE *)script + offset);
2530 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
2532 offset = GET_BE_WORD(script->DefaultLangSys);
2533 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
2534 return NULL;
2537 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
2539 int i;
2540 const GSUB_FeatureList *feature;
2542 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
2543 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
2544 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
2546 int index = GET_BE_WORD(lang->FeatureIndex[i]);
2547 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
2548 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
2550 return NULL;
2553 static const char *get_opentype_script( const struct gdi_font *font )
2556 * I am not sure if this is the correct way to generate our script tag
2558 switch (font->charset)
2560 case ANSI_CHARSET: return "latn";
2561 case BALTIC_CHARSET: return "latn"; /* ?? */
2562 case CHINESEBIG5_CHARSET: return "hani";
2563 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
2564 case GB2312_CHARSET: return "hani";
2565 case GREEK_CHARSET: return "grek";
2566 case HANGUL_CHARSET: return "hang";
2567 case RUSSIAN_CHARSET: return "cyrl";
2568 case SHIFTJIS_CHARSET: return "kana";
2569 case TURKISH_CHARSET: return "latn"; /* ?? */
2570 case VIETNAMESE_CHARSET: return "latn";
2571 case JOHAB_CHARSET: return "latn"; /* ?? */
2572 case ARABIC_CHARSET: return "arab";
2573 case HEBREW_CHARSET: return "hebr";
2574 case THAI_CHARSET: return "thai";
2575 default: return "latn";
2579 static void *get_GSUB_vert_feature( struct gdi_font *font )
2581 GSUB_Header *header;
2582 GSUB_Script *script;
2583 GSUB_LangSys *language;
2584 GSUB_Feature *feature;
2585 DWORD length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2587 if (length == GDI_ERROR) return NULL;
2589 header = malloc( length );
2590 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2591 TRACE( "Loaded GSUB table of %i bytes\n", length );
2593 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2595 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2597 feature = GSUB_get_feature( header, language, "vrt2" );
2598 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2599 if (feature)
2601 font->gsub_table = header;
2602 return feature;
2604 TRACE("vrt2/vert feature not found\n");
2606 else TRACE("Language not found\n");
2608 else TRACE("Script not found\n");
2610 free( header );
2611 return NULL;
2614 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2616 GSUB_CoverageFormat1 *cf1 = table;
2618 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2620 int i, count = GET_BE_WORD(cf1->GlyphCount);
2622 TRACE("Coverage Format 1, %i glyphs\n",count);
2623 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2624 return -1;
2626 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2628 int i, count;
2629 GSUB_CoverageFormat2 *cf2 = table;
2631 count = GET_BE_WORD(cf2->RangeCount);
2632 TRACE("Coverage Format 2, %i ranges\n",count);
2633 for (i = 0; i < count; i++)
2635 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2636 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2637 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2639 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2640 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2643 return -1;
2645 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2647 return -1;
2650 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2652 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2653 int i, j, offset;
2655 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2656 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2658 GSUB_LookupTable *look;
2659 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2660 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2661 TRACE("type %i, flag %x, subtables %i\n",
2662 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2663 if (GET_BE_WORD(look->LookupType) == 1)
2665 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2667 GSUB_SingleSubstFormat1 *ssf1;
2668 offset = GET_BE_WORD(look->SubTable[j]);
2669 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2670 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2672 int offset = GET_BE_WORD(ssf1->Coverage);
2673 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2674 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2676 TRACE(" Glyph 0x%x ->",glyph);
2677 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2678 TRACE(" 0x%x\n",glyph);
2681 else
2683 GSUB_SingleSubstFormat2 *ssf2;
2684 int index, offset;
2686 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2687 offset = GET_BE_WORD(ssf1->Coverage);
2688 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2689 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2690 TRACE(" Coverage index %i\n",index);
2691 if (index != -1)
2693 TRACE(" Glyph is 0x%x ->",glyph);
2694 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2695 TRACE("0x%x\n",glyph);
2700 else FIXME("We only handle SubType 1\n");
2702 return glyph;
2705 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2707 if (!glyph) return glyph;
2708 if (!font->gsub_table) return glyph;
2709 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2712 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2714 FONTSIGNATURE fs = {{0}};
2715 struct gdi_font *child;
2716 struct gdi_font_face *face;
2718 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE, NULL ))) return;
2720 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2721 child->matrix = font->matrix;
2722 child->can_use_bitmap = font->can_use_bitmap;
2723 child->scale_y = font->scale_y;
2724 child->aveWidth = font->aveWidth;
2725 child->charset = font->charset;
2726 child->codepage = font->codepage;
2727 child->base_font = font;
2728 list_add_tail( &font->child_fonts, &child->entry );
2729 TRACE( "created child font %p for base %p\n", child, font );
2732 static void create_child_font_list( struct gdi_font *font )
2734 struct gdi_font_link *font_link;
2735 struct gdi_font_link_entry *entry;
2736 const WCHAR* font_name = (WCHAR *)font->otm.otmpFaceName;
2738 if ((font_link = find_gdi_font_link( font_name )))
2740 TRACE("found entry in system list\n");
2741 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2742 add_child_font( font, entry->family_name );
2745 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2746 * Sans Serif. This is how asian windows get default fallbacks for fonts
2748 if (ansi_cp.MaximumCharacterSize == 2 && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2749 facename_compare( font_name, microsoft_sans_serifW, -1 ) != 0)
2751 if ((font_link = find_gdi_font_link( microsoft_sans_serifW )))
2753 TRACE("found entry in default fallback list\n");
2754 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2755 add_child_font( font, entry->family_name );
2760 /* font cache */
2762 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2763 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2764 static unsigned int unused_font_count;
2765 #define UNUSED_CACHE_SIZE 10
2767 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2768 const FMAT2 *matrix, BOOL can_use_bitmap )
2770 if (font->hash != hash) return TRUE;
2771 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2772 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2773 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2774 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2777 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2779 DWORD hash = 0, *ptr, two_chars;
2780 WORD *pwc;
2781 unsigned int i;
2783 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2784 hash ^= *ptr;
2785 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2786 hash ^= *ptr;
2787 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2789 two_chars = *ptr;
2790 pwc = (WCHAR *)&two_chars;
2791 if(!*pwc) break;
2792 *pwc = towupper(*pwc);
2793 pwc++;
2794 *pwc = towupper(*pwc);
2795 hash ^= two_chars;
2796 if(!*pwc) break;
2798 hash ^= !can_use_bitmap;
2799 return hash;
2802 static void cache_gdi_font( struct gdi_font *font )
2804 static DWORD cache_num = 1;
2806 font->cache_num = cache_num++;
2807 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2808 list_add_head( &gdi_font_list, &font->entry );
2809 TRACE( "font %p\n", font );
2812 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2814 struct gdi_font *font;
2815 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2817 /* try the in-use list */
2818 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2820 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2821 list_remove( &font->entry );
2822 list_add_head( &gdi_font_list, &font->entry );
2823 if (!font->refcount++)
2825 list_remove( &font->unused_entry );
2826 unused_font_count--;
2828 return font;
2830 return NULL;
2833 static void release_gdi_font( struct gdi_font *font )
2835 if (!font) return;
2837 TRACE( "font %p\n", font );
2839 /* add it to the unused list */
2840 pthread_mutex_lock( &font_lock );
2841 if (!--font->refcount)
2843 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2844 if (unused_font_count > UNUSED_CACHE_SIZE)
2846 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2847 TRACE( "freeing %p\n", font );
2848 list_remove( &font->entry );
2849 list_remove( &font->unused_entry );
2850 free_gdi_font( font );
2852 else unused_font_count++;
2854 pthread_mutex_unlock( &font_lock );
2857 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2859 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2861 set_reg_ascii_value( hkey, "Courier", fl->courier );
2862 set_reg_ascii_value( hkey, "MS Serif", fl->serif );
2863 set_reg_ascii_value( hkey, "MS Sans Serif", sserif );
2864 set_reg_ascii_value( hkey, "Small Fonts", fl->small );
2867 static void set_value_key(HKEY hkey, const char *name, const char *value)
2869 if (value)
2870 set_reg_ascii_value( hkey, name, value );
2871 else if (name)
2873 WCHAR nameW[64];
2874 asciiz_to_unicode( nameW, name );
2875 reg_delete_value( hkey, nameW );
2879 static void update_font_association_info(void)
2881 static const WCHAR associated_charsetW[] =
2882 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
2884 if (ansi_cp.MaximumCharacterSize == 2)
2886 HKEY hkey;
2887 if ((hkey = reg_create_key( NULL, font_assoc_keyW, sizeof(font_assoc_keyW), 0, NULL )))
2889 HKEY hsubkey;
2890 if ((hsubkey = reg_create_key( hkey, associated_charsetW, sizeof(associated_charsetW),
2891 0, NULL )))
2893 switch (ansi_cp.CodePage)
2895 case 932:
2896 set_value_key(hsubkey, "ANSI(00)", "NO");
2897 set_value_key(hsubkey, "OEM(FF)", "NO");
2898 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2899 break;
2900 case 936:
2901 case 949:
2902 case 950:
2903 set_value_key(hsubkey, "ANSI(00)", "YES");
2904 set_value_key(hsubkey, "OEM(FF)", "YES");
2905 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2906 break;
2908 NtClose( hsubkey );
2911 /* TODO: Associated DefaultFonts */
2913 NtClose( hkey );
2916 else
2917 reg_delete_tree( NULL, font_assoc_keyW, sizeof(font_assoc_keyW) );
2920 static void set_multi_value_key( HKEY hkey, const WCHAR *name, const char *value, DWORD len )
2922 WCHAR valueW[256];
2923 ascii_to_unicode( valueW, value, len );
2924 if (value)
2925 set_reg_value( hkey, name, REG_MULTI_SZ, valueW, len * sizeof(WCHAR) );
2926 else if (name)
2927 reg_delete_value( hkey, name );
2930 static void update_font_system_link_info(void)
2932 HKEY hkey;
2934 if ((hkey = reg_create_key( NULL, system_link_keyW, sizeof(system_link_keyW), 0, NULL )))
2936 const char *link;
2937 DWORD len, i;
2939 for (i = 0; i < ARRAY_SIZE(default_system_link); ++i)
2941 const struct system_link_reg *link_reg = &default_system_link[i];
2943 link = link_reg->link_non_cjk;
2944 len = link_reg->link_non_cjk_len;
2946 if (link_reg->locale_dependent)
2948 switch (ansi_cp.CodePage)
2950 case 932:
2951 link = link_reg->link_jp;
2952 len = link_reg->link_jp_len;
2953 break;
2954 case 936:
2955 link = link_reg->link_sc;
2956 len = link_reg->link_sc_len;
2957 break;
2958 case 949:
2959 link = link_reg->link_kr;
2960 len = link_reg->link_kr_len;
2961 break;
2962 case 950:
2963 link = link_reg->link_tc;
2964 len = link_reg->link_tc_len;
2965 break;
2968 set_multi_value_key(hkey, link_reg->font_name, link, len);
2970 NtClose( hkey );
2974 static void update_codepage( UINT screen_dpi )
2976 USHORT utf8_hdr[2] = { 0, CP_UTF8 };
2977 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[40 * sizeof(WCHAR)])];
2978 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
2979 char cpbuf[40];
2980 WCHAR cpbufW[40];
2981 HKEY hkey;
2982 DWORD size;
2983 UINT i;
2984 DWORD font_dpi = 0;
2985 BOOL done = FALSE, cp_match = FALSE;
2987 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
2989 size = query_reg_value( wine_fonts_key, log_pixelsW, info, sizeof(value_buffer) );
2990 if (size == sizeof(DWORD) && info->Type == REG_DWORD)
2991 font_dpi = *(DWORD *)info->Data;
2993 RtlInitCodePageTable( utf8_hdr, &utf8_cp );
2994 if (NtCurrentTeb()->Peb->AnsiCodePageData)
2995 RtlInitCodePageTable( NtCurrentTeb()->Peb->AnsiCodePageData, &ansi_cp );
2996 else
2997 ansi_cp = utf8_cp;
2998 if (NtCurrentTeb()->Peb->OemCodePageData)
2999 RtlInitCodePageTable( NtCurrentTeb()->Peb->OemCodePageData, &oem_cp );
3000 else
3001 oem_cp = utf8_cp;
3002 sprintf( cpbuf, "%u,%u", ansi_cp.CodePage, oem_cp.CodePage );
3003 asciiz_to_unicode( cpbufW, cpbuf );
3005 if (query_reg_ascii_value( wine_fonts_key, "Codepages", info, sizeof(value_buffer) ))
3007 cp_match = !wcscmp( (const WCHAR *)info->Data, cpbufW );
3008 if (cp_match && screen_dpi == font_dpi) return; /* already set correctly */
3009 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3010 debugstr_w((const WCHAR *)info->Data), font_dpi, ansi_cp.CodePage, oem_cp.CodePage, screen_dpi );
3012 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3013 ansi_cp.CodePage, oem_cp.CodePage, screen_dpi);
3015 set_reg_ascii_value( wine_fonts_key, "Codepages", cpbuf );
3016 set_reg_value( wine_fonts_key, log_pixelsW, REG_DWORD, &screen_dpi, sizeof(screen_dpi) );
3018 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
3020 if (nls_update_font_list[i].ansi_cp == ansi_cp.CodePage &&
3021 nls_update_font_list[i].oem_cp == oem_cp.CodePage)
3023 HKEY software_hkey;
3024 if ((software_hkey = reg_create_key( NULL, software_config_keyW,
3025 sizeof(software_config_keyW), 0, NULL )))
3027 static const WCHAR fontsW[] = {'F','o','n','t','s'};
3028 hkey = reg_create_key( software_hkey, fontsW, sizeof(fontsW), 0, NULL );
3029 NtClose( software_hkey );
3030 if (hkey)
3032 set_reg_ascii_value( hkey, "OEMFONT.FON", nls_update_font_list[i].oem );
3033 set_reg_ascii_value( hkey, "FIXEDFON.FON", nls_update_font_list[i].fixed );
3034 set_reg_ascii_value( hkey, "FONTS.FON", nls_update_font_list[i].system );
3035 NtClose( hkey );
3038 if ((hkey = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW),
3039 0, NULL )))
3041 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3042 NtClose( hkey );
3044 if ((hkey = reg_create_key( NULL, fonts_win9x_config_keyW,
3045 sizeof(fonts_win9x_config_keyW), 0, NULL )))
3047 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3048 NtClose( hkey );
3050 /* Only update these if the Codepage changed. */
3051 if (!cp_match &&
3052 (hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
3053 0, NULL )))
3055 set_reg_ascii_value( hkey, "MS Shell Dlg", nls_update_font_list[i].shelldlg );
3056 set_reg_ascii_value( hkey, "Tms Rmn", nls_update_font_list[i].tmsrmn );
3058 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3059 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3060 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3061 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3062 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3063 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3064 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3065 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3067 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3068 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3069 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3071 NtClose( hkey );
3073 done = TRUE;
3075 else
3077 /* Delete the FontSubstitutes from other locales */
3078 if ((hkey = reg_create_key( NULL, font_substitutes_keyW, sizeof(font_substitutes_keyW),
3079 0, NULL )))
3081 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3082 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3083 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3084 NtClose( hkey );
3088 if (!done)
3089 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp.CodePage, oem_cp.CodePage);
3091 /* update locale dependent font association info and font system link info in registry.
3092 update only when codepages changed, not logpixels. */
3093 if (!cp_match)
3095 update_font_association_info();
3096 update_font_system_link_info();
3101 /*************************************************************
3102 * font_CreateDC
3104 static BOOL CDECL font_CreateDC( PHYSDEV *dev, LPCWSTR device, LPCWSTR output,
3105 const DEVMODEW *devmode )
3107 struct font_physdev *physdev;
3109 if (!font_funcs) return TRUE;
3110 if (!(physdev = calloc( 1, sizeof(*physdev) ))) return FALSE;
3111 push_dc_driver( dev, &physdev->dev, &font_driver );
3112 return TRUE;
3116 /*************************************************************
3117 * font_DeleteDC
3119 static BOOL CDECL font_DeleteDC( PHYSDEV dev )
3121 struct font_physdev *physdev = get_font_dev( dev );
3123 release_gdi_font( physdev->font );
3124 free( physdev );
3125 return TRUE;
3129 struct gdi_font_enum_data
3131 ENUMLOGFONTEXW elf;
3132 NEWTEXTMETRICEXW ntm;
3135 struct enum_charset
3137 DWORD mask;
3138 DWORD charset;
3139 DWORD script;
3142 static BOOL is_complex_script_ansi_cp(void)
3144 return (ansi_cp.CodePage == 874 /* Thai */
3145 || ansi_cp.CodePage == 1255 /* Hebrew */
3146 || ansi_cp.CodePage == 1256 /* Arabic */
3150 /***************************************************
3151 * create_enum_charset_list
3153 * This function creates charset enumeration list because in DEFAULT_CHARSET
3154 * case, the ANSI codepage's charset takes precedence over other charsets.
3155 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
3156 * This function works as a filter other than DEFAULT_CHARSET case.
3158 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
3160 struct enum_charset *start = list;
3161 CHARSETINFO csi;
3162 int i;
3164 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && csi.fs.fsCsb[0] != 0)
3166 list->mask = csi.fs.fsCsb[0];
3167 list->charset = csi.ciCharset;
3168 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
3169 list++;
3171 else /* charset is DEFAULT_CHARSET or invalid. */
3173 DWORD mask = 0;
3175 /* Set the current codepage's charset as the first element. */
3176 if (!is_complex_script_ansi_cp() &&
3177 translate_charset_info( (DWORD *)(INT_PTR)ansi_cp.CodePage, &csi, TCI_SRCCODEPAGE ) &&
3178 csi.fs.fsCsb[0] != 0)
3180 list->mask = csi.fs.fsCsb[0];
3181 list->charset = csi.ciCharset;
3182 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
3183 mask |= csi.fs.fsCsb[0];
3184 list++;
3187 /* Fill out left elements. */
3188 for (i = 0; i < 32; i++)
3190 FONTSIGNATURE fs;
3191 fs.fsCsb[0] = 1u << i;
3192 fs.fsCsb[1] = 0;
3193 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
3194 if (!translate_charset_info( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
3195 continue; /* skip, this is an invalid fsCsb bit. */
3196 list->mask = fs.fsCsb[0];
3197 list->charset = csi.ciCharset;
3198 list->script = i;
3199 mask |= fs.fsCsb[0];
3200 list++;
3202 /* add catch all mask for remaining bits */
3203 if (~mask)
3205 list->mask = ~mask;
3206 list->charset = DEFAULT_CHARSET;
3207 list->script = 33; /* other */
3208 list++;
3211 return list - start;
3214 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
3216 UINT ret = 0;
3218 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
3219 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
3220 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
3221 return ret;
3224 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
3226 struct gdi_font *font;
3227 LOGFONTW lf = { .lfHeight = -4096 /* preferable EM Square size */ };
3229 if (!face->scalable) lf.lfHeight = 0;
3231 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
3233 if (!font_funcs->load_font( font ))
3235 free_gdi_font( font );
3236 return FALSE;
3239 if (font->scalable && -lf.lfHeight % font->otm.otmEMSquare != 0)
3241 /* reload with the original EM Square size */
3242 lf.lfHeight = -font->otm.otmEMSquare;
3243 free_gdi_font( font );
3245 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
3246 if (!font_funcs->load_font( font ))
3248 free_gdi_font( font );
3249 return FALSE;
3253 if (font_funcs->set_outline_text_metrics( font ))
3255 static const DWORD ntm_ppem = 32;
3256 UINT cell_height;
3258 #define TM font->otm.otmTextMetrics
3259 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
3260 cell_height = TM.tmHeight / ( -lf.lfHeight / font->otm.otmEMSquare );
3261 ntm->ntmTm.tmHeight = muldiv( ntm_ppem, cell_height, font->otm.otmEMSquare );
3262 ntm->ntmTm.tmAscent = SCALE_NTM( TM.tmAscent );
3263 ntm->ntmTm.tmDescent = ntm->ntmTm.tmHeight - ntm->ntmTm.tmAscent;
3264 ntm->ntmTm.tmInternalLeading = SCALE_NTM( TM.tmInternalLeading );
3265 ntm->ntmTm.tmExternalLeading = SCALE_NTM( TM.tmExternalLeading );
3266 ntm->ntmTm.tmAveCharWidth = SCALE_NTM( TM.tmAveCharWidth );
3267 ntm->ntmTm.tmMaxCharWidth = SCALE_NTM( TM.tmMaxCharWidth );
3269 memcpy((char *)&ntm->ntmTm + offsetof( TEXTMETRICW, tmWeight ),
3270 (const char *)&TM + offsetof( TEXTMETRICW, tmWeight ),
3271 sizeof(TEXTMETRICW) - offsetof( TEXTMETRICW, tmWeight ));
3272 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
3273 ntm->ntmTm.ntmCellHeight = cell_height;
3274 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
3275 #undef SCALE_NTM
3276 #undef TM
3278 else if (font_funcs->set_bitmap_text_metrics( font ))
3280 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
3281 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
3282 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
3283 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
3285 ntm->ntmTm.ntmFlags = font->ntmFlags;
3286 ntm->ntmFontSig = font->fs;
3288 elf->elfLogFont.lfEscapement = 0;
3289 elf->elfLogFont.lfOrientation = 0;
3290 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
3291 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
3292 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
3293 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
3294 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
3295 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
3296 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
3297 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3298 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3299 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
3300 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3301 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
3302 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
3303 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
3305 free_gdi_font( font );
3306 return TRUE;
3309 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
3311 struct gdi_font_face *face;
3313 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
3314 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3315 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
3316 return FALSE;
3319 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
3321 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
3322 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
3325 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
3326 struct enum_charset *list, DWORD count, FONTENUMPROCW proc, LPARAM lparam,
3327 const WCHAR *subst )
3329 ENUMLOGFONTEXW elf;
3330 NEWTEXTMETRICEXW ntm;
3331 DWORD type, i;
3333 if (!face->cached_enum_data)
3335 struct gdi_font_enum_data *data;
3337 if (!(data = calloc( 1, sizeof(*data) )) ||
3338 !get_face_enum_data( face, &data->elf, &data->ntm ))
3340 free( data );
3341 return TRUE;
3343 face->cached_enum_data = data;
3346 elf = face->cached_enum_data->elf;
3347 ntm = face->cached_enum_data->ntm;
3348 type = get_font_type( &ntm );
3350 /* font replacement */
3351 if (family != face->family)
3353 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
3354 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
3356 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
3358 for (i = 0; i < count; i++)
3360 if (face->fs.fsCsb[0] == 0) /* OEM */
3362 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3363 elf.elfScript[0] = 32;
3364 i = count; /* break out of loop after enumeration */
3366 else
3368 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
3369 /* use the DEFAULT_CHARSET case only if no other charset is present */
3370 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
3371 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
3372 /* caller may fill elfScript with the actual string, see load_script_name */
3373 elf.elfScript[0] = list[i].script;
3375 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3376 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3377 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
3378 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, ntm.ntmTm.ntmFlags );
3379 /* release section before callback (FIXME) */
3380 pthread_mutex_unlock( &font_lock );
3381 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
3382 pthread_mutex_lock( &font_lock );
3384 return TRUE;
3387 /*************************************************************
3388 * font_EnumFonts
3390 static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
3392 struct gdi_font_family *family;
3393 struct gdi_font_face *face;
3394 struct enum_charset enum_charsets[32];
3395 DWORD count, charset;
3397 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
3399 count = create_enum_charset_list( charset, enum_charsets );
3401 pthread_mutex_lock( &font_lock );
3403 if (lf && lf->lfFaceName[0])
3405 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
3406 const WCHAR *orig_name = NULL;
3408 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
3409 if (face_name)
3411 orig_name = lf->lfFaceName;
3412 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
3414 else face_name = lf->lfFaceName;
3416 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3418 if (!family_matches(family, face_name)) continue;
3419 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
3421 if (!face_matches( family->family_name, face, face_name )) continue;
3422 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
3423 return FALSE;
3427 else
3429 TRACE( "charset %d\n", charset );
3430 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
3432 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
3433 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
3434 return FALSE;
3437 pthread_mutex_unlock( &font_lock );
3438 return TRUE;
3442 static BOOL check_unicode_tategaki( WCHAR ch )
3444 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
3445 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
3447 /* We only reach this code if typographical substitution did not occur */
3448 /* Type: U or Type: Tu */
3449 return (orientation == 1 || orientation == 3);
3452 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
3454 UINT index;
3456 if (glyph < 0x100) glyph += 0xf000;
3457 /* there are a number of old pre-Unicode "broken" TTFs, which
3458 do have symbols at U+00XX instead of U+f0XX */
3459 index = glyph;
3460 font_funcs->get_glyph_index( font, &index, FALSE );
3461 if (!index)
3463 index = glyph - 0xf000;
3464 font_funcs->get_glyph_index( font, &index, FALSE );
3466 return index;
3469 CPTABLEINFO *get_cptable( WORD cp )
3471 static CPTABLEINFO tables[100];
3472 unsigned int i;
3473 USHORT *ptr;
3474 SIZE_T size;
3476 if (cp == CP_ACP) return &ansi_cp;
3477 if (cp == CP_UTF8) return &utf8_cp;
3479 for (i = 0; i < ARRAY_SIZE(tables) && tables[i].CodePage; i++)
3480 if (tables[i].CodePage == cp) return &tables[i];
3481 if (NtGetNlsSectionPtr( 11, cp, NULL, (void **)&ptr, &size )) return NULL;
3482 if (i == ARRAY_SIZE(tables))
3484 ERR( "too many code pages\n" );
3485 return NULL;
3487 RtlInitCodePageTable( ptr, &tables[i] );
3488 return &tables[i];
3491 DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, DWORD srclen )
3493 DWORD ret;
3495 if (info->CodePage == CP_UTF8)
3496 RtlUnicodeToUTF8N( dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3497 else
3498 RtlUnicodeToCustomCPN( info, dst, dstlen, &ret, src, srclen * sizeof(WCHAR) );
3500 return ret;
3503 DWORD win32u_wctomb_size( CPTABLEINFO *info, const WCHAR *src, DWORD srclen )
3505 DWORD ret;
3507 if (info->CodePage == CP_UTF8)
3509 RtlUnicodeToUTF8N( NULL, 0, &ret, src, srclen * sizeof(WCHAR) );
3511 else if(info->DBCSCodePage)
3513 WCHAR *uni2cp = info->WideCharTable;
3514 for (ret = srclen; srclen; srclen--, src++)
3515 if (uni2cp[*src] & 0xff00) ret++;
3517 else
3519 ret = srclen;
3522 return ret;
3525 DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *src, DWORD srclen )
3527 DWORD ret;
3529 if (info->CodePage == CP_UTF8)
3530 RtlUTF8ToUnicodeN( dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3531 else
3532 RtlCustomCPToUnicodeN( info, dst, dstlen * sizeof(WCHAR), &ret, src, srclen );
3534 return ret / sizeof(WCHAR);
3537 static BOOL wc_to_index( UINT cp, WCHAR wc, unsigned char *dst, BOOL allow_default )
3539 const CPTABLEINFO *info;
3541 if (!(info = get_cptable( cp ))) return FALSE;
3543 if (info->CodePage == CP_UTF8)
3545 if (wc < 0x80)
3547 *dst = wc;
3548 return TRUE;
3550 if (!allow_default) return FALSE;
3551 *dst = info->DefaultChar;
3552 return TRUE;
3554 else if (info->DBCSCodePage)
3556 WCHAR *uni2cp = info->WideCharTable;
3557 if (uni2cp[wc] & 0xff00) return FALSE;
3558 *dst = uni2cp[wc];
3560 else
3562 char *uni2cp = info->WideCharTable;
3563 *dst = uni2cp[wc];
3566 if (info->MultiByteTable[*dst] != wc)
3568 if (!allow_default) return FALSE;
3569 *dst = info->DefaultChar;
3572 return TRUE;
3575 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
3577 WCHAR wc = glyph;
3578 unsigned char ch;
3580 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
3582 if (font->codepage == CP_SYMBOL)
3584 glyph = get_glyph_index_symbol( font, wc );
3585 if (!glyph)
3587 if (wc_to_index( CP_ACP, wc, &ch, TRUE ))
3588 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
3591 else if (wc_to_index( font->codepage, wc, &ch, FALSE ))
3593 glyph = (unsigned char)ch;
3594 font_funcs->get_glyph_index( font, &glyph, FALSE );
3596 else return 0;
3598 return glyph;
3601 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
3603 struct gdi_font *child;
3604 UINT res;
3606 if ((res = get_glyph_index( *font, glyph ))) return res;
3607 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
3609 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
3611 if (!child->private && !font_funcs->load_font( child )) continue;
3612 if ((res = get_glyph_index( child, glyph )))
3614 *font = child;
3615 return res;
3618 return 0;
3621 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3622 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
3623 const MAT2 *mat )
3625 GLYPHMETRICS gm;
3626 ABC abc;
3627 DWORD ret = 1;
3628 UINT index = glyph;
3629 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
3631 if (format & GGO_GLYPH_INDEX)
3633 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3634 as glyph index. "Treasure Adventure Game" depends on this. */
3635 font_funcs->get_glyph_index( font, &index, FALSE );
3636 format &= ~GGO_GLYPH_INDEX;
3637 /* TODO: Window also turns off tategaki for glyphs passed in by index
3638 if their unicode code points fall outside of the range that is
3639 rotated. */
3641 else
3643 index = get_glyph_index_linked( &font, glyph );
3644 if (tategaki)
3646 UINT orig = index;
3647 index = get_GSUB_vert_glyph( font, index );
3648 if (index == orig) tategaki = check_unicode_tategaki( glyph );
3652 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
3654 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
3655 goto done;
3657 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
3658 if (ret == GDI_ERROR) return ret;
3660 if (format == GGO_METRICS && !mat)
3661 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
3663 done:
3664 if (gm_ret) *gm_ret = gm;
3665 if (abc_ret) *abc_ret = abc;
3666 return ret;
3670 /*************************************************************
3671 * font_FontIsLinked
3673 static BOOL CDECL font_FontIsLinked( PHYSDEV dev )
3675 struct font_physdev *physdev = get_font_dev( dev );
3677 if (!physdev->font)
3679 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
3680 return dev->funcs->pFontIsLinked( dev );
3682 return !list_empty( &physdev->font->child_fonts );
3686 /*************************************************************
3687 * font_GetCharABCWidths
3689 static BOOL CDECL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT count,
3690 WCHAR *chars, ABC *buffer )
3692 struct font_physdev *physdev = get_font_dev( dev );
3693 UINT c, i;
3695 if (!physdev->font)
3697 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3698 return dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
3701 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3703 pthread_mutex_lock( &font_lock );
3704 for (i = 0; i < count; i++)
3706 c = chars ? chars[i] : first + i;
3707 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &buffer[i], 0, NULL, NULL );
3709 pthread_mutex_unlock( &font_lock );
3710 return TRUE;
3714 /*************************************************************
3715 * font_GetCharABCWidthsI
3717 static BOOL CDECL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3719 struct font_physdev *physdev = get_font_dev( dev );
3720 UINT c;
3722 if (!physdev->font)
3724 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3725 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3728 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3730 pthread_mutex_lock( &font_lock );
3731 for (c = 0; c < count; c++, buffer++)
3732 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3733 NULL, buffer, 0, NULL, NULL );
3734 pthread_mutex_unlock( &font_lock );
3735 return TRUE;
3739 /*************************************************************
3740 * font_GetCharWidth
3742 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT count,
3743 const WCHAR *chars, INT *buffer )
3745 struct font_physdev *physdev = get_font_dev( dev );
3746 UINT c, i;
3747 ABC abc;
3749 if (!physdev->font)
3751 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3752 return dev->funcs->pGetCharWidth( dev, first, count, chars, buffer );
3755 TRACE( "%p, %d, %d, %p\n", physdev->font, first, count, buffer );
3757 pthread_mutex_lock( &font_lock );
3758 for (i = 0; i < count; i++)
3760 c = chars ? chars[i] : i + first;
3761 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3762 buffer[i] = 0;
3763 else
3764 buffer[i] = abc.abcA + abc.abcB + abc.abcC;
3766 pthread_mutex_unlock( &font_lock );
3767 return TRUE;
3771 /*************************************************************
3772 * font_GetCharWidthInfo
3774 static BOOL CDECL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3776 struct font_physdev *physdev = get_font_dev( dev );
3777 struct char_width_info *info = ptr;
3779 if (!physdev->font)
3781 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3782 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3785 info->unk = 0;
3786 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3787 info->lsb = info->rsb = 0;
3789 return TRUE;
3793 /*************************************************************
3794 * font_GetFontData
3796 static DWORD CDECL font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
3798 struct font_physdev *physdev = get_font_dev( dev );
3800 if (!physdev->font)
3802 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
3803 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
3805 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
3809 /*************************************************************
3810 * font_GetFontRealizationInfo
3812 static BOOL CDECL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
3814 struct font_physdev *physdev = get_font_dev( dev );
3815 struct font_realization_info *info = ptr;
3817 if (!physdev->font)
3819 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
3820 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
3823 TRACE( "(%p, %p)\n", physdev->font, info);
3825 info->flags = 1;
3826 if (physdev->font->scalable) info->flags |= 2;
3828 info->cache_num = physdev->font->cache_num;
3829 info->instance_id = physdev->font->handle;
3830 if (info->size == sizeof(*info))
3832 info->file_count = 1;
3833 info->face_index = physdev->font->face_index;
3834 info->simulations = 0;
3835 if (physdev->font->fake_bold) info->simulations |= 0x1;
3836 if (physdev->font->fake_italic) info->simulations |= 0x2;
3838 return TRUE;
3842 /*************************************************************
3843 * font_GetFontUnicodeRanges
3845 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
3847 struct font_physdev *physdev = get_font_dev( dev );
3848 DWORD size, num_ranges;
3850 if (!physdev->font)
3852 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
3853 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
3856 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
3857 size = offsetof( GLYPHSET, ranges[num_ranges] );
3858 if (glyphset)
3860 glyphset->cbThis = size;
3861 glyphset->cRanges = num_ranges;
3862 glyphset->flAccel = 0;
3864 return size;
3868 /*************************************************************
3869 * font_GetGlyphIndices
3871 static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
3873 struct font_physdev *physdev = get_font_dev( dev );
3874 UINT default_char;
3875 unsigned char ch;
3876 BOOL got_default = FALSE;
3877 int i;
3879 if (!physdev->font)
3881 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
3882 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
3885 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3887 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
3888 got_default = TRUE;
3891 pthread_mutex_lock( &font_lock );
3893 for (i = 0; i < count; i++)
3895 UINT glyph = str[i];
3897 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
3899 glyph = 0;
3900 if (physdev->font->codepage == CP_SYMBOL)
3902 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
3903 else if (str[i] < 0x100) glyph = str[i];
3905 else if (wc_to_index( physdev->font->codepage, str[i], &ch, FALSE ))
3906 glyph = (unsigned char)ch;
3908 if (!glyph)
3910 if (!got_default)
3912 default_char = font_funcs->get_default_glyph( physdev->font );
3913 got_default = TRUE;
3915 gi[i] = default_char;
3917 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
3920 pthread_mutex_unlock( &font_lock );
3921 return count;
3925 /*************************************************************
3926 * font_GetGlyphOutline
3928 static DWORD CDECL font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
3929 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
3931 struct font_physdev *physdev = get_font_dev( dev );
3932 DWORD ret;
3934 if (!physdev->font)
3936 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
3937 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
3939 pthread_mutex_lock( &font_lock );
3940 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
3941 pthread_mutex_unlock( &font_lock );
3942 return ret;
3946 /*************************************************************
3947 * font_GetKerningPairs
3949 static DWORD CDECL font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
3951 struct font_physdev *physdev = get_font_dev( dev );
3953 if (!physdev->font)
3955 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
3956 return dev->funcs->pGetKerningPairs( dev, count, pairs );
3959 pthread_mutex_lock( &font_lock );
3960 if (physdev->font->kern_count == -1)
3961 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
3962 &physdev->font->kern_pairs );
3963 pthread_mutex_unlock( &font_lock );
3965 if (count && pairs)
3967 count = min( count, physdev->font->kern_count );
3968 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
3970 else count = physdev->font->kern_count;
3972 return count;
3976 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
3978 double scale_x, scale_y;
3980 if (font->aveWidth)
3982 scale_x = (double)font->aveWidth;
3983 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3985 else
3986 scale_x = font->scale_y;
3988 scale_x *= fabs(font->matrix.eM11);
3989 scale_y = font->scale_y * fabs(font->matrix.eM22);
3991 /* Windows scales these values as signed integers even if they are unsigned */
3992 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3993 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3995 SCALE_Y(otm->otmTextMetrics.tmHeight);
3996 SCALE_Y(otm->otmTextMetrics.tmAscent);
3997 SCALE_Y(otm->otmTextMetrics.tmDescent);
3998 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
3999 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
4001 SCALE_X(otm->otmTextMetrics.tmOverhang);
4002 if (font->fake_bold)
4004 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
4005 otm->otmTextMetrics.tmAveCharWidth++;
4006 otm->otmTextMetrics.tmMaxCharWidth++;
4008 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
4009 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
4011 SCALE_Y(otm->otmAscent);
4012 SCALE_Y(otm->otmDescent);
4013 SCALE_Y(otm->otmLineGap);
4014 SCALE_Y(otm->otmsCapEmHeight);
4015 SCALE_Y(otm->otmsXHeight);
4016 SCALE_Y(otm->otmrcFontBox.top);
4017 SCALE_Y(otm->otmrcFontBox.bottom);
4018 SCALE_X(otm->otmrcFontBox.left);
4019 SCALE_X(otm->otmrcFontBox.right);
4020 SCALE_Y(otm->otmMacAscent);
4021 SCALE_Y(otm->otmMacDescent);
4022 SCALE_Y(otm->otmMacLineGap);
4023 SCALE_X(otm->otmptSubscriptSize.x);
4024 SCALE_Y(otm->otmptSubscriptSize.y);
4025 SCALE_X(otm->otmptSubscriptOffset.x);
4026 SCALE_Y(otm->otmptSubscriptOffset.y);
4027 SCALE_X(otm->otmptSuperscriptSize.x);
4028 SCALE_Y(otm->otmptSuperscriptSize.y);
4029 SCALE_X(otm->otmptSuperscriptOffset.x);
4030 SCALE_Y(otm->otmptSuperscriptOffset.y);
4031 SCALE_Y(otm->otmsStrikeoutSize);
4032 SCALE_Y(otm->otmsStrikeoutPosition);
4033 SCALE_Y(otm->otmsUnderscoreSize);
4034 SCALE_Y(otm->otmsUnderscorePosition);
4036 #undef SCALE_X
4037 #undef SCALE_Y
4040 /*************************************************************
4041 * font_GetOutlineTextMetrics
4043 static UINT CDECL font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
4045 struct font_physdev *physdev = get_font_dev( dev );
4046 UINT ret = 0;
4048 if (!physdev->font)
4050 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
4051 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
4054 if (!physdev->font->scalable) return 0;
4056 pthread_mutex_lock( &font_lock );
4057 if (font_funcs->set_outline_text_metrics( physdev->font ))
4059 ret = physdev->font->otm.otmSize;
4060 if (metrics && size >= physdev->font->otm.otmSize)
4062 WCHAR *ptr = (WCHAR *)(metrics + 1);
4063 *metrics = physdev->font->otm;
4064 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
4065 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
4066 ptr += lstrlenW(ptr) + 1;
4067 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
4068 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
4069 ptr += lstrlenW(ptr) + 1;
4070 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
4071 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
4072 ptr += lstrlenW(ptr) + 1;
4073 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
4074 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
4075 scale_outline_font_metrics( physdev->font, metrics );
4078 pthread_mutex_unlock( &font_lock );
4079 return ret;
4083 /*************************************************************
4084 * font_GetTextCharsetInfo
4086 static UINT CDECL font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
4088 struct font_physdev *physdev = get_font_dev( dev );
4090 if (!physdev->font)
4092 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
4093 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4095 if (fs) *fs = physdev->font->fs;
4096 return physdev->font->charset;
4100 /*************************************************************
4101 * font_GetTextExtentExPoint
4103 static BOOL CDECL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
4105 struct font_physdev *physdev = get_font_dev( dev );
4106 INT i, pos;
4107 ABC abc;
4109 if (!physdev->font)
4111 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
4112 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
4115 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
4117 pthread_mutex_lock( &font_lock );
4118 for (i = pos = 0; i < count; i++)
4120 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
4121 pos += abc.abcA + abc.abcB + abc.abcC;
4122 dxs[i] = pos;
4124 pthread_mutex_unlock( &font_lock );
4125 return TRUE;
4129 /*************************************************************
4130 * font_GetTextExtentExPointI
4132 static BOOL CDECL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
4134 struct font_physdev *physdev = get_font_dev( dev );
4135 INT i, pos;
4136 ABC abc;
4138 if (!physdev->font)
4140 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
4141 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
4144 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
4146 pthread_mutex_lock( &font_lock );
4147 for (i = pos = 0; i < count; i++)
4149 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
4150 NULL, &abc, 0, NULL, NULL );
4151 pos += abc.abcA + abc.abcB + abc.abcC;
4152 dxs[i] = pos;
4154 pthread_mutex_unlock( &font_lock );
4155 return TRUE;
4159 /*************************************************************
4160 * font_GetTextFace
4162 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
4164 struct font_physdev *physdev = get_font_dev( dev );
4165 const WCHAR *font_name;
4166 INT len;
4168 if (!physdev->font)
4170 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
4171 return dev->funcs->pGetTextFace( dev, count, str );
4173 font_name = get_gdi_font_name( physdev->font );
4174 len = lstrlenW( font_name ) + 1;
4175 if (str)
4177 lstrcpynW( str, font_name, count );
4178 len = min( count, len );
4180 return len;
4184 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
4186 double scale_x, scale_y;
4188 /* Make sure that the font has sane width/height ratio */
4189 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
4191 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
4192 font->aveWidth = 0;
4195 if (font->aveWidth)
4197 scale_x = (double)font->aveWidth;
4198 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
4200 else
4201 scale_x = font->scale_y;
4203 scale_x *= fabs(font->matrix.eM11);
4204 scale_y = font->scale_y * fabs(font->matrix.eM22);
4206 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
4207 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
4209 SCALE_Y(tm->tmHeight);
4210 SCALE_Y(tm->tmAscent);
4211 SCALE_Y(tm->tmDescent);
4212 SCALE_Y(tm->tmInternalLeading);
4213 SCALE_Y(tm->tmExternalLeading);
4215 SCALE_X(tm->tmOverhang);
4216 if (font->fake_bold)
4218 if (!font->scalable) tm->tmOverhang++;
4219 tm->tmAveCharWidth++;
4220 tm->tmMaxCharWidth++;
4222 SCALE_X(tm->tmAveCharWidth);
4223 SCALE_X(tm->tmMaxCharWidth);
4225 #undef SCALE_X
4226 #undef SCALE_Y
4229 /*************************************************************
4230 * font_GetTextMetrics
4232 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
4234 struct font_physdev *physdev = get_font_dev( dev );
4235 BOOL ret = FALSE;
4237 if (!physdev->font)
4239 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
4240 return dev->funcs->pGetTextMetrics( dev, metrics );
4243 pthread_mutex_lock( &font_lock );
4244 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
4245 font_funcs->set_bitmap_text_metrics( physdev->font ))
4247 *metrics = physdev->font->otm.otmTextMetrics;
4248 scale_font_metrics( physdev->font, metrics );
4249 ret = TRUE;
4251 pthread_mutex_unlock( &font_lock );
4252 return ret;
4256 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
4258 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4259 a single face with the requested charset. The idea is to check if
4260 the selected font supports the current ANSI codepage, if it does
4261 return the corresponding charset, else return the first charset */
4263 int i;
4265 if (translate_charset_info( (DWORD*)(INT_PTR)ansi_cp.CodePage, csi, TCI_SRCCODEPAGE ))
4267 const struct gdi_font_link *font_link;
4269 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
4270 font_link = find_gdi_font_link(family_name);
4271 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
4273 for (i = 0; i < 32; i++)
4275 DWORD fs0 = 1u << i;
4276 if (face->fs.fsCsb[0] & fs0)
4278 if (translate_charset_info(&fs0, csi, TCI_SRCFONTSIG)) return;
4279 FIXME("TCI failing on %x\n", fs0);
4283 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4284 face->fs.fsCsb[0], debugstr_w(face->file));
4285 csi->ciACP = ansi_cp.CodePage;
4286 csi->ciCharset = DEFAULT_CHARSET;
4289 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
4291 struct gdi_font *font;
4292 struct gdi_font_face *face;
4293 INT height;
4294 CHARSETINFO csi;
4295 const WCHAR *orig_name = NULL;
4296 BOOL substituted = FALSE;
4298 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
4300 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4301 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4302 original value lfCharSet. Note this is a special case for
4303 Symbol and doesn't happen at least for "Wingdings*" */
4304 if (!facename_compare( lf->lfFaceName, symbolW, -1 )) lf->lfCharSet = SYMBOL_CHARSET;
4306 /* check the cache first */
4307 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4309 TRACE( "returning cached gdiFont(%p)\n", font );
4310 return font;
4312 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &substituted, &orig_name )))
4314 FIXME( "can't find a single appropriate font - bailing\n" );
4315 return NULL;
4317 height = lf->lfHeight;
4319 font = create_gdi_font( face, orig_name, lf );
4320 font->use_logfont_name = substituted;
4321 font->matrix = dcmat;
4322 font->can_use_bitmap = can_use_bitmap;
4323 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
4324 font->charset = csi.ciCharset;
4325 font->codepage = csi.ciACP;
4327 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
4328 face->data_ptr, face->face_index );
4330 font->aveWidth = height ? lf->lfWidth : 0;
4331 if (!face->scalable)
4333 /* Windows uses integer scaling factors for bitmap fonts */
4334 INT scale, scaled_height, diff;
4335 struct gdi_font *cachedfont;
4337 if (height > 0)
4338 diff = height - (signed int)face->size.height;
4339 else
4340 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
4342 /* FIXME: rotation of bitmap fonts is ignored */
4343 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
4344 if (font->aveWidth)
4345 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
4346 font->matrix.eM11 = font->matrix.eM22 = 1.0;
4347 dcmat.eM11 = dcmat.eM22 = 1.0;
4348 /* As we changed the matrix, we need to search the cache for the font again,
4349 * otherwise we might explode the cache. */
4350 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
4352 TRACE("Found cached font after non-scalable matrix rescale!\n");
4353 free_gdi_font( font );
4354 return cachedfont;
4357 if (height != 0) height = diff;
4358 height += face->size.height;
4360 scale = (height + face->size.height - 1) / face->size.height;
4361 scaled_height = scale * face->size.height;
4362 /* Only jump to the next height if the difference <= 25% original height */
4363 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4364 /* The jump between unscaled and doubled is delayed by 1 */
4365 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4366 font->scale_y = scale;
4367 TRACE("font scale y: %d\n", font->scale_y);
4370 if (!font_funcs->load_font( font ))
4372 free_gdi_font( font );
4373 return NULL;
4376 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
4377 font->vert_feature = get_GSUB_vert_feature( font );
4379 create_child_font_list( font );
4381 TRACE( "caching: gdiFont=%p\n", font );
4382 cache_gdi_font( font );
4383 return font;
4386 /*************************************************************
4387 * font_SelectFont
4389 static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4391 struct font_physdev *physdev = get_font_dev( dev );
4392 struct gdi_font *font = NULL, *prev = physdev->font;
4393 DC *dc = get_physdev_dc( dev );
4395 if (hfont)
4397 LOGFONTW lf;
4398 FMAT2 dcmat;
4399 BOOL can_use_bitmap = !!(NtGdiGetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
4401 NtGdiExtGetObjectW( hfont, sizeof(lf), &lf );
4402 switch (lf.lfQuality)
4404 case NONANTIALIASED_QUALITY:
4405 if (!*aa_flags) *aa_flags = GGO_BITMAP;
4406 break;
4407 case ANTIALIASED_QUALITY:
4408 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
4409 break;
4412 lf.lfWidth = abs(lf.lfWidth);
4414 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4415 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4416 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4417 lf.lfEscapement );
4419 if (dc->attr->graphics_mode == GM_ADVANCED)
4421 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
4422 /* try to avoid not necessary glyph transformations */
4423 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4425 lf.lfHeight *= fabs(dcmat.eM11);
4426 lf.lfWidth *= fabs(dcmat.eM11);
4427 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4430 else
4432 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4433 dcmat.eM11 = dcmat.eM22 = 1.0;
4434 dcmat.eM21 = dcmat.eM12 = 0;
4435 lf.lfOrientation = lf.lfEscapement;
4436 if (dc->vport2WorldValid)
4438 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4439 lf.lfOrientation = -lf.lfOrientation;
4440 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4441 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4444 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
4446 pthread_mutex_lock( &font_lock );
4448 font = select_font( &lf, dcmat, can_use_bitmap );
4450 if (font)
4452 if (!*aa_flags) *aa_flags = font->aa_flags;
4453 if (!*aa_flags)
4455 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
4456 *aa_flags = subpixel_orientation;
4457 else
4458 *aa_flags = font_smoothing;
4460 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
4462 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
4463 pthread_mutex_unlock( &font_lock );
4465 physdev->font = font;
4466 if (prev) release_gdi_font( prev );
4467 return font ? hfont : 0;
4471 const struct gdi_dc_funcs font_driver =
4473 NULL, /* pAbortDoc */
4474 NULL, /* pAbortPath */
4475 NULL, /* pAlphaBlend */
4476 NULL, /* pAngleArc */
4477 NULL, /* pArc */
4478 NULL, /* pArcTo */
4479 NULL, /* pBeginPath */
4480 NULL, /* pBlendImage */
4481 NULL, /* pChord */
4482 NULL, /* pCloseFigure */
4483 NULL, /* pCreateCompatibleDC */
4484 font_CreateDC, /* pCreateDC */
4485 font_DeleteDC, /* pDeleteDC */
4486 NULL, /* pDeleteObject */
4487 NULL, /* pEllipse */
4488 NULL, /* pEndDoc */
4489 NULL, /* pEndPage */
4490 NULL, /* pEndPath */
4491 font_EnumFonts, /* pEnumFonts */
4492 NULL, /* pExtEscape */
4493 NULL, /* pExtFloodFill */
4494 NULL, /* pExtTextOut */
4495 NULL, /* pFillPath */
4496 NULL, /* pFillRgn */
4497 font_FontIsLinked, /* pFontIsLinked */
4498 NULL, /* pFrameRgn */
4499 NULL, /* pGetBoundsRect */
4500 font_GetCharABCWidths, /* pGetCharABCWidths */
4501 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
4502 font_GetCharWidth, /* pGetCharWidth */
4503 font_GetCharWidthInfo, /* pGetCharWidthInfo */
4504 NULL, /* pGetDeviceCaps */
4505 NULL, /* pGetDeviceGammaRamp */
4506 font_GetFontData, /* pGetFontData */
4507 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
4508 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
4509 font_GetGlyphIndices, /* pGetGlyphIndices */
4510 font_GetGlyphOutline, /* pGetGlyphOutline */
4511 NULL, /* pGetICMProfile */
4512 NULL, /* pGetImage */
4513 font_GetKerningPairs, /* pGetKerningPairs */
4514 NULL, /* pGetNearestColor */
4515 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
4516 NULL, /* pGetPixel */
4517 NULL, /* pGetSystemPaletteEntries */
4518 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
4519 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
4520 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
4521 font_GetTextFace, /* pGetTextFace */
4522 font_GetTextMetrics, /* pGetTextMetrics */
4523 NULL, /* pGradientFill */
4524 NULL, /* pInvertRgn */
4525 NULL, /* pLineTo */
4526 NULL, /* pMoveTo */
4527 NULL, /* pPaintRgn */
4528 NULL, /* pPatBlt */
4529 NULL, /* pPie */
4530 NULL, /* pPolyBezier */
4531 NULL, /* pPolyBezierTo */
4532 NULL, /* pPolyDraw */
4533 NULL, /* pPolyPolygon */
4534 NULL, /* pPolyPolyline */
4535 NULL, /* pPolylineTo */
4536 NULL, /* pPutImage */
4537 NULL, /* pRealizeDefaultPalette */
4538 NULL, /* pRealizePalette */
4539 NULL, /* pRectangle */
4540 NULL, /* pResetDC */
4541 NULL, /* pRoundRect */
4542 NULL, /* pSelectBitmap */
4543 NULL, /* pSelectBrush */
4544 font_SelectFont, /* pSelectFont */
4545 NULL, /* pSelectPen */
4546 NULL, /* pSetBkColor */
4547 NULL, /* pSetBoundsRect */
4548 NULL, /* pSetDCBrushColor */
4549 NULL, /* pSetDCPenColor */
4550 NULL, /* pSetDIBitsToDevice */
4551 NULL, /* pSetDeviceClipping */
4552 NULL, /* pSetDeviceGammaRamp */
4553 NULL, /* pSetPixel */
4554 NULL, /* pSetTextColor */
4555 NULL, /* pStartDoc */
4556 NULL, /* pStartPage */
4557 NULL, /* pStretchBlt */
4558 NULL, /* pStretchDIBits */
4559 NULL, /* pStrokeAndFillPath */
4560 NULL, /* pStrokePath */
4561 NULL, /* pUnrealizePalette */
4562 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
4563 NULL, /* pD3DKMTCloseAdapter */
4564 NULL, /* pD3DKMTOpenAdapterFromLuid */
4565 NULL, /* pD3DKMTQueryVideoMemoryInfo */
4566 NULL, /* pD3DKMTSetVidPnSourceOwner */
4567 GDI_PRIORITY_FONT_DRV /* priority */
4570 static BOOL get_key_value( HKEY key, const char *name, DWORD *value )
4572 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[12 * sizeof(WCHAR)])];
4573 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4574 DWORD count;
4576 count = query_reg_ascii_value( key, name, info, sizeof(value_buffer) );
4577 if (count)
4579 if (info->Type == REG_DWORD) memcpy( value, info->Data, sizeof(*value) );
4580 else *value = wcstol( (const WCHAR *)info->Data, NULL, 10 );
4582 return !!count;
4585 static UINT init_font_options(void)
4587 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[20 * sizeof(WCHAR)])];
4588 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4589 HKEY key;
4590 DWORD i, val, gamma = 1400;
4591 UINT dpi = 0;
4593 if (query_reg_ascii_value( wine_fonts_key, "AntialiasFakeBoldOrItalic",
4594 info, sizeof(value_buffer) ) && info->Type == REG_SZ)
4596 static const WCHAR valsW[] = {'y','Y','t','T','1',0};
4597 antialias_fakes = (wcschr( valsW, *(const WCHAR *)info->Data ) != NULL);
4600 if ((key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
4602 /* FIXME: handle vertical orientations even though Windows doesn't */
4603 if (get_key_value( key, "FontSmoothingOrientation", &val ))
4605 switch (val)
4607 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4608 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
4609 break;
4610 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4611 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
4612 break;
4615 if (get_key_value( key, "FontSmoothing", &val ) && val /* enabled */)
4617 if (get_key_value( key, "FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4618 font_smoothing = subpixel_orientation;
4619 else
4620 font_smoothing = GGO_GRAY4_BITMAP;
4622 if (get_key_value( key, "FontSmoothingGamma", &val ) && val)
4624 gamma = min( max( val, 1000 ), 2200 );
4626 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4627 NtClose( key );
4630 /* Calibrating the difference between the registry value and the Wine gamma value.
4631 This looks roughly similar to Windows Native with the same registry value.
4632 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4633 gamma = 1000 * gamma / 1400;
4634 if (gamma != 1000)
4636 for (i = 0; i < 256; i++)
4638 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
4639 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
4643 if (!dpi && (key = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) )))
4645 if (get_key_value( key, "LogPixels", &val )) dpi = val;
4646 NtClose( key );
4648 if (!dpi) dpi = 96;
4650 font_gamma_ramp.gamma = gamma;
4651 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp.gamma, dpi );
4652 return dpi;
4656 /* compute positions for text rendering, in device coords */
4657 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4659 TEXTMETRICW tm;
4660 PHYSDEV dev;
4662 size->cx = size->cy = 0;
4663 if (!count) return TRUE;
4665 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4666 dev->funcs->pGetTextMetrics( dev, &tm );
4668 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4669 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4671 if (dc->breakExtra || dc->breakRem)
4673 int i, space = 0, rem = dc->breakRem;
4675 for (i = 0; i < count; i++)
4677 if (str[i] == tm.tmBreakChar)
4679 space += dc->breakExtra;
4680 if (rem > 0)
4682 space++;
4683 rem--;
4686 dx[i] += space;
4689 size->cx = dx[count - 1];
4690 size->cy = tm.tmHeight;
4691 return TRUE;
4694 /* compute positions for text rendering, in device coords */
4695 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4697 TEXTMETRICW tm;
4698 PHYSDEV dev;
4700 size->cx = size->cy = 0;
4701 if (!count) return TRUE;
4703 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4704 dev->funcs->pGetTextMetrics( dev, &tm );
4706 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4707 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4709 if (dc->breakExtra || dc->breakRem)
4711 WORD space_index;
4712 int i, space = 0, rem = dc->breakRem;
4714 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4715 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4717 for (i = 0; i < count; i++)
4719 if (indices[i] == space_index)
4721 space += dc->breakExtra;
4722 if (rem > 0)
4724 space++;
4725 rem--;
4728 dx[i] += space;
4731 size->cx = dx[count - 1];
4732 size->cy = tm.tmHeight;
4733 return TRUE;
4736 /***********************************************************************
4737 * get_text_charset_info
4739 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4741 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4743 UINT ret = DEFAULT_CHARSET;
4744 PHYSDEV dev;
4746 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4747 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4749 if (ret == DEFAULT_CHARSET && fs)
4750 memset(fs, 0, sizeof(FONTSIGNATURE));
4751 return ret;
4754 /***********************************************************************
4755 * NtGdiGetTextCharsetInfo (win32u.@)
4757 UINT WINAPI NtGdiGetTextCharsetInfo( HDC hdc, FONTSIGNATURE *fs, DWORD flags )
4759 UINT ret = DEFAULT_CHARSET;
4760 DC *dc = get_dc_ptr(hdc);
4762 if (dc)
4764 ret = get_text_charset_info( dc, fs, flags );
4765 release_dc_ptr( dc );
4767 return ret;
4770 /***********************************************************************
4771 * NtGdiHfontCreate (win32u.@)
4773 HFONT WINAPI NtGdiHfontCreate( const void *logfont, ULONG size, ULONG type,
4774 ULONG flags, void *data )
4776 HFONT hFont;
4777 FONTOBJ *fontPtr;
4778 const LOGFONTW *plf;
4780 if (!logfont) return 0;
4782 if (size == sizeof(ENUMLOGFONTEXDVW) || size == sizeof(ENUMLOGFONTEXW))
4784 const ENUMLOGFONTEXW *lfex = logfont;
4786 if (lfex->elfFullName[0] || lfex->elfStyle[0] || lfex->elfScript[0])
4788 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
4789 debugstr_w( lfex->elfFullName ), debugstr_w( lfex->elfStyle ),
4790 debugstr_w( lfex->elfScript ));
4793 plf = &lfex->elfLogFont;
4795 else if (size != sizeof(LOGFONTW))
4797 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
4798 return 0;
4800 else plf = logfont;
4802 if (!(fontPtr = malloc( sizeof(*fontPtr) ))) return 0;
4804 fontPtr->logfont = *plf;
4806 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, NTGDI_OBJ_FONT, &fontobj_funcs )))
4808 free( fontPtr );
4809 return 0;
4812 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4813 plf->lfHeight, plf->lfWidth,
4814 plf->lfEscapement, plf->lfOrientation,
4815 plf->lfPitchAndFamily,
4816 plf->lfOutPrecision, plf->lfClipPrecision,
4817 plf->lfQuality, plf->lfCharSet,
4818 debugstr_w(plf->lfFaceName),
4819 plf->lfWeight > 400 ? "Bold" : "",
4820 plf->lfItalic ? "Italic" : "",
4821 plf->lfUnderline ? "Underline" : "", hFont);
4823 return hFont;
4826 #define ASSOC_CHARSET_OEM 1
4827 #define ASSOC_CHARSET_ANSI 2
4828 #define ASSOC_CHARSET_SYMBOL 4
4830 static DWORD get_associated_charset_info(void)
4832 static DWORD associated_charset = -1;
4834 if (associated_charset == -1)
4836 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[32 * sizeof(WCHAR)])];
4837 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
4838 HKEY hkey;
4840 static const WCHAR yesW[] = {'y','e','s',0};
4842 associated_charset = 0;
4844 if (!(hkey = reg_open_key( NULL, associated_charset_keyW, sizeof(associated_charset_keyW) )))
4845 return 0;
4847 if (query_reg_ascii_value( hkey, "ANSI(00)", info, sizeof(value_buffer) ) &&
4848 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4849 associated_charset |= ASSOC_CHARSET_ANSI;
4851 if (query_reg_ascii_value( hkey, "OEM(FF)", info, sizeof(value_buffer) ) &&
4852 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4853 associated_charset |= ASSOC_CHARSET_OEM;
4855 if (query_reg_ascii_value( hkey, "SYMBOL(02)", info, sizeof(value_buffer) ) &&
4856 info->Type == REG_SZ && !wcsicmp( (const WCHAR *)info->Data, yesW ))
4857 associated_charset |= ASSOC_CHARSET_SYMBOL;
4859 NtClose( hkey );
4861 TRACE("associated_charset = %d\n", associated_charset);
4864 return associated_charset;
4867 static void update_font_code_page( DC *dc, HANDLE font )
4869 CHARSETINFO csi;
4870 int charset = get_text_charset_info( dc, NULL, 0 );
4872 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
4874 LOGFONTW lf;
4876 NtGdiExtGetObjectW( font, sizeof(lf), &lf );
4877 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
4878 charset = DEFAULT_CHARSET;
4881 /* Hmm, nicely designed api this one! */
4882 if (translate_charset_info( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
4883 dc->attr->font_code_page = csi.ciACP;
4884 else {
4885 switch(charset) {
4886 case OEM_CHARSET:
4887 dc->attr->font_code_page = oem_cp.CodePage;
4888 break;
4889 case DEFAULT_CHARSET:
4890 dc->attr->font_code_page = ansi_cp.CodePage;
4891 break;
4893 case VISCII_CHARSET:
4894 case TCVN_CHARSET:
4895 case KOI8_CHARSET:
4896 case ISO3_CHARSET:
4897 case ISO4_CHARSET:
4898 case ISO10_CHARSET:
4899 case CELTIC_CHARSET:
4900 /* FIXME: These have no place here, but because x11drv
4901 enumerates fonts with these (made up) charsets some apps
4902 might use them and then the FIXME below would become
4903 annoying. Now we could pick the intended codepage for
4904 each of these, but since it's broken anyway we'll just
4905 use CP_ACP and hope it'll go away...
4907 dc->attr->font_code_page = CP_ACP;
4908 break;
4910 default:
4911 FIXME("Can't find codepage for charset %d\n", charset);
4912 dc->attr->font_code_page = CP_ACP;
4913 break;
4917 TRACE( "charset %d => cp %d\n", charset, dc->attr->font_code_page );
4920 /***********************************************************************
4921 * NtGdiSelectFont (win32u.@)
4923 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
4925 HGDIOBJ ret = 0;
4926 DC *dc = get_dc_ptr( hdc );
4927 PHYSDEV physdev;
4928 UINT aa_flags = 0;
4930 if (!dc) return 0;
4932 if (!GDI_inc_ref_count( handle ))
4934 release_dc_ptr( dc );
4935 return 0;
4938 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
4939 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
4941 ret = dc->hFont;
4942 dc->hFont = handle;
4943 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
4944 update_font_code_page( dc, handle );
4945 if (dc->font_gamma_ramp == NULL)
4946 dc->font_gamma_ramp = &font_gamma_ramp;
4947 GDI_dec_ref_count( ret );
4949 else GDI_dec_ref_count( handle );
4951 release_dc_ptr( dc );
4952 return ret;
4956 /***********************************************************************
4957 * FONT_GetObjectW
4959 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
4961 FONTOBJ *font = GDI_GetObjPtr( handle, NTGDI_OBJ_FONT );
4963 if (!font) return 0;
4964 if (buffer)
4966 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
4967 memcpy( buffer, &font->logfont, count );
4969 else count = sizeof(LOGFONTW);
4970 GDI_ReleaseObj( handle );
4971 return count;
4975 /***********************************************************************
4976 * FONT_DeleteObject
4978 static BOOL FONT_DeleteObject( HGDIOBJ handle )
4980 FONTOBJ *obj;
4982 if (!(obj = free_gdi_handle( handle ))) return FALSE;
4983 free( obj );
4984 return TRUE;
4988 struct font_enum
4990 HDC hdc;
4991 struct font_enum_entry *buf;
4992 ULONG size;
4993 ULONG count;
4994 ULONG charset;
4997 static INT WINAPI font_enum_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
4998 DWORD type, LPARAM lp )
5000 struct font_enum *fe = (struct font_enum *)lp;
5002 if (fe->charset != DEFAULT_CHARSET && lf->lfCharSet != fe->charset) return 1;
5003 if ((type & RASTER_FONTTYPE) && !(NtGdiGetDeviceCaps( fe->hdc, TEXTCAPS ) & TC_RA_ABLE))
5004 return 1;
5006 if (fe->buf && fe->count < fe->size)
5008 fe->buf[fe->count].type = type;
5009 fe->buf[fe->count].lf = *(const ENUMLOGFONTEXW *)lf;
5010 fe->buf[fe->count].tm = *(const NEWTEXTMETRICEXW *)tm;
5012 fe->count++;
5013 return 1;
5016 /***********************************************************************
5017 * NtGdiEnumFonts (win32u.@)
5019 BOOL WINAPI NtGdiEnumFonts( HDC hdc, ULONG type, ULONG win32_compat, ULONG face_name_len,
5020 const WCHAR *face_name, ULONG charset, ULONG *count, void *buf )
5022 struct font_enum fe;
5023 PHYSDEV physdev;
5024 LOGFONTW lf;
5025 BOOL ret;
5026 DC *dc;
5028 if (!(dc = get_dc_ptr( hdc ))) return 0;
5030 memset( &lf, 0, sizeof(lf) );
5031 lf.lfCharSet = charset;
5032 if (face_name_len) memcpy( lf.lfFaceName, face_name, face_name_len * sizeof(WCHAR) );
5034 fe.hdc = hdc;
5035 fe.buf = buf;
5036 fe.size = *count / sizeof(*fe.buf);
5037 fe.count = 0;
5038 fe.charset = charset;
5040 physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
5041 ret = physdev->funcs->pEnumFonts( physdev, &lf, font_enum_proc, (LPARAM)&fe );
5042 if (ret && buf) ret = fe.count <= fe.size;
5043 *count = fe.count * sizeof(*fe.buf);
5045 release_dc_ptr( dc );
5046 return ret;
5050 /***********************************************************************
5051 * NtGdiSetTextJustification (win32u.@)
5053 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
5055 DC *dc;
5057 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5059 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
5060 dc->attr->wnd_ext.cx );
5061 if (!extra) breaks = 0;
5062 if (breaks)
5064 dc->breakExtra = extra / breaks;
5065 dc->breakRem = extra - (breaks * dc->breakExtra);
5067 else
5069 dc->breakExtra = 0;
5070 dc->breakRem = 0;
5073 release_dc_ptr( dc );
5074 return TRUE;
5078 /***********************************************************************
5079 * NtGdiGetTextFaceW (win32u.@)
5081 INT WINAPI NtGdiGetTextFaceW( HDC hdc, INT count, WCHAR *name, BOOL alias_name )
5083 PHYSDEV dev;
5084 INT ret;
5086 DC * dc = get_dc_ptr( hdc );
5087 if (!dc) return 0;
5089 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
5090 ret = dev->funcs->pGetTextFace( dev, count, name );
5091 release_dc_ptr( dc );
5092 return ret;
5096 /***********************************************************************
5097 * NtGdiGetTextExtentExW (win32u.@)
5099 * Return the size of the string as it would be if it was output properly by
5100 * e.g. TextOut.
5102 BOOL WINAPI NtGdiGetTextExtentExW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
5103 INT *nfit, INT *dxs, SIZE *size, UINT flags )
5105 DC *dc;
5106 int i;
5107 BOOL ret;
5108 INT buffer[256], *pos = dxs;
5110 if (count < 0) return FALSE;
5112 dc = get_dc_ptr(hdc);
5113 if (!dc) return FALSE;
5115 if (!dxs)
5117 pos = buffer;
5118 if (count > 256 && !(pos = malloc( count * sizeof(*pos) )))
5120 release_dc_ptr( dc );
5121 return FALSE;
5126 if (flags)
5127 ret = get_char_positions_indices( dc, str, count, pos, size );
5128 else
5129 ret = get_char_positions( dc, str, count, pos, size );
5130 if (ret)
5132 if (dxs || nfit)
5134 for (i = 0; i < count; i++)
5136 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
5137 (i + 1) * dc->attr->char_extra;
5138 if (nfit && dx > (unsigned int)max_ext) break;
5139 if (dxs) dxs[i] = dx;
5141 if (nfit) *nfit = i;
5144 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
5145 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5148 if (pos != buffer && pos != dxs) free( pos );
5149 release_dc_ptr( dc );
5151 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
5152 return ret;
5155 /***********************************************************************
5156 * NtGdiGetTextMetricsW (win32u.@)
5158 BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags )
5160 PHYSDEV physdev;
5161 BOOL ret = FALSE;
5162 DC * dc = get_dc_ptr( hdc );
5163 if (!dc) return FALSE;
5165 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5166 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5168 if (ret)
5170 /* device layer returns values in device units
5171 * therefore we have to convert them to logical */
5173 metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5174 metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5175 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5176 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5177 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5178 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5179 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5180 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5181 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5182 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5183 ret = TRUE;
5185 TRACE("text metrics:\n"
5186 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5187 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5188 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5189 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5190 " PitchAndFamily = %02x\n"
5191 " --------------------\n"
5192 " InternalLeading = %i\n"
5193 " Ascent = %i\n"
5194 " Descent = %i\n"
5195 " Height = %i\n",
5196 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
5197 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
5198 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
5199 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5200 metrics->tmPitchAndFamily,
5201 metrics->tmInternalLeading,
5202 metrics->tmAscent,
5203 metrics->tmDescent,
5204 metrics->tmHeight );
5206 release_dc_ptr( dc );
5207 return ret;
5211 /***********************************************************************
5212 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
5214 UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData,
5215 OUTLINETEXTMETRICW *lpOTM, ULONG opts )
5217 DC *dc = get_dc_ptr( hdc );
5218 OUTLINETEXTMETRICW *output = lpOTM;
5219 PHYSDEV dev;
5220 UINT ret;
5222 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5223 if(!dc) return 0;
5225 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5226 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5228 if (lpOTM && ret > cbData)
5230 output = malloc( ret );
5231 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5234 if (lpOTM && ret)
5236 output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX);
5237 output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY);
5238 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5239 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5240 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5241 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5242 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5243 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5244 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5245 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5246 output->otmAscent = height_to_LP( dc, output->otmAscent);
5247 output->otmDescent = height_to_LP( dc, output->otmDescent);
5248 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5249 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5250 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5251 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5252 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5253 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5254 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5255 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5256 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5257 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5258 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5259 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5260 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5261 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5262 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5263 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5264 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5265 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5266 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5267 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5268 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5269 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5271 if(output != lpOTM)
5273 memcpy(lpOTM, output, cbData);
5274 free( output );
5275 ret = cbData;
5278 release_dc_ptr(dc);
5279 return ret;
5282 /***********************************************************************
5283 * NtGdiGetCharWidthW (win32u.@)
5285 BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars,
5286 ULONG flags, void *buf )
5288 UINT i, count = last;
5289 BOOL ret;
5290 PHYSDEV dev;
5291 DC *dc;
5293 if (flags & NTGDI_GETCHARWIDTH_INDICES)
5295 ABC *abc;
5296 unsigned int i;
5298 if (!(abc = malloc( count * sizeof(ABC) )))
5299 return FALSE;
5301 if (!NtGdiGetCharABCWidthsW( hdc, first, last, chars,
5302 NTGDI_GETCHARABCWIDTHS_INT | NTGDI_GETCHARABCWIDTHS_INDICES,
5303 abc ))
5305 free( abc );
5306 return FALSE;
5309 for (i = 0; i < count; i++)
5310 ((INT *)buf)[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5312 free( abc );
5313 return TRUE;
5316 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
5318 if (!chars) count = last - first + 1;
5319 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5320 ret = dev->funcs->pGetCharWidth( dev, first, count, chars, buf );
5322 if (ret)
5324 if (flags & NTGDI_GETCHARWIDTH_INT)
5326 INT *buffer = buf;
5327 /* convert device units to logical */
5328 for (i = 0; i < count; i++)
5329 buffer[i] = width_to_LP( dc, buffer[i] );
5331 else
5333 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
5334 for (i = 0; i < count; i++)
5335 ((float *)buf)[i] = ((int *)buf)[i] * scale;
5338 release_dc_ptr( dc );
5339 return ret;
5343 /* helper for nulldrv_ExtTextOut */
5344 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5345 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5347 UINT indices[3] = {0, 0, 0x20};
5348 unsigned int i;
5349 DWORD ret, size;
5350 int stride;
5352 indices[0] = index;
5353 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5355 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5357 index = indices[i];
5358 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, 0, NULL, &identity, FALSE );
5359 if (ret != GDI_ERROR) break;
5362 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5363 if (!image) return ERROR_SUCCESS;
5365 image->ptr = NULL;
5366 image->free = NULL;
5367 if (!ret) /* empty glyph */
5369 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5370 return ERROR_SUCCESS;
5373 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5374 size = metrics->gmBlackBoxY * stride;
5376 if (!(image->ptr = malloc( size ))) return ERROR_OUTOFMEMORY;
5377 image->is_copy = TRUE;
5378 image->free = free_heap_bits;
5380 ret = NtGdiGetGlyphOutline( hdc, index, aa_flags, metrics, size, image->ptr,
5381 &identity, FALSE );
5382 if (ret == GDI_ERROR)
5384 free( image->ptr );
5385 return ERROR_NOT_FOUND;
5387 return ERROR_SUCCESS;
5390 /* helper for nulldrv_ExtTextOut */
5391 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5392 LPCWSTR str, UINT count, const INT *dx )
5394 UINT i;
5395 RECT rect, bounds;
5397 reset_bounds( &bounds );
5398 for (i = 0; i < count; i++)
5400 GLYPHMETRICS metrics;
5402 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5404 rect.left = x + metrics.gmptGlyphOrigin.x;
5405 rect.top = y - metrics.gmptGlyphOrigin.y;
5406 rect.right = rect.left + metrics.gmBlackBoxX;
5407 rect.bottom = rect.top + metrics.gmBlackBoxY;
5408 add_bounds_rect( &bounds, &rect );
5410 if (dx)
5412 if (flags & ETO_PDY)
5414 x += dx[ i * 2 ];
5415 y += dx[ i * 2 + 1];
5417 else x += dx[ i ];
5419 else
5421 x += metrics.gmCellIncX;
5422 y += metrics.gmCellIncY;
5425 return bounds;
5428 /* helper for nulldrv_ExtTextOut */
5429 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5430 const struct gdi_image_bits *image, const RECT *clip )
5432 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5433 UINT i, count, max_count;
5434 LONG x, y;
5435 BYTE *ptr = image->ptr;
5436 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5437 POINT *pts;
5438 RECT rect, clipped_rect;
5440 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5441 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5442 rect.right = rect.left + metrics->gmBlackBoxX;
5443 rect.bottom = rect.top + metrics->gmBlackBoxY;
5444 if (!clip) clipped_rect = rect;
5445 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5447 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5448 pts = malloc( max_count * sizeof(*pts) );
5449 if (!pts) return;
5451 count = 0;
5452 ptr += (clipped_rect.top - rect.top) * stride;
5453 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5455 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5457 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5458 pts[count].x = rect.left + x;
5459 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5460 pts[count + 1].x = rect.left + x;
5461 if (pts[count + 1].x > pts[count].x)
5463 pts[count].y = pts[count + 1].y = y;
5464 count += 2;
5468 assert( count <= max_count );
5469 dp_to_lp( dc, pts, count );
5470 for (i = 0; i < count; i += 2)
5472 const ULONG pts_count = 2;
5473 NtGdiPolyPolyDraw( dc->hSelf, pts + i, &pts_count, 1, NtGdiPolyPolyline );
5475 free( pts );
5478 /***********************************************************************
5479 * nulldrv_ExtTextOut
5481 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5482 LPCWSTR str, UINT count, const INT *dx )
5484 DC *dc = get_nulldrv_dc( dev );
5485 UINT i;
5486 DWORD err;
5487 HGDIOBJ orig;
5488 HPEN pen;
5490 if (flags & ETO_OPAQUE)
5492 RECT rc = *rect;
5493 COLORREF brush_color = NtGdiGetNearestColor( dev->hdc, dc->attr->background_color );
5494 HBRUSH brush = NtGdiCreateSolidBrush( brush_color, NULL);
5496 if (brush)
5498 orig = NtGdiSelectBrush( dev->hdc, brush );
5499 dp_to_lp( dc, (POINT *)&rc, 2 );
5500 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5501 NtGdiSelectBrush( dev->hdc, orig );
5502 NtGdiDeleteObjectApp( brush );
5506 if (!count) return TRUE;
5508 if (dc->aa_flags != GGO_BITMAP)
5510 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5511 BITMAPINFO *info = (BITMAPINFO *)buffer;
5512 struct gdi_image_bits bits;
5513 struct bitblt_coords src, dst;
5514 PHYSDEV dst_dev;
5515 /* FIXME Subpixel modes */
5516 UINT aa_flags = GGO_GRAY4_BITMAP;
5518 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5519 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5520 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5521 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5523 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5524 src.x = src.visrect.left;
5525 src.y = src.visrect.top;
5526 src.width = src.visrect.right - src.visrect.left;
5527 src.height = src.visrect.bottom - src.visrect.top;
5528 dst = src;
5529 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5530 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5532 /* we can avoid the GetImage, just query the needed format */
5533 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5534 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5535 info->bmiHeader.biWidth = src.width;
5536 info->bmiHeader.biHeight = -src.height;
5537 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5538 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5539 if (!err || err == ERROR_BAD_FORMAT)
5541 /* make the source rectangle relative to the source bits */
5542 src.x = src.y = 0;
5543 src.visrect.left = src.visrect.top = 0;
5544 src.visrect.right = src.width;
5545 src.visrect.bottom = src.height;
5547 bits.ptr = malloc( info->bmiHeader.biSizeImage );
5548 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5549 bits.is_copy = TRUE;
5550 bits.free = free_heap_bits;
5551 err = ERROR_SUCCESS;
5554 else
5556 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5557 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5558 if (!err && !bits.is_copy)
5560 void *ptr = malloc( info->bmiHeader.biSizeImage );
5561 if (!ptr)
5563 if (bits.free) bits.free( &bits );
5564 return ERROR_OUTOFMEMORY;
5566 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5567 if (bits.free) bits.free( &bits );
5568 bits.ptr = ptr;
5569 bits.is_copy = TRUE;
5570 bits.free = free_heap_bits;
5573 if (!err)
5575 /* make x,y relative to the image bits */
5576 x += src.visrect.left - dst.visrect.left;
5577 y += src.visrect.top - dst.visrect.top;
5578 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5579 aa_flags, str, count, dx );
5580 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5581 if (bits.free) bits.free( &bits );
5582 return !err;
5586 pen = NtGdiCreatePen( PS_SOLID, 1, dc->attr->text_color, NULL );
5587 orig = NtGdiSelectPen( dev->hdc, pen );
5589 for (i = 0; i < count; i++)
5591 GLYPHMETRICS metrics;
5592 struct gdi_image_bits image;
5594 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5595 if (err) continue;
5597 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5598 if (image.free) image.free( &image );
5600 if (dx)
5602 if (flags & ETO_PDY)
5604 x += dx[ i * 2 ];
5605 y += dx[ i * 2 + 1];
5607 else x += dx[ i ];
5609 else
5611 x += metrics.gmCellIncX;
5612 y += metrics.gmCellIncY;
5616 NtGdiSelectPen( dev->hdc, orig );
5617 NtGdiDeleteObjectApp( pen );
5618 return TRUE;
5621 /***********************************************************************
5622 * get_line_width
5624 * Scale the underline / strikeout line width.
5626 static inline int get_line_width( DC *dc, int metric_size )
5628 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5629 if (width == 0) width = 1;
5630 if (metric_size < 0) width = -width;
5631 return width;
5634 /***********************************************************************
5635 * NtGdiExtTextOutW (win32u.@)
5637 * Draws text using the currently selected font, background color, and text color.
5640 * PARAMS
5641 * x,y [I] coordinates of string
5642 * flags [I]
5643 * ETO_GRAYED - undocumented on MSDN
5644 * ETO_OPAQUE - use background color for fill the rectangle
5645 * ETO_CLIPPED - clipping text to the rectangle
5646 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5647 * than encoded characters. Implies ETO_IGNORELANGUAGE
5648 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5649 * Affects BiDi ordering
5650 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5651 * ETO_PDY - unimplemented
5652 * ETO_NUMERICSLATIN - unimplemented always assumed -
5653 * do not translate numbers into locale representations
5654 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5655 * lprect [I] dimensions for clipping or/and opaquing
5656 * str [I] text string
5657 * count [I] number of symbols in string
5658 * lpDx [I] optional parameter with distance between drawing characters
5660 * RETURNS
5661 * Success: TRUE
5662 * Failure: FALSE
5664 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5665 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5667 BOOL ret = FALSE;
5668 UINT align;
5669 DWORD layout;
5670 POINT pt;
5671 TEXTMETRICW tm;
5672 LOGFONTW lf;
5673 double cosEsc, sinEsc;
5674 INT char_extra;
5675 SIZE sz;
5676 RECT rc;
5677 POINT *deltas = NULL, width = {0, 0};
5678 DC * dc = get_dc_ptr( hdc );
5679 PHYSDEV physdev;
5680 INT breakRem;
5681 static int quietfixme = 0;
5683 if (!dc) return FALSE;
5684 if (count > INT_MAX) return FALSE;
5686 align = dc->attr->text_align;
5687 breakRem = dc->breakRem;
5688 layout = dc->attr->layout;
5690 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5692 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5693 quietfixme = 1;
5696 update_dc( dc );
5697 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5699 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5700 if (layout & LAYOUT_RTL)
5702 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5703 align ^= TA_RTLREADING;
5706 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5707 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5708 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5709 dc->attr->map_mode);
5711 if(align & TA_UPDATECP)
5713 pt = dc->attr->cur_pos;
5714 x = pt.x;
5715 y = pt.y;
5718 NtGdiGetTextMetricsW( hdc, &tm, 0 );
5719 NtGdiExtGetObjectW( dc->hFont, sizeof(lf), &lf );
5721 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5722 lf.lfEscapement = 0;
5724 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5725 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5727 lf.lfEscapement = -lf.lfEscapement;
5730 if(lf.lfEscapement != 0)
5732 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5733 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5735 else
5737 cosEsc = 1;
5738 sinEsc = 0;
5741 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5743 rc = *lprect;
5744 lp_to_dp(dc, (POINT*)&rc, 2);
5745 order_rect( &rc );
5746 if (flags & ETO_OPAQUE)
5747 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5749 else flags &= ~ETO_CLIPPED;
5751 if(count == 0)
5753 ret = TRUE;
5754 goto done;
5757 pt.x = x;
5758 pt.y = y;
5759 lp_to_dp(dc, &pt, 1);
5760 x = pt.x;
5761 y = pt.y;
5763 char_extra = dc->attr->char_extra;
5764 if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5765 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5767 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
5769 UINT i;
5770 POINT total = {0, 0}, desired[2];
5772 deltas = malloc( count * sizeof(*deltas) );
5773 if (lpDx)
5775 if (flags & ETO_PDY)
5777 for (i = 0; i < count; i++)
5779 deltas[i].x = lpDx[i * 2] + char_extra;
5780 deltas[i].y = -lpDx[i * 2 + 1];
5783 else
5785 for (i = 0; i < count; i++)
5787 deltas[i].x = lpDx[i] + char_extra;
5788 deltas[i].y = 0;
5792 else
5794 INT *dx = malloc( count * sizeof(*dx) );
5796 NtGdiGetTextExtentExW( hdc, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX) );
5798 deltas[0].x = dx[0];
5799 deltas[0].y = 0;
5800 for (i = 1; i < count; i++)
5802 deltas[i].x = dx[i] - dx[i - 1];
5803 deltas[i].y = 0;
5805 free( dx );
5808 for(i = 0; i < count; i++)
5810 total.x += deltas[i].x;
5811 total.y += deltas[i].y;
5813 desired[0].x = desired[0].y = 0;
5815 desired[1].x = cosEsc * total.x + sinEsc * total.y;
5816 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
5818 lp_to_dp(dc, desired, 2);
5819 desired[1].x -= desired[0].x;
5820 desired[1].y -= desired[0].y;
5822 if (dc->attr->graphics_mode == GM_COMPATIBLE)
5824 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
5825 desired[1].x = -desired[1].x;
5826 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
5827 desired[1].y = -desired[1].y;
5830 deltas[i].x = desired[1].x - width.x;
5831 deltas[i].y = desired[1].y - width.y;
5833 width = desired[1];
5835 flags |= ETO_PDY;
5837 else
5839 POINT desired[2];
5841 NtGdiGetTextExtentExW( hdc, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX) );
5842 desired[0].x = desired[0].y = 0;
5843 desired[1].x = sz.cx;
5844 desired[1].y = 0;
5845 lp_to_dp(dc, desired, 2);
5846 desired[1].x -= desired[0].x;
5847 desired[1].y -= desired[0].y;
5849 if (dc->attr->graphics_mode == GM_COMPATIBLE)
5851 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
5852 desired[1].x = -desired[1].x;
5853 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
5854 desired[1].y = -desired[1].y;
5856 width = desired[1];
5859 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
5860 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
5861 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
5863 case TA_LEFT:
5864 if (align & TA_UPDATECP)
5866 pt.x = x + width.x;
5867 pt.y = y + width.y;
5868 dp_to_lp(dc, &pt, 1);
5869 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
5871 break;
5873 case TA_CENTER:
5874 x -= width.x / 2;
5875 y -= width.y / 2;
5876 break;
5878 case TA_RIGHT:
5879 x -= width.x;
5880 y -= width.y;
5881 if (align & TA_UPDATECP)
5883 pt.x = x;
5884 pt.y = y;
5885 dp_to_lp(dc, &pt, 1);
5886 NtGdiMoveTo( hdc, pt.x, pt.y, NULL );
5888 break;
5891 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
5893 case TA_TOP:
5894 y += tm.tmAscent * cosEsc;
5895 x += tm.tmAscent * sinEsc;
5896 break;
5898 case TA_BOTTOM:
5899 y -= tm.tmDescent * cosEsc;
5900 x -= tm.tmDescent * sinEsc;
5901 break;
5903 case TA_BASELINE:
5904 break;
5907 if (dc->attr->background_mode != TRANSPARENT)
5909 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
5911 if(!(flags & ETO_OPAQUE) || !lprect ||
5912 x < rc.left || x + width.x >= rc.right ||
5913 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
5915 RECT text_box;
5916 text_box.left = x;
5917 text_box.right = x + width.x;
5918 text_box.top = y - tm.tmAscent;
5919 text_box.bottom = y + tm.tmDescent;
5921 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
5922 if (!IsRectEmpty( &text_box ))
5923 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
5928 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
5929 str, count, (INT*)deltas );
5931 done:
5932 free( deltas );
5934 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
5936 int underlinePos, strikeoutPos;
5937 int underlineWidth, strikeoutWidth;
5938 UINT size = NtGdiGetOutlineTextMetricsInternalW( hdc, 0, NULL, 0 );
5939 OUTLINETEXTMETRICW* otm = NULL;
5940 POINT pts[5];
5941 HPEN hpen = NtGdiSelectPen( hdc, GetStockObject(NULL_PEN) );
5942 HBRUSH hbrush = NtGdiCreateSolidBrush( dc->attr->text_color, NULL );
5944 hbrush = NtGdiSelectBrush(hdc, hbrush);
5946 if(!size)
5948 underlinePos = 0;
5949 underlineWidth = tm.tmAscent / 20 + 1;
5950 strikeoutPos = tm.tmAscent / 2;
5951 strikeoutWidth = underlineWidth;
5953 else
5955 otm = malloc( size );
5956 NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
5957 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
5958 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
5959 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
5960 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
5961 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
5962 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
5963 free( otm );
5967 if (lf.lfUnderline)
5969 const ULONG cnt = 5;
5970 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
5971 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
5972 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
5973 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
5974 pts[2].x = pts[1].x + underlineWidth * sinEsc;
5975 pts[2].y = pts[1].y + underlineWidth * cosEsc;
5976 pts[3].x = pts[0].x + underlineWidth * sinEsc;
5977 pts[3].y = pts[0].y + underlineWidth * cosEsc;
5978 pts[4].x = pts[0].x;
5979 pts[4].y = pts[0].y;
5980 dp_to_lp(dc, pts, 5);
5981 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
5984 if (lf.lfStrikeOut)
5986 const ULONG cnt = 5;
5987 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
5988 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
5989 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
5990 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
5991 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
5992 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
5993 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
5994 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
5995 pts[4].x = pts[0].x;
5996 pts[4].y = pts[0].y;
5997 dp_to_lp(dc, pts, 5);
5998 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6001 NtGdiSelectPen(hdc, hpen);
6002 hbrush = NtGdiSelectBrush(hdc, hbrush);
6003 NtGdiDeleteObjectApp( hbrush );
6006 release_dc_ptr( dc );
6008 return ret;
6012 /******************************************************************************
6013 * NtGdiGetCharABCWidthsW (win32u.@)
6015 * Retrieves widths of characters in range.
6017 * PARAMS
6018 * hdc [I] Handle of device context
6019 * firstChar [I] First character in range to query
6020 * lastChar [I] Last character in range to query
6021 * abc [O] Address of character-width structure
6023 * NOTES
6024 * Only works with TrueType fonts
6026 BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars,
6027 ULONG flags, void *buffer )
6029 DC *dc = get_dc_ptr(hdc);
6030 PHYSDEV dev;
6031 unsigned int i, count = last;
6032 BOOL ret;
6033 TEXTMETRICW tm;
6035 if (!dc) return FALSE;
6037 if (!buffer)
6039 release_dc_ptr( dc );
6040 return FALSE;
6043 if (flags & NTGDI_GETCHARABCWIDTHS_INDICES)
6045 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6046 ret = dev->funcs->pGetCharABCWidthsI( dev, first, count, chars, buffer );
6048 else
6050 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6052 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
6053 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
6054 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
6056 release_dc_ptr( dc );
6057 return FALSE;
6061 if (!chars) count = last - first + 1;
6062 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6063 ret = dev->funcs->pGetCharABCWidths( dev, first, count, chars, buffer );
6066 if (ret)
6068 ABC *abc = buffer;
6069 if (flags & NTGDI_GETCHARABCWIDTHS_INT)
6071 /* convert device units to logical */
6072 for (i = 0; i < count; i++)
6074 abc[i].abcA = width_to_LP( dc, abc[i].abcA );
6075 abc[i].abcB = width_to_LP( dc, abc[i].abcB );
6076 abc[i].abcC = width_to_LP( dc, abc[i].abcC );
6079 else
6081 /* convert device units to logical */
6082 FLOAT scale = fabs( dc->xformVport2World.eM11 );
6083 ABCFLOAT *abcf = buffer;
6085 for (i = 0; i < count; i++)
6087 abcf[i].abcfA = abc[i].abcA * scale;
6088 abcf[i].abcfB = abc[i].abcB * scale;
6089 abcf[i].abcfC = abc[i].abcC * scale;
6094 release_dc_ptr( dc );
6095 return ret;
6099 /***********************************************************************
6100 * NtGdiGetGlyphOutline (win32u.@)
6102 DWORD WINAPI NtGdiGetGlyphOutline( HDC hdc, UINT ch, UINT format, GLYPHMETRICS *metrics,
6103 DWORD size, void *buffer, const MAT2 *mat2,
6104 BOOL ignore_rotation )
6106 DC *dc;
6107 DWORD ret;
6108 PHYSDEV dev;
6110 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc, ch, format, metrics, size, buffer, mat2 );
6112 if (!mat2) return GDI_ERROR;
6114 dc = get_dc_ptr(hdc);
6115 if(!dc) return GDI_ERROR;
6117 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6118 ret = dev->funcs->pGetGlyphOutline( dev, ch & 0xffff, format, metrics, size, buffer, mat2 );
6119 release_dc_ptr( dc );
6120 return ret;
6124 /**********************************************************************
6125 * __wine_get_file_outline_text_metric (win32u.@)
6127 BOOL CDECL __wine_get_file_outline_text_metric( const WCHAR *path, OUTLINETEXTMETRICW *otm )
6129 struct gdi_font *font = NULL;
6131 if (!path || !font_funcs) return FALSE;
6133 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6134 font->lf.lfHeight = 100;
6135 if (!font_funcs->load_font( font )) goto done;
6136 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6137 *otm = font->otm;
6138 free_gdi_font( font );
6139 return TRUE;
6141 done:
6142 if (font) free_gdi_font( font );
6143 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6144 return FALSE;
6147 /*************************************************************************
6148 * NtGdiGetKerningPairs (win32u.@)
6150 DWORD WINAPI NtGdiGetKerningPairs( HDC hdc, DWORD count, KERNINGPAIR *kern_pair )
6152 DC *dc;
6153 DWORD ret;
6154 PHYSDEV dev;
6156 TRACE( "(%p,%d,%p)\n", hdc, count, kern_pair );
6158 if (!count && kern_pair)
6160 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6161 return 0;
6164 dc = get_dc_ptr( hdc );
6165 if (!dc) return 0;
6167 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
6168 ret = dev->funcs->pGetKerningPairs( dev, count, kern_pair );
6169 release_dc_ptr( dc );
6170 return ret;
6173 /*************************************************************************
6174 * NtGdiGetFontData (win32u.@)
6176 * Retrieve data for TrueType font.
6178 * RETURNS
6180 * success: Number of bytes returned
6181 * failure: GDI_ERROR
6183 * NOTES
6185 * Calls RtlSetLastWin32Error()
6188 DWORD WINAPI NtGdiGetFontData( HDC hdc, DWORD table, DWORD offset, void *buffer, DWORD length )
6190 DC *dc = get_dc_ptr(hdc);
6191 PHYSDEV dev;
6192 DWORD ret;
6194 if(!dc) return GDI_ERROR;
6196 dev = GET_DC_PHYSDEV( dc, pGetFontData );
6197 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
6198 release_dc_ptr( dc );
6199 return ret;
6202 /*************************************************************************
6203 * NtGdiGetGlyphIndicesW (win32u.@)
6205 DWORD WINAPI NtGdiGetGlyphIndicesW( HDC hdc, const WCHAR *str, INT count,
6206 WORD *indices, DWORD flags )
6208 DC *dc = get_dc_ptr(hdc);
6209 PHYSDEV dev;
6210 DWORD ret;
6212 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc, debugstr_wn(str, count), count, indices, flags );
6214 if(!dc) return GDI_ERROR;
6216 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
6217 ret = dev->funcs->pGetGlyphIndices( dev, str, count, indices, flags );
6218 release_dc_ptr( dc );
6219 return ret;
6222 /***********************************************************************
6224 * Font Resource API *
6226 ***********************************************************************/
6229 static int add_system_font_resource( const WCHAR *file, DWORD flags )
6231 WCHAR path[MAX_PATH];
6232 int ret;
6234 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6235 get_fonts_win_dir_path( file, path );
6236 pthread_mutex_lock( &font_lock );
6237 ret = font_funcs->add_font( path, flags );
6238 pthread_mutex_unlock( &font_lock );
6239 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6240 if (!ret)
6242 get_fonts_data_dir_path( file, path );
6243 pthread_mutex_lock( &font_lock );
6244 ret = font_funcs->add_font( path, flags );
6245 pthread_mutex_unlock( &font_lock );
6247 return ret;
6250 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
6252 WCHAR path[MAX_PATH];
6253 int ret;
6255 get_fonts_win_dir_path( file, path );
6256 if (!(ret = remove_font( path, flags )))
6258 get_fonts_data_dir_path( file, path );
6259 ret = remove_font( path, flags );
6261 return ret;
6264 static int add_font_resource( LPCWSTR file, DWORD flags )
6266 int ret = 0;
6268 if (*file == '\\')
6270 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6272 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6273 pthread_mutex_lock( &font_lock );
6274 ret = font_funcs->add_font( file, addfont_flags );
6275 pthread_mutex_unlock( &font_lock );
6277 else if (!wcschr( file, '\\' ))
6278 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6280 return ret;
6283 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
6285 BOOL ret = FALSE;
6287 if (*file == '\\')
6289 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
6291 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
6292 ret = remove_font( file, addfont_flags );
6294 else if (!wcschr( file, '\\' ))
6295 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6297 return ret;
6300 static void load_system_bitmap_fonts(void)
6302 static const char * const fonts[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6303 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6304 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6305 HKEY hkey;
6306 DWORD i;
6308 if (!(hkey = reg_open_key( NULL, fonts_config_keyW, sizeof(fonts_config_keyW) ))) return;
6309 for (i = 0; i < ARRAY_SIZE(fonts); i++)
6311 if (query_reg_ascii_value( hkey, fonts[i], info, sizeof(value_buffer) ) && info->Type == REG_SZ)
6312 add_system_font_resource( (const WCHAR *)info->Data, ADDFONT_ALLOW_BITMAP );
6314 NtClose( hkey );
6317 static void load_directory_fonts( WCHAR *path, UINT flags )
6319 OBJECT_ATTRIBUTES attr;
6320 UNICODE_STRING nt_name;
6321 IO_STATUS_BLOCK io;
6322 HANDLE handle;
6323 char buf[8192];
6324 size_t len;
6326 len = lstrlenW( path );
6327 while (len && path[len - 1] == '\\') len--;
6329 nt_name.Buffer = path;
6330 nt_name.MaximumLength = nt_name.Length = len * sizeof(WCHAR);
6332 attr.Length = sizeof(attr);
6333 attr.RootDirectory = 0;
6334 attr.Attributes = OBJ_CASE_INSENSITIVE;
6335 attr.ObjectName = &nt_name;
6336 attr.SecurityDescriptor = NULL;
6337 attr.SecurityQualityOfService = NULL;
6339 if (NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
6340 FILE_SHARE_READ | FILE_SHARE_WRITE,
6341 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ))
6342 return;
6344 path[len++] = '\\';
6346 while (!NtQueryDirectoryFile( handle, 0, NULL, NULL, &io, buf, sizeof(buf),
6347 FileBothDirectoryInformation, FALSE, NULL, FALSE ) &&
6348 io.Information)
6350 FILE_BOTH_DIR_INFORMATION *info = (FILE_BOTH_DIR_INFORMATION *)buf;
6351 for (;;)
6353 if (!(info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
6355 memcpy( path + len, info->FileName, info->FileNameLength );
6356 path[len + info->FileNameLength / sizeof(WCHAR)] = 0;
6357 font_funcs->add_font( path, flags );
6359 if (!info->NextEntryOffset) break;
6360 info = (FILE_BOTH_DIR_INFORMATION *)((char *)info + info->NextEntryOffset);
6364 NtClose( handle );
6367 static void load_file_system_fonts(void)
6369 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024 * sizeof(WCHAR)])];
6370 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6371 WCHAR *ptr, *next, path[MAX_PATH];
6373 /* Windows directory */
6374 get_fonts_win_dir_path( NULL, path );
6375 load_directory_fonts( path, 0 );
6377 /* Wine data directory */
6378 get_fonts_data_dir_path( NULL, path );
6379 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6381 /* custom paths */
6382 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6383 if (query_reg_ascii_value( wine_fonts_key, "Path", info, sizeof(value_buffer) ) &&
6384 info->Type == REG_SZ)
6386 for (ptr = (WCHAR *)info->Data; ptr; ptr = next)
6388 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
6389 if (next && next - ptr < 2) continue;
6390 lstrcpynW( path, ptr, MAX_PATH );
6391 if (path[1] == ':')
6393 memmove( path + ARRAYSIZE(nt_prefixW), path, (lstrlenW( path ) + 1) * sizeof(WCHAR) );
6394 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6396 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
6401 struct external_key
6403 struct list entry;
6404 WCHAR value[LF_FULLFACESIZE + 12];
6407 static void update_external_font_keys(void)
6409 struct list external_keys = LIST_INIT(external_keys);
6410 HKEY winnt_key = 0, win9x_key = 0;
6411 struct gdi_font_family *family;
6412 struct external_key *key, *next;
6413 struct gdi_font_face *face;
6414 DWORD len, i = 0;
6415 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6416 char buffer[2048];
6417 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
6418 WCHAR *file;
6419 HKEY hkey;
6421 static const WCHAR external_fontsW[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6423 winnt_key = reg_create_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW), 0, NULL );
6424 win9x_key = reg_create_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW), 0, NULL );
6426 /* enumerate the fonts and add external ones to the two keys */
6428 if (!(hkey = reg_create_key( wine_fonts_key, external_fontsW, sizeof(external_fontsW), 0, NULL )))
6429 return;
6431 while (reg_enum_value( hkey, i++, info, sizeof(buffer) - sizeof(nt_prefixW),
6432 value, LF_FULLFACESIZE * sizeof(WCHAR) ))
6434 if (info->Type != REG_SZ) continue;
6436 path = (WCHAR *)(buffer + info->DataOffset);
6437 if (path[0] && path[1] == ':')
6439 memmove( path + ARRAYSIZE(nt_prefixW), path, info->DataLength );
6440 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6443 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6444 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
6446 face->flags |= ADDFONT_EXTERNAL_FOUND;
6447 continue;
6449 if (tmp && !*tmp) *tmp = ' ';
6450 if (!(key = malloc( sizeof(*key) ))) break;
6451 lstrcpyW( key->value, value );
6452 list_add_tail( &external_keys, &key->entry );
6455 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
6457 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
6459 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
6460 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
6462 lstrcpyW( value, face->full_name );
6463 if (face->scalable) lstrcatW( value, true_type_suffixW );
6465 if (face->file[0] == '\\')
6467 file = face->file;
6468 if (file[5] == ':') file += ARRAYSIZE(nt_prefixW);
6470 else if ((file = wcsrchr( face->file, '\\' )))
6471 file++;
6472 else
6473 file = face->file;
6475 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
6476 set_reg_value( winnt_key, value, REG_SZ, file, len );
6477 set_reg_value( win9x_key, value, REG_SZ, file, len );
6478 set_reg_value( hkey, value, REG_SZ, file, len );
6481 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
6483 reg_delete_value( win9x_key, key->value );
6484 reg_delete_value( winnt_key, key->value );
6485 reg_delete_value( hkey, key->value );
6486 list_remove( &key->entry );
6487 free( key );
6489 NtClose( win9x_key );
6490 NtClose( winnt_key );
6491 NtClose( hkey );
6494 static void load_registry_fonts(void)
6496 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
6497 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer;
6498 KEY_VALUE_FULL_INFORMATION *enum_info = (KEY_VALUE_FULL_INFORMATION *)value_buffer;
6499 WCHAR value[LF_FULLFACESIZE + 12], *tmp, *path;
6500 DWORD i = 0, dlen;
6501 HKEY hkey;
6503 static const WCHAR dot_fonW[] = {'.','f','o','n',0};
6505 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6506 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6507 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6508 will skip these. */
6509 if (is_win9x())
6510 hkey = reg_open_key( NULL, fonts_win9x_config_keyW, sizeof(fonts_win9x_config_keyW) );
6511 else
6512 hkey = reg_open_key( NULL, fonts_winnt_config_keyW, sizeof(fonts_winnt_config_keyW) );
6513 if (!hkey) return;
6515 while (reg_enum_value( hkey, i++, enum_info, sizeof(value_buffer), value, sizeof(value) ))
6517 if (enum_info->Type != REG_SZ) continue;
6518 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, true_type_suffixW, -1 )) *tmp = 0;
6519 if (find_face_from_full_name( value )) continue;
6520 if (tmp && !*tmp) *tmp = ' ';
6522 if (!(dlen = query_reg_value( hkey, value, info, sizeof(value_buffer) - sizeof(nt_prefixW) )) ||
6523 info->Type != REG_SZ)
6525 WARN( "Unable to get face path %s\n", debugstr_w(value) );
6526 continue;
6529 path = (WCHAR *)info->Data;
6530 if (path[0] && path[1] == ':')
6532 memmove( path + ARRAYSIZE(nt_prefixW), path, dlen );
6533 memcpy( path, nt_prefixW, sizeof(nt_prefixW) );
6534 dlen += sizeof(nt_prefixW);
6537 dlen /= sizeof(WCHAR);
6538 if (*path == '\\')
6539 add_font_resource( path, ADDFONT_ALLOW_BITMAP );
6540 else if (dlen >= 6 && !wcsicmp( path + dlen - 5, dot_fonW ))
6541 add_system_font_resource( path, ADDFONT_ALLOW_BITMAP );
6543 NtClose( hkey );
6546 static HKEY open_hkcu(void)
6548 char buffer[256];
6549 WCHAR bufferW[256];
6550 DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
6551 DWORD i, len = sizeof(sid_data);
6552 SID *sid;
6554 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
6555 return 0;
6557 sid = ((TOKEN_USER *)sid_data)->User.Sid;
6558 len = sprintf( buffer, "\\Registry\\User\\S-%u-%u", sid->Revision,
6559 MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
6560 MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
6561 for (i = 0; i < sid->SubAuthorityCount; i++)
6562 len += sprintf( buffer + len, "-%u", sid->SubAuthority[i] );
6563 ascii_to_unicode( bufferW, buffer, len + 1 );
6565 return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
6568 /***********************************************************************
6569 * font_init
6571 UINT font_init(void)
6573 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
6574 UNICODE_STRING name;
6575 HANDLE mutex;
6576 DWORD disposition;
6577 UINT dpi = 0;
6579 static WCHAR wine_font_mutexW[] =
6580 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6581 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6582 static const WCHAR wine_fonts_keyW[] =
6583 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6584 static const WCHAR cacheW[] = {'C','a','c','h','e'};
6586 if (!(hkcu_key = open_hkcu())) return 0;
6587 wine_fonts_key = reg_create_key( hkcu_key, wine_fonts_keyW, sizeof(wine_fonts_keyW), 0, NULL );
6588 if (wine_fonts_key) dpi = init_font_options();
6589 if (!dpi) return 96;
6590 update_codepage( dpi );
6592 if (!(font_funcs = init_freetype_lib()))
6593 return dpi;
6595 load_system_bitmap_fonts();
6596 load_file_system_fonts();
6597 font_funcs->load_fonts();
6599 attr.Attributes = OBJ_OPENIF;
6600 attr.ObjectName = &name;
6601 name.Buffer = wine_font_mutexW;
6602 name.Length = name.MaximumLength = sizeof(wine_font_mutexW);
6604 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return dpi;
6605 NtWaitForSingleObject( mutex, FALSE, NULL );
6607 wine_fonts_cache_key = reg_create_key( wine_fonts_key, cacheW, sizeof(cacheW),
6608 REG_OPTION_VOLATILE, &disposition );
6610 if (disposition == REG_CREATED_NEW_KEY)
6612 load_registry_fonts();
6613 update_external_font_keys();
6616 NtReleaseMutant( mutex, NULL );
6618 if (disposition != REG_CREATED_NEW_KEY)
6620 load_registry_fonts();
6621 load_font_list_from_cache();
6624 reorder_font_list();
6625 load_gdi_font_subst();
6626 load_gdi_font_replacements();
6627 load_system_links();
6628 dump_gdi_font_list();
6629 dump_gdi_font_subst();
6630 return dpi;
6633 /***********************************************************************
6634 * NtGdiAddFontResourceW (win32u.@)
6636 INT WINAPI NtGdiAddFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6637 DWORD tid, void *dv )
6639 if (!font_funcs) return 1;
6640 return add_font_resource( str, flags );
6643 /***********************************************************************
6644 * NtGdiAddFontMemResourceEx (win32u.@)
6646 HANDLE WINAPI NtGdiAddFontMemResourceEx( void *ptr, DWORD size, void *dv, ULONG dv_size,
6647 DWORD *count )
6649 HANDLE ret;
6650 DWORD num_fonts;
6651 void *copy;
6653 if (!ptr || !size || !count)
6655 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER);
6656 return NULL;
6658 if (!font_funcs) return NULL;
6659 if (!(copy = malloc( size ))) return NULL;
6660 memcpy( copy, ptr, size );
6662 pthread_mutex_lock( &font_lock );
6663 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
6664 pthread_mutex_unlock( &font_lock );
6666 if (!num_fonts)
6668 free( copy );
6669 return NULL;
6672 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6673 * For now return something unique but quite random
6675 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
6677 __TRY
6679 *count = num_fonts;
6681 __EXCEPT
6683 WARN( "page fault while writing to *count (%p)\n", count );
6684 NtGdiRemoveFontMemResourceEx( ret );
6685 ret = 0;
6687 __ENDTRY
6688 TRACE( "Returning handle %p\n", ret );
6689 return ret;
6692 /***********************************************************************
6693 * NtGdiRemoveFontMemResourceEx (win32u.@)
6695 BOOL WINAPI NtGdiRemoveFontMemResourceEx( HANDLE handle )
6697 FIXME( "(%p) stub\n", handle );
6698 return TRUE;
6701 /***********************************************************************
6702 * NtGdiRemoveFontResourceW (win32u.@)
6704 BOOL WINAPI NtGdiRemoveFontResourceW( const WCHAR *str, ULONG size, ULONG files, DWORD flags,
6705 DWORD tid, void *dv )
6707 if (!font_funcs) return TRUE;
6708 return remove_font_resource( str, flags );
6711 /***********************************************************************
6712 * NtGdiGetFontUnicodeRanges (win32u.@)
6714 * Retrieve a list of supported Unicode characters in a font.
6716 * PARAMS
6717 * hdc [I] Handle to a device context.
6718 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6720 * RETURNS
6721 * Success: Number of bytes written to the buffer pointed to by lpgs.
6722 * Failure: 0
6725 DWORD WINAPI NtGdiGetFontUnicodeRanges( HDC hdc, GLYPHSET *lpgs )
6727 DWORD ret;
6728 PHYSDEV dev;
6729 DC *dc = get_dc_ptr(hdc);
6731 TRACE("(%p, %p)\n", hdc, lpgs);
6733 if (!dc) return 0;
6735 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
6736 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
6737 release_dc_ptr(dc);
6738 return ret;
6742 /*************************************************************
6743 * NtGdiFontIsLinked (win32u.@)
6745 BOOL WINAPI NtGdiFontIsLinked( HDC hdc )
6747 DC *dc = get_dc_ptr(hdc);
6748 PHYSDEV dev;
6749 BOOL ret;
6751 if (!dc) return FALSE;
6752 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
6753 ret = dev->funcs->pFontIsLinked( dev );
6754 release_dc_ptr(dc);
6755 TRACE("returning %d\n", ret);
6756 return ret;
6759 /*************************************************************
6760 * NtGdiGetRealizationInfo (win32u.@)
6762 BOOL WINAPI NtGdiGetRealizationInfo( HDC hdc, struct font_realization_info *info )
6764 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, file_count);
6765 PHYSDEV dev;
6766 BOOL ret;
6767 DC *dc;
6769 if (info->size != sizeof(*info) && !is_v0)
6770 return FALSE;
6772 dc = get_dc_ptr(hdc);
6773 if (!dc) return FALSE;
6774 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
6775 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
6776 release_dc_ptr(dc);
6777 return ret;
6780 /*************************************************************************
6781 * NtGdiGetRasterizerCaps (win32u.@)
6783 BOOL WINAPI NtGdiGetRasterizerCaps( RASTERIZER_STATUS *status, UINT size )
6785 status->nSize = sizeof(RASTERIZER_STATUS);
6786 status->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
6787 status->nLanguageID = 0;
6788 return TRUE;
6791 /*************************************************************************
6792 * NtGdiGetFontFileData (win32u.@)
6794 BOOL WINAPI NtGdiGetFontFileData( DWORD instance_id, DWORD file_index, UINT64 *offset,
6795 void *buff, DWORD buff_size )
6797 struct gdi_font *font;
6798 DWORD tag = 0, size;
6799 BOOL ret = FALSE;
6801 if (!font_funcs) return FALSE;
6802 pthread_mutex_lock( &font_lock );
6803 if ((font = get_font_from_handle( instance_id )))
6805 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
6806 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
6807 if (size != GDI_ERROR && size >= buff_size && *offset <= size - buff_size)
6808 ret = font_funcs->get_font_data( font, tag, *offset, buff, buff_size ) != GDI_ERROR;
6809 else
6810 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
6812 pthread_mutex_unlock( &font_lock );
6813 return ret;
6816 /*************************************************************************
6817 * NtGdiGetFontFileInfo (win32u.@)
6819 BOOL WINAPI NtGdiGetFontFileInfo( DWORD instance_id, DWORD file_index, struct font_fileinfo *info,
6820 SIZE_T size, SIZE_T *needed )
6822 SIZE_T required_size = 0;
6823 struct gdi_font *font;
6824 BOOL ret = FALSE;
6826 pthread_mutex_lock( &font_lock );
6828 if ((font = get_font_from_handle( instance_id )))
6830 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
6831 if (required_size <= size)
6833 info->writetime = font->writetime;
6834 info->size.QuadPart = font->data_size;
6835 lstrcpyW( info->path, font->file );
6836 ret = TRUE;
6838 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
6841 pthread_mutex_unlock( &font_lock );
6842 if (needed) *needed = required_size;
6843 return ret;
6846 /*************************************************************
6847 * NtGdiGetCharWidthInfo (win32u.@)
6849 BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info )
6851 PHYSDEV dev;
6852 BOOL ret;
6853 DC *dc;
6855 dc = get_dc_ptr(hdc);
6856 if (!dc) return FALSE;
6857 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
6858 ret = dev->funcs->pGetCharWidthInfo( dev, info );
6860 if (ret)
6862 info->lsb = width_to_LP( dc, info->lsb );
6863 info->rsb = width_to_LP( dc, info->rsb );
6865 release_dc_ptr(dc);
6866 return ret;
6869 /***********************************************************************
6870 * DrawTextW (win32u.so)
6872 INT WINAPI DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags )
6874 struct draw_text_params *params;
6875 ULONG ret_len, size;
6876 void *ret_ptr;
6877 int ret;
6879 if (count == -1) count = wcslen( str );
6880 size = FIELD_OFFSET( struct draw_text_params, str[count] );
6881 if (!(params = malloc( size ))) return 0;
6882 params->hdc = hdc;
6883 params->rect = *rect;
6884 params->ret_rect = rect;
6885 params->flags = flags;
6886 if (count) memcpy( params->str, str, count * sizeof(WCHAR) );
6887 ret = KeUserModeCallback( NtUserDrawText, params, size, &ret_ptr, &ret_len );
6888 if (ret_len == sizeof(*rect)) *rect = *(const RECT *)ret_ptr;
6889 free( params );
6890 return ret;