4 * Copyright 1993 Alexandre Julliard
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
35 #define WIN32_NO_STATUS
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
;
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
];
73 struct gdi_font_family
*replacement
;
79 unsigned int refcount
;
89 UINT flags
; /* ADDFONT flags */
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
);
213 static inline int facename_compare( const WCHAR
*str1
, const WCHAR
*str2
, SIZE_T len
)
217 WCHAR c1
= facename_tolower( *str1
++ ), c2
= facename_tolower( *str2
++ );
218 if (c1
!= c2
) return c1
- c2
;
219 else if (!c1
) 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
)
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
)
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
)
267 pt
[0].x
= pt
[0].y
= 0;
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 */
286 struct gdi_obj_header obj
;
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] =
316 "Bitstream Vera Serif"
318 static const char * const default_fixed_list
[3] =
322 "Bitstream Vera Sans Mono"
324 static const char * const default_sans_list
[3] =
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 */
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 */
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" }
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" }
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" }
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" }
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"
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"
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" }
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 */
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 */
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",
452 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
453 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
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 #ifdef WORDS_BIGENDIAN
466 #define GET_BE_WORD(x) (x)
467 #define GET_BE_DWORD(x) (x)
469 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
470 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
473 static void get_fonts_data_dir_path( const WCHAR
*file
, WCHAR
*path
)
475 const char *dir
= ntdll_get_build_dir();
476 ULONG len
= MAX_PATH
;
478 if (!dir
) dir
= ntdll_get_data_dir();
479 wine_unix_to_nt_file_name( dir
, path
, &len
);
480 asciiz_to_unicode( path
+ len
- 1, "\\fonts\\" );
481 if (file
) lstrcatW( path
, file
);
484 static void get_fonts_win_dir_path( const WCHAR
*file
, WCHAR
*path
)
486 asciiz_to_unicode( path
, "\\??\\C:\\windows\\fonts\\" );
487 if (file
) lstrcatW( path
, file
);
490 HKEY
reg_open_key( HKEY root
, const WCHAR
*name
, ULONG name_len
)
492 UNICODE_STRING nameW
= { name_len
, name_len
, (WCHAR
*)name
};
493 OBJECT_ATTRIBUTES attr
;
496 attr
.Length
= sizeof(attr
);
497 attr
.RootDirectory
= root
;
498 attr
.ObjectName
= &nameW
;
500 attr
.SecurityDescriptor
= NULL
;
501 attr
.SecurityQualityOfService
= NULL
;
503 if (NtOpenKeyEx( &ret
, MAXIMUM_ALLOWED
, &attr
, 0 )) return 0;
507 HKEY
reg_open_ascii_key( HKEY root
, const char *name
)
509 WCHAR nameW
[MAX_PATH
];
510 return reg_open_key( root
, nameW
, asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
) );
513 /* wrapper for NtCreateKey that creates the key recursively if necessary */
514 HKEY
reg_create_key( HKEY root
, const WCHAR
*name
, ULONG name_len
,
515 DWORD options
, DWORD
*disposition
)
517 UNICODE_STRING nameW
= { name_len
, name_len
, (WCHAR
*)name
};
518 OBJECT_ATTRIBUTES attr
;
522 attr
.Length
= sizeof(attr
);
523 attr
.RootDirectory
= root
;
524 attr
.ObjectName
= &nameW
;
526 attr
.SecurityDescriptor
= NULL
;
527 attr
.SecurityQualityOfService
= NULL
;
529 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, options
, disposition
);
530 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
532 static const WCHAR registry_rootW
[] = { '\\','R','e','g','i','s','t','r','y','\\' };
533 DWORD pos
= 0, i
= 0, len
= name_len
/ sizeof(WCHAR
);
535 /* don't try to create registry root */
536 if (!root
&& len
> ARRAY_SIZE(registry_rootW
) &&
537 !memcmp( name
, registry_rootW
, sizeof(registry_rootW
) ))
538 i
+= ARRAY_SIZE(registry_rootW
);
540 while (i
< len
&& name
[i
] != '\\') i
++;
541 if (i
== len
) return 0;
544 unsigned int subkey_options
= options
;
545 if (i
< len
) subkey_options
&= ~(REG_OPTION_CREATE_LINK
| REG_OPTION_OPEN_LINK
);
546 nameW
.Buffer
= (WCHAR
*)name
+ pos
;
547 nameW
.Length
= (i
- pos
) * sizeof(WCHAR
);
548 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, subkey_options
, disposition
);
550 if (attr
.RootDirectory
!= root
) NtClose( attr
.RootDirectory
);
551 if (!NT_SUCCESS(status
)) return 0;
553 attr
.RootDirectory
= ret
;
554 while (i
< len
&& name
[i
] == '\\') i
++;
556 while (i
< len
&& name
[i
] != '\\') i
++;
562 HKEY
reg_create_ascii_key( HKEY root
, const char *name
, DWORD options
,
565 WCHAR nameW
[MAX_PATH
];
566 return reg_create_key( root
, nameW
, asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
),
567 options
, disposition
);
570 HKEY
reg_open_hkcu_key( const char *name
)
572 return reg_open_ascii_key( hkcu_key
, name
);
575 BOOL
set_reg_value( HKEY hkey
, const WCHAR
*name
, UINT type
, const void *value
, DWORD count
)
577 unsigned int name_size
= name
? lstrlenW( name
) * sizeof(WCHAR
) : 0;
578 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
579 return !NtSetValueKey( hkey
, &nameW
, 0, type
, value
, count
);
582 void set_reg_ascii_value( HKEY hkey
, const char *name
, const char *value
)
584 WCHAR nameW
[64], valueW
[128];
585 asciiz_to_unicode( nameW
, name
);
586 set_reg_value( hkey
, nameW
, REG_SZ
, valueW
, asciiz_to_unicode( valueW
, value
));
589 ULONG
query_reg_value( HKEY hkey
, const WCHAR
*name
,
590 KEY_VALUE_PARTIAL_INFORMATION
*info
, ULONG size
)
592 unsigned int name_size
= name
? lstrlenW( name
) * sizeof(WCHAR
) : 0;
593 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
595 if (NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
599 return size
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
602 ULONG
query_reg_ascii_value( HKEY hkey
, const char *name
,
603 KEY_VALUE_PARTIAL_INFORMATION
*info
, ULONG size
)
606 asciiz_to_unicode( nameW
, name
);
607 return query_reg_value( hkey
, nameW
, info
, size
);
610 static BOOL
reg_enum_value( HKEY hkey
, unsigned int index
, KEY_VALUE_FULL_INFORMATION
*info
,
611 ULONG size
, WCHAR
*name
, ULONG name_size
)
615 if (NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
616 info
, size
, &full_size
))
621 if (name_size
< info
->NameLength
+ sizeof(WCHAR
)) return FALSE
;
622 memcpy( name
, info
->Name
, info
->NameLength
);
623 name
[info
->NameLength
/ sizeof(WCHAR
)] = 0;
628 void reg_delete_value( HKEY hkey
, const WCHAR
*name
)
630 unsigned int name_size
= lstrlenW( name
) * sizeof(WCHAR
);
631 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
632 NtDeleteValueKey( hkey
, &nameW
);
635 BOOL
reg_delete_tree( HKEY parent
, const WCHAR
*name
, ULONG name_len
)
638 KEY_NODE_INFORMATION
*key_info
= (KEY_NODE_INFORMATION
*)buffer
;
643 if (!(key
= reg_open_key( parent
, name
, name_len
))) return FALSE
;
645 while (ret
&& !NtEnumerateKey( key
, 0, KeyNodeInformation
, key_info
, sizeof(buffer
), &size
))
646 ret
= reg_delete_tree( key
, key_info
->Name
, key_info
->NameLength
);
648 if (ret
) ret
= !NtDeleteKey( key
);
653 /* font substitutions */
655 struct gdi_font_subst
663 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
665 static inline WCHAR
*get_subst_to_name( struct gdi_font_subst
*subst
)
667 return subst
->names
+ lstrlenW( subst
->names
) + 1;
670 static void dump_gdi_font_subst(void)
672 struct gdi_font_subst
*subst
;
674 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
676 if (subst
->from_charset
!= -1 || subst
->to_charset
!= -1)
677 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst
->names
),
678 subst
->from_charset
, debugstr_w(get_subst_to_name(subst
)), subst
->to_charset
);
680 TRACE("%s -> %s\n", debugstr_w(subst
->names
), debugstr_w(get_subst_to_name(subst
)));
684 static const WCHAR
*get_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, int *to_charset
)
686 struct gdi_font_subst
*subst
;
688 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
690 if (!facename_compare( subst
->names
, from_name
, -1 ) &&
691 (subst
->from_charset
== from_charset
|| subst
->from_charset
== -1))
693 if (to_charset
) *to_charset
= subst
->to_charset
;
694 return get_subst_to_name( subst
);
700 static BOOL
add_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, const WCHAR
*to_name
, int to_charset
)
702 struct gdi_font_subst
*subst
;
703 int len
= lstrlenW( from_name
) + lstrlenW( to_name
) + 2;
705 if (get_gdi_font_subst( from_name
, from_charset
, NULL
)) return FALSE
; /* already exists */
707 if (!(subst
= malloc( offsetof( struct gdi_font_subst
, names
[len
] ) )))
709 lstrcpyW( subst
->names
, from_name
);
710 lstrcpyW( get_subst_to_name(subst
), to_name
);
711 subst
->from_charset
= from_charset
;
712 subst
->to_charset
= to_charset
;
713 list_add_tail( &font_subst_list
, &subst
->entry
);
717 static void load_gdi_font_subst(void)
720 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
723 WCHAR
*data
, *p
, value
[64];
725 if (!(hkey
= reg_open_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
) )))
728 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
730 int from_charset
= -1, to_charset
= -1;
732 if (info
->Type
!= REG_SZ
) continue;
733 data
= (WCHAR
*)((char *)info
+ info
->DataOffset
);
735 TRACE( "Got %s=%s\n", debugstr_w(value
), debugstr_w(data
) );
736 if ((p
= wcsrchr( value
, ',' )) && p
[1])
739 from_charset
= wcstol( p
, NULL
, 10 );
741 if ((p
= wcsrchr( data
, ',' )) && p
[1])
744 to_charset
= wcstol( p
, NULL
, 10 );
747 /* Win 2000 doesn't allow mapping between different charsets
748 or mapping of DEFAULT_CHARSET */
749 if ((!from_charset
|| to_charset
== from_charset
) && to_charset
!= DEFAULT_CHARSET
)
750 add_gdi_font_subst( value
, from_charset
, data
, to_charset
);
757 static int family_namecmp( const WCHAR
*str1
, const WCHAR
*str2
)
759 int prio1
, prio2
, vert1
= (str1
[0] == '@' ? 1 : 0), vert2
= (str2
[0] == '@' ? 1 : 0);
761 if (!facename_compare( str1
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio1
= 0;
762 else if (!facename_compare( str1
, ff_modern_default
, LF_FACESIZE
- 1 )) prio1
= 1;
763 else if (!facename_compare( str1
, ff_roman_default
, LF_FACESIZE
- 1 )) prio1
= 2;
766 if (!facename_compare( str2
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio2
= 0;
767 else if (!facename_compare( str2
, ff_modern_default
, LF_FACESIZE
- 1 )) prio2
= 1;
768 else if (!facename_compare( str2
, ff_roman_default
, LF_FACESIZE
- 1 )) prio2
= 2;
771 if (prio1
!= prio2
) return prio1
- prio2
;
772 if (vert1
!= vert2
) return vert1
- vert2
;
773 return facename_compare( str1
+ vert1
, str2
+ vert2
, LF_FACESIZE
- 1 );
776 static int family_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
778 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, name_entry
);
779 return family_namecmp( (const WCHAR
*)key
, family
->family_name
);
782 static int family_second_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
784 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, second_name_entry
);
785 return family_namecmp( (const WCHAR
*)key
, family
->second_name
);
788 static int face_full_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
790 const struct gdi_font_face
*face
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_face
, full_name_entry
);
791 return facename_compare( (const WCHAR
*)key
, face
->full_name
, LF_FULLFACESIZE
- 1 );
794 static struct wine_rb_tree family_name_tree
= { family_name_compare
};
795 static struct wine_rb_tree family_second_name_tree
= { family_second_name_compare
};
796 static struct wine_rb_tree face_full_name_tree
= { face_full_name_compare
};
798 static int face_is_in_full_name_tree( const struct gdi_font_face
*face
)
800 return face
->full_name_entry
.parent
|| face_full_name_tree
.root
== &face
->full_name_entry
;
803 static struct gdi_font_family
*create_family( const WCHAR
*name
, const WCHAR
*second_name
)
805 struct gdi_font_family
*family
= malloc( sizeof(*family
) );
807 family
->refcount
= 1;
808 lstrcpynW( family
->family_name
, name
, LF_FACESIZE
);
809 if (second_name
&& second_name
[0] && wcsicmp( name
, second_name
))
811 lstrcpynW( family
->second_name
, second_name
, LF_FACESIZE
);
812 add_gdi_font_subst( second_name
, -1, name
, -1 );
814 else family
->second_name
[0] = 0;
815 list_init( &family
->faces
);
816 family
->replacement
= NULL
;
817 wine_rb_put( &family_name_tree
, family
->family_name
, &family
->name_entry
);
818 if (family
->second_name
[0]) wine_rb_put( &family_second_name_tree
, family
->second_name
, &family
->second_name_entry
);
822 static void release_family( struct gdi_font_family
*family
)
824 if (--family
->refcount
) return;
825 assert( list_empty( &family
->faces
));
826 wine_rb_remove( &family_name_tree
, &family
->name_entry
);
827 if (family
->second_name
[0]) wine_rb_remove( &family_second_name_tree
, &family
->second_name_entry
);
828 if (family
->replacement
) release_family( family
->replacement
);
832 static struct gdi_font_family
*find_family_from_name( const WCHAR
*name
)
834 struct wine_rb_entry
*entry
;
835 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) return NULL
;
836 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, name_entry
);
839 static struct gdi_font_family
*find_family_from_any_name( const WCHAR
*name
)
841 struct wine_rb_entry
*entry
;
842 struct gdi_font_family
*family
;
843 if ((family
= find_family_from_name( name
))) return family
;
844 if (!(entry
= wine_rb_get( &family_second_name_tree
, name
))) return NULL
;
845 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, second_name_entry
);
848 static struct gdi_font_face
*find_face_from_full_name( const WCHAR
*full_name
)
850 struct wine_rb_entry
*entry
;
851 if (!(entry
= wine_rb_get( &face_full_name_tree
, full_name
))) return NULL
;
852 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_face
, full_name_entry
);
855 static const struct list
*get_family_face_list( const struct gdi_font_family
*family
)
857 return family
->replacement
? &family
->replacement
->faces
: &family
->faces
;
860 static struct gdi_font_face
*family_find_face_from_filename( struct gdi_font_family
*family
, const WCHAR
*file_name
)
862 struct gdi_font_face
*face
;
864 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
866 if (!face
->file
) continue;
867 file
= wcsrchr(face
->file
, '\\');
868 if (!file
) file
= face
->file
;
870 if (wcsicmp( file
, file_name
)) continue;
877 static struct gdi_font_face
*find_face_from_filename( const WCHAR
*file_name
, const WCHAR
*family_name
)
879 struct gdi_font_family
*family
;
880 struct gdi_font_face
*face
;
882 TRACE( "looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(family_name
) );
886 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
887 if ((face
= family_find_face_from_filename( family
, file_name
))) return face
;
891 if (!(family
= find_family_from_name( family_name
))) return NULL
;
892 return family_find_face_from_filename( family
, file_name
);
895 static BOOL
add_family_replacement( const WCHAR
*new_name
, const WCHAR
*replace
)
897 struct gdi_font_family
*new_family
, *family
;
898 struct gdi_font_face
*face
;
899 WCHAR new_name_vert
[LF_FACESIZE
], replace_vert
[LF_FACESIZE
];
901 if (!(family
= find_family_from_any_name( replace
)))
903 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace
) );
907 if (family
->replacement
)
909 TRACE( "%s is replaced by another font, skipping.\n", debugstr_w(replace
) );
913 if (!(new_family
= create_family( new_name
, NULL
))) return FALSE
;
914 new_family
->replacement
= family
;
916 TRACE( "mapping %s to %s\n", debugstr_w(replace
), debugstr_w(new_name
) );
918 /* also add replacement for vertical font if necessary */
919 if (replace
[0] == '@') return TRUE
;
920 if (list_empty( &family
->faces
)) return TRUE
;
921 face
= LIST_ENTRY( list_head(&family
->faces
), struct gdi_font_face
, entry
);
922 if (!(face
->fs
.fsCsb
[0] & FS_DBCS_MASK
)) return TRUE
;
924 new_name_vert
[0] = '@';
925 lstrcpynW( new_name_vert
+ 1, new_name
, LF_FACESIZE
- 1 );
926 if (find_family_from_any_name( new_name_vert
)) return TRUE
; /* already exists */
928 replace_vert
[0] = '@';
929 lstrcpynW( replace_vert
+ 1, replace
, LF_FACESIZE
- 1 );
930 add_family_replacement( new_name_vert
, replace_vert
);
935 * The replacement list is a way to map an entire font
936 * family onto another family. For example adding
938 * [HKCU\Software\Wine\Fonts\Replacements]
939 * "Wingdings"="Winedings"
941 * would enumerate the Winedings font both as Winedings and
942 * Wingdings. However if a real Wingdings font is present the
943 * replacement does not take place.
945 static void load_gdi_font_replacements(void)
948 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
951 WCHAR value
[LF_FACESIZE
];
953 static const WCHAR replacementsW
[] = {'R','e','p','l','a','c','e','m','e','n','t','s'};
955 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
956 if (!(hkey
= reg_open_key( wine_fonts_key
, replacementsW
, sizeof(replacementsW
) ))) return;
958 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
960 WCHAR
*data
= (WCHAR
*)((char *)info
+ info
->DataOffset
);
961 /* "NewName"="Oldname" */
962 if (!find_family_from_any_name( value
))
964 if (info
->Type
== REG_MULTI_SZ
)
966 WCHAR
*replace
= data
;
969 if (add_family_replacement( value
, replace
)) break;
970 replace
+= lstrlenW(replace
) + 1;
973 else if (info
->Type
== REG_SZ
) add_family_replacement( value
, data
);
975 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
980 static void dump_gdi_font_list(void)
982 struct gdi_font_family
*family
;
983 struct gdi_font_face
*face
;
985 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
987 TRACE( "Family: %s\n", debugstr_w(family
->family_name
) );
988 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
990 TRACE( "\t%s\t%s\t%08x", debugstr_w(face
->style_name
), debugstr_w(face
->full_name
),
991 (int)face
->fs
.fsCsb
[0] );
992 if (!face
->scalable
) TRACE(" %d", face
->size
.height
);
998 static BOOL
enum_fallbacks( DWORD pitch_and_family
, int index
, WCHAR buffer
[LF_FACESIZE
] )
1002 const char * const *defaults
;
1004 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
)
1005 defaults
= default_fixed_list
;
1006 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
)
1007 defaults
= default_serif_list
;
1009 defaults
= default_sans_list
;
1010 asciiz_to_unicode( buffer
, defaults
[index
] );
1013 return font_funcs
->enum_family_fallbacks( pitch_and_family
, index
- 3, buffer
);
1016 static void set_default_family( DWORD pitch_and_family
, WCHAR
*default_name
)
1018 struct wine_rb_entry
*entry
;
1019 WCHAR name
[LF_FACESIZE
];
1022 while (enum_fallbacks( pitch_and_family
, i
++, name
))
1024 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) continue;
1025 wine_rb_remove( &family_name_tree
, entry
);
1026 lstrcpynW( default_name
, name
, LF_FACESIZE
- 1 );
1027 wine_rb_put( &family_name_tree
, name
, entry
);
1032 static void reorder_font_list(void)
1034 set_default_family( FF_ROMAN
, ff_roman_default
);
1035 set_default_family( FF_MODERN
, ff_modern_default
);
1036 set_default_family( FF_SWISS
, ff_swiss_default
);
1039 static void release_face( struct gdi_font_face
*face
)
1041 if (--face
->refcount
) return;
1044 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1045 list_remove( &face
->entry
);
1046 release_family( face
->family
);
1048 if (face_is_in_full_name_tree( face
)) wine_rb_remove( &face_full_name_tree
, &face
->full_name_entry
);
1050 free( face
->style_name
);
1051 free( face
->full_name
);
1052 free( face
->cached_enum_data
);
1056 static int remove_font( const WCHAR
*file
, DWORD flags
)
1058 struct gdi_font_family
*family
, *family_next
;
1059 struct gdi_font_face
*face
, *face_next
;
1062 pthread_mutex_lock( &font_lock
);
1063 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family
, family_next
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1066 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, struct gdi_font_face
, entry
)
1068 if (!face
->file
) continue;
1069 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
1070 if (!wcsicmp( face
->file
, file
))
1072 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
1073 release_face( face
);
1077 release_family( family
);
1079 pthread_mutex_unlock( &font_lock
);
1083 static inline BOOL
faces_equal( const struct gdi_font_face
*f1
, const struct gdi_font_face
*f2
)
1085 if (facename_compare( f1
->full_name
, f2
->full_name
, -1 )) return FALSE
;
1086 if (f1
->scalable
) return TRUE
;
1087 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1088 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1091 static inline int style_order( const struct gdi_font_face
*face
)
1093 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1101 case NTM_BOLD
| NTM_ITALIC
:
1104 WARN( "Don't know how to order face %s with flags 0x%08x\n",
1105 debugstr_w(face
->full_name
), face
->ntmFlags
);
1110 static BOOL
insert_face_in_family_list( struct gdi_font_face
*face
, struct gdi_font_family
*family
)
1112 struct gdi_font_face
*cursor
;
1114 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, struct gdi_font_face
, entry
)
1116 if (faces_equal( face
, cursor
))
1118 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
1119 debugstr_w(face
->full_name
), debugstr_w(family
->family_name
),
1120 cursor
->version
, face
->version
);
1122 if (face
->file
&& cursor
->file
&& !wcsicmp( face
->file
, cursor
->file
))
1125 TRACE("Font %s already in list, refcount now %d\n",
1126 debugstr_w(face
->file
), cursor
->refcount
);
1129 if (face
->version
<= cursor
->version
)
1131 TRACE("Original font %s is newer so skipping %s\n",
1132 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1137 TRACE("Replacing original %s with %s\n",
1138 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1139 list_add_before( &cursor
->entry
, &face
->entry
);
1140 face
->family
= family
;
1143 if (face_is_in_full_name_tree( cursor
))
1145 wine_rb_replace( &face_full_name_tree
, &cursor
->full_name_entry
, &face
->full_name_entry
);
1146 memset( &cursor
->full_name_entry
, 0, sizeof(cursor
->full_name_entry
) );
1148 release_face( cursor
);
1152 if (style_order( face
) < style_order( cursor
)) break;
1155 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face
->full_name
),
1156 debugstr_w(family
->family_name
), debugstr_w(face
->file
) );
1157 list_add_before( &cursor
->entry
, &face
->entry
);
1158 if (face
->scalable
) wine_rb_put( &face_full_name_tree
, face
->full_name
, &face
->full_name_entry
);
1159 face
->family
= family
;
1165 static struct gdi_font_face
*create_face( struct gdi_font_family
*family
, const WCHAR
*style
,
1166 const WCHAR
*fullname
, const WCHAR
*file
,
1167 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
1168 DWORD ntmflags
, DWORD version
, DWORD flags
,
1169 const struct bitmap_font_size
*size
)
1171 struct gdi_font_face
*face
= calloc( 1, sizeof(*face
) );
1174 face
->style_name
= wcsdup( style
);
1175 face
->full_name
= wcsdup( fullname
);
1176 face
->face_index
= index
;
1178 face
->ntmFlags
= ntmflags
;
1179 face
->version
= version
;
1180 face
->flags
= flags
;
1181 face
->data_ptr
= data_ptr
;
1182 face
->data_size
= data_size
;
1183 if (file
) face
->file
= wcsdup( file
);
1184 if (size
) face
->size
= *size
;
1185 else face
->scalable
= TRUE
;
1186 if (insert_face_in_family_list( face
, family
)) return face
;
1187 release_face( face
);
1191 int add_gdi_face( const WCHAR
*family_name
, const WCHAR
*second_name
,
1192 const WCHAR
*style
, const WCHAR
*fullname
, const WCHAR
*file
,
1193 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
1194 DWORD ntmflags
, DWORD version
, DWORD flags
,
1195 const struct bitmap_font_size
*size
)
1197 struct gdi_font_face
*face
;
1198 struct gdi_font_family
*family
;
1201 if ((family
= find_family_from_name( family_name
))) family
->refcount
++;
1202 else if (!(family
= create_family( family_name
, second_name
))) return ret
;
1204 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1205 index
, fs
, ntmflags
, version
, flags
, size
)))
1207 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1208 release_face( face
);
1210 release_family( family
);
1213 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
1215 WCHAR vert_family
[LF_FACESIZE
], vert_second
[LF_FACESIZE
], vert_full
[LF_FULLFACESIZE
];
1217 vert_family
[0] = '@';
1218 lstrcpynW( vert_family
+ 1, family_name
, LF_FACESIZE
- 1 );
1220 if (second_name
&& second_name
[0])
1222 vert_second
[0] = '@';
1223 lstrcpynW( vert_second
+ 1, second_name
, LF_FACESIZE
- 1 );
1225 else vert_second
[0] = 0;
1230 lstrcpynW( vert_full
+ 1, fullname
, LF_FULLFACESIZE
- 1 );
1231 fullname
= vert_full
;
1234 if ((family
= find_family_from_name( vert_family
))) family
->refcount
++;
1235 else if (!(family
= create_family( vert_family
, vert_second
))) return ret
;
1237 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1238 index
, fs
, ntmflags
, version
, flags
| ADDFONT_VERTICAL_FONT
, size
)))
1240 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1241 release_face( face
);
1243 release_family( family
);
1257 struct bitmap_font_size size
;
1260 /* WCHAR file_name[]; */
1263 static void load_face_from_cache( HKEY hkey_family
, struct gdi_font_family
*family
,
1264 void *buffer
, DWORD buffer_size
, BOOL scalable
)
1266 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1267 KEY_NODE_INFORMATION
*node_info
= (KEY_NODE_INFORMATION
*)buffer
;
1268 DWORD index
= 0, total_size
;
1269 struct gdi_font_face
*face
;
1272 struct cached_face
*cached
;
1274 while (reg_enum_value( hkey_family
, index
++, info
,
1275 buffer_size
- sizeof(DWORD
), name
, sizeof(name
) ))
1277 cached
= (struct cached_face
*)((char *)info
+ info
->DataOffset
);
1278 if (info
->Type
== REG_BINARY
&& info
->DataLength
> sizeof(*cached
))
1280 ((DWORD
*)cached
)[info
->DataLength
/ sizeof(DWORD
)] = 0;
1281 if ((face
= create_face( family
, name
, cached
->full_name
,
1282 cached
->full_name
+ lstrlenW(cached
->full_name
) + 1,
1283 NULL
, 0, cached
->index
, cached
->fs
, cached
->ntmflags
, cached
->version
,
1284 cached
->flags
, scalable
? NULL
: &cached
->size
)))
1287 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1288 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1289 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1291 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1292 (int)face
->fs
.fsCsb
[0], (int)face
->fs
.fsCsb
[1],
1293 (int)face
->fs
.fsUsb
[0], (int)face
->fs
.fsUsb
[1],
1294 (int)face
->fs
.fsUsb
[2], (int)face
->fs
.fsUsb
[3]);
1296 release_face( face
);
1301 /* load bitmap strikes */
1304 while (!NtEnumerateKey( hkey_family
, index
++, KeyNodeInformation
, node_info
,
1305 buffer_size
, &total_size
))
1307 if ((hkey_strike
= reg_open_key( hkey_family
, node_info
->Name
, node_info
->NameLength
)))
1309 load_face_from_cache( hkey_strike
, family
, buffer
, buffer_size
, FALSE
);
1310 NtClose( hkey_strike
);
1315 static void load_font_list_from_cache(void)
1318 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)buffer
;
1319 KEY_NODE_INFORMATION
*enum_info
= (KEY_NODE_INFORMATION
*)buffer
;
1320 DWORD family_index
= 0, total_size
;
1321 struct gdi_font_family
*family
;
1323 WCHAR
*second_name
= (WCHAR
*)info
->Data
;
1325 while (!NtEnumerateKey( wine_fonts_cache_key
, family_index
++, KeyNodeInformation
, enum_info
,
1326 sizeof(buffer
), &total_size
))
1328 if (!(hkey_family
= reg_open_key( wine_fonts_cache_key
, enum_info
->Name
,
1329 enum_info
->NameLength
)))
1331 TRACE( "opened family key %s\n", debugstr_wn(enum_info
->Name
, enum_info
->NameLength
/ sizeof(WCHAR
)) );
1332 if (!query_reg_value( hkey_family
, NULL
, info
, sizeof(buffer
) ))
1335 family
= create_family( buffer
, second_name
);
1337 load_face_from_cache( hkey_family
, family
, buffer
, sizeof(buffer
), TRUE
);
1339 NtClose( hkey_family
);
1340 release_family( family
);
1344 static void add_face_to_cache( struct gdi_font_face
*face
)
1346 HKEY hkey_family
, hkey_face
;
1347 DWORD len
, buffer
[1024];
1348 struct cached_face
*cached
= (struct cached_face
*)buffer
;
1350 if (!(hkey_family
= reg_create_key( wine_fonts_cache_key
, face
->family
->family_name
,
1351 lstrlenW( face
->family
->family_name
) * sizeof(WCHAR
),
1352 REG_OPTION_VOLATILE
, NULL
)))
1355 if (face
->family
->second_name
[0])
1356 set_reg_value( hkey_family
, NULL
, REG_SZ
, face
->family
->second_name
,
1357 (lstrlenW( face
->family
->second_name
) + 1) * sizeof(WCHAR
) );
1359 if (!face
->scalable
)
1364 snprintf( name
, sizeof(name
), "%d", face
->size
.y_ppem
);
1365 hkey_face
= reg_create_key( hkey_family
, nameW
,
1366 asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
),
1367 REG_OPTION_VOLATILE
, NULL
);
1369 else hkey_face
= hkey_family
;
1371 memset( cached
, 0, sizeof(*cached
) );
1372 cached
->index
= face
->face_index
;
1373 cached
->flags
= face
->flags
;
1374 cached
->ntmflags
= face
->ntmFlags
;
1375 cached
->version
= face
->version
;
1376 cached
->fs
= face
->fs
;
1377 if (!face
->scalable
) cached
->size
= face
->size
;
1378 lstrcpyW( cached
->full_name
, face
->full_name
);
1379 len
= lstrlenW( face
->full_name
) + 1;
1380 lstrcpyW( cached
->full_name
+ len
, face
->file
);
1381 len
+= lstrlenW( face
->file
) + 1;
1383 set_reg_value( hkey_face
, face
->style_name
, REG_BINARY
, cached
,
1384 offsetof( struct cached_face
, full_name
[len
] ));
1386 if (hkey_face
!= hkey_family
) NtClose( hkey_face
);
1387 NtClose( hkey_family
);
1390 static void remove_face_from_cache( struct gdi_font_face
*face
)
1392 HKEY hkey_family
, hkey
;
1394 if (!(hkey_family
= reg_open_key( wine_fonts_cache_key
, face
->family
->family_name
,
1395 lstrlenW( face
->family
->family_name
) * sizeof(WCHAR
) )))
1398 if (!face
->scalable
)
1402 snprintf( name
, sizeof(name
), "%d", face
->size
.y_ppem
);
1403 if ((hkey
= reg_open_key( hkey_family
, nameW
,
1404 asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
) )))
1406 NtDeleteKey( hkey
);
1410 else reg_delete_value( hkey_family
, face
->style_name
);
1412 NtClose( hkey_family
);
1417 struct gdi_font_link
1421 WCHAR name
[LF_FACESIZE
];
1425 struct gdi_font_link_entry
1429 WCHAR family_name
[LF_FACESIZE
];
1432 static struct list font_links
= LIST_INIT(font_links
);
1434 static struct gdi_font_link
*find_gdi_font_link( const WCHAR
*name
)
1436 struct gdi_font_link
*link
;
1438 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1439 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 )) return link
;
1443 static struct gdi_font_family
*find_family_from_font_links( const WCHAR
*name
, const WCHAR
*subst
,
1446 struct gdi_font_link
*link
;
1447 struct gdi_font_link_entry
*entry
;
1448 struct gdi_font_family
*family
;
1450 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1452 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 ) ||
1453 (subst
&& !facename_compare( link
->name
, subst
, LF_FACESIZE
- 1 )))
1455 TRACE("found entry in system list\n");
1456 LIST_FOR_EACH_ENTRY( entry
, &link
->links
, struct gdi_font_link_entry
, entry
)
1458 const struct gdi_font_link
*links
;
1460 family
= find_family_from_name( entry
->family_name
);
1461 if (!fs
.fsCsb
[0]) return family
;
1462 if (fs
.fsCsb
[0] & entry
->fs
.fsCsb
[0]) return family
;
1463 if ((links
= find_gdi_font_link( family
->family_name
)) && fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
1471 static struct gdi_font_link
*add_gdi_font_link( const WCHAR
*name
)
1473 struct gdi_font_link
*link
= find_gdi_font_link( name
);
1475 if (link
) return link
;
1476 if ((link
= malloc( sizeof(*link
) )))
1478 lstrcpynW( link
->name
, name
, LF_FACESIZE
);
1479 memset( &link
->fs
, 0, sizeof(link
->fs
) );
1480 list_init( &link
->links
);
1481 list_add_tail( &font_links
, &link
->entry
);
1486 static void add_gdi_font_link_entry( struct gdi_font_link
*link
, const WCHAR
*family_name
, FONTSIGNATURE fs
)
1488 struct gdi_font_link_entry
*entry
;
1490 entry
= malloc( sizeof(*entry
) );
1491 lstrcpynW( entry
->family_name
, family_name
, LF_FACESIZE
);
1493 link
->fs
.fsCsb
[0] |= fs
.fsCsb
[0];
1494 link
->fs
.fsCsb
[1] |= fs
.fsCsb
[1];
1495 list_add_tail( &link
->links
, &entry
->entry
);
1498 static const WCHAR lucida_sans_unicodeW
[] =
1499 {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
1500 static const WCHAR microsoft_sans_serifW
[] =
1501 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1502 static const WCHAR tahomaW
[] =
1503 {'T','a','h','o','m','a',0};
1504 static const WCHAR ms_gothicW
[] =
1505 {'M','S',' ','G','o','t','h','i','c',0};
1506 static const WCHAR ms_p_gothicW
[] =
1507 {'M','S',' ','P','G','o','t','h','i','c',0};
1508 static const WCHAR ms_ui_gothicW
[] =
1509 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1510 static const WCHAR sim_sunW
[] =
1511 {'S','i','m','S','u','n',0};
1512 static const WCHAR gulimW
[] =
1513 {'G','u','l','i','m',0};
1514 static const WCHAR ming_li_uW
[] =
1515 {'M','i','n','g','L','i','U',0};
1516 static const WCHAR p_ming_li_uW
[] =
1517 {'P','M','i','n','g','L','i','U',0};
1518 static const WCHAR ming_li_u_hkscsW
[] =
1519 {'M','i','n','g','L','i','U','_','H','K','S','C','S',0};
1520 static const WCHAR ming_li_u_ext_bW
[] =
1521 {'M','i','n','g','L','i','U','-','E','x','t','B',0};
1522 static const WCHAR p_ming_li_u_ext_bW
[] =
1523 {'P','M','i','n','g','L','i','U','-','E','x','t','B',0};
1524 static const WCHAR ming_li_u_hkscs_ext_bW
[] =
1525 {'M','i','n','g','L','i','U','_','H','K','S','C','S','-','E','x','t','B',0};
1526 static const WCHAR batangW
[] =
1527 {'B','a','t','a','n','g',0};
1528 static const WCHAR microsoft_jheng_heiW
[] =
1529 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',0};
1530 static const WCHAR microsoft_jheng_hei_boldW
[] =
1531 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','B','o','l','d',0};
1532 static const WCHAR microsoft_jheng_hei_uiW
[] =
1533 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',0};
1534 static const WCHAR microsoft_jheng_hei_ui_boldW
[] =
1535 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','B','o','l','d',0};
1536 static const WCHAR microsoft_jheng_hei_ui_lightW
[] =
1537 {'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 yu_gothic_uiW
[] =
1539 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',0};
1540 static const WCHAR yu_gothic_ui_boldW
[] =
1541 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','B','o','l','d',0};
1542 static const WCHAR yu_gothic_ui_lightW
[] =
1543 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','L','i','g','h','t',0};
1544 static const WCHAR yu_gothic_ui_semilightW
[] =
1545 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','S','e','m','i','l','i','g','h','t',0};
1546 static const WCHAR yu_gothic_ui_semiboldW
[] =
1547 {'Y','u',' ','G','o','t','h','i','c',' ','U','I',' ','S','e','m','i','b','o','l','d',0};
1548 static const WCHAR meiryoW
[] =
1549 {'M','e','i','r','y','o',0};
1550 static const WCHAR meiryo_boldW
[] =
1551 {'M','e','i','r','y','o',' ','B','o','l','d',0};
1552 static const WCHAR meiryo_uiW
[] =
1553 {'M','e','i','r','y','o',' ','U','I',0};
1554 static const WCHAR meiryo_ui_boldW
[] =
1555 {'M','e','i','r','y','o',' ','U','I',' ','B','o','l','d',0};
1556 static const WCHAR ms_minchoW
[] =
1557 {'M','S',' ','M','i','n','c','h','o',0};
1558 static const WCHAR ms_p_minchoW
[] =
1559 {'M','S',' ','P','M','i','n','c','h','o',0};
1561 static const WCHAR
* const font_links_list
[] =
1563 lucida_sans_unicodeW
,
1564 microsoft_sans_serifW
,
1568 static const struct font_links_defaults_list
1570 /* Keyed off substitution for "MS Shell Dlg" */
1571 const WCHAR
*shelldlg
;
1572 /* Maximum of four substitutes, plus terminating NULL pointer */
1573 const WCHAR
*substitutes
[5];
1574 } font_links_defaults_list
[] =
1576 /* Non East-Asian */
1577 { tahomaW
, /* FIXME unverified ordering */
1578 { ms_ui_gothicW
, sim_sunW
, gulimW
, p_ming_li_uW
, NULL
}
1580 /* Below lists are courtesy of
1581 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1585 { ms_ui_gothicW
, p_ming_li_uW
, sim_sunW
, gulimW
, NULL
}
1587 /* Chinese Simplified */
1589 { sim_sunW
, p_ming_li_uW
, ms_ui_gothicW
, batangW
, NULL
}
1593 { gulimW
, p_ming_li_uW
, ms_ui_gothicW
, sim_sunW
, NULL
}
1595 /* Chinese Traditional */
1597 { p_ming_li_uW
, sim_sunW
, ms_ui_gothicW
, batangW
, NULL
}
1601 static const char system_link_tahoma_sc
[] =
1602 "SIMSUN.TTC,SimSun\0"
1603 "MINGLIU.TTC,PMingLiu\0"
1604 "MSGOTHIC.TTC,MS UI Gothic\0"
1605 "BATANG.TTC,Batang\0"
1606 "MSYH.TTC,Microsoft YaHei UI\0"
1607 "MSJH.TTC,Microsoft JhengHei UI\0"
1608 "YUGOTHM.TTC,Yu Gothic UI\0"
1609 "MALGUN.TTF,Malgun Gothic\0"
1610 "SEGUISYM.TTF,Segoe UI Symbol\0";
1612 static const char system_link_tahoma_tc
[] =
1613 "MINGLIU.TTC,PMingLiu\0"
1614 "SIMSUN.TTC,SimSun\0"
1615 "MSGOTHIC.TTC,MS UI Gothic\0"
1616 "BATANG.TTC,Batang\0"
1617 "MSJH.TTC,Microsoft JhengHei UI\0"
1618 "MSYH.TTC,Microsoft YaHei UI\0"
1619 "YUGOTHM.TTC,Yu Gothic UI\0"
1620 "MALGUN.TTF,Malgun Gothic\0"
1621 "SEGUISYM.TTF,Segoe UI Symbol\0";
1623 static const char system_link_tahoma_jp
[] =
1624 "MSGOTHIC.TTC,MS UI Gothic\0"
1625 "MINGLIU.TTC,PMingLiU\0"
1626 "SIMSUN.TTC,SimSun\0"
1628 "YUGOTHM.TTC,Yu Gothic UI\0"
1629 "MSJH.TTC,Microsoft JhengHei UI\0"
1630 "MSYH.TTC,Microsoft YaHei UI\0"
1631 "MALGUN.TTF,Malgun Gothic\0"
1632 "SEGUISYM.TTF,Segoe UI Symbol\0";
1634 static const char system_link_tahoma_kr
[] =
1636 "MSGOTHIC.TTC,MS UI Gothic\0"
1637 "MINGLIU.TTC,PMingLiU\0"
1638 "SIMSUN.TTC,SimSun\0"
1639 "MALGUN.TTF,Malgun Gothic\0"
1640 "YUGOTHM.TTC,Yu Gothic UI\0"
1641 "MSJH.TTC,Microsoft JhengHei UI\0"
1642 "MSYH.TTC,Microsoft YaHei UI\0"
1643 "SEGUISYM.TTF,Segoe UI Symbol\0";
1645 static const char system_link_tahoma_non_cjk
[] =
1646 "MSGOTHIC.TTC,MS UI Gothic\0"
1647 "MINGLIU.TTC,PMingLiU\0"
1648 "SIMSUN.TTC,SimSun\0"
1650 "YUGOTHM.TTC,Yu Gothic UI\0"
1651 "MSJH.TTC,Microsoft JhengHei UI\0"
1652 "MSYH.TTC,Microsoft YaHei UI\0"
1653 "MALGUN.TTF,Malgun Gothic\0"
1654 "SEGUISYM.TTF,Segoe UI Symbol\0";
1656 static const char system_link_ms_gothic
[] =
1657 "MINGLIU.TTC,MingLiU\0"
1658 "SIMSUN.TTC,SimSun\0"
1659 "GULIM.TTC,GulimChe\0"
1660 "YUGOTHM.TTC,Yu Gothic UI\0"
1661 "MSJH.TTC,Microsoft JhengHei UI\0"
1662 "MSYH.TTC,Microsoft YaHei UI\0"
1663 "MALGUN.TTF,Malgun Gothic\0"
1664 "SEGUISYM.TTF,Segoe UI Symbol\0";
1666 static const char system_link_ms_p_gothic
[] =
1667 "MINGLIU.TTC,PMingLiU\0"
1668 "SIMSUN.TTC,SimSun\0"
1670 "YUGOTHM.TTC,Yu Gothic UI\0"
1671 "MSJH.TTC,Microsoft JhengHei UI\0"
1672 "MSYH.TTC,Microsoft YaHei UI\0"
1673 "MALGUN.TTF,Malgun Gothic\0"
1674 "SEGUISYM.TTF,Segoe UI Symbol\0";
1676 static const char system_link_ms_ui_gothic
[] =
1677 "MICROSS.TTF,Microsoft Sans Serif\0"
1678 "MINGLIU.TTC,PMingLiU\0"
1679 "SIMSUN.TTC,SimSun\0"
1681 "YUGOTHM.TTC,Yu Gothic UI\0"
1682 "MSJH.TTC,Microsoft JhengHei UI\0"
1683 "MSYH.TTC,Microsoft YaHei UI\0"
1684 "MALGUN.TTF,Malgun Gothic\0"
1685 "SEGUISYM.TTF,Segoe UI Symbol\0";
1687 static const char system_link_microsoft_jheng_hei
[] =
1688 "SEGOEUI.TTF,Segoe UI\0"
1689 "MINGLIU.TTC,MingLiU\0"
1690 "MSYH.TTC,Microsoft YaHei\0"
1691 "MEIRYO.TTC,Meiryo\0"
1692 "MALGUN.TTF,Malgun Gothic\0"
1693 "YUGOTHM.TTC,Yu Gothic UI\0"
1694 "SEGUISYM.TTF,Segoe UI Symbol\0";
1696 static const char system_link_microsoft_jheng_hei_bold
[] =
1697 "SEGOEUIB.TTF,Segoe UI Bold\0"
1698 "MINGLIU.TTC,MingLiU\0"
1699 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1700 "MEIRYOB.TTC,Meiryo Bold\0"
1701 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1702 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1703 "SEGUISYM.TTF,Segoe UI Symbol\0";
1705 static const char system_link_microsoft_jheng_hei_ui
[] =
1706 "SEGOEUI.TTF,Segoe UI\0"
1707 "MINGLIU.TTC,MingLiU\0"
1708 "MSYH.TTC,Microsoft YaHei UI\0"
1709 "MEIRYO.TTC,Meiryo UI\0"
1710 "MALGUN.TTF,Malgun Gothic\0"
1711 "YUGOTHM.TTC,Yu Gothic UI\0"
1712 "SEGUISYM.TTF,Segoe UI Symbol\0";
1714 static const char system_link_microsoft_jheng_hei_ui_bold
[] =
1715 "SEGOEUIB.TTF,Segoe UI Bold\0"
1716 "MINGLIU.TTC,MingLiU\0"
1717 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1718 "MEIRYOB.TTC,Meiryo UI Bold\0"
1719 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1720 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1721 "SEGUISYM.TTF,Segoe UI Symbol\0";
1723 static const char system_link_microsoft_jheng_hei_ui_light
[] =
1724 "SEGOEUIL.TTF,Segoe UI Light\0"
1725 "MINGLIU.TTC,MingLiU\0"
1726 "MSYHL.TTC,Microsoft YaHei UI Light\0"
1727 "MEIRYO.TTC,Meiryo UI\0"
1728 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1729 "YUGOTHL.TTC,Yu Gothic UI Light\0"
1730 "SEGUISYM.TTF,Segoe UI Symbol\0";
1732 static const char system_link_ming_li_u
[] =
1733 "MICROSS.TTF,Microsoft Sans Serif\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_p_ming_li_u
[] =
1744 "MICROSS.TTF,Microsoft Sans Serif\0"
1745 "SIMSUN.TTC,SimSun\0"
1746 "MSMINCHO.TTC,MS PMincho\0"
1747 "BATANG.TTC,Batang\0"
1748 "MSJH.TTC,Microsoft JhengHei UI\0"
1749 "MSYH.TTC,Microsoft YaHei UI\0"
1750 "YUGOTHM.TTC,Yu Gothic UI\0"
1751 "MALGUN.TTF,Malgun Gothic\0"
1752 "SEGUISYM.TTF,Segoe UI Symbol\0";
1754 static const char system_link_ming_li_u_hkscs
[] =
1755 "MICROSS.TTF,Microsoft Sans Serif\0"
1756 "MINGLIU.TTC,MingLiU\0"
1757 "SIMSUN.TTC,SimSun\0"
1758 "MSMINCHO.TTC,MS Mincho\0"
1759 "BATANG.TTC,BatangChe\0"
1760 "MSJH.TTC,Microsoft JhengHei UI\0"
1761 "MSYH.TTC,Microsoft YaHei UI\0"
1762 "YUGOTHM.TTC,Yu Gothic UI\0"
1763 "MALGUN.TTF,Malgun Gothic\0"
1764 "SEGUISYM.TTF,Segoe UI Symbol\0";
1766 static const char system_link_ming_li_u_ext_b
[] =
1767 "MICROSS.TTF,Microsoft Sans Serif\0"
1768 "MINGLIU.TTC,MingLiU\0"
1769 "SIMSUN.TTC,SimSun\0"
1770 "MSMINCHO.TTC,MS Mincho\0"
1771 "BATANG.TTC,BatangChe\0"
1772 "MSJH.TTC,Microsoft JhengHei UI\0"
1773 "MSYH.TTC,Microsoft YaHei UI\0"
1774 "YUGOTHM.TTC,Yu Gothic UI\0"
1775 "MALGUN.TTF,Malgun Gothic\0"
1776 "SEGUISYM.TTF,Segoe UI Symbol\0";
1778 static const char system_link_p_ming_li_u_ext_b
[] =
1779 "MICROSS.TTF,Microsoft Sans Serif\0"
1780 "MINGLIU.TTC,PMingLiU\0"
1781 "SIMSUN.TTC,SimSun\0"
1782 "MSMINCHO.TTC,MS PMincho\0"
1783 "BATANG.TTC,Batang\0"
1784 "MSJH.TTC,Microsoft JhengHei UI\0"
1785 "MSYH.TTC,Microsoft YaHei UI\0"
1786 "YUGOTHM.TTC,Yu Gothic UI\0"
1787 "MALGUN.TTF,Malgun Gothic\0"
1788 "SEGUISYM.TTF,Segoe UI Symbol\0";
1790 static const char system_link_ming_li_u_hkscs_ext_b
[] =
1791 "MICROSS.TTF,Microsoft Sans Serif\0"
1792 "MINGLIU.TTC,MingLiU_HKSCS\0"
1793 "MINGLIU.TTC,MingLiU\0"
1794 "SIMSUN.TTC,SimSun\0"
1795 "MSMINCHO.TTC,MS Mincho\0"
1796 "BATANG.TTC,BatangChe\0"
1797 "MSJH.TTC,Microsoft JhengHei UI\0"
1798 "MSYH.TTC,Microsoft YaHei UI\0"
1799 "YUGOTHM.TTC,Yu Gothic UI\0"
1800 "MALGUN.TTF,Malgun Gothic\0"
1801 "SEGUISYM.TTF,Segoe UI Symbol\0";
1803 static const char system_link_yu_gothic_ui
[] =
1804 "SEGOEUI.TTF,Segoe UI\0"
1805 "MSJH.TTC,Microsoft JhengHei\0"
1806 "MSYH.TTC,Microsoft YaHei\0"
1807 "MALGUN.TTF,Malgun Gothic\0"
1808 "SEGUISYM.TTF,Segoe UI Symbol\0";
1810 static const char system_link_yu_gothic_ui_bold
[] =
1811 "SEGOEUIB.TTF,Segoe UI Bold\0"
1812 "MSJHBD.TTC,Microsoft Jhenghei UI Bold\0"
1813 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1814 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1815 "SEGUISYM.TTF,Segoe UI Symbol\0";
1817 static const char system_link_yu_gothic_ui_light
[] =
1818 "SEGOEUIL.TTF,Segoe UI Light\0"
1819 "MSJHL.TTC,Microsoft Jhenghei UI Light\0"
1820 "MSYHL.TTC,Microsoft YaHei Light\0"
1821 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1822 "SEGUISYM.TTF,Segoe UI Symbol\0";
1824 static const char system_link_yu_gothic_ui_semilight
[] =
1825 "SEGOEUISL.TTF,Segoe UI Semilight\0"
1826 "MSJH.TTC,Microsoft Jhenghei UI\0"
1827 "MSYH.TTC,Microsoft YaHei\0"
1828 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1829 "SEGUISYM.TTF,Segoe UI Symbol\0";
1831 static const char system_link_yu_gothic_ui_semibold
[] =
1832 "SEGUISB.TTF,Segoe UI Semibold\0"
1833 "MSJH.TTC,Microsoft Jhenghei UI\0"
1834 "MSYH.TTC,Microsoft YaHei\0"
1835 "MALGUN.TTF,Malgun Gothic\0"
1836 "SEGUISYM.TTF,Segoe UI Symbol\0";
1838 static const char system_link_meiryo
[] =
1839 "SEGOEUI.TTF,Segoe UI\0"
1840 "YUGOTHM.TTC,Yu Gothic UI\0"
1841 "MSGOTHIC.TTC,MS UI Gothic\0"
1842 "MSJH.TTC,Microsoft JhengHei\0"
1843 "MSYH.TTC,Microsoft YaHei\0"
1844 "MALGUN.TTF,Malgun Gothic\0"
1845 "SEGUISYM.TTF,Segoe UI Symbol\0";
1847 static const char system_link_meiryo_bold
[] =
1848 "SEGOEUIB.TTF,Segoe UI Bold\0"
1849 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1850 "MSGOTHIC.TTC,MS UI Gothic\0"
1851 "MSJHBD.TTC,Microsoft Jhenghei Bold\0"
1852 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1853 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1854 "SEGUISYM.TTF,Segoe UI Symbol\0";
1856 static const char system_link_meiryo_ui
[] =
1857 "SEGOEUI.TTF,Segoe UI\0"
1858 "YUGOTHM.TTC,Yu Gothic UI\0"
1859 "MSGOTHIC.TTC,MS UI Gothic\0"
1860 "MSJH.TTC,Microsoft Jhenghei UI\0"
1861 "MSYH.TTC,Microsoft YaHei UI\0"
1862 "MALGUN.TTF,Malgun Gothic\0"
1863 "SEGUISYM.TTF,Segoe UI Symbol\0";
1865 static const char system_link_meiryo_ui_bold
[] =
1866 "SEGOEUIB.TTF,Segoe UI Bold\0"
1867 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1868 "MSGOTHIC.TTC,MS UI Gothic\0"
1869 "MSJHBD.TTC,Microsoft Jhenghei UI Bold\0"
1870 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1871 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1872 "SEGUISYM.TTF,Segoe UI Symbol\0";
1874 static const char system_link_ms_mincho
[] =
1875 "MINGLIU.TTC,MingLiU\0"
1876 "SIMSUN.TTC,SimSun\0"
1877 "BATANG.TTC,Batang\0"
1878 "YUGOTHM.TTC,Yu Gothic UI\0"
1879 "MSJH.TTC,Microsoft JhengHei UI\0"
1880 "MSYH.TTC,Microsoft YaHei UI\0"
1881 "MALGUN.TTF,Malgun Gothic\0"
1882 "SEGUISYM.TTF,Segoe UI Symbol\0";
1884 static const char system_link_ms_p_mincho
[] =
1885 "MINGLIU.TTC,PMingLiU\0"
1886 "SIMSUN.TTC,SimSun\0"
1887 "BATANG.TTC,Batang\0"
1888 "YUGOTHM.TTC,Yu Gothic UI\0"
1889 "MSJH.TTC,Microsoft JhengHei UI\0"
1890 "MSYH.TTC,Microsoft YaHei UI\0"
1891 "MALGUN.TTF,Malgun Gothic\0"
1892 "SEGUISYM.TTF,Segoe UI Symbol\0";
1894 static const struct system_link_reg
1896 const WCHAR
*font_name
;
1897 BOOL locale_dependent
;
1898 const char *link_non_cjk
;
1899 DWORD link_non_cjk_len
;
1900 const char *link_sc
;
1902 const char *link_tc
;
1904 const char *link_jp
;
1906 const char *link_kr
;
1909 default_system_link
[] =
1913 system_link_tahoma_non_cjk
, sizeof(system_link_tahoma_non_cjk
),
1914 system_link_tahoma_sc
, sizeof(system_link_tahoma_sc
),
1915 system_link_tahoma_tc
, sizeof(system_link_tahoma_tc
),
1916 system_link_tahoma_jp
, sizeof(system_link_tahoma_jp
),
1917 system_link_tahoma_kr
, sizeof(system_link_tahoma_kr
),
1920 microsoft_sans_serifW
, TRUE
,
1921 system_link_tahoma_non_cjk
, sizeof(system_link_tahoma_non_cjk
),
1922 system_link_tahoma_sc
, sizeof(system_link_tahoma_sc
),
1923 system_link_tahoma_tc
, sizeof(system_link_tahoma_tc
),
1924 system_link_tahoma_jp
, sizeof(system_link_tahoma_jp
),
1925 system_link_tahoma_kr
, sizeof(system_link_tahoma_kr
),
1928 lucida_sans_unicodeW
, TRUE
,
1929 system_link_tahoma_non_cjk
, sizeof(system_link_tahoma_non_cjk
),
1930 system_link_tahoma_sc
, sizeof(system_link_tahoma_sc
),
1931 system_link_tahoma_tc
, sizeof(system_link_tahoma_tc
),
1932 system_link_tahoma_jp
, sizeof(system_link_tahoma_jp
),
1933 system_link_tahoma_kr
, sizeof(system_link_tahoma_kr
),
1935 { ms_gothicW
, FALSE
, system_link_ms_gothic
, sizeof(system_link_ms_gothic
) },
1936 { ms_p_gothicW
, FALSE
, system_link_ms_p_gothic
, sizeof(system_link_ms_p_gothic
) },
1937 { ms_ui_gothicW
, FALSE
, system_link_ms_ui_gothic
, sizeof(system_link_ms_ui_gothic
) },
1938 { microsoft_jheng_heiW
, FALSE
, system_link_microsoft_jheng_hei
, sizeof(system_link_microsoft_jheng_hei
) },
1939 { microsoft_jheng_hei_boldW
, FALSE
, system_link_microsoft_jheng_hei_bold
, sizeof(system_link_microsoft_jheng_hei_bold
) },
1940 { microsoft_jheng_hei_uiW
, FALSE
, system_link_microsoft_jheng_hei_ui
, sizeof(system_link_microsoft_jheng_hei_ui
) },
1941 { microsoft_jheng_hei_ui_boldW
, FALSE
, system_link_microsoft_jheng_hei_ui_bold
, sizeof(system_link_microsoft_jheng_hei_ui_bold
) },
1942 { microsoft_jheng_hei_ui_lightW
, FALSE
, system_link_microsoft_jheng_hei_ui_light
, sizeof(system_link_microsoft_jheng_hei_ui_light
) },
1943 { ming_li_uW
, FALSE
, system_link_ming_li_u
, sizeof(system_link_ming_li_u
) },
1944 { p_ming_li_uW
, FALSE
, system_link_p_ming_li_u
, sizeof(system_link_p_ming_li_u
) },
1945 { ming_li_u_hkscsW
, FALSE
, system_link_ming_li_u_hkscs
, sizeof(system_link_ming_li_u_hkscs
) },
1946 { ming_li_u_ext_bW
, FALSE
, system_link_ming_li_u_ext_b
, sizeof(system_link_ming_li_u_ext_b
) },
1947 { p_ming_li_u_ext_bW
, FALSE
, system_link_p_ming_li_u_ext_b
, sizeof(system_link_p_ming_li_u_ext_b
) },
1948 { ming_li_u_hkscs_ext_bW
, FALSE
, system_link_ming_li_u_hkscs_ext_b
, sizeof(system_link_ming_li_u_hkscs_ext_b
) },
1949 { yu_gothic_uiW
, FALSE
, system_link_yu_gothic_ui
, sizeof(system_link_yu_gothic_ui
) },
1950 { yu_gothic_ui_boldW
, FALSE
, system_link_yu_gothic_ui_bold
, sizeof(system_link_yu_gothic_ui_bold
) },
1951 { yu_gothic_ui_lightW
, FALSE
, system_link_yu_gothic_ui_light
, sizeof(system_link_yu_gothic_ui_light
) },
1952 { yu_gothic_ui_semiboldW
, FALSE
, system_link_yu_gothic_ui_semibold
, sizeof(system_link_yu_gothic_ui_semibold
) },
1953 { yu_gothic_ui_semilightW
, FALSE
, system_link_yu_gothic_ui_semilight
, sizeof(system_link_yu_gothic_ui_semilight
) },
1954 { meiryoW
, FALSE
, system_link_meiryo
, sizeof(system_link_meiryo
) },
1955 { meiryo_boldW
, FALSE
, system_link_meiryo_bold
, sizeof(system_link_meiryo_bold
) },
1956 { meiryo_uiW
, FALSE
, system_link_meiryo_ui
, sizeof(system_link_meiryo_ui
) },
1957 { meiryo_ui_boldW
, FALSE
, system_link_meiryo_ui_bold
, sizeof(system_link_meiryo_ui_bold
) },
1958 { ms_minchoW
, FALSE
, system_link_ms_mincho
, sizeof(system_link_ms_mincho
) },
1959 { ms_p_minchoW
, FALSE
, system_link_ms_p_mincho
, sizeof(system_link_ms_p_mincho
) },
1962 static void populate_system_links( const WCHAR
*name
, const WCHAR
* const *values
)
1964 struct gdi_font_family
*family
;
1965 struct gdi_font_face
*face
;
1966 struct gdi_font_link
*font_link
;
1967 const WCHAR
*file
, *value
;
1969 /* Don't store fonts that are only substitutes for other fonts */
1970 if (get_gdi_font_subst( name
, -1, NULL
))
1972 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
) );
1975 font_link
= add_gdi_font_link( name
);
1976 for ( ; *values
; values
++)
1978 if (!facename_compare( name
, *values
, -1 )) continue;
1979 if (!(value
= get_gdi_font_subst( *values
, -1, NULL
))) value
= *values
;
1980 if (!(family
= find_family_from_name( value
))) continue;
1981 /* use first extant filename for this Family */
1982 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1984 if (!face
->file
) continue;
1985 file
= wcsrchr(face
->file
, '\\');
1986 if (!file
) file
= face
->file
;
1988 if ((face
= find_face_from_filename( file
, value
)))
1990 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1991 TRACE( "added internal SystemLink for %s to %s in %s\n",
1992 debugstr_w(name
), debugstr_w(value
), debugstr_w(file
) );
1994 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
) );
2000 static void load_system_links(void)
2004 const WCHAR
*shelldlg_name
;
2005 struct gdi_font_link
*font_link
, *system_font_link
;
2006 struct gdi_font_face
*face
;
2008 static const WCHAR ms_shell_dlgW
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2009 static const WCHAR systemW
[] = {'S','y','s','t','e','m',0};
2010 static const WCHAR tahoma_ttfW
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2012 if ((hkey
= reg_open_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
) )))
2015 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2016 WCHAR value
[MAX_PATH
];
2017 WCHAR
*entry
, *next
;
2020 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
2022 /* Don't store fonts that are only substitutes for other fonts */
2023 if (!get_gdi_font_subst( value
, -1, NULL
))
2025 char *data
= (char *)info
+ info
->DataOffset
;
2026 font_link
= add_gdi_font_link( value
);
2027 for (entry
= (WCHAR
*)data
; (char *)entry
< data
+ info
->DataLength
&& *entry
; entry
= next
)
2029 const WCHAR
*family_name
= NULL
;
2032 TRACE( "%s: %s\n", debugstr_w(value
), debugstr_w(entry
) );
2034 next
= entry
+ lstrlenW(entry
) + 1;
2035 if ((p
= wcschr( entry
, ',' )))
2038 while (*p
== ' ' || *p
== '\t') p
++;
2039 if (!(family_name
= get_gdi_font_subst( p
, -1, NULL
))) family_name
= p
;
2041 if ((face
= find_face_from_filename( entry
, family_name
)))
2043 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
2044 TRACE("Adding file %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
2046 else TRACE( "Unable to find file %s family %s\n",
2047 debugstr_w(entry
), debugstr_w(family_name
) );
2050 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2055 if ((shelldlg_name
= get_gdi_font_subst( ms_shell_dlgW
, -1, NULL
)))
2057 for (i
= 0; i
< ARRAY_SIZE(font_links_defaults_list
); i
++)
2059 const WCHAR
*subst
= get_gdi_font_subst( font_links_defaults_list
[i
].shelldlg
, -1, NULL
);
2061 if ((!facename_compare( font_links_defaults_list
[i
].shelldlg
, shelldlg_name
, -1 ) ||
2062 (subst
&& !facename_compare( subst
, shelldlg_name
, -1 ))))
2064 for (j
= 0; j
< ARRAY_SIZE(font_links_list
); j
++)
2065 populate_system_links( font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2066 if (!facename_compare(shelldlg_name
, font_links_defaults_list
[i
].substitutes
[0], -1))
2067 populate_system_links( shelldlg_name
, font_links_defaults_list
[i
].substitutes
);
2071 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
2073 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2076 system_font_link
= add_gdi_font_link( systemW
);
2077 if ((face
= find_face_from_filename( tahoma_ttfW
, tahomaW
)))
2079 add_gdi_font_link_entry( system_font_link
, face
->family
->family_name
, face
->fs
);
2080 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
2082 if ((font_link
= find_gdi_font_link( tahomaW
)))
2084 struct gdi_font_link_entry
*entry
;
2085 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2086 add_gdi_font_link_entry( system_font_link
, entry
->family_name
, entry
->fs
);
2090 /* see TranslateCharsetInfo */
2091 BOOL
translate_charset_info( DWORD
*src
, CHARSETINFO
*cs
, DWORD flags
)
2097 case TCI_SRCFONTSIG
:
2098 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
2099 if (charset_info
[i
].fs
.fsCsb
[0] & src
[0]) goto found
;
2101 case TCI_SRCCODEPAGE
:
2102 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
2103 if (PtrToUlong(src
) == charset_info
[i
].ciACP
) goto found
;
2105 case TCI_SRCCHARSET
:
2106 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
2107 if (PtrToUlong(src
) == charset_info
[i
].ciCharset
) goto found
;
2113 *cs
= charset_info
[i
];
2119 static BOOL
can_select_face( const struct gdi_font_face
*face
, FONTSIGNATURE fs
, BOOL can_use_bitmap
)
2121 struct gdi_font_link
*font_link
;
2123 if (!face
->scalable
&& !can_use_bitmap
) return FALSE
;
2124 if (!fs
.fsCsb
[0]) return TRUE
;
2125 if (fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return TRUE
;
2126 if (!(font_link
= find_gdi_font_link( face
->family
->family_name
))) return FALSE
;
2127 if (fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) return TRUE
;
2131 static struct gdi_font_face
*find_best_matching_face( const struct gdi_font_family
*family
,
2132 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
2133 BOOL can_use_bitmap
)
2135 struct gdi_font_face
*face
= NULL
, *best
= NULL
, *best_bitmap
= NULL
;
2136 unsigned int best_score
= 4;
2138 int it
= !!lf
->lfItalic
;
2139 int bd
= lf
->lfWeight
> 550;
2140 int height
= lf
->lfHeight
;
2142 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2144 int italic
= !!(face
->ntmFlags
& NTM_ITALIC
);
2145 int bold
= !!(face
->ntmFlags
& NTM_BOLD
);
2146 int score
= (italic
^ it
) + (bold
^ bd
);
2148 if (!can_select_face( face
, fs
, can_use_bitmap
)) continue;
2149 if (score
> best_score
) continue;
2150 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic
, bold
, it
, bd
);
2153 if (best
->scalable
&& best_score
== 0) break;
2154 if (!best
->scalable
)
2158 diff
= height
- (signed int)best
->size
.height
;
2160 diff
= -height
- ((signed int)best
->size
.height
- best
->size
.internal_leading
);
2162 (best_diff
> 0 && diff
>= 0 && diff
< best_diff
) ||
2163 (best_diff
< 0 && diff
> best_diff
))
2165 TRACE( "%d is better for %d diff was %d\n", best
->size
.height
, height
, best_diff
);
2168 if (best_score
== 0 && best_diff
== 0) break;
2172 if (!best
) return NULL
;
2173 return best
->scalable
? best
: best_bitmap
;
2176 static struct gdi_font_face
*find_matching_face_by_name( const WCHAR
*name
, const WCHAR
*subst
,
2177 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
2178 BOOL can_use_bitmap
, const WCHAR
**orig_name
)
2180 struct gdi_font_family
*family
;
2181 struct gdi_font_face
*face
;
2183 family
= find_family_from_any_name( name
);
2184 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
2187 family
= find_family_from_any_name( subst
);
2188 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
2191 /* search by full face name */
2192 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2193 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2194 if (!facename_compare( face
->full_name
, name
, LF_FACESIZE
- 1 ) &&
2195 can_select_face( face
, fs
, can_use_bitmap
))
2198 if ((family
= find_family_from_font_links( name
, subst
, fs
)))
2200 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
2205 if (orig_name
&& family
!= face
->family
)
2206 *orig_name
= family
->family_name
;
2210 static struct gdi_font_face
*find_any_face( const LOGFONTW
*lf
, FONTSIGNATURE fs
,
2211 BOOL can_use_bitmap
, BOOL want_vertical
)
2213 struct gdi_font_family
*family
;
2214 struct gdi_font_face
*face
;
2215 WCHAR name
[LF_FACESIZE
+ 1];
2218 /* first try the family fallbacks */
2219 while (enum_fallbacks( lf
->lfPitchAndFamily
, i
++, name
))
2223 memmove(name
+ 1, name
, min(lstrlenW(name
), LF_FACESIZE
));
2227 if (!(family
= find_family_from_any_name(name
))) continue;
2228 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
2230 /* otherwise try only scalable */
2231 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2233 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
2234 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
2236 if (!can_use_bitmap
) return NULL
;
2237 /* then also bitmap fonts */
2238 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2240 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
2241 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
2246 static struct gdi_font_face
*find_matching_face( const LOGFONTW
*lf
, CHARSETINFO
*csi
, BOOL can_use_bitmap
,
2247 BOOL
*substituted
, const WCHAR
**orig_name
)
2249 BOOL want_vertical
= (lf
->lfFaceName
[0] == '@');
2250 struct gdi_font_face
*face
;
2252 if (!translate_charset_info( (DWORD
*)(INT_PTR
)lf
->lfCharSet
, csi
, TCI_SRCCHARSET
))
2254 if (lf
->lfCharSet
!= DEFAULT_CHARSET
) FIXME( "Untranslated charset %d\n", lf
->lfCharSet
);
2255 csi
->fs
.fsCsb
[0] = 0;
2258 if (lf
->lfFaceName
[0])
2261 const WCHAR
*subst
= get_gdi_font_subst( lf
->lfFaceName
, lf
->lfCharSet
, &subst_charset
);
2265 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf
->lfFaceName
), lf
->lfCharSet
,
2266 debugstr_w(subst
), (subst_charset
!= -1) ? subst_charset
: lf
->lfCharSet
);
2267 if (subst_charset
!= -1)
2268 translate_charset_info( (DWORD
*)(INT_PTR
)subst_charset
, csi
, TCI_SRCCHARSET
);
2269 *substituted
= TRUE
;
2272 if ((face
= find_matching_face_by_name( lf
->lfFaceName
, subst
, lf
, csi
->fs
, can_use_bitmap
, orig_name
)))
2275 *substituted
= FALSE
; /* substitution is no longer relevant */
2277 /* If requested charset was DEFAULT_CHARSET then try using charset
2278 corresponding to the current ansi codepage */
2279 if (!csi
->fs
.fsCsb
[0])
2281 if (!translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, csi
, TCI_SRCCODEPAGE
))
2283 FIXME( "TCI failed on codepage %d\n", ansi_cp
.CodePage
);
2284 csi
->fs
.fsCsb
[0] = 0;
2288 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
2289 if (csi
->fs
.fsCsb
[0])
2291 csi
->fs
.fsCsb
[0] = 0;
2292 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
2294 if (want_vertical
&& (face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, FALSE
))) return face
;
2298 /* realized font objects */
2300 #define FIRST_FONT_HANDLE 1
2301 #define MAX_FONT_HANDLES 256
2303 struct font_handle_entry
2305 struct gdi_font
*font
;
2306 WORD generation
; /* generation count for reusing handle values */
2309 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
2310 static struct font_handle_entry
*next_free
;
2311 static struct font_handle_entry
*next_unused
= font_handles
;
2313 static struct font_handle_entry
*handle_entry( unsigned int handle
)
2315 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
2317 if (idx
< MAX_FONT_HANDLES
)
2319 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
2320 return &font_handles
[idx
];
2322 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
2326 static struct gdi_font
*get_font_from_handle( unsigned int handle
)
2328 struct font_handle_entry
*entry
= handle_entry( handle
);
2330 if (entry
) return entry
->font
;
2331 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2335 static DWORD
alloc_font_handle( struct gdi_font
*font
)
2337 struct font_handle_entry
*entry
;
2341 next_free
= (struct font_handle_entry
*)entry
->font
;
2342 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
2343 entry
= next_unused
++;
2346 ERR( "out of realized font handles\n" );
2350 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
2351 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
2354 static void free_font_handle( DWORD handle
)
2356 struct font_handle_entry
*entry
;
2358 if ((entry
= handle_entry( handle
)))
2360 entry
->font
= (struct gdi_font
*)next_free
;
2365 static struct gdi_font
*alloc_gdi_font( const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
)
2367 UINT len
= file
? lstrlenW(file
) : 0;
2368 struct gdi_font
*font
= calloc( 1, offsetof( struct gdi_font
, file
[len
+ 1] ));
2371 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
2373 font
->kern_count
= -1;
2374 list_init( &font
->child_fonts
);
2378 FILE_NETWORK_OPEN_INFORMATION info
;
2379 UNICODE_STRING nt_name
;
2380 OBJECT_ATTRIBUTES attr
;
2382 nt_name
.Buffer
= (WCHAR
*)file
;
2383 nt_name
.Length
= nt_name
.MaximumLength
= len
* sizeof(WCHAR
);
2385 attr
.Length
= sizeof(attr
);
2386 attr
.RootDirectory
= 0;
2387 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2388 attr
.ObjectName
= &nt_name
;
2389 attr
.SecurityDescriptor
= NULL
;
2390 attr
.SecurityQualityOfService
= NULL
;
2392 if (!NtQueryFullAttributesFile( &attr
, &info
))
2394 font
->writetime
.dwLowDateTime
= info
.LastWriteTime
.LowPart
;
2395 font
->writetime
.dwHighDateTime
= info
.LastWriteTime
.HighPart
;
2396 font
->data_size
= info
.EndOfFile
.QuadPart
;
2397 memcpy( font
->file
, file
, len
* sizeof(WCHAR
) );
2402 font
->data_ptr
= data_ptr
;
2403 font
->data_size
= data_size
;
2406 font
->handle
= alloc_font_handle( font
);
2410 static void free_gdi_font( struct gdi_font
*font
)
2413 struct gdi_font
*child
, *child_next
;
2415 if (font
->private) font_funcs
->destroy_font( font
);
2416 free_font_handle( font
->handle
);
2417 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, struct gdi_font
, entry
)
2419 list_remove( &child
->entry
);
2420 free_gdi_font( child
);
2422 for (i
= 0; i
< font
->gm_size
; i
++) free( font
->gm
[i
] );
2423 free( font
->otm
.otmpFamilyName
);
2424 free( font
->otm
.otmpStyleName
);
2425 free( font
->otm
.otmpFaceName
);
2426 free( font
->otm
.otmpFullName
);
2428 free( font
->kern_pairs
);
2429 free( font
->gsub_table
);
2433 static inline const WCHAR
*get_gdi_font_name( struct gdi_font
*font
)
2435 return font
->use_logfont_name
? font
->lf
.lfFaceName
: (WCHAR
*)font
->otm
.otmpFamilyName
;
2438 static struct gdi_font
*create_gdi_font( const struct gdi_font_face
*face
, const WCHAR
*family_name
,
2439 const LOGFONTW
*lf
)
2441 struct gdi_font
*font
;
2443 if (!(font
= alloc_gdi_font( face
->file
, face
->data_ptr
, face
->data_size
))) return NULL
;
2444 font
->fs
= face
->fs
;
2446 font
->fake_italic
= (lf
->lfItalic
&& !(face
->ntmFlags
& NTM_ITALIC
));
2447 font
->fake_bold
= (lf
->lfWeight
> 550 && !(face
->ntmFlags
& NTM_BOLD
));
2448 font
->scalable
= face
->scalable
;
2449 font
->face_index
= face
->face_index
;
2450 font
->ntmFlags
= face
->ntmFlags
;
2451 font
->aa_flags
= HIWORD( face
->flags
);
2452 if (!family_name
) family_name
= face
->family
->family_name
;
2453 font
->otm
.otmpFamilyName
= (char *)wcsdup( family_name
);
2454 font
->otm
.otmpStyleName
= (char *)wcsdup( face
->style_name
);
2455 font
->otm
.otmpFaceName
= (char *)wcsdup( face
->full_name
);
2459 struct glyph_metrics
2462 ABC abc
; /* metrics of the unrotated char */
2466 #define GM_BLOCK_SIZE 128
2468 /* TODO: GGO format support */
2469 static BOOL
get_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
, GLYPHMETRICS
*gm
, ABC
*abc
)
2471 UINT block
= index
/ GM_BLOCK_SIZE
;
2472 UINT entry
= index
% GM_BLOCK_SIZE
;
2474 if (block
< font
->gm_size
&& font
->gm
[block
] && font
->gm
[block
][entry
].init
)
2476 *gm
= font
->gm
[block
][entry
].gm
;
2477 *abc
= font
->gm
[block
][entry
].abc
;
2479 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2480 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point( &gm
->gmptGlyphOrigin
),
2481 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2488 static void set_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
,
2489 const GLYPHMETRICS
*gm
, const ABC
*abc
)
2491 UINT block
= index
/ GM_BLOCK_SIZE
;
2492 UINT entry
= index
% GM_BLOCK_SIZE
;
2494 if (block
>= font
->gm_size
)
2496 struct glyph_metrics
**ptr
;
2498 if (!(ptr
= realloc( font
->gm
, (block
+ 1) * sizeof(*ptr
) ))) return;
2499 memset( ptr
+ font
->gm_size
, 0, (block
+ 1 - font
->gm_size
) * sizeof(*ptr
) );
2500 font
->gm_size
= block
+ 1;
2503 if (!font
->gm
[block
])
2505 font
->gm
[block
] = calloc( sizeof(**font
->gm
), GM_BLOCK_SIZE
);
2506 if (!font
->gm
[block
]) return;
2508 font
->gm
[block
][entry
].gm
= *gm
;
2509 font
->gm
[block
][entry
].abc
= *abc
;
2510 font
->gm
[block
][entry
].init
= TRUE
;
2514 /* GSUB table support */
2528 } GSUB_ScriptRecord
;
2533 GSUB_ScriptRecord ScriptRecord
[1];
2540 } GSUB_LangSysRecord
;
2544 WORD DefaultLangSys
;
2546 GSUB_LangSysRecord LangSysRecord
[1];
2551 WORD LookupOrder
; /* Reserved */
2552 WORD ReqFeatureIndex
;
2554 WORD FeatureIndex
[1];
2561 } GSUB_FeatureRecord
;
2566 GSUB_FeatureRecord FeatureRecord
[1];
2571 WORD FeatureParams
; /* Reserved */
2573 WORD LookupListIndex
[1];
2592 WORD CoverageFormat
;
2595 } GSUB_CoverageFormat1
;
2601 WORD StartCoverageIndex
;
2606 WORD CoverageFormat
;
2608 GSUB_RangeRecord RangeRecord
[1];
2609 } GSUB_CoverageFormat2
;
2613 WORD SubstFormat
; /* = 1 */
2616 } GSUB_SingleSubstFormat1
;
2620 WORD SubstFormat
; /* = 2 */
2624 } GSUB_SingleSubstFormat2
;
2626 static GSUB_Script
*GSUB_get_script_table( GSUB_Header
*header
, const char *tag
)
2628 GSUB_ScriptList
*script
;
2629 GSUB_Script
*deflt
= NULL
;
2632 script
= (GSUB_ScriptList
*)((BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
2633 TRACE("%i scripts in this font\n", GET_BE_WORD(script
->ScriptCount
) );
2634 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
2636 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
2637 GSUB_Script
*scr
= (GSUB_Script
*)((BYTE
*)script
+ offset
);
2638 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, tag
, 4 )) return scr
;
2639 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, "dflt", 4 )) deflt
= scr
;
2644 static GSUB_LangSys
*GSUB_get_lang_table( GSUB_Script
*script
, const char *tag
)
2649 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
2651 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
2653 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
2654 lang
= (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2655 if (!memcmp( script
->LangSysRecord
[i
].LangSysTag
, tag
, 4 )) return lang
;
2657 offset
= GET_BE_WORD(script
->DefaultLangSys
);
2658 if (offset
) return (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2662 static GSUB_Feature
*GSUB_get_feature( GSUB_Header
*header
, GSUB_LangSys
*lang
, const char *tag
)
2665 const GSUB_FeatureList
*feature
;
2667 feature
= (GSUB_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
2668 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
2669 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
2671 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
2672 if (!memcmp( feature
->FeatureRecord
[index
].FeatureTag
, tag
, 4 ))
2673 return (GSUB_Feature
*)((BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
2678 static const char *get_opentype_script( const struct gdi_font
*font
)
2681 * I am not sure if this is the correct way to generate our script tag
2683 switch (font
->charset
)
2685 case ANSI_CHARSET
: return "latn";
2686 case BALTIC_CHARSET
: return "latn"; /* ?? */
2687 case CHINESEBIG5_CHARSET
: return "hani";
2688 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
2689 case GB2312_CHARSET
: return "hani";
2690 case GREEK_CHARSET
: return "grek";
2691 case HANGUL_CHARSET
: return "hang";
2692 case RUSSIAN_CHARSET
: return "cyrl";
2693 case SHIFTJIS_CHARSET
: return "kana";
2694 case TURKISH_CHARSET
: return "latn"; /* ?? */
2695 case VIETNAMESE_CHARSET
: return "latn";
2696 case JOHAB_CHARSET
: return "latn"; /* ?? */
2697 case ARABIC_CHARSET
: return "arab";
2698 case HEBREW_CHARSET
: return "hebr";
2699 case THAI_CHARSET
: return "thai";
2700 default: return "latn";
2704 static void *get_GSUB_vert_feature( struct gdi_font
*font
)
2706 GSUB_Header
*header
;
2707 GSUB_Script
*script
;
2708 GSUB_LangSys
*language
;
2709 GSUB_Feature
*feature
;
2710 UINT length
= font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, NULL
, 0 );
2712 if (length
== GDI_ERROR
) return NULL
;
2714 header
= malloc( length
);
2715 font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, header
, length
);
2716 TRACE( "Loaded GSUB table of %i bytes\n", length
);
2718 if ((script
= GSUB_get_script_table( header
, get_opentype_script(font
) )))
2720 if ((language
= GSUB_get_lang_table( script
, "xxxx" ))) /* Need to get Lang tag */
2722 feature
= GSUB_get_feature( header
, language
, "vrt2" );
2723 if (!feature
) feature
= GSUB_get_feature( header
, language
, "vert" );
2726 font
->gsub_table
= header
;
2729 TRACE("vrt2/vert feature not found\n");
2731 else TRACE("Language not found\n");
2733 else TRACE("Script not found\n");
2739 static int GSUB_is_glyph_covered( void *table
, UINT glyph
)
2741 GSUB_CoverageFormat1
*cf1
= table
;
2743 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
2745 int i
, count
= GET_BE_WORD(cf1
->GlyphCount
);
2747 TRACE("Coverage Format 1, %i glyphs\n",count
);
2748 for (i
= 0; i
< count
; i
++) if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
])) return i
;
2751 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
2754 GSUB_CoverageFormat2
*cf2
= table
;
2756 count
= GET_BE_WORD(cf2
->RangeCount
);
2757 TRACE("Coverage Format 2, %i ranges\n",count
);
2758 for (i
= 0; i
< count
; i
++)
2760 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) return -1;
2761 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
2762 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
2764 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
2765 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
2770 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
2775 static UINT
GSUB_apply_feature( GSUB_Header
*header
, GSUB_Feature
*feature
, UINT glyph
)
2777 GSUB_LookupList
*lookup
= (GSUB_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2780 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
2781 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
2783 GSUB_LookupTable
*look
;
2784 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
2785 look
= (GSUB_LookupTable
*)((BYTE
*)lookup
+ offset
);
2786 TRACE("type %i, flag %x, subtables %i\n",
2787 GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
2788 if (GET_BE_WORD(look
->LookupType
) == 1)
2790 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
2792 GSUB_SingleSubstFormat1
*ssf1
;
2793 offset
= GET_BE_WORD(look
->SubTable
[j
]);
2794 ssf1
= (GSUB_SingleSubstFormat1
*)((BYTE
*)look
+ offset
);
2795 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
2797 int offset
= GET_BE_WORD(ssf1
->Coverage
);
2798 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
2799 if (GSUB_is_glyph_covered( (BYTE
*) ssf1
+ offset
, glyph
) != -1)
2801 TRACE(" Glyph 0x%x ->",glyph
);
2802 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
2803 TRACE(" 0x%x\n",glyph
);
2808 GSUB_SingleSubstFormat2
*ssf2
;
2811 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
2812 offset
= GET_BE_WORD(ssf1
->Coverage
);
2813 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
2814 index
= GSUB_is_glyph_covered( (BYTE
*)ssf2
+ offset
, glyph
);
2815 TRACE(" Coverage index %i\n",index
);
2818 TRACE(" Glyph is 0x%x ->",glyph
);
2819 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
2820 TRACE("0x%x\n",glyph
);
2825 else FIXME("We only handle SubType 1\n");
2830 static UINT
get_GSUB_vert_glyph( struct gdi_font
*font
, UINT glyph
)
2832 if (!glyph
) return glyph
;
2833 if (!font
->gsub_table
) return glyph
;
2834 return GSUB_apply_feature( font
->gsub_table
, font
->vert_feature
, glyph
);
2837 static void add_child_font( struct gdi_font
*font
, const WCHAR
*family_name
)
2839 FONTSIGNATURE fs
= {{0}};
2840 struct gdi_font
*child
;
2841 struct gdi_font_face
*face
;
2843 if (!(face
= find_matching_face_by_name( family_name
, NULL
, &font
->lf
, fs
, FALSE
, NULL
))) return;
2845 if (!(child
= create_gdi_font( face
, family_name
, &font
->lf
))) return;
2846 child
->matrix
= font
->matrix
;
2847 child
->can_use_bitmap
= font
->can_use_bitmap
;
2848 child
->scale_y
= font
->scale_y
;
2849 child
->aveWidth
= font
->aveWidth
;
2850 child
->charset
= font
->charset
;
2851 child
->codepage
= font
->codepage
;
2852 child
->base_font
= font
;
2853 list_add_tail( &font
->child_fonts
, &child
->entry
);
2854 TRACE( "created child font %p for base %p\n", child
, font
);
2857 static void create_child_font_list( struct gdi_font
*font
)
2859 struct gdi_font_link
*font_link
;
2860 struct gdi_font_link_entry
*entry
;
2861 const WCHAR
* font_name
= (WCHAR
*)font
->otm
.otmpFaceName
;
2863 if ((font_link
= find_gdi_font_link( font_name
)))
2865 TRACE("found entry in system list\n");
2866 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2867 add_child_font( font
, entry
->family_name
);
2870 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2871 * Sans Serif. This is how asian windows get default fallbacks for fonts
2873 if (ansi_cp
.MaximumCharacterSize
== 2 && font
->charset
!= SYMBOL_CHARSET
&& font
->charset
!= OEM_CHARSET
&&
2874 facename_compare( font_name
, microsoft_sans_serifW
, -1 ) != 0)
2876 if ((font_link
= find_gdi_font_link( microsoft_sans_serifW
)))
2878 TRACE("found entry in default fallback list\n");
2879 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2880 add_child_font( font
, entry
->family_name
);
2887 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
2888 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
2889 static unsigned int unused_font_count
;
2890 #define UNUSED_CACHE_SIZE 10
2892 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
2893 const FMAT2
*matrix
, BOOL can_use_bitmap
)
2895 if (font
->hash
!= hash
) return TRUE
;
2896 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
2897 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2898 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
2899 return facename_compare( font
->lf
.lfFaceName
, lf
->lfFaceName
, -1 );
2902 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2904 DWORD hash
= 0, *ptr
, two_chars
;
2908 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
2910 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
2912 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
2915 pwc
= (WCHAR
*)&two_chars
;
2917 *pwc
= towupper(*pwc
);
2919 *pwc
= towupper(*pwc
);
2923 hash
^= !can_use_bitmap
;
2927 static void cache_gdi_font( struct gdi_font
*font
)
2929 static DWORD cache_num
= 1;
2931 font
->cache_num
= cache_num
++;
2932 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
2933 list_add_head( &gdi_font_list
, &font
->entry
);
2934 TRACE( "font %p\n", font
);
2937 static struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2939 struct gdi_font
*font
;
2940 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
2942 /* try the in-use list */
2943 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
2945 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
2946 list_remove( &font
->entry
);
2947 list_add_head( &gdi_font_list
, &font
->entry
);
2948 if (!font
->refcount
++)
2950 list_remove( &font
->unused_entry
);
2951 unused_font_count
--;
2958 static void release_gdi_font( struct gdi_font
*font
)
2962 TRACE( "font %p\n", font
);
2964 /* add it to the unused list */
2965 pthread_mutex_lock( &font_lock
);
2966 if (!--font
->refcount
)
2968 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
2969 if (unused_font_count
> UNUSED_CACHE_SIZE
)
2971 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
2972 TRACE( "freeing %p\n", font
);
2973 list_remove( &font
->entry
);
2974 list_remove( &font
->unused_entry
);
2975 free_gdi_font( font
);
2977 else unused_font_count
++;
2979 pthread_mutex_unlock( &font_lock
);
2982 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
2984 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
2986 set_reg_ascii_value( hkey
, "Courier", fl
->courier
);
2987 set_reg_ascii_value( hkey
, "MS Serif", fl
->serif
);
2988 set_reg_ascii_value( hkey
, "MS Sans Serif", sserif
);
2989 set_reg_ascii_value( hkey
, "Small Fonts", fl
->small
);
2992 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2995 set_reg_ascii_value( hkey
, name
, value
);
2999 asciiz_to_unicode( nameW
, name
);
3000 reg_delete_value( hkey
, nameW
);
3004 static void update_font_association_info(void)
3006 static const WCHAR associated_charsetW
[] =
3007 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
3009 if (ansi_cp
.MaximumCharacterSize
== 2)
3012 if ((hkey
= reg_create_key( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
), 0, NULL
)))
3015 if ((hsubkey
= reg_create_key( hkey
, associated_charsetW
, sizeof(associated_charsetW
),
3018 switch (ansi_cp
.CodePage
)
3021 set_value_key(hsubkey
, "ANSI(00)", "NO");
3022 set_value_key(hsubkey
, "OEM(FF)", "NO");
3023 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3028 set_value_key(hsubkey
, "ANSI(00)", "YES");
3029 set_value_key(hsubkey
, "OEM(FF)", "YES");
3030 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3036 /* TODO: Associated DefaultFonts */
3042 reg_delete_tree( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
) );
3045 static void set_multi_value_key( HKEY hkey
, const WCHAR
*name
, const char *value
, UINT len
)
3049 if (!(valueW
= malloc( len
* sizeof(WCHAR
) )))
3051 ERR( "malloc of %d * WCHAR failed\n", len
);
3054 ascii_to_unicode( valueW
, value
, len
);
3056 set_reg_value( hkey
, name
, REG_MULTI_SZ
, valueW
, len
* sizeof(WCHAR
) );
3058 reg_delete_value( hkey
, name
);
3062 static void update_font_system_link_info(void)
3066 if ((hkey
= reg_create_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
), 0, NULL
)))
3071 for (i
= 0; i
< ARRAY_SIZE(default_system_link
); ++i
)
3073 const struct system_link_reg
*link_reg
= &default_system_link
[i
];
3075 link
= link_reg
->link_non_cjk
;
3076 len
= link_reg
->link_non_cjk_len
;
3078 if (link_reg
->locale_dependent
)
3080 switch (ansi_cp
.CodePage
)
3083 link
= link_reg
->link_jp
;
3084 len
= link_reg
->link_jp_len
;
3087 link
= link_reg
->link_sc
;
3088 len
= link_reg
->link_sc_len
;
3091 link
= link_reg
->link_kr
;
3092 len
= link_reg
->link_kr_len
;
3095 link
= link_reg
->link_tc
;
3096 len
= link_reg
->link_tc_len
;
3100 set_multi_value_key(hkey
, link_reg
->font_name
, link
, len
);
3106 static void update_codepage( UINT screen_dpi
)
3108 USHORT utf8_hdr
[2] = { 0, CP_UTF8
};
3109 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[40 * sizeof(WCHAR
)])];
3110 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
3117 BOOL done
= FALSE
, cp_match
= FALSE
;
3119 static const WCHAR log_pixelsW
[] = {'L','o','g','P','i','x','e','l','s',0};
3121 size
= query_reg_value( wine_fonts_key
, log_pixelsW
, info
, sizeof(value_buffer
) );
3122 if (size
== sizeof(DWORD
) && info
->Type
== REG_DWORD
)
3123 font_dpi
= *(DWORD
*)info
->Data
;
3125 RtlInitCodePageTable( utf8_hdr
, &utf8_cp
);
3126 if (NtCurrentTeb()->Peb
->AnsiCodePageData
)
3127 RtlInitCodePageTable( NtCurrentTeb()->Peb
->AnsiCodePageData
, &ansi_cp
);
3130 if (NtCurrentTeb()->Peb
->OemCodePageData
)
3131 RtlInitCodePageTable( NtCurrentTeb()->Peb
->OemCodePageData
, &oem_cp
);
3134 snprintf( cpbuf
, sizeof(cpbuf
), "%u,%u", ansi_cp
.CodePage
, oem_cp
.CodePage
);
3135 asciiz_to_unicode( cpbufW
, cpbuf
);
3137 if (query_reg_ascii_value( wine_fonts_key
, "Codepages", info
, sizeof(value_buffer
) ))
3139 cp_match
= !wcscmp( (const WCHAR
*)info
->Data
, cpbufW
);
3140 if (cp_match
&& screen_dpi
== font_dpi
) return; /* already set correctly */
3141 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3142 debugstr_w((const WCHAR
*)info
->Data
), font_dpi
, ansi_cp
.CodePage
, oem_cp
.CodePage
, screen_dpi
);
3144 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3145 ansi_cp
.CodePage
, oem_cp
.CodePage
, screen_dpi
);
3147 set_reg_ascii_value( wine_fonts_key
, "Codepages", cpbuf
);
3148 set_reg_value( wine_fonts_key
, log_pixelsW
, REG_DWORD
, &screen_dpi
, sizeof(screen_dpi
) );
3150 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
3152 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
.CodePage
&&
3153 nls_update_font_list
[i
].oem_cp
== oem_cp
.CodePage
)
3156 if ((software_hkey
= reg_create_key( NULL
, software_config_keyW
,
3157 sizeof(software_config_keyW
), 0, NULL
)))
3159 static const WCHAR fontsW
[] = {'F','o','n','t','s'};
3160 hkey
= reg_create_key( software_hkey
, fontsW
, sizeof(fontsW
), 0, NULL
);
3161 NtClose( software_hkey
);
3164 set_reg_ascii_value( hkey
, "OEMFONT.FON", nls_update_font_list
[i
].oem
);
3165 set_reg_ascii_value( hkey
, "FIXEDFON.FON", nls_update_font_list
[i
].fixed
);
3166 set_reg_ascii_value( hkey
, "FONTS.FON", nls_update_font_list
[i
].system
);
3170 if ((hkey
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
),
3173 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3176 if ((hkey
= reg_create_key( NULL
, fonts_win9x_config_keyW
,
3177 sizeof(fonts_win9x_config_keyW
), 0, NULL
)))
3179 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3182 /* Only update these if the Codepage changed. */
3184 (hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
3187 set_reg_ascii_value( hkey
, "MS Shell Dlg", nls_update_font_list
[i
].shelldlg
);
3188 set_reg_ascii_value( hkey
, "Tms Rmn", nls_update_font_list
[i
].tmsrmn
);
3190 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3191 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3192 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3193 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3194 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3195 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3196 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3197 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3199 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3200 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3201 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3209 /* Delete the FontSubstitutes from other locales */
3210 if ((hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
3213 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3214 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3215 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3221 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
.CodePage
, oem_cp
.CodePage
);
3223 /* update locale dependent font association info and font system link info in registry.
3224 update only when codepages changed, not logpixels. */
3227 update_font_association_info();
3228 update_font_system_link_info();
3233 /*************************************************************
3236 static BOOL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR device
, LPCWSTR output
, const DEVMODEW
*devmode
)
3238 struct font_physdev
*physdev
;
3240 if (!font_funcs
) return TRUE
;
3241 if (!(physdev
= calloc( 1, sizeof(*physdev
) ))) return FALSE
;
3242 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
3247 /*************************************************************
3250 static BOOL
font_DeleteDC( PHYSDEV dev
)
3252 struct font_physdev
*physdev
= get_font_dev( dev
);
3254 release_gdi_font( physdev
->font
);
3260 struct gdi_font_enum_data
3263 NEWTEXTMETRICEXW ntm
;
3273 static BOOL
is_complex_script_ansi_cp(void)
3275 return (ansi_cp
.CodePage
== 874 /* Thai */
3276 || ansi_cp
.CodePage
== 1255 /* Hebrew */
3277 || ansi_cp
.CodePage
== 1256 /* Arabic */
3281 /***************************************************
3282 * create_enum_charset_list
3284 * This function creates charset enumeration list because in DEFAULT_CHARSET
3285 * case, the ANSI codepage's charset takes precedence over other charsets.
3286 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
3287 * This function works as a filter other than DEFAULT_CHARSET case.
3289 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset
*list
)
3291 struct enum_charset
*start
= list
;
3295 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) && csi
.fs
.fsCsb
[0] != 0)
3297 list
->mask
= csi
.fs
.fsCsb
[0];
3298 list
->charset
= csi
.ciCharset
;
3299 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
3302 else /* charset is DEFAULT_CHARSET or invalid. */
3306 /* Set the current codepage's charset as the first element. */
3307 if (!is_complex_script_ansi_cp() &&
3308 translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, &csi
, TCI_SRCCODEPAGE
) &&
3309 csi
.fs
.fsCsb
[0] != 0)
3311 list
->mask
= csi
.fs
.fsCsb
[0];
3312 list
->charset
= csi
.ciCharset
;
3313 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
3314 mask
|= csi
.fs
.fsCsb
[0];
3318 /* Fill out left elements. */
3319 for (i
= 0; i
< 32; i
++)
3322 fs
.fsCsb
[0] = 1u << i
;
3324 if (fs
.fsCsb
[0] & mask
) continue; /* skip, already added. */
3325 if (!translate_charset_info( fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
3326 continue; /* skip, this is an invalid fsCsb bit. */
3327 list
->mask
= fs
.fsCsb
[0];
3328 list
->charset
= csi
.ciCharset
;
3330 mask
|= fs
.fsCsb
[0];
3333 /* add catch all mask for remaining bits */
3337 list
->charset
= DEFAULT_CHARSET
;
3338 list
->script
= 33; /* other */
3342 return list
- start
;
3345 static UINT
get_font_type( const NEWTEXTMETRICEXW
*ntm
)
3349 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ret
|= TRUETYPE_FONTTYPE
;
3350 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
) ret
|= DEVICE_FONTTYPE
;
3351 if (!(ntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
)) ret
|= RASTER_FONTTYPE
;
3355 static BOOL
get_face_enum_data( struct gdi_font_face
*face
, ENUMLOGFONTEXW
*elf
, NEWTEXTMETRICEXW
*ntm
)
3357 struct gdi_font
*font
;
3358 LOGFONTW lf
= { .lfHeight
= -4096 /* preferable EM Square size */ };
3360 if (!face
->scalable
) lf
.lfHeight
= 0;
3362 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
3364 if (!font_funcs
->load_font( font
))
3366 free_gdi_font( font
);
3370 if (font
->scalable
&& -lf
.lfHeight
% font
->otm
.otmEMSquare
!= 0)
3372 /* reload with the original EM Square size */
3373 lf
.lfHeight
= -font
->otm
.otmEMSquare
;
3374 free_gdi_font( font
);
3376 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
3377 if (!font_funcs
->load_font( font
))
3379 free_gdi_font( font
);
3384 if (font_funcs
->set_outline_text_metrics( font
))
3386 static const DWORD ntm_ppem
= 32;
3389 #define TM font->otm.otmTextMetrics
3390 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
3391 cell_height
= TM
.tmHeight
/ ( -lf
.lfHeight
/ font
->otm
.otmEMSquare
);
3392 ntm
->ntmTm
.tmHeight
= muldiv( ntm_ppem
, cell_height
, font
->otm
.otmEMSquare
);
3393 ntm
->ntmTm
.tmAscent
= SCALE_NTM( TM
.tmAscent
);
3394 ntm
->ntmTm
.tmDescent
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmAscent
;
3395 ntm
->ntmTm
.tmInternalLeading
= SCALE_NTM( TM
.tmInternalLeading
);
3396 ntm
->ntmTm
.tmExternalLeading
= SCALE_NTM( TM
.tmExternalLeading
);
3397 ntm
->ntmTm
.tmAveCharWidth
= SCALE_NTM( TM
.tmAveCharWidth
);
3398 ntm
->ntmTm
.tmMaxCharWidth
= SCALE_NTM( TM
.tmMaxCharWidth
);
3400 memcpy((char *)&ntm
->ntmTm
+ offsetof( TEXTMETRICW
, tmWeight
),
3401 (const char *)&TM
+ offsetof( TEXTMETRICW
, tmWeight
),
3402 sizeof(TEXTMETRICW
) - offsetof( TEXTMETRICW
, tmWeight
));
3403 ntm
->ntmTm
.ntmSizeEM
= font
->otm
.otmEMSquare
;
3404 ntm
->ntmTm
.ntmCellHeight
= cell_height
;
3405 ntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
3409 else if (font_funcs
->set_bitmap_text_metrics( font
))
3411 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
3412 ntm
->ntmTm
.ntmSizeEM
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmInternalLeading
;
3413 ntm
->ntmTm
.ntmCellHeight
= ntm
->ntmTm
.tmHeight
;
3414 ntm
->ntmTm
.ntmAvgWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3416 ntm
->ntmTm
.ntmFlags
= font
->ntmFlags
;
3417 ntm
->ntmFontSig
= font
->fs
;
3419 elf
->elfLogFont
.lfEscapement
= 0;
3420 elf
->elfLogFont
.lfOrientation
= 0;
3421 elf
->elfLogFont
.lfHeight
= ntm
->ntmTm
.tmHeight
;
3422 elf
->elfLogFont
.lfWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3423 elf
->elfLogFont
.lfWeight
= ntm
->ntmTm
.tmWeight
;
3424 elf
->elfLogFont
.lfItalic
= ntm
->ntmTm
.tmItalic
;
3425 elf
->elfLogFont
.lfUnderline
= ntm
->ntmTm
.tmUnderlined
;
3426 elf
->elfLogFont
.lfStrikeOut
= ntm
->ntmTm
.tmStruckOut
;
3427 elf
->elfLogFont
.lfCharSet
= ntm
->ntmTm
.tmCharSet
;
3428 elf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3429 elf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3430 elf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3431 elf
->elfLogFont
.lfPitchAndFamily
= (ntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3432 lstrcpynW( elf
->elfLogFont
.lfFaceName
, (WCHAR
*)font
->otm
.otmpFamilyName
, LF_FACESIZE
);
3433 lstrcpynW( elf
->elfFullName
, (WCHAR
*)font
->otm
.otmpFaceName
, LF_FULLFACESIZE
);
3434 lstrcpynW( elf
->elfStyle
, (WCHAR
*)font
->otm
.otmpStyleName
, LF_FACESIZE
);
3436 free_gdi_font( font
);
3440 static BOOL
family_matches( struct gdi_font_family
*family
, const WCHAR
*face_name
)
3442 struct gdi_font_face
*face
;
3444 if (!facename_compare( face_name
, family
->family_name
, LF_FACESIZE
- 1 )) return TRUE
;
3445 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3446 if (!facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 )) return TRUE
;
3450 static BOOL
face_matches( const WCHAR
*family_name
, struct gdi_font_face
*face
, const WCHAR
*face_name
)
3452 if (!facename_compare( face_name
, family_name
, LF_FACESIZE
- 1)) return TRUE
;
3453 return !facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 );
3456 static BOOL
enum_face_charsets( const struct gdi_font_family
*family
, struct gdi_font_face
*face
,
3457 struct enum_charset
*list
, DWORD count
, font_enum_proc proc
, LPARAM lparam
,
3458 const WCHAR
*subst
)
3461 NEWTEXTMETRICEXW ntm
;
3464 if (!face
->cached_enum_data
)
3466 struct gdi_font_enum_data
*data
;
3468 if (!(data
= calloc( 1, sizeof(*data
) )) ||
3469 !get_face_enum_data( face
, &data
->elf
, &data
->ntm
))
3474 face
->cached_enum_data
= data
;
3477 elf
= face
->cached_enum_data
->elf
;
3478 ntm
= face
->cached_enum_data
->ntm
;
3479 type
= get_font_type( &ntm
);
3481 /* font replacement */
3482 if (family
!= face
->family
)
3484 lstrcpynW( elf
.elfLogFont
.lfFaceName
, family
->family_name
, LF_FACESIZE
);
3485 lstrcpynW( elf
.elfFullName
, face
->full_name
, LF_FULLFACESIZE
);
3487 if (subst
) lstrcpynW( elf
.elfLogFont
.lfFaceName
, subst
, LF_FACESIZE
);
3489 for (i
= 0; i
< count
; i
++)
3491 if (face
->fs
.fsCsb
[0] == 0) /* OEM */
3493 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3494 elf
.elfScript
[0] = 32;
3495 i
= count
; /* break out of loop after enumeration */
3499 if (!(face
->fs
.fsCsb
[0] & list
[i
].mask
)) continue;
3500 /* use the DEFAULT_CHARSET case only if no other charset is present */
3501 if (list
[i
].charset
== DEFAULT_CHARSET
&& (face
->fs
.fsCsb
[0] & ~list
[i
].mask
)) continue;
3502 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
[i
].charset
;
3503 /* caller may fill elfScript with the actual string, see load_script_name */
3504 elf
.elfScript
[0] = list
[i
].script
;
3506 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3507 debugstr_w(elf
.elfLogFont
.lfFaceName
), debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3508 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
3509 elf
.elfLogFont
.lfItalic
, (int)elf
.elfLogFont
.lfWeight
, (int)ntm
.ntmTm
.ntmFlags
);
3510 /* release section before callback (FIXME) */
3511 pthread_mutex_unlock( &font_lock
);
3512 if (!proc( &elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
3513 pthread_mutex_lock( &font_lock
);
3518 /*************************************************************
3521 static BOOL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, font_enum_proc proc
, LPARAM lparam
)
3523 struct gdi_font_family
*family
;
3524 struct gdi_font_face
*face
;
3525 struct enum_charset enum_charsets
[32];
3526 UINT count
, charset
;
3528 charset
= lf
? lf
->lfCharSet
: DEFAULT_CHARSET
;
3530 count
= create_enum_charset_list( charset
, enum_charsets
);
3532 pthread_mutex_lock( &font_lock
);
3534 if (lf
&& lf
->lfFaceName
[0])
3536 const WCHAR
*face_name
= get_gdi_font_subst( lf
->lfFaceName
, charset
, NULL
);
3537 const WCHAR
*orig_name
= NULL
;
3539 TRACE( "facename = %s charset %d\n", debugstr_w(lf
->lfFaceName
), charset
);
3542 orig_name
= lf
->lfFaceName
;
3543 TRACE( "substituting %s -> %s\n", debugstr_w(lf
->lfFaceName
), debugstr_w(face_name
) );
3545 else face_name
= lf
->lfFaceName
;
3547 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3549 if (!family_matches(family
, face_name
)) continue;
3550 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3552 if (!face_matches( family
->family_name
, face
, face_name
)) continue;
3553 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, orig_name
))
3554 return FALSE
; /* enum_face_charsets() unlocked font_lock */
3560 TRACE( "charset %d\n", charset
);
3561 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3563 face
= LIST_ENTRY( list_head(get_family_face_list(family
)), struct gdi_font_face
, entry
);
3564 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, NULL
))
3565 return FALSE
; /* enum_face_charsets() unlocked font_lock */
3568 pthread_mutex_unlock( &font_lock
);
3573 static BOOL
check_unicode_tategaki( WCHAR ch
)
3575 extern const unsigned short vertical_orientation_table
[];
3576 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[ch
>> 8]+((ch
>> 4) & 0x0f)]+ (ch
& 0xf)];
3578 /* We only reach this code if typographical substitution did not occur */
3579 /* Type: U or Type: Tu */
3580 return (orientation
== 1 || orientation
== 3);
3583 static UINT
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
3587 if (glyph
< 0x100) glyph
+= 0xf000;
3588 /* there are a number of old pre-Unicode "broken" TTFs, which
3589 do have symbols at U+00XX instead of U+f0XX */
3591 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3594 index
= glyph
- 0xf000;
3595 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3600 CPTABLEINFO
*get_cptable( WORD cp
)
3602 static CPTABLEINFO tables
[100];
3607 if (cp
== CP_ACP
) return &ansi_cp
;
3608 if (cp
== CP_UTF8
) return &utf8_cp
;
3610 for (i
= 0; i
< ARRAY_SIZE(tables
) && tables
[i
].CodePage
; i
++)
3611 if (tables
[i
].CodePage
== cp
) return &tables
[i
];
3612 if (NtGetNlsSectionPtr( 11, cp
, NULL
, (void **)&ptr
, &size
)) return NULL
;
3613 if (i
== ARRAY_SIZE(tables
))
3615 ERR( "too many code pages\n" );
3618 RtlInitCodePageTable( ptr
, &tables
[i
] );
3622 /* Based on NlsValidateLocale */
3623 const NLS_LOCALE_DATA
*get_locale_data( LCID lcid
)
3625 static const NLS_LOCALE_HEADER
*locale_table
;
3626 static const NLS_LOCALE_LCID_INDEX
*lcids_index
;
3647 status
= NtInitializeNlsFiles( &addr
, &lcid
, &size
);
3650 ERR( "Failed to load nls file\n" );
3654 if (InterlockedCompareExchangePointer( (void **)&header
, addr
, NULL
))
3655 NtUnmapViewOfSection( GetCurrentProcess(), addr
);
3657 locale_table
= (const NLS_LOCALE_HEADER
*)((char *)header
+ header
->locales
);
3658 lcids_index
= (const NLS_LOCALE_LCID_INDEX
*)((char *)locale_table
+ locale_table
->lcids_offset
);
3661 max
= locale_table
->nb_lcids
- 1;
3664 int pos
= (min
+ max
) / 2;
3665 if (lcid
< lcids_index
[pos
].id
) max
= pos
- 1;
3666 else if (lcid
> lcids_index
[pos
].id
) min
= pos
+ 1;
3669 ULONG offset
= locale_table
->locales_offset
+ pos
* locale_table
->locale_size
;
3670 return (const NLS_LOCALE_DATA
*)((const char *)locale_table
+ offset
);
3676 DWORD
win32u_wctomb( CPTABLEINFO
*info
, char *dst
, DWORD dstlen
, const WCHAR
*src
, DWORD srclen
)
3680 if (info
->CodePage
== CP_UTF8
)
3681 RtlUnicodeToUTF8N( dst
, dstlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
3683 RtlUnicodeToCustomCPN( info
, dst
, dstlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
3688 DWORD
win32u_wctomb_size( CPTABLEINFO
*info
, const WCHAR
*src
, DWORD srclen
)
3692 if (info
->CodePage
== CP_UTF8
)
3694 RtlUnicodeToUTF8N( NULL
, 0, &ret
, src
, srclen
* sizeof(WCHAR
) );
3696 else if(info
->DBCSCodePage
)
3698 WCHAR
*uni2cp
= info
->WideCharTable
;
3699 for (ret
= srclen
; srclen
; srclen
--, src
++)
3700 if (uni2cp
[*src
] & 0xff00) ret
++;
3710 DWORD
win32u_mbtowc( CPTABLEINFO
*info
, WCHAR
*dst
, DWORD dstlen
, const char *src
, DWORD srclen
)
3714 if (info
->CodePage
== CP_UTF8
)
3715 RtlUTF8ToUnicodeN( dst
, dstlen
* sizeof(WCHAR
), &ret
, src
, srclen
);
3717 RtlCustomCPToUnicodeN( info
, dst
, dstlen
* sizeof(WCHAR
), &ret
, src
, srclen
);
3719 return ret
/ sizeof(WCHAR
);
3722 DWORD
win32u_mbtowc_size( CPTABLEINFO
*info
, const char *src
, DWORD srclen
)
3726 if (info
->CodePage
== CP_UTF8
)
3728 RtlUTF8ToUnicodeN( NULL
, 0, &ret
, src
, srclen
);
3729 ret
/= sizeof(WCHAR
);
3731 else if (info
->DBCSCodePage
)
3733 for (ret
= 0; srclen
; srclen
--, src
++, ret
++)
3735 if (info
->DBCSOffsets
[(unsigned char)*src
] && srclen
> 1)
3750 static BOOL
wc_to_index( UINT cp
, WCHAR wc
, unsigned char *dst
, BOOL allow_default
)
3752 const CPTABLEINFO
*info
;
3754 if (!(info
= get_cptable( cp
))) return FALSE
;
3756 if (info
->CodePage
== CP_UTF8
)
3763 if (!allow_default
) return FALSE
;
3764 *dst
= info
->DefaultChar
;
3767 else if (info
->DBCSCodePage
)
3769 WCHAR
*uni2cp
= info
->WideCharTable
;
3770 if (uni2cp
[wc
] & 0xff00) return FALSE
;
3775 char *uni2cp
= info
->WideCharTable
;
3779 if (info
->MultiByteTable
[*dst
] != wc
)
3781 if (!allow_default
) return FALSE
;
3782 *dst
= info
->DefaultChar
;
3788 static UINT
get_glyph_index( struct gdi_font
*font
, UINT glyph
)
3793 if (font_funcs
->get_glyph_index( font
, &glyph
, TRUE
)) return glyph
;
3795 if (font
->codepage
== CP_SYMBOL
)
3797 glyph
= get_glyph_index_symbol( font
, wc
);
3800 if (wc_to_index( CP_ACP
, wc
, &ch
, TRUE
))
3801 glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
3804 else if (wc_to_index( font
->codepage
, wc
, &ch
, FALSE
))
3806 glyph
= (unsigned char)ch
;
3807 font_funcs
->get_glyph_index( font
, &glyph
, FALSE
);
3814 static UINT
get_glyph_index_linked( struct gdi_font
**font
, UINT glyph
)
3816 struct gdi_font
*child
;
3819 if ((res
= get_glyph_index( *font
, glyph
))) return res
;
3820 if (glyph
< 32) return 0; /* don't check linked fonts for control characters */
3822 LIST_FOR_EACH_ENTRY( child
, &(*font
)->child_fonts
, struct gdi_font
, entry
)
3824 if (!child
->private && !font_funcs
->load_font( child
)) continue;
3825 if ((res
= get_glyph_index( child
, glyph
)))
3834 static DWORD
get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3835 GLYPHMETRICS
*gm_ret
, ABC
*abc_ret
, DWORD buflen
, void *buf
,
3842 BOOL tategaki
= (*get_gdi_font_name( font
) == '@');
3844 if (format
& GGO_GLYPH_INDEX
)
3846 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3847 as glyph index. "Treasure Adventure Game" depends on this. */
3848 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3849 format
&= ~GGO_GLYPH_INDEX
;
3850 /* TODO: Window also turns off tategaki for glyphs passed in by index
3851 if their unicode code points fall outside of the range that is
3856 index
= get_glyph_index_linked( &font
, glyph
);
3860 index
= get_GSUB_vert_glyph( font
, index
);
3861 if (index
== orig
) tategaki
= check_unicode_tategaki( glyph
);
3865 if (mat
&& !memcmp( mat
, &identity
, sizeof(*mat
) )) mat
= NULL
;
3867 if (format
== GGO_METRICS
&& !mat
&& get_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
))
3870 ret
= font_funcs
->get_glyph_outline( font
, index
, format
, &gm
, &abc
, buflen
, buf
, mat
, tategaki
);
3871 if (ret
== GDI_ERROR
) return ret
;
3873 if (format
== GGO_METRICS
&& !mat
)
3874 set_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
);
3877 if (gm_ret
) *gm_ret
= gm
;
3878 if (abc_ret
) *abc_ret
= abc
;
3883 /*************************************************************
3886 static BOOL
font_FontIsLinked( PHYSDEV dev
)
3888 struct font_physdev
*physdev
= get_font_dev( dev
);
3892 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
3893 return dev
->funcs
->pFontIsLinked( dev
);
3895 return !list_empty( &physdev
->font
->child_fonts
);
3899 /*************************************************************
3900 * font_GetCharABCWidths
3902 static BOOL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT count
, WCHAR
*chars
, ABC
*buffer
)
3904 struct font_physdev
*physdev
= get_font_dev( dev
);
3909 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
3910 return dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
3913 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3915 pthread_mutex_lock( &font_lock
);
3916 for (i
= 0; i
< count
; i
++)
3918 c
= chars
? chars
[i
] : first
+ i
;
3919 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &buffer
[i
], 0, NULL
, NULL
);
3921 pthread_mutex_unlock( &font_lock
);
3926 /*************************************************************
3927 * font_GetCharABCWidthsI
3929 static BOOL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
3931 struct font_physdev
*physdev
= get_font_dev( dev
);
3936 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
3937 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
3940 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3942 pthread_mutex_lock( &font_lock
);
3943 for (c
= 0; c
< count
; c
++, buffer
++)
3944 get_glyph_outline( physdev
->font
, gi
? gi
[c
] : first
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3945 NULL
, buffer
, 0, NULL
, NULL
);
3946 pthread_mutex_unlock( &font_lock
);
3951 /*************************************************************
3954 static BOOL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT count
, const WCHAR
*chars
, INT
*buffer
)
3956 struct font_physdev
*physdev
= get_font_dev( dev
);
3962 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
3963 return dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buffer
);
3966 TRACE( "%p, %d, %d, %p\n", physdev
->font
, first
, count
, buffer
);
3968 pthread_mutex_lock( &font_lock
);
3969 for (i
= 0; i
< count
; i
++)
3971 c
= chars
? chars
[i
] : i
+ first
;
3972 if (get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
) == GDI_ERROR
)
3975 buffer
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3977 pthread_mutex_unlock( &font_lock
);
3982 /*************************************************************
3983 * font_GetCharWidthInfo
3985 static BOOL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
3987 struct font_physdev
*physdev
= get_font_dev( dev
);
3988 struct char_width_info
*info
= ptr
;
3992 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
3993 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
3997 if (!physdev
->font
->scalable
|| !font_funcs
->get_char_width_info( physdev
->font
, info
))
3998 info
->lsb
= info
->rsb
= 0;
4004 /*************************************************************
4007 static DWORD
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
4009 struct font_physdev
*physdev
= get_font_dev( dev
);
4013 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
4014 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
4016 return font_funcs
->get_font_data( physdev
->font
, table
, offset
, buf
, size
);
4020 /*************************************************************
4021 * font_GetFontRealizationInfo
4023 static BOOL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
4025 struct font_physdev
*physdev
= get_font_dev( dev
);
4026 struct font_realization_info
*info
= ptr
;
4030 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
4031 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
4034 TRACE( "(%p, %p)\n", physdev
->font
, info
);
4037 if (physdev
->font
->scalable
) info
->flags
|= 2;
4039 info
->cache_num
= physdev
->font
->cache_num
;
4040 info
->instance_id
= physdev
->font
->handle
;
4041 if (info
->size
== sizeof(*info
))
4043 info
->file_count
= 1;
4044 info
->face_index
= physdev
->font
->face_index
;
4045 info
->simulations
= 0;
4046 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
4047 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
4053 /*************************************************************
4054 * font_GetFontUnicodeRanges
4056 static DWORD
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
4058 struct font_physdev
*physdev
= get_font_dev( dev
);
4059 DWORD size
, num_ranges
;
4063 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
4064 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
4067 num_ranges
= font_funcs
->get_unicode_ranges( physdev
->font
, glyphset
);
4068 size
= offsetof( GLYPHSET
, ranges
[num_ranges
] );
4071 glyphset
->cbThis
= size
;
4072 glyphset
->cRanges
= num_ranges
;
4073 glyphset
->flAccel
= 0;
4079 /*************************************************************
4080 * font_GetGlyphIndices
4082 static DWORD
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
4084 struct font_physdev
*physdev
= get_font_dev( dev
);
4087 BOOL got_default
= FALSE
;
4092 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
4093 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
4096 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
4098 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4102 pthread_mutex_lock( &font_lock
);
4104 for (i
= 0; i
< count
; i
++)
4106 UINT glyph
= str
[i
];
4108 if (!font_funcs
->get_glyph_index( physdev
->font
, &glyph
, TRUE
))
4111 if (physdev
->font
->codepage
== CP_SYMBOL
)
4113 if (str
[i
] >= 0xf020 && str
[i
] <= 0xf100) glyph
= str
[i
] - 0xf000;
4114 else if (str
[i
] < 0x100) glyph
= str
[i
];
4116 else if (wc_to_index( physdev
->font
->codepage
, str
[i
], &ch
, FALSE
))
4117 glyph
= (unsigned char)ch
;
4123 default_char
= font_funcs
->get_default_glyph( physdev
->font
);
4126 gi
[i
] = default_char
;
4128 else gi
[i
] = get_GSUB_vert_glyph( physdev
->font
, glyph
);
4131 pthread_mutex_unlock( &font_lock
);
4136 /*************************************************************
4137 * font_GetGlyphOutline
4139 static DWORD
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
4140 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
4142 struct font_physdev
*physdev
= get_font_dev( dev
);
4147 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
4148 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
4150 pthread_mutex_lock( &font_lock
);
4151 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, gm
, NULL
, buflen
, buf
, mat
);
4152 pthread_mutex_unlock( &font_lock
);
4157 /*************************************************************
4158 * font_GetKerningPairs
4160 static DWORD
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
4162 struct font_physdev
*physdev
= get_font_dev( dev
);
4166 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
4167 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
4170 pthread_mutex_lock( &font_lock
);
4171 if (physdev
->font
->kern_count
== -1)
4172 physdev
->font
->kern_count
= font_funcs
->get_kerning_pairs( physdev
->font
,
4173 &physdev
->font
->kern_pairs
);
4174 pthread_mutex_unlock( &font_lock
);
4178 count
= min( count
, physdev
->font
->kern_count
);
4179 memcpy( pairs
, physdev
->font
->kern_pairs
, count
* sizeof(*pairs
) );
4181 else count
= physdev
->font
->kern_count
;
4187 static void scale_outline_font_metrics( const struct gdi_font
*font
, OUTLINETEXTMETRICW
*otm
)
4189 double scale_x
, scale_y
;
4193 scale_x
= (double)font
->aveWidth
;
4194 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
4197 scale_x
= font
->scale_y
;
4199 scale_x
*= fabs(font
->matrix
.eM11
);
4200 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
4202 /* Windows scales these values as signed integers even if they are unsigned */
4203 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
4204 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
4206 SCALE_Y(otm
->otmTextMetrics
.tmHeight
);
4207 SCALE_Y(otm
->otmTextMetrics
.tmAscent
);
4208 SCALE_Y(otm
->otmTextMetrics
.tmDescent
);
4209 SCALE_Y(otm
->otmTextMetrics
.tmInternalLeading
);
4210 SCALE_Y(otm
->otmTextMetrics
.tmExternalLeading
);
4212 SCALE_X(otm
->otmTextMetrics
.tmOverhang
);
4213 if (font
->fake_bold
)
4215 if (!font
->scalable
) otm
->otmTextMetrics
.tmOverhang
++;
4216 otm
->otmTextMetrics
.tmAveCharWidth
++;
4217 otm
->otmTextMetrics
.tmMaxCharWidth
++;
4219 SCALE_X(otm
->otmTextMetrics
.tmAveCharWidth
);
4220 SCALE_X(otm
->otmTextMetrics
.tmMaxCharWidth
);
4222 SCALE_Y(otm
->otmAscent
);
4223 SCALE_Y(otm
->otmDescent
);
4224 SCALE_Y(otm
->otmLineGap
);
4225 SCALE_Y(otm
->otmsCapEmHeight
);
4226 SCALE_Y(otm
->otmsXHeight
);
4227 SCALE_Y(otm
->otmrcFontBox
.top
);
4228 SCALE_Y(otm
->otmrcFontBox
.bottom
);
4229 SCALE_X(otm
->otmrcFontBox
.left
);
4230 SCALE_X(otm
->otmrcFontBox
.right
);
4231 SCALE_Y(otm
->otmMacAscent
);
4232 SCALE_Y(otm
->otmMacDescent
);
4233 SCALE_Y(otm
->otmMacLineGap
);
4234 SCALE_X(otm
->otmptSubscriptSize
.x
);
4235 SCALE_Y(otm
->otmptSubscriptSize
.y
);
4236 SCALE_X(otm
->otmptSubscriptOffset
.x
);
4237 SCALE_Y(otm
->otmptSubscriptOffset
.y
);
4238 SCALE_X(otm
->otmptSuperscriptSize
.x
);
4239 SCALE_Y(otm
->otmptSuperscriptSize
.y
);
4240 SCALE_X(otm
->otmptSuperscriptOffset
.x
);
4241 SCALE_Y(otm
->otmptSuperscriptOffset
.y
);
4242 SCALE_Y(otm
->otmsStrikeoutSize
);
4243 SCALE_Y(otm
->otmsStrikeoutPosition
);
4244 SCALE_Y(otm
->otmsUnderscoreSize
);
4245 SCALE_Y(otm
->otmsUnderscorePosition
);
4251 /*************************************************************
4252 * font_GetOutlineTextMetrics
4254 static UINT
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
4256 struct font_physdev
*physdev
= get_font_dev( dev
);
4261 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
4262 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
4265 if (!physdev
->font
->scalable
) return 0;
4267 pthread_mutex_lock( &font_lock
);
4268 if (font_funcs
->set_outline_text_metrics( physdev
->font
))
4270 ret
= physdev
->font
->otm
.otmSize
;
4271 if (metrics
&& size
>= physdev
->font
->otm
.otmSize
)
4273 WCHAR
*ptr
= (WCHAR
*)(metrics
+ 1);
4274 *metrics
= physdev
->font
->otm
;
4275 metrics
->otmpFamilyName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4276 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFamilyName
);
4277 ptr
+= lstrlenW(ptr
) + 1;
4278 metrics
->otmpStyleName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4279 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpStyleName
);
4280 ptr
+= lstrlenW(ptr
) + 1;
4281 metrics
->otmpFaceName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4282 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFaceName
);
4283 ptr
+= lstrlenW(ptr
) + 1;
4284 metrics
->otmpFullName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4285 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFullName
);
4286 scale_outline_font_metrics( physdev
->font
, metrics
);
4289 pthread_mutex_unlock( &font_lock
);
4294 /*************************************************************
4295 * font_GetTextCharsetInfo
4297 static UINT
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
4299 struct font_physdev
*physdev
= get_font_dev( dev
);
4303 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
4304 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4306 if (fs
) *fs
= physdev
->font
->fs
;
4307 return physdev
->font
->charset
;
4311 /*************************************************************
4312 * font_GetTextExtentExPoint
4314 static BOOL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
4316 struct font_physdev
*physdev
= get_font_dev( dev
);
4322 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
4323 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
4326 TRACE( "%p, %s, %d\n", physdev
->font
, debugstr_wn(str
, count
), count
);
4328 pthread_mutex_lock( &font_lock
);
4329 for (i
= pos
= 0; i
< count
; i
++)
4331 get_glyph_outline( physdev
->font
, str
[i
], GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
);
4332 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
4335 pthread_mutex_unlock( &font_lock
);
4340 /*************************************************************
4341 * font_GetTextExtentExPointI
4343 static BOOL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
4345 struct font_physdev
*physdev
= get_font_dev( dev
);
4351 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
4352 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
4355 TRACE( "%p, %p, %d\n", physdev
->font
, indices
, count
);
4357 pthread_mutex_lock( &font_lock
);
4358 for (i
= pos
= 0; i
< count
; i
++)
4360 get_glyph_outline( physdev
->font
, indices
[i
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4361 NULL
, &abc
, 0, NULL
, NULL
);
4362 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
4365 pthread_mutex_unlock( &font_lock
);
4370 /*************************************************************
4373 static INT
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
4375 struct font_physdev
*physdev
= get_font_dev( dev
);
4376 const WCHAR
*font_name
;
4381 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
4382 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
4384 font_name
= get_gdi_font_name( physdev
->font
);
4385 len
= lstrlenW( font_name
) + 1;
4388 lstrcpynW( str
, font_name
, count
);
4389 len
= min( count
, len
);
4395 static void scale_font_metrics( struct gdi_font
*font
, TEXTMETRICW
*tm
)
4397 double scale_x
, scale_y
;
4399 /* Make sure that the font has sane width/height ratio */
4400 if (font
->aveWidth
&& (font
->aveWidth
+ tm
->tmHeight
- 1) / tm
->tmHeight
> 100)
4402 WARN( "Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
4408 scale_x
= (double)font
->aveWidth
;
4409 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
4412 scale_x
= font
->scale_y
;
4414 scale_x
*= fabs(font
->matrix
.eM11
);
4415 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
4417 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
4418 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
4420 SCALE_Y(tm
->tmHeight
);
4421 SCALE_Y(tm
->tmAscent
);
4422 SCALE_Y(tm
->tmDescent
);
4423 SCALE_Y(tm
->tmInternalLeading
);
4424 SCALE_Y(tm
->tmExternalLeading
);
4426 SCALE_X(tm
->tmOverhang
);
4427 if (font
->fake_bold
)
4429 if (!font
->scalable
) tm
->tmOverhang
++;
4430 tm
->tmAveCharWidth
++;
4431 tm
->tmMaxCharWidth
++;
4433 SCALE_X(tm
->tmAveCharWidth
);
4434 SCALE_X(tm
->tmMaxCharWidth
);
4440 /*************************************************************
4441 * font_GetTextMetrics
4443 static BOOL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
4445 struct font_physdev
*physdev
= get_font_dev( dev
);
4450 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
4451 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
4454 pthread_mutex_lock( &font_lock
);
4455 if (font_funcs
->set_outline_text_metrics( physdev
->font
) ||
4456 font_funcs
->set_bitmap_text_metrics( physdev
->font
))
4458 *metrics
= physdev
->font
->otm
.otmTextMetrics
;
4459 scale_font_metrics( physdev
->font
, metrics
);
4462 pthread_mutex_unlock( &font_lock
);
4467 static void get_nearest_charset( const WCHAR
*family_name
, struct gdi_font_face
*face
, CHARSETINFO
*csi
)
4469 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4470 a single face with the requested charset. The idea is to check if
4471 the selected font supports the current ANSI codepage, if it does
4472 return the corresponding charset, else return the first charset */
4476 if (translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, csi
, TCI_SRCCODEPAGE
))
4478 const struct gdi_font_link
*font_link
;
4480 if (csi
->fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return;
4481 font_link
= find_gdi_font_link(family_name
);
4482 if (font_link
&& (csi
->fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])) return;
4484 for (i
= 0; i
< 32; i
++)
4486 DWORD fs0
= 1u << i
;
4487 if (face
->fs
.fsCsb
[0] & fs0
)
4489 if (translate_charset_info(&fs0
, csi
, TCI_SRCFONTSIG
)) return;
4490 FIXME("TCI failing on %x\n", (int)fs0
);
4494 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4495 (int)face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4496 csi
->ciACP
= ansi_cp
.CodePage
;
4497 csi
->ciCharset
= DEFAULT_CHARSET
;
4500 static struct gdi_font
*select_font( LOGFONTW
*lf
, FMAT2 dcmat
, BOOL can_use_bitmap
)
4502 struct gdi_font
*font
;
4503 struct gdi_font_face
*face
;
4506 const WCHAR
*orig_name
= NULL
;
4507 BOOL substituted
= FALSE
;
4509 static const WCHAR symbolW
[] = {'S','y','m','b','o','l',0};
4511 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4512 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4513 original value lfCharSet. Note this is a special case for
4514 Symbol and doesn't happen at least for "Wingdings*" */
4515 if (!facename_compare( lf
->lfFaceName
, symbolW
, -1 )) lf
->lfCharSet
= SYMBOL_CHARSET
;
4517 /* check the cache first */
4518 if ((font
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4520 TRACE( "returning cached gdiFont(%p)\n", font
);
4523 if (!(face
= find_matching_face( lf
, &csi
, can_use_bitmap
, &substituted
, &orig_name
)))
4525 FIXME( "can't find a single appropriate font - bailing\n" );
4528 height
= lf
->lfHeight
;
4530 font
= create_gdi_font( face
, orig_name
, lf
);
4531 font
->use_logfont_name
= substituted
;
4532 font
->matrix
= dcmat
;
4533 font
->can_use_bitmap
= can_use_bitmap
;
4534 if (!csi
.fs
.fsCsb
[0]) get_nearest_charset( face
->family
->family_name
, face
, &csi
);
4535 font
->charset
= csi
.ciCharset
;
4536 font
->codepage
= csi
.ciACP
;
4538 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face
->full_name
), debugstr_w(face
->file
),
4539 face
->data_ptr
, face
->face_index
);
4541 font
->aveWidth
= height
? lf
->lfWidth
: 0;
4542 if (!face
->scalable
)
4544 /* Windows uses integer scaling factors for bitmap fonts */
4545 INT scale
, scaled_height
, diff
;
4546 struct gdi_font
*cachedfont
;
4549 diff
= height
- (signed int)face
->size
.height
;
4551 diff
= -height
- ((signed int)face
->size
.height
- face
->size
.internal_leading
);
4553 /* FIXME: rotation of bitmap fonts is ignored */
4554 height
= abs(GDI_ROUND( (double)height
* font
->matrix
.eM22
));
4556 font
->aveWidth
= (double)font
->aveWidth
* font
->matrix
.eM11
;
4557 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
4558 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4559 /* As we changed the matrix, we need to search the cache for the font again,
4560 * otherwise we might explode the cache. */
4561 if ((cachedfont
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4563 TRACE("Found cached font after non-scalable matrix rescale!\n");
4564 free_gdi_font( font
);
4568 if (height
!= 0) height
= diff
;
4569 height
+= face
->size
.height
;
4571 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4572 scaled_height
= scale
* face
->size
.height
;
4573 /* Only jump to the next height if the difference <= 25% original height */
4574 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4575 /* The jump between unscaled and doubled is delayed by 1 */
4576 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4577 font
->scale_y
= scale
;
4578 TRACE("font scale y: %d\n", font
->scale_y
);
4581 if (!font_funcs
->load_font( font
))
4583 free_gdi_font( font
);
4587 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
4588 font
->vert_feature
= get_GSUB_vert_feature( font
);
4590 create_child_font_list( font
);
4592 TRACE( "caching: gdiFont=%p\n", font
);
4593 cache_gdi_font( font
);
4597 /*************************************************************
4600 static HFONT
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4602 struct font_physdev
*physdev
= get_font_dev( dev
);
4603 struct gdi_font
*font
= NULL
, *prev
= physdev
->font
;
4604 DC
*dc
= get_physdev_dc( dev
);
4610 BOOL can_use_bitmap
= !!(NtGdiGetDeviceCaps( dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
);
4612 NtGdiExtGetObjectW( hfont
, sizeof(lf
), &lf
);
4613 switch (lf
.lfQuality
)
4615 case NONANTIALIASED_QUALITY
:
4616 if (!*aa_flags
) *aa_flags
= GGO_BITMAP
;
4618 case ANTIALIASED_QUALITY
:
4619 if (!*aa_flags
) *aa_flags
= GGO_GRAY4_BITMAP
;
4623 if (lf
.lfOutPrecision
== OUT_TT_ONLY_PRECIS
)
4624 can_use_bitmap
= FALSE
;
4626 lf
.lfWidth
= abs(lf
.lfWidth
);
4628 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4629 debugstr_w(lf
.lfFaceName
), (int)lf
.lfHeight
, lf
.lfItalic
,
4630 (int)lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, (int)lf
.lfOrientation
,
4631 (int)lf
.lfEscapement
);
4633 if (dc
->attr
->graphics_mode
== GM_ADVANCED
)
4635 memcpy( &dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
) );
4636 /* try to avoid not necessary glyph transformations */
4637 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4639 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4640 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4641 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4646 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4647 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4648 dcmat
.eM21
= dcmat
.eM12
= 0;
4649 lf
.lfOrientation
= lf
.lfEscapement
;
4650 if (dc
->vport2WorldValid
)
4652 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4653 lf
.lfOrientation
= -lf
.lfOrientation
;
4654 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4655 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4658 TRACE( "DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
, dcmat
.eM21
, dcmat
.eM22
);
4660 pthread_mutex_lock( &font_lock
);
4662 font
= select_font( &lf
, dcmat
, can_use_bitmap
);
4666 if (!*aa_flags
) *aa_flags
= font
->aa_flags
;
4669 if (lf
.lfQuality
== CLEARTYPE_QUALITY
|| lf
.lfQuality
== CLEARTYPE_NATURAL_QUALITY
)
4670 *aa_flags
= subpixel_orientation
;
4672 *aa_flags
= font_smoothing
;
4674 *aa_flags
= font_funcs
->get_aa_flags( font
, *aa_flags
, antialias_fakes
);
4676 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), (int)lf
.lfHeight
, *aa_flags
);
4677 pthread_mutex_unlock( &font_lock
);
4679 physdev
->font
= font
;
4680 if (prev
) release_gdi_font( prev
);
4681 return font
? hfont
: 0;
4685 const struct gdi_dc_funcs font_driver
=
4687 NULL
, /* pAbortDoc */
4688 NULL
, /* pAbortPath */
4689 NULL
, /* pAlphaBlend */
4690 NULL
, /* pAngleArc */
4693 NULL
, /* pBeginPath */
4694 NULL
, /* pBlendImage */
4696 NULL
, /* pCloseFigure */
4697 NULL
, /* pCreateCompatibleDC */
4698 font_CreateDC
, /* pCreateDC */
4699 font_DeleteDC
, /* pDeleteDC */
4700 NULL
, /* pDeleteObject */
4701 NULL
, /* pEllipse */
4703 NULL
, /* pEndPage */
4704 NULL
, /* pEndPath */
4705 font_EnumFonts
, /* pEnumFonts */
4706 NULL
, /* pExtEscape */
4707 NULL
, /* pExtFloodFill */
4708 NULL
, /* pExtTextOut */
4709 NULL
, /* pFillPath */
4710 NULL
, /* pFillRgn */
4711 font_FontIsLinked
, /* pFontIsLinked */
4712 NULL
, /* pFrameRgn */
4713 NULL
, /* pGetBoundsRect */
4714 font_GetCharABCWidths
, /* pGetCharABCWidths */
4715 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
4716 font_GetCharWidth
, /* pGetCharWidth */
4717 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
4718 NULL
, /* pGetDeviceCaps */
4719 NULL
, /* pGetDeviceGammaRamp */
4720 font_GetFontData
, /* pGetFontData */
4721 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
4722 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
4723 font_GetGlyphIndices
, /* pGetGlyphIndices */
4724 font_GetGlyphOutline
, /* pGetGlyphOutline */
4725 NULL
, /* pGetICMProfile */
4726 NULL
, /* pGetImage */
4727 font_GetKerningPairs
, /* pGetKerningPairs */
4728 NULL
, /* pGetNearestColor */
4729 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
4730 NULL
, /* pGetPixel */
4731 NULL
, /* pGetSystemPaletteEntries */
4732 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
4733 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
4734 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
4735 font_GetTextFace
, /* pGetTextFace */
4736 font_GetTextMetrics
, /* pGetTextMetrics */
4737 NULL
, /* pGradientFill */
4738 NULL
, /* pInvertRgn */
4741 NULL
, /* pPaintRgn */
4744 NULL
, /* pPolyBezier */
4745 NULL
, /* pPolyBezierTo */
4746 NULL
, /* pPolyDraw */
4747 NULL
, /* pPolyPolygon */
4748 NULL
, /* pPolyPolyline */
4749 NULL
, /* pPolylineTo */
4750 NULL
, /* pPutImage */
4751 NULL
, /* pRealizeDefaultPalette */
4752 NULL
, /* pRealizePalette */
4753 NULL
, /* pRectangle */
4754 NULL
, /* pResetDC */
4755 NULL
, /* pRoundRect */
4756 NULL
, /* pSelectBitmap */
4757 NULL
, /* pSelectBrush */
4758 font_SelectFont
, /* pSelectFont */
4759 NULL
, /* pSelectPen */
4760 NULL
, /* pSetBkColor */
4761 NULL
, /* pSetBoundsRect */
4762 NULL
, /* pSetDCBrushColor */
4763 NULL
, /* pSetDCPenColor */
4764 NULL
, /* pSetDIBitsToDevice */
4765 NULL
, /* pSetDeviceClipping */
4766 NULL
, /* pSetDeviceGammaRamp */
4767 NULL
, /* pSetPixel */
4768 NULL
, /* pSetTextColor */
4769 NULL
, /* pStartDoc */
4770 NULL
, /* pStartPage */
4771 NULL
, /* pStretchBlt */
4772 NULL
, /* pStretchDIBits */
4773 NULL
, /* pStrokeAndFillPath */
4774 NULL
, /* pStrokePath */
4775 NULL
, /* pUnrealizePalette */
4776 GDI_PRIORITY_FONT_DRV
/* priority */
4779 static BOOL
get_key_value( HKEY key
, const char *name
, DWORD
*value
)
4781 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[12 * sizeof(WCHAR
)])];
4782 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4785 count
= query_reg_ascii_value( key
, name
, info
, sizeof(value_buffer
) );
4788 if (info
->Type
== REG_DWORD
) memcpy( value
, info
->Data
, sizeof(*value
) );
4789 else *value
= wcstol( (const WCHAR
*)info
->Data
, NULL
, 10 );
4794 static UINT
init_font_options(void)
4796 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[20 * sizeof(WCHAR
)])];
4797 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4799 DWORD i
, val
, gamma
= 1400;
4802 if (query_reg_ascii_value( wine_fonts_key
, "AntialiasFakeBoldOrItalic",
4803 info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
4805 static const WCHAR valsW
[] = {'y','Y','t','T','1',0};
4806 antialias_fakes
= (wcschr( valsW
, *(const WCHAR
*)info
->Data
) != NULL
);
4809 if ((key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
4811 /* FIXME: handle vertical orientations even though Windows doesn't */
4812 if (get_key_value( key
, "FontSmoothingOrientation", &val
))
4816 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4817 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
4819 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4820 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
4824 if (get_key_value( key
, "FontSmoothing", &val
) && val
/* enabled */)
4826 if (get_key_value( key
, "FontSmoothingType", &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4827 font_smoothing
= subpixel_orientation
;
4829 font_smoothing
= GGO_GRAY4_BITMAP
;
4831 if (get_key_value( key
, "FontSmoothingGamma", &val
) && val
)
4833 gamma
= min( max( val
, 1000 ), 2200 );
4835 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4839 /* Calibrating the difference between the registry value and the Wine gamma value.
4840 This looks roughly similar to Windows Native with the same registry value.
4841 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4842 gamma
= 1000 * gamma
/ 1400;
4845 for (i
= 0; i
< 256; i
++)
4847 font_gamma_ramp
.encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
4848 font_gamma_ramp
.decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
4852 if (!dpi
&& (key
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) )))
4854 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4859 font_gamma_ramp
.gamma
= gamma
;
4860 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp
.gamma
, dpi
);
4865 /* compute positions for text rendering, in device coords */
4866 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
4871 size
->cx
= size
->cy
= 0;
4872 if (!count
) return TRUE
;
4874 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4875 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4877 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
4878 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
4880 if (dc
->breakExtra
|| dc
->breakRem
)
4882 int i
, space
= 0, rem
= dc
->breakRem
;
4884 for (i
= 0; i
< count
; i
++)
4886 if (str
[i
] == tm
.tmBreakChar
)
4888 space
+= dc
->breakExtra
;
4898 size
->cx
= dx
[count
- 1];
4899 size
->cy
= tm
.tmHeight
;
4903 /* compute positions for text rendering, in device coords */
4904 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
4909 size
->cx
= size
->cy
= 0;
4910 if (!count
) return TRUE
;
4912 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4913 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4915 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
4916 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
4918 if (dc
->breakExtra
|| dc
->breakRem
)
4921 int i
, space
= 0, rem
= dc
->breakRem
;
4923 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4924 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
4926 for (i
= 0; i
< count
; i
++)
4928 if (indices
[i
] == space_index
)
4930 space
+= dc
->breakExtra
;
4940 size
->cx
= dx
[count
- 1];
4941 size
->cy
= tm
.tmHeight
;
4945 /***********************************************************************
4946 * get_text_charset_info
4948 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4950 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
4952 UINT ret
= DEFAULT_CHARSET
;
4955 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
4956 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4958 if (ret
== DEFAULT_CHARSET
&& fs
)
4959 memset(fs
, 0, sizeof(FONTSIGNATURE
));
4963 /***********************************************************************
4964 * NtGdiGetTextCharsetInfo (win32u.@)
4966 UINT WINAPI
NtGdiGetTextCharsetInfo( HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
4968 UINT ret
= DEFAULT_CHARSET
;
4969 DC
*dc
= get_dc_ptr(hdc
);
4973 ret
= get_text_charset_info( dc
, fs
, flags
);
4974 release_dc_ptr( dc
);
4979 /***********************************************************************
4980 * NtGdiHfontCreate (win32u.@)
4982 HFONT WINAPI
NtGdiHfontCreate( const void *logfont
, ULONG size
, ULONG type
,
4983 ULONG flags
, void *data
)
4987 const LOGFONTW
*plf
;
4989 if (!logfont
) return 0;
4991 if (size
== sizeof(ENUMLOGFONTEXDVW
) || size
== sizeof(ENUMLOGFONTEXW
))
4993 const ENUMLOGFONTEXW
*lfex
= logfont
;
4995 if (lfex
->elfFullName
[0] || lfex
->elfStyle
[0] || lfex
->elfScript
[0])
4997 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
4998 debugstr_w( lfex
->elfFullName
), debugstr_w( lfex
->elfStyle
),
4999 debugstr_w( lfex
->elfScript
));
5002 plf
= &lfex
->elfLogFont
;
5004 else if (size
!= sizeof(LOGFONTW
))
5006 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
5011 if (!(fontPtr
= malloc( sizeof(*fontPtr
) ))) return 0;
5013 fontPtr
->logfont
= *plf
;
5015 if (!(hFont
= alloc_gdi_handle( &fontPtr
->obj
, NTGDI_OBJ_FONT
, &fontobj_funcs
)))
5021 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
5022 (int)plf
->lfHeight
, (int)plf
->lfWidth
,
5023 (int)plf
->lfEscapement
, (int)plf
->lfOrientation
,
5024 plf
->lfPitchAndFamily
,
5025 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
5026 plf
->lfQuality
, plf
->lfCharSet
,
5027 debugstr_w(plf
->lfFaceName
),
5028 plf
->lfWeight
> 400 ? "Bold" : "",
5029 plf
->lfItalic
? "Italic" : "",
5030 plf
->lfUnderline
? "Underline" : "", hFont
);
5035 #define ASSOC_CHARSET_OEM 1
5036 #define ASSOC_CHARSET_ANSI 2
5037 #define ASSOC_CHARSET_SYMBOL 4
5039 static DWORD
get_associated_charset_info(void)
5041 static int associated_charset
= -1;
5043 if (associated_charset
== -1)
5045 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[32 * sizeof(WCHAR
)])];
5046 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
5049 static const WCHAR yesW
[] = {'y','e','s',0};
5051 associated_charset
= 0;
5053 if (!(hkey
= reg_open_key( NULL
, associated_charset_keyW
, sizeof(associated_charset_keyW
) )))
5056 if (query_reg_ascii_value( hkey
, "ANSI(00)", info
, sizeof(value_buffer
) ) &&
5057 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
5058 associated_charset
|= ASSOC_CHARSET_ANSI
;
5060 if (query_reg_ascii_value( hkey
, "OEM(FF)", info
, sizeof(value_buffer
) ) &&
5061 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
5062 associated_charset
|= ASSOC_CHARSET_OEM
;
5064 if (query_reg_ascii_value( hkey
, "SYMBOL(02)", info
, sizeof(value_buffer
) ) &&
5065 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
5066 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
5070 TRACE("associated_charset = %d\n", associated_charset
);
5073 return associated_charset
;
5076 static void update_font_code_page( DC
*dc
, HANDLE font
)
5079 int charset
= get_text_charset_info( dc
, NULL
, 0 );
5081 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
5085 NtGdiExtGetObjectW( font
, sizeof(lf
), &lf
);
5086 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
5087 charset
= DEFAULT_CHARSET
;
5090 /* Hmm, nicely designed api this one! */
5091 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
5092 dc
->attr
->font_code_page
= csi
.ciACP
;
5096 dc
->attr
->font_code_page
= oem_cp
.CodePage
;
5098 case DEFAULT_CHARSET
:
5099 dc
->attr
->font_code_page
= ansi_cp
.CodePage
;
5102 case VISCII_CHARSET
:
5108 case CELTIC_CHARSET
:
5109 /* FIXME: These have no place here, but because x11drv
5110 enumerates fonts with these (made up) charsets some apps
5111 might use them and then the FIXME below would become
5112 annoying. Now we could pick the intended codepage for
5113 each of these, but since it's broken anyway we'll just
5114 use CP_ACP and hope it'll go away...
5116 dc
->attr
->font_code_page
= CP_ACP
;
5120 FIXME("Can't find codepage for charset %d\n", charset
);
5121 dc
->attr
->font_code_page
= CP_ACP
;
5126 TRACE( "charset %d => cp %d\n", charset
, dc
->attr
->font_code_page
);
5129 /***********************************************************************
5130 * NtGdiSelectFont (win32u.@)
5132 HGDIOBJ WINAPI
NtGdiSelectFont( HDC hdc
, HGDIOBJ handle
)
5135 DC
*dc
= get_dc_ptr( hdc
);
5141 if (!GDI_inc_ref_count( handle
))
5143 release_dc_ptr( dc
);
5147 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
5148 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
5152 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
5153 update_font_code_page( dc
, handle
);
5154 if (dc
->font_gamma_ramp
== NULL
)
5155 dc
->font_gamma_ramp
= &font_gamma_ramp
;
5156 GDI_dec_ref_count( ret
);
5158 else GDI_dec_ref_count( handle
);
5160 release_dc_ptr( dc
);
5165 /***********************************************************************
5168 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
5170 FONTOBJ
*font
= GDI_GetObjPtr( handle
, NTGDI_OBJ_FONT
);
5172 if (!font
) return 0;
5175 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
5176 memcpy( buffer
, &font
->logfont
, count
);
5178 else count
= sizeof(LOGFONTW
);
5179 GDI_ReleaseObj( handle
);
5184 /***********************************************************************
5187 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
5191 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
5200 struct font_enum_entry
*buf
;
5206 static INT
enum_fonts( const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lp
)
5208 struct font_enum
*fe
= (struct font_enum
*)lp
;
5210 if (fe
->charset
!= DEFAULT_CHARSET
&& lf
->lfCharSet
!= fe
->charset
) return 1;
5211 if ((type
& RASTER_FONTTYPE
) && !(NtGdiGetDeviceCaps( fe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
))
5214 if (fe
->buf
&& fe
->count
< fe
->size
)
5216 fe
->buf
[fe
->count
].type
= type
;
5217 fe
->buf
[fe
->count
].lf
= *(const ENUMLOGFONTEXW
*)lf
;
5218 fe
->buf
[fe
->count
].tm
= *(const NEWTEXTMETRICEXW
*)tm
;
5224 /***********************************************************************
5225 * NtGdiEnumFonts (win32u.@)
5227 BOOL WINAPI
NtGdiEnumFonts( HDC hdc
, ULONG type
, ULONG win32_compat
, ULONG face_name_len
,
5228 const WCHAR
*face_name
, ULONG charset
, ULONG
*count
, void *buf
)
5230 struct font_enum fe
;
5236 if (!(dc
= get_dc_ptr( hdc
))) return 0;
5238 memset( &lf
, 0, sizeof(lf
) );
5239 lf
.lfCharSet
= charset
;
5240 if (face_name_len
) memcpy( lf
.lfFaceName
, face_name
, face_name_len
* sizeof(WCHAR
) );
5244 fe
.size
= *count
/ sizeof(*fe
.buf
);
5246 fe
.charset
= charset
;
5248 physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
5249 ret
= physdev
->funcs
->pEnumFonts( physdev
, &lf
, enum_fonts
, (LPARAM
)&fe
);
5250 if (ret
&& buf
) ret
= fe
.count
<= fe
.size
;
5251 *count
= fe
.count
* sizeof(*fe
.buf
);
5253 release_dc_ptr( dc
);
5258 /***********************************************************************
5259 * NtGdiSetTextJustification (win32u.@)
5261 BOOL WINAPI
NtGdiSetTextJustification( HDC hdc
, INT extra
, INT breaks
)
5265 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
5267 extra
= abs( (extra
* dc
->attr
->vport_ext
.cx
+ dc
->attr
->wnd_ext
.cx
/ 2) /
5268 dc
->attr
->wnd_ext
.cx
);
5269 if (!extra
) breaks
= 0;
5272 dc
->breakExtra
= extra
/ breaks
;
5273 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
5281 release_dc_ptr( dc
);
5286 /***********************************************************************
5287 * NtGdiGetTextFaceW (win32u.@)
5289 INT WINAPI
NtGdiGetTextFaceW( HDC hdc
, INT count
, WCHAR
*name
, BOOL alias_name
)
5294 DC
* dc
= get_dc_ptr( hdc
);
5297 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
5298 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
5299 release_dc_ptr( dc
);
5304 /***********************************************************************
5305 * NtGdiGetTextExtentExW (win32u.@)
5307 * Return the size of the string as it would be if it was output properly by
5310 BOOL WINAPI
NtGdiGetTextExtentExW( HDC hdc
, const WCHAR
*str
, INT count
, INT max_ext
,
5311 INT
*nfit
, INT
*dxs
, SIZE
*size
, UINT flags
)
5316 INT buffer
[256], *pos
= dxs
;
5318 if (count
< 0) return FALSE
;
5320 dc
= get_dc_ptr(hdc
);
5321 if (!dc
) return FALSE
;
5326 if (count
> 256 && !(pos
= malloc( count
* sizeof(*pos
) )))
5328 release_dc_ptr( dc
);
5335 ret
= get_char_positions_indices( dc
, str
, count
, pos
, size
);
5337 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
5342 for (i
= 0; i
< count
; i
++)
5344 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) +
5345 (i
+ 1) * dc
->attr
->char_extra
;
5346 if (nfit
&& dx
> (unsigned int)max_ext
) break;
5347 if (dxs
) dxs
[i
] = dx
;
5349 if (nfit
) *nfit
= i
;
5352 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->attr
->char_extra
;
5353 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
5356 if (pos
!= buffer
&& pos
!= dxs
) free( pos
);
5357 release_dc_ptr( dc
);
5359 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
),
5360 max_ext
, (int)size
->cx
, (int)size
->cy
);
5364 /***********************************************************************
5365 * NtGdiGetTextMetricsW (win32u.@)
5367 BOOL WINAPI
NtGdiGetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
, ULONG flags
)
5371 DC
* dc
= get_dc_ptr( hdc
);
5372 if (!dc
) return FALSE
;
5374 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5375 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
5379 /* device layer returns values in device units
5380 * therefore we have to convert them to logical */
5382 metrics
->tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
5383 metrics
->tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
5384 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
5385 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
5386 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
5387 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
5388 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
5389 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
5390 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
5391 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
5394 TRACE("text metrics:\n"
5395 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5396 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5397 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5398 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5399 " PitchAndFamily = %02x\n"
5400 " --------------------\n"
5401 " InternalLeading = %i\n"
5405 (int)metrics
->tmWeight
, metrics
->tmFirstChar
, (int)metrics
->tmAveCharWidth
,
5406 metrics
->tmItalic
, metrics
->tmLastChar
, (int)metrics
->tmMaxCharWidth
,
5407 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, (int)metrics
->tmOverhang
,
5408 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
5409 metrics
->tmPitchAndFamily
,
5410 (int)metrics
->tmInternalLeading
,
5411 (int)metrics
->tmAscent
,
5412 (int)metrics
->tmDescent
,
5413 (int)metrics
->tmHeight
);
5415 release_dc_ptr( dc
);
5420 /***********************************************************************
5421 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
5423 UINT WINAPI
NtGdiGetOutlineTextMetricsInternalW( HDC hdc
, UINT cbData
,
5424 OUTLINETEXTMETRICW
*lpOTM
, ULONG opts
)
5426 DC
*dc
= get_dc_ptr( hdc
);
5427 OUTLINETEXTMETRICW
*output
= lpOTM
;
5431 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
5434 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
5435 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
5437 if (lpOTM
&& ret
> cbData
)
5439 output
= malloc( ret
);
5440 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
5445 output
->otmTextMetrics
.tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
5446 output
->otmTextMetrics
.tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
5447 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
5448 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
5449 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
5450 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
5451 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
5452 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
5453 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
5454 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
5455 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
5456 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
5457 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
5458 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
5459 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
5460 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
5461 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
5462 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
5463 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
5464 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
5465 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
5466 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
5467 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
5468 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
5469 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
5470 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
5471 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
5472 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
5473 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
5474 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
5475 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
5476 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
5477 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
5478 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
5482 memcpy(lpOTM
, output
, cbData
);
5491 /***********************************************************************
5492 * NtGdiGetCharWidthW (win32u.@)
5494 BOOL WINAPI
NtGdiGetCharWidthW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5495 ULONG flags
, void *buf
)
5497 UINT i
, count
= last
;
5502 if (flags
& NTGDI_GETCHARWIDTH_INDICES
)
5507 if (!(abc
= malloc( count
* sizeof(ABC
) )))
5510 if (!NtGdiGetCharABCWidthsW( hdc
, first
, last
, chars
,
5511 NTGDI_GETCHARABCWIDTHS_INT
| NTGDI_GETCHARABCWIDTHS_INDICES
,
5518 for (i
= 0; i
< count
; i
++)
5519 ((INT
*)buf
)[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
5525 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
5527 if (!chars
) count
= last
- first
+ 1;
5528 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
5529 ret
= dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buf
);
5533 if (flags
& NTGDI_GETCHARWIDTH_INT
)
5536 /* convert device units to logical */
5537 for (i
= 0; i
< count
; i
++)
5538 buffer
[i
] = width_to_LP( dc
, buffer
[i
] );
5542 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
5543 for (i
= 0; i
< count
; i
++)
5544 ((float *)buf
)[i
] = ((int *)buf
)[i
] * scale
;
5547 release_dc_ptr( dc
);
5552 /* helper for nulldrv_ExtTextOut */
5553 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
5554 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
5556 UINT indices
[3] = {0, 0, 0x20};
5562 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
5564 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
5567 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
, FALSE
);
5568 if (ret
!= GDI_ERROR
) break;
5571 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
5572 if (!image
) return ERROR_SUCCESS
;
5576 if (!ret
) /* empty glyph */
5578 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
5579 return ERROR_SUCCESS
;
5582 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5583 size
= metrics
->gmBlackBoxY
* stride
;
5585 if (!(image
->ptr
= malloc( size
))) return ERROR_OUTOFMEMORY
;
5586 image
->is_copy
= TRUE
;
5587 image
->free
= free_heap_bits
;
5589 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
,
5591 if (ret
== GDI_ERROR
)
5594 return ERROR_NOT_FOUND
;
5596 return ERROR_SUCCESS
;
5599 /* helper for nulldrv_ExtTextOut */
5600 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
5601 LPCWSTR str
, UINT count
, const INT
*dx
)
5606 reset_bounds( &bounds
);
5607 for (i
= 0; i
< count
; i
++)
5609 GLYPHMETRICS metrics
;
5611 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
5613 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
5614 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
5615 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
5616 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
5617 add_bounds_rect( &bounds
, &rect
);
5621 if (flags
& ETO_PDY
)
5624 y
+= dx
[ i
* 2 + 1];
5630 x
+= metrics
.gmCellIncX
;
5631 y
+= metrics
.gmCellIncY
;
5637 /* helper for nulldrv_ExtTextOut */
5638 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
5639 const struct gdi_image_bits
*image
, const RECT
*clip
)
5641 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5642 UINT i
, count
, max_count
;
5644 BYTE
*ptr
= image
->ptr
;
5645 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5647 RECT rect
, clipped_rect
;
5649 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
5650 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
5651 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
5652 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
5653 if (!clip
) clipped_rect
= rect
;
5654 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
5656 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
5657 pts
= malloc( max_count
* sizeof(*pts
) );
5661 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
5662 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
5664 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
5666 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5667 pts
[count
].x
= rect
.left
+ x
;
5668 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5669 pts
[count
+ 1].x
= rect
.left
+ x
;
5670 if (pts
[count
+ 1].x
> pts
[count
].x
)
5672 pts
[count
].y
= pts
[count
+ 1].y
= y
;
5677 assert( count
<= max_count
);
5678 dp_to_lp( dc
, pts
, count
);
5679 for (i
= 0; i
< count
; i
+= 2)
5681 const ULONG pts_count
= 2;
5682 NtGdiPolyPolyDraw( dc
->hSelf
, pts
+ i
, &pts_count
, 1, NtGdiPolyPolyline
);
5687 /***********************************************************************
5688 * nulldrv_ExtTextOut
5690 BOOL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5691 LPCWSTR str
, UINT count
, const INT
*dx
)
5693 DC
*dc
= get_nulldrv_dc( dev
);
5699 if (flags
& ETO_OPAQUE
)
5702 COLORREF brush_color
= NtGdiGetNearestColor( dev
->hdc
, dc
->attr
->background_color
);
5703 HBRUSH brush
= NtGdiCreateSolidBrush( brush_color
, NULL
);
5707 orig
= NtGdiSelectBrush( dev
->hdc
, brush
);
5708 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5709 NtGdiPatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5710 NtGdiSelectBrush( dev
->hdc
, orig
);
5711 NtGdiDeleteObjectApp( brush
);
5715 if (!count
) return TRUE
;
5717 if (dc
->aa_flags
!= GGO_BITMAP
)
5719 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5720 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5721 struct gdi_image_bits bits
;
5722 struct bitblt_coords src
, dst
;
5724 /* FIXME Subpixel modes */
5725 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5727 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5728 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5729 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5730 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5732 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5733 src
.x
= src
.visrect
.left
;
5734 src
.y
= src
.visrect
.top
;
5735 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5736 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5738 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5739 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5741 /* we can avoid the GetImage, just query the needed format */
5742 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5743 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5744 info
->bmiHeader
.biWidth
= src
.width
;
5745 info
->bmiHeader
.biHeight
= -src
.height
;
5746 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5747 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5748 if (!err
|| err
== ERROR_BAD_FORMAT
)
5750 /* make the source rectangle relative to the source bits */
5752 src
.visrect
.left
= src
.visrect
.top
= 0;
5753 src
.visrect
.right
= src
.width
;
5754 src
.visrect
.bottom
= src
.height
;
5756 bits
.ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5757 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5758 bits
.is_copy
= TRUE
;
5759 bits
.free
= free_heap_bits
;
5760 err
= ERROR_SUCCESS
;
5765 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5766 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5767 if (!err
&& !bits
.is_copy
)
5769 void *ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5772 if (bits
.free
) bits
.free( &bits
);
5773 return ERROR_OUTOFMEMORY
;
5775 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5776 if (bits
.free
) bits
.free( &bits
);
5778 bits
.is_copy
= TRUE
;
5779 bits
.free
= free_heap_bits
;
5784 /* make x,y relative to the image bits */
5785 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5786 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5787 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5788 aa_flags
, str
, count
, dx
);
5789 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5790 if (bits
.free
) bits
.free( &bits
);
5795 pen
= NtGdiCreatePen( PS_SOLID
, 1, dc
->attr
->text_color
, NULL
);
5796 orig
= NtGdiSelectPen( dev
->hdc
, pen
);
5798 for (i
= 0; i
< count
; i
++)
5800 GLYPHMETRICS metrics
;
5801 struct gdi_image_bits image
;
5803 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5806 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5807 if (image
.free
) image
.free( &image
);
5811 if (flags
& ETO_PDY
)
5814 y
+= dx
[ i
* 2 + 1];
5820 x
+= metrics
.gmCellIncX
;
5821 y
+= metrics
.gmCellIncY
;
5825 NtGdiSelectPen( dev
->hdc
, orig
);
5826 NtGdiDeleteObjectApp( pen
);
5830 /***********************************************************************
5833 * Scale the underline / strikeout line width.
5835 static inline int get_line_width( DC
*dc
, int metric_size
)
5837 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5838 if (width
== 0) width
= 1;
5839 if (metric_size
< 0) width
= -width
;
5843 /***********************************************************************
5844 * NtGdiExtTextOutW (win32u.@)
5846 * Draws text using the currently selected font, background color, and text color.
5850 * x,y [I] coordinates of string
5852 * ETO_GRAYED - undocumented on MSDN
5853 * ETO_OPAQUE - use background color for fill the rectangle
5854 * ETO_CLIPPED - clipping text to the rectangle
5855 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5856 * than encoded characters. Implies ETO_IGNORELANGUAGE
5857 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5858 * Affects BiDi ordering
5859 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5860 * ETO_PDY - unimplemented
5861 * ETO_NUMERICSLATIN - unimplemented always assumed -
5862 * do not translate numbers into locale representations
5863 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5864 * lprect [I] dimensions for clipping or/and opaquing
5865 * str [I] text string
5866 * count [I] number of symbols in string
5867 * lpDx [I] optional parameter with distance between drawing characters
5873 BOOL WINAPI
NtGdiExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
, const RECT
*lprect
,
5874 const WCHAR
*str
, UINT count
, const INT
*lpDx
, DWORD cp
)
5882 double cosEsc
, sinEsc
;
5886 POINT
*deltas
= NULL
, width
= {0, 0};
5887 DC
* dc
= get_dc_ptr( hdc
);
5890 static int quietfixme
= 0;
5892 if (!dc
) return FALSE
;
5893 if (count
> INT_MAX
) return FALSE
;
5895 align
= dc
->attr
->text_align
;
5896 breakRem
= dc
->breakRem
;
5897 layout
= dc
->attr
->layout
;
5899 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5901 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5906 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5908 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5909 if (layout
& LAYOUT_RTL
)
5911 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5912 align
^= TA_RTLREADING
;
5915 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
5916 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
5917 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->attr
->background_mode
,
5918 dc
->attr
->map_mode
);
5920 if(align
& TA_UPDATECP
)
5922 pt
= dc
->attr
->cur_pos
;
5927 NtGdiGetTextMetricsW( hdc
, &tm
, 0 );
5928 NtGdiExtGetObjectW( dc
->hFont
, sizeof(lf
), &lf
);
5930 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
5931 lf
.lfEscapement
= 0;
5933 if ((dc
->attr
->graphics_mode
== GM_COMPATIBLE
) &&
5934 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
5936 lf
.lfEscapement
= -lf
.lfEscapement
;
5939 if(lf
.lfEscapement
!= 0)
5941 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
5942 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
5950 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
5953 lp_to_dp(dc
, (POINT
*)&rc
, 2);
5955 if (flags
& ETO_OPAQUE
)
5956 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
5958 else flags
&= ~ETO_CLIPPED
;
5968 lp_to_dp(dc
, &pt
, 1);
5972 char_extra
= dc
->attr
->char_extra
;
5973 if (char_extra
&& lpDx
&& NtGdiGetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
5974 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5976 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
5979 POINT total
= {0, 0}, desired
[2];
5981 deltas
= malloc( count
* sizeof(*deltas
) );
5984 if (flags
& ETO_PDY
)
5986 for (i
= 0; i
< count
; i
++)
5988 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
5989 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
5994 for (i
= 0; i
< count
; i
++)
5996 deltas
[i
].x
= lpDx
[i
] + char_extra
;
6003 INT
*dx
= malloc( count
* sizeof(*dx
) );
6005 NtGdiGetTextExtentExW( hdc
, str
, count
, -1, NULL
, dx
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
6007 deltas
[0].x
= dx
[0];
6009 for (i
= 1; i
< count
; i
++)
6011 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
6017 for(i
= 0; i
< count
; i
++)
6019 total
.x
+= deltas
[i
].x
;
6020 total
.y
+= deltas
[i
].y
;
6022 desired
[0].x
= desired
[0].y
= 0;
6024 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
6025 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
6027 lp_to_dp(dc
, desired
, 2);
6028 desired
[1].x
-= desired
[0].x
;
6029 desired
[1].y
-= desired
[0].y
;
6031 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
6033 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
6034 desired
[1].x
= -desired
[1].x
;
6035 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
6036 desired
[1].y
= -desired
[1].y
;
6039 deltas
[i
].x
= desired
[1].x
- width
.x
;
6040 deltas
[i
].y
= desired
[1].y
- width
.y
;
6050 NtGdiGetTextExtentExW( hdc
, str
, count
, 0, NULL
, NULL
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
6051 desired
[0].x
= desired
[0].y
= 0;
6052 desired
[1].x
= sz
.cx
;
6054 lp_to_dp(dc
, desired
, 2);
6055 desired
[1].x
-= desired
[0].x
;
6056 desired
[1].y
-= desired
[0].y
;
6058 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
6060 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
6061 desired
[1].x
= -desired
[1].x
;
6062 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
6063 desired
[1].y
= -desired
[1].y
;
6068 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
6069 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
6070 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
6073 if (align
& TA_UPDATECP
)
6077 dp_to_lp(dc
, &pt
, 1);
6078 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
6090 if (align
& TA_UPDATECP
)
6094 dp_to_lp(dc
, &pt
, 1);
6095 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
6100 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
6103 y
+= tm
.tmAscent
* cosEsc
;
6104 x
+= tm
.tmAscent
* sinEsc
;
6108 y
-= tm
.tmDescent
* cosEsc
;
6109 x
-= tm
.tmDescent
* sinEsc
;
6116 if (dc
->attr
->background_mode
!= TRANSPARENT
)
6118 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
6120 if(!(flags
& ETO_OPAQUE
) || !lprect
||
6121 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
6122 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
6126 text_box
.right
= x
+ width
.x
;
6127 text_box
.top
= y
- tm
.tmAscent
;
6128 text_box
.bottom
= y
+ tm
.tmDescent
;
6130 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
6131 if (!IsRectEmpty( &text_box
))
6132 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
6137 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
6138 str
, count
, (INT
*)deltas
);
6143 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
6145 int underlinePos
, strikeoutPos
;
6146 int underlineWidth
, strikeoutWidth
;
6147 UINT size
= NtGdiGetOutlineTextMetricsInternalW( hdc
, 0, NULL
, 0 );
6148 OUTLINETEXTMETRICW
* otm
= NULL
;
6150 HPEN hpen
= NtGdiSelectPen( hdc
, GetStockObject(NULL_PEN
) );
6151 HBRUSH hbrush
= NtGdiCreateSolidBrush( dc
->attr
->text_color
, NULL
);
6153 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
6158 underlineWidth
= tm
.tmAscent
/ 20 + 1;
6159 strikeoutPos
= tm
.tmAscent
/ 2;
6160 strikeoutWidth
= underlineWidth
;
6164 otm
= malloc( size
);
6165 NtGdiGetOutlineTextMetricsInternalW( hdc
, size
, otm
, 0 );
6166 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
6167 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
6168 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
6169 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
6170 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
6171 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
6178 const ULONG cnt
= 5;
6179 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
6180 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
6181 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
6182 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
6183 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
6184 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
6185 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
6186 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
6187 pts
[4].x
= pts
[0].x
;
6188 pts
[4].y
= pts
[0].y
;
6189 dp_to_lp(dc
, pts
, 5);
6190 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
6195 const ULONG cnt
= 5;
6196 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
6197 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
6198 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
6199 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
6200 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
6201 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
6202 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
6203 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
6204 pts
[4].x
= pts
[0].x
;
6205 pts
[4].y
= pts
[0].y
;
6206 dp_to_lp(dc
, pts
, 5);
6207 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
6210 NtGdiSelectPen(hdc
, hpen
);
6211 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
6212 NtGdiDeleteObjectApp( hbrush
);
6215 release_dc_ptr( dc
);
6221 /******************************************************************************
6222 * NtGdiGetCharABCWidthsW (win32u.@)
6224 * Retrieves widths of characters in range.
6227 * hdc [I] Handle of device context
6228 * firstChar [I] First character in range to query
6229 * lastChar [I] Last character in range to query
6230 * abc [O] Address of character-width structure
6233 * Only works with TrueType fonts
6235 BOOL WINAPI
NtGdiGetCharABCWidthsW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
6236 ULONG flags
, void *buffer
)
6238 DC
*dc
= get_dc_ptr(hdc
);
6240 unsigned int i
, count
= last
;
6243 if (!dc
) return FALSE
;
6247 release_dc_ptr( dc
);
6251 if (flags
& NTGDI_GETCHARABCWIDTHS_INDICES
)
6253 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
6254 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, chars
, buffer
);
6258 if (!chars
) count
= last
- first
+ 1;
6259 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
6260 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
6266 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
6268 /* convert device units to logical */
6269 for (i
= 0; i
< count
; i
++)
6271 abc
[i
].abcA
= width_to_LP( dc
, abc
[i
].abcA
);
6272 abc
[i
].abcB
= width_to_LP( dc
, abc
[i
].abcB
);
6273 abc
[i
].abcC
= width_to_LP( dc
, abc
[i
].abcC
);
6278 /* convert device units to logical */
6279 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
6280 ABCFLOAT
*abcf
= buffer
;
6282 for (i
= 0; i
< count
; i
++)
6284 abcf
[i
].abcfA
= abc
[i
].abcA
* scale
;
6285 abcf
[i
].abcfB
= abc
[i
].abcB
* scale
;
6286 abcf
[i
].abcfC
= abc
[i
].abcC
* scale
;
6291 release_dc_ptr( dc
);
6296 /***********************************************************************
6297 * NtGdiGetGlyphOutline (win32u.@)
6299 DWORD WINAPI
NtGdiGetGlyphOutline( HDC hdc
, UINT ch
, UINT format
, GLYPHMETRICS
*metrics
,
6300 DWORD size
, void *buffer
, const MAT2
*mat2
,
6301 BOOL ignore_rotation
)
6307 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc
, ch
, format
, metrics
, (int)size
, buffer
, mat2
);
6309 if (!mat2
) return GDI_ERROR
;
6311 dc
= get_dc_ptr(hdc
);
6312 if(!dc
) return GDI_ERROR
;
6314 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
6315 ret
= dev
->funcs
->pGetGlyphOutline( dev
, ch
& 0xffff, format
, metrics
, size
, buffer
, mat2
);
6316 release_dc_ptr( dc
);
6321 /**********************************************************************
6322 * __wine_get_file_outline_text_metric (win32u.@)
6324 BOOL WINAPI
__wine_get_file_outline_text_metric( const WCHAR
*path
, TEXTMETRICW
*otm
,
6325 UINT
*em_square
, WCHAR
*face_name
)
6327 struct gdi_font
*font
= NULL
;
6329 if (!path
|| !font_funcs
) return FALSE
;
6331 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
6332 font
->lf
.lfHeight
= 100;
6333 if (!font_funcs
->load_font( font
)) goto done
;
6334 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
6335 *otm
= font
->otm
.otmTextMetrics
;
6336 *em_square
= font
->otm
.otmEMSquare
;
6337 wcscpy( face_name
, (const WCHAR
*)font
->otm
.otmpFamilyName
);
6338 free_gdi_font( font
);
6342 if (font
) free_gdi_font( font
);
6343 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
6347 /*************************************************************************
6348 * NtGdiGetKerningPairs (win32u.@)
6350 DWORD WINAPI
NtGdiGetKerningPairs( HDC hdc
, DWORD count
, KERNINGPAIR
*kern_pair
)
6356 TRACE( "(%p,%d,%p)\n", hdc
, (int)count
, kern_pair
);
6358 if (!count
&& kern_pair
)
6360 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
6364 dc
= get_dc_ptr( hdc
);
6367 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
6368 ret
= dev
->funcs
->pGetKerningPairs( dev
, count
, kern_pair
);
6369 release_dc_ptr( dc
);
6373 /*************************************************************************
6374 * NtGdiGetFontData (win32u.@)
6376 * Retrieve data for TrueType font.
6380 * success: Number of bytes returned
6381 * failure: GDI_ERROR
6385 * Calls RtlSetLastWin32Error()
6388 DWORD WINAPI
NtGdiGetFontData( HDC hdc
, DWORD table
, DWORD offset
, void *buffer
, DWORD length
)
6390 DC
*dc
= get_dc_ptr(hdc
);
6394 if(!dc
) return GDI_ERROR
;
6396 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
6397 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
6398 release_dc_ptr( dc
);
6402 /*************************************************************************
6403 * NtGdiGetGlyphIndicesW (win32u.@)
6405 DWORD WINAPI
NtGdiGetGlyphIndicesW( HDC hdc
, const WCHAR
*str
, INT count
,
6406 WORD
*indices
, DWORD flags
)
6408 DC
*dc
= get_dc_ptr(hdc
);
6412 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc
, debugstr_wn(str
, count
), count
, indices
, (int)flags
);
6414 if(!dc
) return GDI_ERROR
;
6416 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
6417 ret
= dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, indices
, flags
);
6418 release_dc_ptr( dc
);
6422 /***********************************************************************
6424 * Font Resource API *
6426 ***********************************************************************/
6429 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
6431 WCHAR path
[MAX_PATH
];
6434 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6435 get_fonts_win_dir_path( file
, path
);
6436 pthread_mutex_lock( &font_lock
);
6437 ret
= font_funcs
->add_font( path
, flags
);
6438 pthread_mutex_unlock( &font_lock
);
6439 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6442 get_fonts_data_dir_path( file
, path
);
6443 pthread_mutex_lock( &font_lock
);
6444 ret
= font_funcs
->add_font( path
, flags
);
6445 pthread_mutex_unlock( &font_lock
);
6450 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
6452 WCHAR path
[MAX_PATH
];
6455 get_fonts_win_dir_path( file
, path
);
6456 if (!(ret
= remove_font( path
, flags
)))
6458 get_fonts_data_dir_path( file
, path
);
6459 ret
= remove_font( path
, flags
);
6464 static int add_font_resource( LPCWSTR file
, DWORD flags
)
6470 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6472 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6473 pthread_mutex_lock( &font_lock
);
6474 ret
= font_funcs
->add_font( file
, addfont_flags
);
6475 pthread_mutex_unlock( &font_lock
);
6477 else if (!wcschr( file
, '\\' ))
6478 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6483 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
6489 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6491 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6492 ret
= remove_font( file
, addfont_flags
);
6494 else if (!wcschr( file
, '\\' ))
6495 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6500 static void load_system_bitmap_fonts(void)
6502 static const char * const fonts
[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6503 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6504 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6508 if (!(hkey
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) ))) return;
6509 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
6511 if (query_reg_ascii_value( hkey
, fonts
[i
], info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
6512 add_system_font_resource( (const WCHAR
*)info
->Data
, ADDFONT_ALLOW_BITMAP
);
6517 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
6519 IO_STATUS_BLOCK io
= {{0}};
6520 OBJECT_ATTRIBUTES attr
;
6521 UNICODE_STRING nt_name
;
6526 len
= lstrlenW( path
);
6527 while (len
&& path
[len
- 1] == '\\') len
--;
6529 nt_name
.Buffer
= path
;
6530 nt_name
.MaximumLength
= nt_name
.Length
= len
* sizeof(WCHAR
);
6532 attr
.Length
= sizeof(attr
);
6533 attr
.RootDirectory
= 0;
6534 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
6535 attr
.ObjectName
= &nt_name
;
6536 attr
.SecurityDescriptor
= NULL
;
6537 attr
.SecurityQualityOfService
= NULL
;
6539 if (NtOpenFile( &handle
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
,
6540 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
6541 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
))
6546 while (!NtQueryDirectoryFile( handle
, 0, NULL
, NULL
, &io
, buf
, sizeof(buf
),
6547 FileBothDirectoryInformation
, FALSE
, NULL
, FALSE
) &&
6550 FILE_BOTH_DIR_INFORMATION
*info
= (FILE_BOTH_DIR_INFORMATION
*)buf
;
6553 if (!(info
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
6555 memcpy( path
+ len
, info
->FileName
, info
->FileNameLength
);
6556 path
[len
+ info
->FileNameLength
/ sizeof(WCHAR
)] = 0;
6557 font_funcs
->add_font( path
, flags
);
6559 if (!info
->NextEntryOffset
) break;
6560 info
= (FILE_BOTH_DIR_INFORMATION
*)((char *)info
+ info
->NextEntryOffset
);
6567 static void load_file_system_fonts(void)
6569 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024 * sizeof(WCHAR
)])];
6570 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6571 WCHAR
*ptr
, *next
, path
[MAX_PATH
];
6573 /* Windows directory */
6574 get_fonts_win_dir_path( NULL
, path
);
6575 load_directory_fonts( path
, 0 );
6577 /* Wine data directory */
6578 get_fonts_data_dir_path( NULL
, path
);
6579 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6582 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6583 if (query_reg_ascii_value( wine_fonts_key
, "Path", info
, sizeof(value_buffer
) ) &&
6584 info
->Type
== REG_SZ
)
6586 for (ptr
= (WCHAR
*)info
->Data
; ptr
; ptr
= next
)
6588 if ((next
= wcschr( ptr
, ';' ))) *next
++ = 0;
6589 if (next
&& next
- ptr
< 2) continue;
6590 lstrcpynW( path
, ptr
, MAX_PATH
);
6593 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, (lstrlenW( path
) + 1) * sizeof(WCHAR
) );
6594 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6596 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6604 WCHAR value
[LF_FULLFACESIZE
+ 12];
6607 static void update_external_font_keys(void)
6609 struct list external_keys
= LIST_INIT(external_keys
);
6610 HKEY winnt_key
= 0, win9x_key
= 0;
6611 struct gdi_font_family
*family
;
6612 struct external_key
*key
, *next
;
6613 struct gdi_font_face
*face
;
6615 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6617 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
6621 static const WCHAR external_fontsW
[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6623 winnt_key
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
), 0, NULL
);
6624 win9x_key
= reg_create_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
), 0, NULL
);
6626 /* enumerate the fonts and add external ones to the two keys */
6628 if (!(hkey
= reg_create_key( wine_fonts_key
, external_fontsW
, sizeof(external_fontsW
), 0, NULL
)))
6631 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
) - sizeof(nt_prefixW
),
6632 value
, LF_FULLFACESIZE
* sizeof(WCHAR
) ))
6634 if (info
->Type
!= REG_SZ
) continue;
6636 path
= (WCHAR
*)(buffer
+ info
->DataOffset
);
6637 if (path
[0] && path
[1] == ':')
6639 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, info
->DataLength
);
6640 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6643 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6644 if ((face
= find_face_from_full_name( value
)) && !wcsicmp( face
->file
, path
))
6646 face
->flags
|= ADDFONT_EXTERNAL_FOUND
;
6649 if (tmp
&& !*tmp
) *tmp
= ' ';
6650 if (!(key
= malloc( sizeof(*key
) ))) break;
6651 lstrcpyW( key
->value
, value
);
6652 list_add_tail( &external_keys
, &key
->entry
);
6655 LIST_FOR_EACH_ENTRY_SAFE( key
, next
, &external_keys
, struct external_key
, entry
)
6657 reg_delete_value( win9x_key
, key
->value
);
6658 reg_delete_value( winnt_key
, key
->value
);
6659 reg_delete_value( hkey
, key
->value
);
6660 list_remove( &key
->entry
);
6663 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
6665 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
6667 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
6668 if ((face
->flags
& ADDFONT_EXTERNAL_FOUND
)) continue;
6670 lstrcpyW( value
, face
->full_name
);
6671 if (face
->scalable
) lstrcatW( value
, true_type_suffixW
);
6673 if (face
->file
[0] == '\\')
6676 if (file
[5] == ':') file
+= ARRAYSIZE(nt_prefixW
);
6678 else if ((file
= wcsrchr( face
->file
, '\\' )))
6683 len
= (lstrlenW(file
) + 1) * sizeof(WCHAR
);
6684 set_reg_value( winnt_key
, value
, REG_SZ
, file
, len
);
6685 set_reg_value( win9x_key
, value
, REG_SZ
, file
, len
);
6686 set_reg_value( hkey
, value
, REG_SZ
, file
, len
);
6689 NtClose( win9x_key
);
6690 NtClose( winnt_key
);
6694 static void load_registry_fonts(void)
6696 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6697 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6698 KEY_VALUE_FULL_INFORMATION
*enum_info
= (KEY_VALUE_FULL_INFORMATION
*)value_buffer
;
6699 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6703 static const WCHAR dot_fonW
[] = {'.','f','o','n',0};
6705 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6706 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6707 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6710 hkey
= reg_open_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
) );
6712 hkey
= reg_open_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
) );
6715 while (reg_enum_value( hkey
, i
++, enum_info
, sizeof(value_buffer
), value
, sizeof(value
) ))
6717 if (enum_info
->Type
!= REG_SZ
) continue;
6718 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6719 if (find_face_from_full_name( value
)) continue;
6720 if (tmp
&& !*tmp
) *tmp
= ' ';
6722 if (!(dlen
= query_reg_value( hkey
, value
, info
, sizeof(value_buffer
) - sizeof(nt_prefixW
) )) ||
6723 info
->Type
!= REG_SZ
)
6725 WARN( "Unable to get face path %s\n", debugstr_w(value
) );
6729 path
= (WCHAR
*)info
->Data
;
6730 if (path
[0] && path
[1] == ':')
6732 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, dlen
);
6733 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6734 dlen
+= sizeof(nt_prefixW
);
6737 dlen
/= sizeof(WCHAR
);
6739 add_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6740 else if (dlen
>= 6 && !wcsicmp( path
+ dlen
- 5, dot_fonW
))
6741 add_system_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6746 static HKEY
open_hkcu(void)
6750 DWORD_PTR sid_data
[(sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
) / sizeof(DWORD_PTR
)];
6751 DWORD i
, len
= sizeof(sid_data
);
6754 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser
, sid_data
, len
, &len
))
6757 sid
= ((TOKEN_USER
*)sid_data
)->User
.Sid
;
6758 len
= snprintf( buffer
, sizeof(buffer
), "\\Registry\\User\\S-%u-%u", (int)sid
->Revision
,
6759 (int)MAKELONG( MAKEWORD( sid
->IdentifierAuthority
.Value
[5], sid
->IdentifierAuthority
.Value
[4] ),
6760 MAKEWORD( sid
->IdentifierAuthority
.Value
[3], sid
->IdentifierAuthority
.Value
[2] )));
6761 for (i
= 0; i
< sid
->SubAuthorityCount
; i
++)
6762 len
+= snprintf( buffer
+ len
, sizeof(buffer
) - len
, "-%u", (int)sid
->SubAuthority
[i
] );
6763 ascii_to_unicode( bufferW
, buffer
, len
+ 1 );
6765 return reg_open_key( NULL
, bufferW
, len
* sizeof(WCHAR
) );
6768 /***********************************************************************
6771 UINT
font_init(void)
6773 OBJECT_ATTRIBUTES attr
= { sizeof(attr
) };
6774 UNICODE_STRING name
;
6779 static WCHAR wine_font_mutexW
[] =
6780 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6781 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6782 static const WCHAR wine_fonts_keyW
[] =
6783 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6784 static const WCHAR cacheW
[] = {'C','a','c','h','e'};
6786 if (!(hkcu_key
= open_hkcu())) return 0;
6787 wine_fonts_key
= reg_create_key( hkcu_key
, wine_fonts_keyW
, sizeof(wine_fonts_keyW
), 0, NULL
);
6788 if (wine_fonts_key
) dpi
= init_font_options();
6789 if (!dpi
) return 96;
6790 update_codepage( dpi
);
6792 if (!(font_funcs
= init_freetype_lib()))
6795 load_system_bitmap_fonts();
6796 load_file_system_fonts();
6797 font_funcs
->load_fonts();
6799 attr
.Attributes
= OBJ_OPENIF
;
6800 attr
.ObjectName
= &name
;
6801 name
.Buffer
= wine_font_mutexW
;
6802 name
.Length
= name
.MaximumLength
= sizeof(wine_font_mutexW
);
6804 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return dpi
;
6805 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
6807 wine_fonts_cache_key
= reg_create_key( wine_fonts_key
, cacheW
, sizeof(cacheW
),
6808 REG_OPTION_VOLATILE
, &disposition
);
6810 if (disposition
== REG_CREATED_NEW_KEY
)
6812 load_registry_fonts();
6813 update_external_font_keys();
6816 NtReleaseMutant( mutex
, NULL
);
6818 if (disposition
!= REG_CREATED_NEW_KEY
)
6820 load_registry_fonts();
6821 load_font_list_from_cache();
6824 reorder_font_list();
6825 load_gdi_font_subst();
6826 load_gdi_font_replacements();
6827 load_system_links();
6828 dump_gdi_font_list();
6829 dump_gdi_font_subst();
6833 /***********************************************************************
6834 * NtGdiAddFontResourceW (win32u.@)
6836 INT WINAPI
NtGdiAddFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6837 DWORD tid
, void *dv
)
6839 if (!font_funcs
) return 1;
6840 return add_font_resource( str
, flags
);
6843 /***********************************************************************
6844 * NtGdiAddFontMemResourceEx (win32u.@)
6846 HANDLE WINAPI
NtGdiAddFontMemResourceEx( void *ptr
, DWORD size
, void *dv
, ULONG dv_size
,
6853 if (!ptr
|| !size
|| !count
)
6855 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER
);
6858 if (!font_funcs
) return NULL
;
6859 if (!(copy
= malloc( size
))) return NULL
;
6860 memcpy( copy
, ptr
, size
);
6862 pthread_mutex_lock( &font_lock
);
6863 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6864 pthread_mutex_unlock( &font_lock
);
6872 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6873 * For now return something unique but quite random
6875 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
6883 WARN( "page fault while writing to *count (%p)\n", count
);
6884 NtGdiRemoveFontMemResourceEx( ret
);
6888 TRACE( "Returning handle %p\n", ret
);
6892 /***********************************************************************
6893 * NtGdiRemoveFontMemResourceEx (win32u.@)
6895 BOOL WINAPI
NtGdiRemoveFontMemResourceEx( HANDLE handle
)
6897 FIXME( "(%p) stub\n", handle
);
6901 /***********************************************************************
6902 * NtGdiRemoveFontResourceW (win32u.@)
6904 BOOL WINAPI
NtGdiRemoveFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6905 DWORD tid
, void *dv
)
6907 if (!font_funcs
) return TRUE
;
6908 return remove_font_resource( str
, flags
);
6911 /***********************************************************************
6912 * NtGdiGetFontUnicodeRanges (win32u.@)
6914 * Retrieve a list of supported Unicode characters in a font.
6917 * hdc [I] Handle to a device context.
6918 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6921 * Success: Number of bytes written to the buffer pointed to by lpgs.
6925 DWORD WINAPI
NtGdiGetFontUnicodeRanges( HDC hdc
, GLYPHSET
*lpgs
)
6929 DC
*dc
= get_dc_ptr(hdc
);
6931 TRACE("(%p, %p)\n", hdc
, lpgs
);
6935 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
6936 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
6942 /*************************************************************
6943 * NtGdiFontIsLinked (win32u.@)
6945 BOOL WINAPI
NtGdiFontIsLinked( HDC hdc
)
6947 DC
*dc
= get_dc_ptr(hdc
);
6951 if (!dc
) return FALSE
;
6952 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
6953 ret
= dev
->funcs
->pFontIsLinked( dev
);
6955 TRACE("returning %d\n", ret
);
6959 /*************************************************************
6960 * NtGdiGetRealizationInfo (win32u.@)
6962 BOOL WINAPI
NtGdiGetRealizationInfo( HDC hdc
, struct font_realization_info
*info
)
6964 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, file_count
);
6969 if (info
->size
!= sizeof(*info
) && !is_v0
)
6972 dc
= get_dc_ptr(hdc
);
6973 if (!dc
) return FALSE
;
6974 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
6975 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
6980 /*************************************************************************
6981 * NtGdiGetRasterizerCaps (win32u.@)
6983 BOOL WINAPI
NtGdiGetRasterizerCaps( RASTERIZER_STATUS
*status
, UINT size
)
6985 status
->nSize
= sizeof(RASTERIZER_STATUS
);
6986 status
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
6987 status
->nLanguageID
= 0;
6991 /*************************************************************************
6992 * NtGdiGetFontFileData (win32u.@)
6994 BOOL WINAPI
NtGdiGetFontFileData( DWORD instance_id
, DWORD file_index
, UINT64
*offset
,
6995 void *buff
, SIZE_T buff_size
)
6997 struct gdi_font
*font
;
6998 DWORD tag
= 0, size
;
7001 if (!font_funcs
) return FALSE
;
7002 pthread_mutex_lock( &font_lock
);
7003 if ((font
= get_font_from_handle( instance_id
)))
7005 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
7006 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
7007 if (size
!= GDI_ERROR
&& size
>= buff_size
&& *offset
<= size
- buff_size
)
7008 ret
= font_funcs
->get_font_data( font
, tag
, *offset
, buff
, buff_size
) != GDI_ERROR
;
7010 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
7012 pthread_mutex_unlock( &font_lock
);
7016 /*************************************************************************
7017 * NtGdiGetFontFileInfo (win32u.@)
7019 BOOL WINAPI
NtGdiGetFontFileInfo( DWORD instance_id
, DWORD file_index
, struct font_fileinfo
*info
,
7020 SIZE_T size
, SIZE_T
*needed
)
7022 SIZE_T required_size
= 0;
7023 struct gdi_font
*font
;
7026 pthread_mutex_lock( &font_lock
);
7028 if ((font
= get_font_from_handle( instance_id
)))
7030 required_size
= sizeof(*info
) + lstrlenW( font
->file
) * sizeof(WCHAR
);
7031 if (required_size
<= size
)
7033 info
->writetime
= font
->writetime
;
7034 info
->size
.QuadPart
= font
->data_size
;
7035 lstrcpyW( info
->path
, font
->file
);
7038 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
7041 pthread_mutex_unlock( &font_lock
);
7042 if (needed
) *needed
= required_size
;
7046 /*************************************************************
7047 * NtGdiGetCharWidthInfo (win32u.@)
7049 BOOL WINAPI
NtGdiGetCharWidthInfo( HDC hdc
, struct char_width_info
*info
)
7055 dc
= get_dc_ptr(hdc
);
7056 if (!dc
) return FALSE
;
7057 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
7058 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
7062 info
->lsb
= width_to_LP( dc
, info
->lsb
);
7063 info
->rsb
= width_to_LP( dc
, info
->rsb
);
7069 /***********************************************************************
7070 * DrawTextW (win32u.so)
7072 INT WINAPI
DrawTextW( HDC hdc
, const WCHAR
*str
, INT count
, RECT
*rect
, UINT flags
)
7074 struct draw_text_params
*params
;
7075 struct draw_text_result
*result
;
7076 ULONG ret_len
, size
;
7080 if (count
== -1) count
= wcslen( str
);
7081 size
= FIELD_OFFSET( struct draw_text_params
, str
[count
] );
7082 if (!(params
= malloc( size
))) return 0;
7084 params
->rect
= *rect
;
7085 params
->flags
= flags
;
7086 if (count
) memcpy( params
->str
, str
, count
* sizeof(WCHAR
) );
7088 status
= KeUserModeCallback( NtUserDrawText
, params
, size
, (void **)&result
, &ret_len
);
7089 if (!status
&& ret_len
== sizeof(*result
))
7091 ret
= result
->height
;
7092 *rect
= result
->rect
;