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 DWORD 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
);
204 return ((const WORD
*)NtCurrentTeb()->Peb
->AnsiCodePageData
)[1];
207 static UINT
get_oemcp(void)
209 return ((const WORD
*)NtCurrentTeb()->Peb
->OemCodePageData
)[1];
212 static inline WCHAR
facename_tolower( WCHAR c
)
214 if (c
>= 'A' && c
<= 'Z') return c
- 'A' + 'a';
215 else if (c
> 127) return RtlDowncaseUnicodeChar( c
);
219 static inline int facename_compare( const WCHAR
*str1
, const WCHAR
*str2
, SIZE_T len
)
223 WCHAR c1
= facename_tolower( *str1
++ ), c2
= facename_tolower( *str2
++ );
224 if (c1
!= c2
) return c1
- c2
;
225 else if (!c1
) return 0;
230 /* Device -> World size conversion */
232 /* Performs a device to world transformation on the specified width (which
233 * is in integer format).
235 static inline INT
INTERNAL_XDSTOWS(DC
*dc
, INT width
)
239 /* Perform operation with floating point */
240 floatWidth
= (double)width
* dc
->xformVport2World
.eM11
;
241 /* Round to integers */
242 return GDI_ROUND(floatWidth
);
245 /* Performs a device to world transformation on the specified size (which
246 * is in integer format).
248 static inline INT
INTERNAL_YDSTOWS(DC
*dc
, INT height
)
252 /* Perform operation with floating point */
253 floatHeight
= (double)height
* dc
->xformVport2World
.eM22
;
254 /* Round to integers */
255 return GDI_ROUND(floatHeight
);
258 /* scale width and height but don't mirror them */
260 static inline INT
width_to_LP( DC
*dc
, INT width
)
262 return GDI_ROUND( (double)width
* fabs( dc
->xformVport2World
.eM11
));
265 static inline INT
height_to_LP( DC
*dc
, INT height
)
267 return GDI_ROUND( (double)height
* fabs( dc
->xformVport2World
.eM22
));
270 static inline INT
INTERNAL_YWSTODS(DC
*dc
, INT height
)
273 pt
[0].x
= pt
[0].y
= 0;
277 return pt
[1].y
- pt
[0].y
;
280 static inline WCHAR
*strdupW( const WCHAR
*p
)
283 DWORD len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
289 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
);
290 static BOOL
FONT_DeleteObject( HGDIOBJ handle
);
292 static const struct gdi_obj_funcs fontobj_funcs
=
294 FONT_GetObjectW
, /* pGetObjectW */
295 NULL
, /* pUnrealizeObject */
296 FONT_DeleteObject
/* pDeleteObject */
301 struct gdi_obj_header obj
;
305 /* for translate_charset_info */
306 static const CHARSETINFO charset_info
[] = {
308 { ANSI_CHARSET
, 1252, {{0,0,0,0},{FS_LATIN1
,0}} },
309 { EASTEUROPE_CHARSET
, 1250, {{0,0,0,0},{FS_LATIN2
,0}} },
310 { RUSSIAN_CHARSET
, 1251, {{0,0,0,0},{FS_CYRILLIC
,0}} },
311 { GREEK_CHARSET
, 1253, {{0,0,0,0},{FS_GREEK
,0}} },
312 { TURKISH_CHARSET
, 1254, {{0,0,0,0},{FS_TURKISH
,0}} },
313 { HEBREW_CHARSET
, 1255, {{0,0,0,0},{FS_HEBREW
,0}} },
314 { ARABIC_CHARSET
, 1256, {{0,0,0,0},{FS_ARABIC
,0}} },
315 { BALTIC_CHARSET
, 1257, {{0,0,0,0},{FS_BALTIC
,0}} },
316 { VIETNAMESE_CHARSET
, 1258, {{0,0,0,0},{FS_VIETNAMESE
,0}} },
317 /* reserved by ANSI */
318 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
319 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
320 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
321 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
322 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
323 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
324 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
326 { THAI_CHARSET
, 874, {{0,0,0,0},{FS_THAI
,0}} },
327 { SHIFTJIS_CHARSET
, 932, {{0,0,0,0},{FS_JISJAPAN
,0}} },
328 { GB2312_CHARSET
, 936, {{0,0,0,0},{FS_CHINESESIMP
,0}} },
329 { HANGEUL_CHARSET
, 949, {{0,0,0,0},{FS_WANSUNG
,0}} },
330 { CHINESEBIG5_CHARSET
, 950, {{0,0,0,0},{FS_CHINESETRAD
,0}} },
331 { JOHAB_CHARSET
, 1361, {{0,0,0,0},{FS_JOHAB
,0}} },
332 /* reserved for alternate ANSI and OEM */
333 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
334 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
335 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
336 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
337 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
338 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
339 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
340 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
341 /* reserved for system */
342 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
343 { SYMBOL_CHARSET
, CP_SYMBOL
, {{0,0,0,0},{FS_SYMBOL
,0}} }
346 static const char * const default_serif_list
[3] =
350 "Bitstream Vera Serif"
352 static const char * const default_fixed_list
[3] =
356 "Bitstream Vera Sans Mono"
358 static const char * const default_sans_list
[3] =
362 "Bitstream Vera Sans"
364 static WCHAR ff_roman_default
[LF_FACESIZE
];
365 static WCHAR ff_modern_default
[LF_FACESIZE
];
366 static WCHAR ff_swiss_default
[LF_FACESIZE
];
368 static const struct nls_update_font_list
370 UINT ansi_cp
, oem_cp
;
371 const char *oem
, *fixed
, *system
;
372 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
373 /* these are for font substitutes */
374 const char *shelldlg
, *tmsrmn
;
375 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
, *helv_0
, *tmsrmn_0
;
376 struct subst
{ const char *from
, *to
; } arial_0
, courier_new_0
, times_new_roman_0
;
377 } nls_update_font_list
[] =
379 /* Latin 1 (United States) */
380 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
381 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
382 "Tahoma","Times New Roman"
384 /* Latin 1 (Multilingual) */
385 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
386 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
387 "Tahoma","Times New Roman" /* FIXME unverified */
390 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
391 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
392 "Tahoma","Times New Roman", /* FIXME unverified */
393 "Fixedsys,238", "System,238",
394 "Courier New,238", "MS Serif,238", "Small Fonts,238",
395 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
396 { "Arial CE,0", "Arial,238" },
397 { "Courier New CE,0", "Courier New,238" },
398 { "Times New Roman CE,0", "Times New Roman,238" }
401 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
402 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
403 "Tahoma","Times New Roman", /* FIXME unverified */
404 "Fixedsys,204", "System,204",
405 "Courier New,204", "MS Serif,204", "Small Fonts,204",
406 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
407 { "Arial Cyr,0", "Arial,204" },
408 { "Courier New Cyr,0", "Courier New,204" },
409 { "Times New Roman Cyr,0", "Times New Roman,204" }
412 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
413 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
414 "Tahoma","Times New Roman", /* FIXME unverified */
415 "Fixedsys,161", "System,161",
416 "Courier New,161", "MS Serif,161", "Small Fonts,161",
417 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
418 { "Arial Greek,0", "Arial,161" },
419 { "Courier New Greek,0", "Courier New,161" },
420 { "Times New Roman Greek,0", "Times New Roman,161" }
423 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
424 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
425 "Tahoma","Times New Roman", /* FIXME unverified */
426 "Fixedsys,162", "System,162",
427 "Courier New,162", "MS Serif,162", "Small Fonts,162",
428 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
429 { "Arial Tur,0", "Arial,162" },
430 { "Courier New Tur,0", "Courier New,162" },
431 { "Times New Roman Tur,0", "Times New Roman,162" }
434 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
435 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
436 "Tahoma","Times New Roman", /* FIXME unverified */
437 "Fixedsys,177", "System,177",
438 "Courier New,177", "MS Serif,177", "Small Fonts,177",
439 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
442 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
443 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
444 "Microsoft Sans Serif","Times New Roman",
445 "Fixedsys,178", "System,178",
446 "Courier New,178", "MS Serif,178", "Small Fonts,178",
447 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
450 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
451 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
452 "Tahoma","Times New Roman", /* FIXME unverified */
453 "Fixedsys,186", "System,186",
454 "Courier New,186", "MS Serif,186", "Small Fonts,186",
455 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
456 { "Arial Baltic,0", "Arial,186" },
457 { "Courier New Baltic,0", "Courier New,186" },
458 { "Times New Roman Baltic,0", "Times New Roman,186" }
461 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
462 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
463 "Tahoma","Times New Roman" /* FIXME unverified */
466 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
467 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
468 "Tahoma","Times New Roman" /* FIXME unverified */
471 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
472 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
473 "MS UI Gothic","MS Serif"
475 /* Chinese Simplified */
476 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
477 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
481 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
482 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
485 /* Chinese Traditional */
486 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
487 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
488 "PMingLiU", "MingLiU"
492 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
494 return ( ansi_cp
== 932 /* CP932 for Japanese */
495 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
496 || ansi_cp
== 949 /* CP949 for Korean */
497 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
500 static pthread_mutex_t font_lock
= PTHREAD_MUTEX_INITIALIZER
;
502 #ifndef WINE_FONT_DIR
503 #define WINE_FONT_DIR "fonts"
506 #ifdef WORDS_BIGENDIAN
507 #define GET_BE_WORD(x) (x)
508 #define GET_BE_DWORD(x) (x)
510 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
511 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
514 static void get_fonts_data_dir_path( const WCHAR
*file
, WCHAR
*path
)
517 ULONG len
= MAX_PATH
;
519 if ((dir
= ntdll_get_data_dir()))
521 wine_unix_to_nt_file_name( dir
, path
, &len
);
522 asciiz_to_unicode( path
+ len
- 1, "\\" WINE_FONT_DIR
"\\" );
524 else if ((dir
= ntdll_get_build_dir()))
526 wine_unix_to_nt_file_name( dir
, path
, &len
);
527 asciiz_to_unicode( path
+ len
- 1, "\\fonts\\" );
530 if (file
) lstrcatW( path
, file
);
533 static void get_fonts_win_dir_path( const WCHAR
*file
, WCHAR
*path
)
535 asciiz_to_unicode( path
, "\\??\\C:\\windows\\fonts\\" );
536 if (file
) lstrcatW( path
, file
);
539 HKEY
reg_open_key( HKEY root
, const WCHAR
*name
, ULONG name_len
)
541 UNICODE_STRING nameW
= { name_len
, name_len
, (WCHAR
*)name
};
542 OBJECT_ATTRIBUTES attr
;
545 attr
.Length
= sizeof(attr
);
546 attr
.RootDirectory
= root
;
547 attr
.ObjectName
= &nameW
;
549 attr
.SecurityDescriptor
= NULL
;
550 attr
.SecurityQualityOfService
= NULL
;
552 if (NtOpenKeyEx( &ret
, MAXIMUM_ALLOWED
, &attr
, 0 )) return 0;
556 /* wrapper for NtCreateKey that creates the key recursively if necessary */
557 HKEY
reg_create_key( HKEY root
, const WCHAR
*name
, ULONG name_len
,
558 DWORD options
, DWORD
*disposition
)
560 UNICODE_STRING nameW
= { name_len
, name_len
, (WCHAR
*)name
};
561 OBJECT_ATTRIBUTES attr
;
565 attr
.Length
= sizeof(attr
);
566 attr
.RootDirectory
= root
;
567 attr
.ObjectName
= &nameW
;
569 attr
.SecurityDescriptor
= NULL
;
570 attr
.SecurityQualityOfService
= NULL
;
572 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, options
, disposition
);
573 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
575 static const WCHAR registry_rootW
[] = { '\\','R','e','g','i','s','t','r','y','\\' };
576 DWORD pos
= 0, i
= 0, len
= name_len
/ sizeof(WCHAR
);
578 /* don't try to create registry root */
579 if (!root
&& len
> ARRAY_SIZE(registry_rootW
) &&
580 !memcmp( name
, registry_rootW
, sizeof(registry_rootW
) ))
581 i
+= ARRAY_SIZE(registry_rootW
);
583 while (i
< len
&& name
[i
] != '\\') i
++;
584 if (i
== len
) return 0;
587 unsigned int subkey_options
= options
;
588 if (i
< len
) subkey_options
&= ~(REG_OPTION_CREATE_LINK
| REG_OPTION_OPEN_LINK
);
589 nameW
.Buffer
= (WCHAR
*)name
+ pos
;
590 nameW
.Length
= (i
- pos
) * sizeof(WCHAR
);
591 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, subkey_options
, disposition
);
593 if (attr
.RootDirectory
!= root
) NtClose( attr
.RootDirectory
);
594 if (!NT_SUCCESS(status
)) return 0;
596 attr
.RootDirectory
= ret
;
597 while (i
< len
&& name
[i
] == '\\') i
++;
599 while (i
< len
&& name
[i
] != '\\') i
++;
605 HKEY
reg_open_hkcu_key( const char *name
)
608 return reg_open_key( hkcu_key
, nameW
, asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
) );
611 BOOL
set_reg_value( HKEY hkey
, const WCHAR
*name
, UINT type
, const void *value
, DWORD count
)
613 unsigned int name_size
= name
? lstrlenW( name
) * sizeof(WCHAR
) : 0;
614 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
615 return !NtSetValueKey( hkey
, &nameW
, 0, type
, value
, count
);
618 void set_reg_ascii_value( HKEY hkey
, const char *name
, const char *value
)
620 WCHAR nameW
[64], valueW
[128];
621 asciiz_to_unicode( nameW
, name
);
622 set_reg_value( hkey
, nameW
, REG_SZ
, valueW
, asciiz_to_unicode( valueW
, value
));
625 ULONG
query_reg_value( HKEY hkey
, const WCHAR
*name
,
626 KEY_VALUE_PARTIAL_INFORMATION
*info
, ULONG size
)
628 unsigned int name_size
= name
? lstrlenW( name
) * sizeof(WCHAR
) : 0;
629 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
631 if (NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
635 return size
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
638 ULONG
query_reg_ascii_value( HKEY hkey
, const char *name
,
639 KEY_VALUE_PARTIAL_INFORMATION
*info
, ULONG size
)
642 asciiz_to_unicode( nameW
, name
);
643 return query_reg_value( hkey
, nameW
, info
, size
);
646 static BOOL
reg_enum_value( HKEY hkey
, unsigned int index
, KEY_VALUE_FULL_INFORMATION
*info
,
647 ULONG size
, WCHAR
*name
, ULONG name_size
)
651 if (NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
652 info
, size
, &full_size
))
657 if (name_size
< info
->NameLength
+ sizeof(WCHAR
)) return FALSE
;
658 memcpy( name
, info
->Name
, info
->NameLength
);
659 name
[info
->NameLength
/ sizeof(WCHAR
)] = 0;
664 void reg_delete_value( HKEY hkey
, const WCHAR
*name
)
666 unsigned int name_size
= lstrlenW( name
) * sizeof(WCHAR
);
667 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
668 NtDeleteValueKey( hkey
, &nameW
);
671 BOOL
reg_delete_tree( HKEY parent
, const WCHAR
*name
, ULONG name_len
)
674 KEY_NODE_INFORMATION
*key_info
= (KEY_NODE_INFORMATION
*)buffer
;
679 if (!(key
= reg_open_key( parent
, name
, name_len
))) return FALSE
;
681 while (ret
&& !NtEnumerateKey( key
, 0, KeyNodeInformation
, key_info
, sizeof(buffer
), &size
))
682 ret
= reg_delete_tree( key
, key_info
->Name
, key_info
->NameLength
);
684 if (ret
) ret
= !NtDeleteKey( key
);
689 /* font substitutions */
691 struct gdi_font_subst
699 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
701 static inline WCHAR
*get_subst_to_name( struct gdi_font_subst
*subst
)
703 return subst
->names
+ lstrlenW( subst
->names
) + 1;
706 static void dump_gdi_font_subst(void)
708 struct gdi_font_subst
*subst
;
710 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
712 if (subst
->from_charset
!= -1 || subst
->to_charset
!= -1)
713 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst
->names
),
714 subst
->from_charset
, debugstr_w(get_subst_to_name(subst
)), subst
->to_charset
);
716 TRACE("%s -> %s\n", debugstr_w(subst
->names
), debugstr_w(get_subst_to_name(subst
)));
720 static const WCHAR
*get_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, int *to_charset
)
722 struct gdi_font_subst
*subst
;
724 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
726 if (!facename_compare( subst
->names
, from_name
, -1 ) &&
727 (subst
->from_charset
== from_charset
|| subst
->from_charset
== -1))
729 if (to_charset
) *to_charset
= subst
->to_charset
;
730 return get_subst_to_name( subst
);
736 static BOOL
add_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, const WCHAR
*to_name
, int to_charset
)
738 struct gdi_font_subst
*subst
;
739 int len
= lstrlenW( from_name
) + lstrlenW( to_name
) + 2;
741 if (get_gdi_font_subst( from_name
, from_charset
, NULL
)) return FALSE
; /* already exists */
743 if (!(subst
= malloc( offsetof( struct gdi_font_subst
, names
[len
] ) )))
745 lstrcpyW( subst
->names
, from_name
);
746 lstrcpyW( get_subst_to_name(subst
), to_name
);
747 subst
->from_charset
= from_charset
;
748 subst
->to_charset
= to_charset
;
749 list_add_tail( &font_subst_list
, &subst
->entry
);
753 static void load_gdi_font_subst(void)
756 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
759 WCHAR
*data
, *p
, value
[64];
761 if (!(hkey
= reg_open_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
) )))
764 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
766 int from_charset
= -1, to_charset
= -1;
768 if (info
->Type
!= REG_SZ
) continue;
769 data
= (WCHAR
*)((char *)info
+ info
->DataOffset
);
771 TRACE( "Got %s=%s\n", debugstr_w(value
), debugstr_w(data
) );
772 if ((p
= wcsrchr( value
, ',' )) && p
[1])
775 from_charset
= wcstol( p
, NULL
, 10 );
777 if ((p
= wcsrchr( data
, ',' )) && p
[1])
780 to_charset
= wcstol( p
, NULL
, 10 );
783 /* Win 2000 doesn't allow mapping between different charsets
784 or mapping of DEFAULT_CHARSET */
785 if ((!from_charset
|| to_charset
== from_charset
) && to_charset
!= DEFAULT_CHARSET
)
786 add_gdi_font_subst( value
, from_charset
, data
, to_charset
);
793 static int family_namecmp( const WCHAR
*str1
, const WCHAR
*str2
)
795 int prio1
, prio2
, vert1
= (str1
[0] == '@' ? 1 : 0), vert2
= (str2
[0] == '@' ? 1 : 0);
797 if (!facename_compare( str1
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio1
= 0;
798 else if (!facename_compare( str1
, ff_modern_default
, LF_FACESIZE
- 1 )) prio1
= 1;
799 else if (!facename_compare( str1
, ff_roman_default
, LF_FACESIZE
- 1 )) prio1
= 2;
802 if (!facename_compare( str2
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio2
= 0;
803 else if (!facename_compare( str2
, ff_modern_default
, LF_FACESIZE
- 1 )) prio2
= 1;
804 else if (!facename_compare( str2
, ff_roman_default
, LF_FACESIZE
- 1 )) prio2
= 2;
807 if (prio1
!= prio2
) return prio1
- prio2
;
808 if (vert1
!= vert2
) return vert1
- vert2
;
809 return facename_compare( str1
+ vert1
, str2
+ vert2
, LF_FACESIZE
- 1 );
812 static int family_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
814 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, name_entry
);
815 return family_namecmp( (const WCHAR
*)key
, family
->family_name
);
818 static int family_second_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
820 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, second_name_entry
);
821 return family_namecmp( (const WCHAR
*)key
, family
->second_name
);
824 static int face_full_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
826 const struct gdi_font_face
*face
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_face
, full_name_entry
);
827 return facename_compare( (const WCHAR
*)key
, face
->full_name
, LF_FULLFACESIZE
- 1 );
830 static struct wine_rb_tree family_name_tree
= { family_name_compare
};
831 static struct wine_rb_tree family_second_name_tree
= { family_second_name_compare
};
832 static struct wine_rb_tree face_full_name_tree
= { face_full_name_compare
};
834 static int face_is_in_full_name_tree( const struct gdi_font_face
*face
)
836 return face
->full_name_entry
.parent
|| face_full_name_tree
.root
== &face
->full_name_entry
;
839 static struct gdi_font_family
*create_family( const WCHAR
*name
, const WCHAR
*second_name
)
841 struct gdi_font_family
*family
= malloc( sizeof(*family
) );
843 family
->refcount
= 1;
844 lstrcpynW( family
->family_name
, name
, LF_FACESIZE
);
845 if (second_name
&& second_name
[0] && wcsicmp( name
, second_name
))
847 lstrcpynW( family
->second_name
, second_name
, LF_FACESIZE
);
848 add_gdi_font_subst( second_name
, -1, name
, -1 );
850 else family
->second_name
[0] = 0;
851 list_init( &family
->faces
);
852 family
->replacement
= NULL
;
853 wine_rb_put( &family_name_tree
, family
->family_name
, &family
->name_entry
);
854 if (family
->second_name
[0]) wine_rb_put( &family_second_name_tree
, family
->second_name
, &family
->second_name_entry
);
858 static void release_family( struct gdi_font_family
*family
)
860 if (--family
->refcount
) return;
861 assert( list_empty( &family
->faces
));
862 wine_rb_remove( &family_name_tree
, &family
->name_entry
);
863 if (family
->second_name
[0]) wine_rb_remove( &family_second_name_tree
, &family
->second_name_entry
);
864 if (family
->replacement
) release_family( family
->replacement
);
868 static struct gdi_font_family
*find_family_from_name( const WCHAR
*name
)
870 struct wine_rb_entry
*entry
;
871 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) return NULL
;
872 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, name_entry
);
875 static struct gdi_font_family
*find_family_from_any_name( const WCHAR
*name
)
877 struct wine_rb_entry
*entry
;
878 struct gdi_font_family
*family
;
879 if ((family
= find_family_from_name( name
))) return family
;
880 if (!(entry
= wine_rb_get( &family_second_name_tree
, name
))) return NULL
;
881 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, second_name_entry
);
884 static struct gdi_font_face
*find_face_from_full_name( const WCHAR
*full_name
)
886 struct wine_rb_entry
*entry
;
887 if (!(entry
= wine_rb_get( &face_full_name_tree
, full_name
))) return NULL
;
888 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_face
, full_name_entry
);
891 static const struct list
*get_family_face_list( const struct gdi_font_family
*family
)
893 return family
->replacement
? &family
->replacement
->faces
: &family
->faces
;
896 static struct gdi_font_face
*family_find_face_from_filename( struct gdi_font_family
*family
, const WCHAR
*file_name
)
898 struct gdi_font_face
*face
;
900 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
902 if (!face
->file
) continue;
903 file
= wcsrchr(face
->file
, '\\');
904 if (!file
) file
= face
->file
;
906 if (wcsicmp( file
, file_name
)) continue;
913 static struct gdi_font_face
*find_face_from_filename( const WCHAR
*file_name
, const WCHAR
*family_name
)
915 struct gdi_font_family
*family
;
916 struct gdi_font_face
*face
;
918 TRACE( "looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(family_name
) );
922 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
923 if ((face
= family_find_face_from_filename( family
, file_name
))) return face
;
927 if (!(family
= find_family_from_name( family_name
))) return NULL
;
928 return family_find_face_from_filename( family
, file_name
);
931 static BOOL
add_family_replacement( const WCHAR
*new_name
, const WCHAR
*replace
)
933 struct gdi_font_family
*new_family
, *family
;
934 struct gdi_font_face
*face
;
935 WCHAR new_name_vert
[LF_FACESIZE
], replace_vert
[LF_FACESIZE
];
937 if (!(family
= find_family_from_any_name( replace
)))
939 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace
) );
943 if (!(new_family
= create_family( new_name
, NULL
))) return FALSE
;
944 new_family
->replacement
= family
;
946 TRACE( "mapping %s to %s\n", debugstr_w(replace
), debugstr_w(new_name
) );
948 /* also add replacement for vertical font if necessary */
949 if (replace
[0] == '@') return TRUE
;
950 if (list_empty( &family
->faces
)) return TRUE
;
951 face
= LIST_ENTRY( list_head(&family
->faces
), struct gdi_font_face
, entry
);
952 if (!(face
->fs
.fsCsb
[0] & FS_DBCS_MASK
)) return TRUE
;
954 new_name_vert
[0] = '@';
955 lstrcpynW( new_name_vert
+ 1, new_name
, LF_FACESIZE
- 1 );
956 if (find_family_from_any_name( new_name_vert
)) return TRUE
; /* already exists */
958 replace_vert
[0] = '@';
959 lstrcpynW( replace_vert
+ 1, replace
, LF_FACESIZE
- 1 );
960 add_family_replacement( new_name_vert
, replace_vert
);
965 * The replacement list is a way to map an entire font
966 * family onto another family. For example adding
968 * [HKCU\Software\Wine\Fonts\Replacements]
969 * "Wingdings"="Winedings"
971 * would enumerate the Winedings font both as Winedings and
972 * Wingdings. However if a real Wingdings font is present the
973 * replacement does not take place.
975 static void load_gdi_font_replacements(void)
978 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
981 WCHAR value
[LF_FACESIZE
];
983 static const WCHAR replacementsW
[] = {'R','e','p','l','a','c','e','m','e','n','t','s'};
985 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
986 if (!(hkey
= reg_open_key( wine_fonts_key
, replacementsW
, sizeof(replacementsW
) ))) return;
988 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
990 WCHAR
*data
= (WCHAR
*)((char *)info
+ info
->DataOffset
);
991 /* "NewName"="Oldname" */
992 if (!find_family_from_any_name( value
))
994 if (info
->Type
== REG_MULTI_SZ
)
996 WCHAR
*replace
= data
;
999 if (add_family_replacement( value
, replace
)) break;
1000 replace
+= lstrlenW(replace
) + 1;
1003 else if (info
->Type
== REG_SZ
) add_family_replacement( value
, data
);
1005 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
1010 static void dump_gdi_font_list(void)
1012 struct gdi_font_family
*family
;
1013 struct gdi_font_face
*face
;
1015 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1017 TRACE( "Family: %s\n", debugstr_w(family
->family_name
) );
1018 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
1020 TRACE( "\t%s\t%s\t%08x", debugstr_w(face
->style_name
), debugstr_w(face
->full_name
),
1021 face
->fs
.fsCsb
[0] );
1022 if (!face
->scalable
) TRACE(" %d", face
->size
.height
);
1028 static BOOL
enum_fallbacks( DWORD pitch_and_family
, int index
, WCHAR buffer
[LF_FACESIZE
] )
1032 const char * const *defaults
;
1034 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
)
1035 defaults
= default_fixed_list
;
1036 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
)
1037 defaults
= default_serif_list
;
1039 defaults
= default_sans_list
;
1040 asciiz_to_unicode( buffer
, defaults
[index
] );
1043 return font_funcs
->enum_family_fallbacks( pitch_and_family
, index
- 3, buffer
);
1046 static void set_default_family( DWORD pitch_and_family
, WCHAR
*default_name
)
1048 struct wine_rb_entry
*entry
;
1049 WCHAR name
[LF_FACESIZE
];
1052 while (enum_fallbacks( pitch_and_family
, i
++, name
))
1054 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) continue;
1055 wine_rb_remove( &family_name_tree
, entry
);
1056 lstrcpynW( default_name
, name
, LF_FACESIZE
- 1 );
1057 wine_rb_put( &family_name_tree
, name
, entry
);
1062 static void reorder_font_list(void)
1064 set_default_family( FF_ROMAN
, ff_roman_default
);
1065 set_default_family( FF_MODERN
, ff_modern_default
);
1066 set_default_family( FF_SWISS
, ff_swiss_default
);
1069 static void release_face( struct gdi_font_face
*face
)
1071 if (--face
->refcount
) return;
1074 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1075 list_remove( &face
->entry
);
1076 release_family( face
->family
);
1078 if (face_is_in_full_name_tree( face
)) wine_rb_remove( &face_full_name_tree
, &face
->full_name_entry
);
1080 free( face
->style_name
);
1081 free( face
->full_name
);
1082 free( face
->cached_enum_data
);
1086 static int remove_font( const WCHAR
*file
, DWORD flags
)
1088 struct gdi_font_family
*family
, *family_next
;
1089 struct gdi_font_face
*face
, *face_next
;
1092 pthread_mutex_lock( &font_lock
);
1093 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family
, family_next
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1096 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, struct gdi_font_face
, entry
)
1098 if (!face
->file
) continue;
1099 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
1100 if (!wcsicmp( face
->file
, file
))
1102 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
1103 release_face( face
);
1107 release_family( family
);
1109 pthread_mutex_unlock( &font_lock
);
1113 static inline BOOL
faces_equal( const struct gdi_font_face
*f1
, const struct gdi_font_face
*f2
)
1115 if (facename_compare( f1
->full_name
, f2
->full_name
, -1 )) return FALSE
;
1116 if (f1
->scalable
) return TRUE
;
1117 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1118 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1121 static inline int style_order( const struct gdi_font_face
*face
)
1123 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1131 case NTM_BOLD
| NTM_ITALIC
:
1134 WARN( "Don't know how to order face %s with flags 0x%08x\n",
1135 debugstr_w(face
->full_name
), face
->ntmFlags
);
1140 static BOOL
insert_face_in_family_list( struct gdi_font_face
*face
, struct gdi_font_family
*family
)
1142 struct gdi_font_face
*cursor
;
1144 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, struct gdi_font_face
, entry
)
1146 if (faces_equal( face
, cursor
))
1148 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
1149 debugstr_w(face
->full_name
), debugstr_w(family
->family_name
),
1150 cursor
->version
, face
->version
);
1152 if (face
->file
&& cursor
->file
&& !wcsicmp( face
->file
, cursor
->file
))
1155 TRACE("Font %s already in list, refcount now %d\n",
1156 debugstr_w(face
->file
), cursor
->refcount
);
1159 if (face
->version
<= cursor
->version
)
1161 TRACE("Original font %s is newer so skipping %s\n",
1162 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1167 TRACE("Replacing original %s with %s\n",
1168 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1169 list_add_before( &cursor
->entry
, &face
->entry
);
1170 face
->family
= family
;
1173 if (face_is_in_full_name_tree( cursor
))
1175 wine_rb_replace( &face_full_name_tree
, &cursor
->full_name_entry
, &face
->full_name_entry
);
1176 memset( &cursor
->full_name_entry
, 0, sizeof(cursor
->full_name_entry
) );
1178 release_face( cursor
);
1182 if (style_order( face
) < style_order( cursor
)) break;
1185 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face
->full_name
),
1186 debugstr_w(family
->family_name
), debugstr_w(face
->file
) );
1187 list_add_before( &cursor
->entry
, &face
->entry
);
1188 if (face
->scalable
) wine_rb_put( &face_full_name_tree
, face
->full_name
, &face
->full_name_entry
);
1189 face
->family
= family
;
1195 static struct gdi_font_face
*create_face( struct gdi_font_family
*family
, const WCHAR
*style
,
1196 const WCHAR
*fullname
, const WCHAR
*file
,
1197 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
1198 DWORD ntmflags
, DWORD version
, DWORD flags
,
1199 const struct bitmap_font_size
*size
)
1201 struct gdi_font_face
*face
= calloc( 1, sizeof(*face
) );
1204 face
->style_name
= strdupW( style
);
1205 face
->full_name
= strdupW( fullname
);
1206 face
->face_index
= index
;
1208 face
->ntmFlags
= ntmflags
;
1209 face
->version
= version
;
1210 face
->flags
= flags
;
1211 face
->data_ptr
= data_ptr
;
1212 face
->data_size
= data_size
;
1213 if (file
) face
->file
= strdupW( file
);
1214 if (size
) face
->size
= *size
;
1215 else face
->scalable
= TRUE
;
1216 if (insert_face_in_family_list( face
, family
)) return face
;
1217 release_face( face
);
1221 int add_gdi_face( const WCHAR
*family_name
, const WCHAR
*second_name
,
1222 const WCHAR
*style
, const WCHAR
*fullname
, const WCHAR
*file
,
1223 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
1224 DWORD ntmflags
, DWORD version
, DWORD flags
,
1225 const struct bitmap_font_size
*size
)
1227 struct gdi_font_face
*face
;
1228 struct gdi_font_family
*family
;
1231 if ((family
= find_family_from_name( family_name
))) family
->refcount
++;
1232 else if (!(family
= create_family( family_name
, second_name
))) return ret
;
1234 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1235 index
, fs
, ntmflags
, version
, flags
, size
)))
1237 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1238 release_face( face
);
1240 release_family( family
);
1243 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
1245 WCHAR vert_family
[LF_FACESIZE
], vert_second
[LF_FACESIZE
], vert_full
[LF_FULLFACESIZE
];
1247 vert_family
[0] = '@';
1248 lstrcpynW( vert_family
+ 1, family_name
, LF_FACESIZE
- 1 );
1250 if (second_name
&& second_name
[0])
1252 vert_second
[0] = '@';
1253 lstrcpynW( vert_second
+ 1, second_name
, LF_FACESIZE
- 1 );
1255 else vert_second
[0] = 0;
1260 lstrcpynW( vert_full
+ 1, fullname
, LF_FULLFACESIZE
- 1 );
1261 fullname
= vert_full
;
1264 if ((family
= find_family_from_name( vert_family
))) family
->refcount
++;
1265 else if (!(family
= create_family( vert_family
, vert_second
))) return ret
;
1267 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1268 index
, fs
, ntmflags
, version
, flags
| ADDFONT_VERTICAL_FONT
, size
)))
1270 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1271 release_face( face
);
1273 release_family( family
);
1287 struct bitmap_font_size size
;
1290 /* WCHAR file_name[]; */
1293 static void load_face_from_cache( HKEY hkey_family
, struct gdi_font_family
*family
,
1294 void *buffer
, DWORD buffer_size
, BOOL scalable
)
1296 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1297 KEY_NODE_INFORMATION
*node_info
= (KEY_NODE_INFORMATION
*)buffer
;
1298 DWORD index
= 0, total_size
;
1299 struct gdi_font_face
*face
;
1302 struct cached_face
*cached
;
1304 while (reg_enum_value( hkey_family
, index
++, info
,
1305 buffer_size
- sizeof(DWORD
), name
, sizeof(name
) ))
1307 cached
= (struct cached_face
*)((char *)info
+ info
->DataOffset
);
1308 if (info
->Type
== REG_BINARY
&& info
->DataLength
> sizeof(*cached
))
1310 ((DWORD
*)cached
)[info
->DataLength
/ sizeof(DWORD
)] = 0;
1311 if ((face
= create_face( family
, name
, cached
->full_name
,
1312 cached
->full_name
+ lstrlenW(cached
->full_name
) + 1,
1313 NULL
, 0, cached
->index
, cached
->fs
, cached
->ntmflags
, cached
->version
,
1314 cached
->flags
, scalable
? NULL
: &cached
->size
)))
1317 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1318 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1319 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1321 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1322 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1323 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1324 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1326 release_face( face
);
1331 /* load bitmap strikes */
1334 while (!NtEnumerateKey( hkey_family
, index
++, KeyNodeInformation
, node_info
,
1335 buffer_size
, &total_size
))
1337 if ((hkey_strike
= reg_open_key( hkey_family
, node_info
->Name
, node_info
->NameLength
)))
1339 load_face_from_cache( hkey_strike
, family
, buffer
, buffer_size
, FALSE
);
1340 NtClose( hkey_strike
);
1345 static void load_font_list_from_cache(void)
1348 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)buffer
;
1349 KEY_NODE_INFORMATION
*enum_info
= (KEY_NODE_INFORMATION
*)buffer
;
1350 DWORD family_index
= 0, total_size
;
1351 struct gdi_font_family
*family
;
1353 WCHAR
*second_name
= (WCHAR
*)info
->Data
;
1355 while (!NtEnumerateKey( wine_fonts_cache_key
, family_index
++, KeyNodeInformation
, enum_info
,
1356 sizeof(buffer
), &total_size
))
1358 if (!(hkey_family
= reg_open_key( wine_fonts_cache_key
, enum_info
->Name
,
1359 enum_info
->NameLength
)))
1361 TRACE( "opened family key %s\n", debugstr_wn(enum_info
->Name
, enum_info
->NameLength
/ sizeof(WCHAR
)) );
1362 if (!query_reg_value( hkey_family
, NULL
, info
, sizeof(buffer
) ))
1365 family
= create_family( buffer
, second_name
);
1367 load_face_from_cache( hkey_family
, family
, buffer
, sizeof(buffer
), TRUE
);
1369 NtClose( hkey_family
);
1370 release_family( family
);
1374 static void add_face_to_cache( struct gdi_font_face
*face
)
1376 HKEY hkey_family
, hkey_face
;
1377 DWORD len
, buffer
[1024];
1378 struct cached_face
*cached
= (struct cached_face
*)buffer
;
1380 if (!(hkey_family
= reg_create_key( wine_fonts_cache_key
, face
->family
->family_name
,
1381 lstrlenW( face
->family
->family_name
) * sizeof(WCHAR
),
1382 REG_OPTION_VOLATILE
, NULL
)))
1385 if (face
->family
->second_name
[0])
1386 set_reg_value( hkey_family
, NULL
, REG_SZ
, face
->family
->second_name
,
1387 (lstrlenW( face
->family
->second_name
) + 1) * sizeof(WCHAR
) );
1389 if (!face
->scalable
)
1394 sprintf( name
, "%d", face
->size
.y_ppem
);
1395 hkey_face
= reg_create_key( hkey_family
, nameW
,
1396 asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
),
1397 REG_OPTION_VOLATILE
, NULL
);
1399 else hkey_face
= hkey_family
;
1401 memset( cached
, 0, sizeof(*cached
) );
1402 cached
->index
= face
->face_index
;
1403 cached
->flags
= face
->flags
;
1404 cached
->ntmflags
= face
->ntmFlags
;
1405 cached
->version
= face
->version
;
1406 cached
->fs
= face
->fs
;
1407 if (!face
->scalable
) cached
->size
= face
->size
;
1408 lstrcpyW( cached
->full_name
, face
->full_name
);
1409 len
= lstrlenW( face
->full_name
) + 1;
1410 lstrcpyW( cached
->full_name
+ len
, face
->file
);
1411 len
+= lstrlenW( face
->file
) + 1;
1413 set_reg_value( hkey_face
, face
->style_name
, REG_BINARY
, cached
,
1414 offsetof( struct cached_face
, full_name
[len
] ));
1416 if (hkey_face
!= hkey_family
) NtClose( hkey_face
);
1417 NtClose( hkey_family
);
1420 static void remove_face_from_cache( struct gdi_font_face
*face
)
1422 HKEY hkey_family
, hkey
;
1424 if (!(hkey_family
= reg_open_key( wine_fonts_cache_key
, face
->family
->family_name
,
1425 lstrlenW( face
->family
->family_name
) * sizeof(WCHAR
) )))
1428 if (!face
->scalable
)
1432 sprintf( name
, "%d", face
->size
.y_ppem
);
1433 if ((hkey
= reg_open_key( hkey_family
, nameW
,
1434 asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
) )))
1436 NtDeleteKey( hkey
);
1440 else reg_delete_value( hkey_family
, face
->style_name
);
1442 NtClose( hkey_family
);
1447 struct gdi_font_link
1451 WCHAR name
[LF_FACESIZE
];
1455 struct gdi_font_link_entry
1459 WCHAR family_name
[LF_FACESIZE
];
1462 static struct list font_links
= LIST_INIT(font_links
);
1464 static struct gdi_font_link
*find_gdi_font_link( const WCHAR
*name
)
1466 struct gdi_font_link
*link
;
1468 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1469 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 )) return link
;
1473 static struct gdi_font_family
*find_family_from_font_links( const WCHAR
*name
, const WCHAR
*subst
,
1476 struct gdi_font_link
*link
;
1477 struct gdi_font_link_entry
*entry
;
1478 struct gdi_font_family
*family
;
1480 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1482 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 ) ||
1483 (subst
&& !facename_compare( link
->name
, subst
, LF_FACESIZE
- 1 )))
1485 TRACE("found entry in system list\n");
1486 LIST_FOR_EACH_ENTRY( entry
, &link
->links
, struct gdi_font_link_entry
, entry
)
1488 const struct gdi_font_link
*links
;
1490 family
= find_family_from_name( entry
->family_name
);
1491 if (!fs
.fsCsb
[0]) return family
;
1492 if (fs
.fsCsb
[0] & entry
->fs
.fsCsb
[0]) return family
;
1493 if ((links
= find_gdi_font_link( family
->family_name
)) && fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
1501 static struct gdi_font_link
*add_gdi_font_link( const WCHAR
*name
)
1503 struct gdi_font_link
*link
= find_gdi_font_link( name
);
1505 if (link
) return link
;
1506 if ((link
= malloc( sizeof(*link
) )))
1508 lstrcpynW( link
->name
, name
, LF_FACESIZE
);
1509 memset( &link
->fs
, 0, sizeof(link
->fs
) );
1510 list_init( &link
->links
);
1511 list_add_tail( &font_links
, &link
->entry
);
1516 static void add_gdi_font_link_entry( struct gdi_font_link
*link
, const WCHAR
*family_name
, FONTSIGNATURE fs
)
1518 struct gdi_font_link_entry
*entry
;
1520 entry
= malloc( sizeof(*entry
) );
1521 lstrcpynW( entry
->family_name
, family_name
, LF_FACESIZE
);
1523 link
->fs
.fsCsb
[0] |= fs
.fsCsb
[0];
1524 link
->fs
.fsCsb
[1] |= fs
.fsCsb
[1];
1525 list_add_tail( &link
->links
, &entry
->entry
);
1528 static const WCHAR lucida_sans_unicodeW
[] =
1529 {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
1530 static const WCHAR microsoft_sans_serifW
[] =
1531 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1532 static const WCHAR tahomaW
[] =
1533 {'T','a','h','o','m','a',0};
1534 static const WCHAR ms_ui_gothicW
[] =
1535 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1536 static const WCHAR sim_sunW
[] =
1537 {'S','i','m','S','u','n',0};
1538 static const WCHAR gulimW
[] =
1539 {'G','u','l','i','m',0};
1540 static const WCHAR p_ming_li_uW
[] =
1541 {'P','M','i','n','g','L','i','U',0};
1542 static const WCHAR batangW
[] =
1543 {'B','a','t','a','n','g',0};
1545 static const WCHAR
* const font_links_list
[] =
1547 lucida_sans_unicodeW
,
1548 microsoft_sans_serifW
,
1552 static const struct font_links_defaults_list
1554 /* Keyed off substitution for "MS Shell Dlg" */
1555 const WCHAR
*shelldlg
;
1556 /* Maximum of four substitutes, plus terminating NULL pointer */
1557 const WCHAR
*substitutes
[5];
1558 } font_links_defaults_list
[] =
1560 /* Non East-Asian */
1561 { tahomaW
, /* FIXME unverified ordering */
1562 { ms_ui_gothicW
, sim_sunW
, gulimW
, p_ming_li_uW
, NULL
}
1564 /* Below lists are courtesy of
1565 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1569 { ms_ui_gothicW
, p_ming_li_uW
, sim_sunW
, gulimW
, NULL
}
1571 /* Chinese Simplified */
1573 { sim_sunW
, p_ming_li_uW
, ms_ui_gothicW
, batangW
, NULL
}
1577 { gulimW
, p_ming_li_uW
, ms_ui_gothicW
, sim_sunW
, NULL
}
1579 /* Chinese Traditional */
1581 { p_ming_li_uW
, sim_sunW
, ms_ui_gothicW
, batangW
, NULL
}
1585 static void populate_system_links( const WCHAR
*name
, const WCHAR
* const *values
)
1587 struct gdi_font_family
*family
;
1588 struct gdi_font_face
*face
;
1589 struct gdi_font_link
*font_link
;
1590 const WCHAR
*file
, *value
;
1592 /* Don't store fonts that are only substitutes for other fonts */
1593 if (get_gdi_font_subst( name
, -1, NULL
))
1595 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
) );
1598 font_link
= add_gdi_font_link( name
);
1599 for ( ; *values
; values
++)
1601 if (!facename_compare( name
, *values
, -1 )) continue;
1602 if (!(value
= get_gdi_font_subst( *values
, -1, NULL
))) value
= *values
;
1603 if (!(family
= find_family_from_name( value
))) continue;
1604 /* use first extant filename for this Family */
1605 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1607 if (!face
->file
) continue;
1608 file
= wcsrchr(face
->file
, '\\');
1609 if (!file
) file
= face
->file
;
1611 if ((face
= find_face_from_filename( file
, value
)))
1613 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1614 TRACE( "added internal SystemLink for %s to %s in %s\n",
1615 debugstr_w(name
), debugstr_w(value
), debugstr_w(file
) );
1617 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
) );
1623 static void load_system_links(void)
1627 const WCHAR
*shelldlg_name
;
1628 struct gdi_font_link
*font_link
, *system_font_link
;
1629 struct gdi_font_face
*face
;
1631 static const WCHAR ms_shell_dlgW
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
1632 static const WCHAR systemW
[] = {'S','y','s','t','e','m',0};
1633 static const WCHAR tahoma_ttfW
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1635 if ((hkey
= reg_open_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
) )))
1638 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1639 WCHAR value
[MAX_PATH
];
1640 WCHAR
*entry
, *next
;
1643 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
1645 /* Don't store fonts that are only substitutes for other fonts */
1646 if (!get_gdi_font_subst( value
, -1, NULL
))
1648 char *data
= (char *)info
+ info
->DataOffset
;
1649 font_link
= add_gdi_font_link( value
);
1650 for (entry
= (WCHAR
*)data
; (char *)entry
< data
+ info
->DataLength
&& *entry
; entry
= next
)
1652 const WCHAR
*family_name
= NULL
;
1655 TRACE( "%s: %s\n", debugstr_w(value
), debugstr_w(entry
) );
1657 next
= entry
+ lstrlenW(entry
) + 1;
1658 if ((p
= wcschr( entry
, ',' )))
1661 while (*p
== ' ' || *p
== '\t') p
++;
1662 if (!(family_name
= get_gdi_font_subst( p
, -1, NULL
))) family_name
= p
;
1664 if ((face
= find_face_from_filename( entry
, family_name
)))
1666 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1667 TRACE("Adding file %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1669 else TRACE( "Unable to find file %s family %s\n",
1670 debugstr_w(entry
), debugstr_w(family_name
) );
1673 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1678 if ((shelldlg_name
= get_gdi_font_subst( ms_shell_dlgW
, -1, NULL
)))
1680 for (i
= 0; i
< ARRAY_SIZE(font_links_defaults_list
); i
++)
1682 const WCHAR
*subst
= get_gdi_font_subst( font_links_defaults_list
[i
].shelldlg
, -1, NULL
);
1684 if ((!facename_compare( font_links_defaults_list
[i
].shelldlg
, shelldlg_name
, -1 ) ||
1685 (subst
&& !facename_compare( subst
, shelldlg_name
, -1 ))))
1687 for (j
= 0; j
< ARRAY_SIZE(font_links_list
); j
++)
1688 populate_system_links( font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
1689 if (!facename_compare(shelldlg_name
, font_links_defaults_list
[i
].substitutes
[0], -1))
1690 populate_system_links( shelldlg_name
, font_links_defaults_list
[i
].substitutes
);
1694 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1696 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1699 system_font_link
= add_gdi_font_link( systemW
);
1700 if ((face
= find_face_from_filename( tahoma_ttfW
, tahomaW
)))
1702 add_gdi_font_link_entry( system_font_link
, face
->family
->family_name
, face
->fs
);
1703 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1705 if ((font_link
= find_gdi_font_link( tahomaW
)))
1707 struct gdi_font_link_entry
*entry
;
1708 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1709 add_gdi_font_link_entry( system_font_link
, entry
->family_name
, entry
->fs
);
1713 /* see TranslateCharsetInfo */
1714 BOOL
translate_charset_info( DWORD
*src
, CHARSETINFO
*cs
, DWORD flags
)
1720 case TCI_SRCFONTSIG
:
1721 while (index
< ARRAY_SIZE(charset_info
) && !(*src
>>index
& 0x0001)) index
++;
1723 case TCI_SRCCODEPAGE
:
1724 while (index
< ARRAY_SIZE(charset_info
) && PtrToUlong(src
) != charset_info
[index
].ciACP
)
1727 case TCI_SRCCHARSET
:
1728 while (index
< ARRAY_SIZE(charset_info
) &&
1729 PtrToUlong(src
) != charset_info
[index
].ciCharset
)
1736 if (index
>= ARRAY_SIZE(charset_info
) || charset_info
[index
].ciCharset
== DEFAULT_CHARSET
) return FALSE
;
1737 *cs
= charset_info
[index
];
1743 static BOOL
can_select_face( const struct gdi_font_face
*face
, FONTSIGNATURE fs
, BOOL can_use_bitmap
)
1745 struct gdi_font_link
*font_link
;
1747 if (!face
->scalable
&& !can_use_bitmap
) return FALSE
;
1748 if (!fs
.fsCsb
[0]) return TRUE
;
1749 if (fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return TRUE
;
1750 if (!(font_link
= find_gdi_font_link( face
->family
->family_name
))) return FALSE
;
1751 if (fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) return TRUE
;
1755 static struct gdi_font_face
*find_best_matching_face( const struct gdi_font_family
*family
,
1756 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1757 BOOL can_use_bitmap
)
1759 struct gdi_font_face
*face
= NULL
, *best
= NULL
, *best_bitmap
= NULL
;
1760 unsigned int best_score
= 4;
1762 int it
= !!lf
->lfItalic
;
1763 int bd
= lf
->lfWeight
> 550;
1764 int height
= lf
->lfHeight
;
1766 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1768 int italic
= !!(face
->ntmFlags
& NTM_ITALIC
);
1769 int bold
= !!(face
->ntmFlags
& NTM_BOLD
);
1770 int score
= (italic
^ it
) + (bold
^ bd
);
1772 if (!can_select_face( face
, fs
, can_use_bitmap
)) continue;
1773 if (score
> best_score
) continue;
1774 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic
, bold
, it
, bd
);
1777 if (best
->scalable
&& best_score
== 0) break;
1778 if (!best
->scalable
)
1782 diff
= height
- (signed int)best
->size
.height
;
1784 diff
= -height
- ((signed int)best
->size
.height
- best
->size
.internal_leading
);
1786 (best_diff
> 0 && diff
>= 0 && diff
< best_diff
) ||
1787 (best_diff
< 0 && diff
> best_diff
))
1789 TRACE( "%d is better for %d diff was %d\n", best
->size
.height
, height
, best_diff
);
1792 if (best_score
== 0 && best_diff
== 0) break;
1796 if (!best
) return NULL
;
1797 return best
->scalable
? best
: best_bitmap
;
1800 static struct gdi_font_face
*find_matching_face_by_name( const WCHAR
*name
, const WCHAR
*subst
,
1801 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1802 BOOL can_use_bitmap
, const WCHAR
**orig_name
)
1804 struct gdi_font_family
*family
;
1805 struct gdi_font_face
*face
;
1807 family
= find_family_from_any_name( name
);
1808 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
1811 family
= find_family_from_any_name( subst
);
1812 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
1815 /* search by full face name */
1816 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1817 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1818 if (!facename_compare( face
->full_name
, name
, LF_FACESIZE
- 1 ) &&
1819 can_select_face( face
, fs
, can_use_bitmap
))
1822 if ((family
= find_family_from_font_links( name
, subst
, fs
)))
1824 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1829 if (orig_name
&& family
!= face
->family
)
1830 *orig_name
= family
->family_name
;
1834 static struct gdi_font_face
*find_any_face( const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1835 BOOL can_use_bitmap
, BOOL want_vertical
)
1837 struct gdi_font_family
*family
;
1838 struct gdi_font_face
*face
;
1839 WCHAR name
[LF_FACESIZE
+ 1];
1842 /* first try the family fallbacks */
1843 while (enum_fallbacks( lf
->lfPitchAndFamily
, i
++, name
))
1847 memmove(name
+ 1, name
, min(lstrlenW(name
), LF_FACESIZE
));
1851 if (!(family
= find_family_from_any_name(name
))) continue;
1852 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1854 /* otherwise try only scalable */
1855 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1857 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1858 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1860 if (!can_use_bitmap
) return NULL
;
1861 /* then also bitmap fonts */
1862 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1864 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1865 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1870 static struct gdi_font_face
*find_matching_face( const LOGFONTW
*lf
, CHARSETINFO
*csi
, BOOL can_use_bitmap
,
1871 BOOL
*substituted
, const WCHAR
**orig_name
)
1873 BOOL want_vertical
= (lf
->lfFaceName
[0] == '@');
1874 struct gdi_font_face
*face
;
1876 if (!translate_charset_info( (DWORD
*)(INT_PTR
)lf
->lfCharSet
, csi
, TCI_SRCCHARSET
))
1878 if (lf
->lfCharSet
!= DEFAULT_CHARSET
) FIXME( "Untranslated charset %d\n", lf
->lfCharSet
);
1879 csi
->fs
.fsCsb
[0] = 0;
1882 if (lf
->lfFaceName
[0])
1885 const WCHAR
*subst
= get_gdi_font_subst( lf
->lfFaceName
, lf
->lfCharSet
, &subst_charset
);
1889 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf
->lfFaceName
), lf
->lfCharSet
,
1890 debugstr_w(subst
), (subst_charset
!= -1) ? subst_charset
: lf
->lfCharSet
);
1891 if (subst_charset
!= -1)
1892 translate_charset_info( (DWORD
*)(INT_PTR
)subst_charset
, csi
, TCI_SRCCHARSET
);
1893 *substituted
= TRUE
;
1896 if ((face
= find_matching_face_by_name( lf
->lfFaceName
, subst
, lf
, csi
->fs
, can_use_bitmap
, orig_name
)))
1899 *substituted
= FALSE
; /* substitution is no longer relevant */
1901 /* If requested charset was DEFAULT_CHARSET then try using charset
1902 corresponding to the current ansi codepage */
1903 if (!csi
->fs
.fsCsb
[0])
1905 INT acp
= get_acp();
1906 if (!translate_charset_info( (DWORD
*)(INT_PTR
)acp
, csi
, TCI_SRCCODEPAGE
))
1908 FIXME( "TCI failed on codepage %d\n", acp
);
1909 csi
->fs
.fsCsb
[0] = 0;
1913 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1914 if (csi
->fs
.fsCsb
[0])
1916 csi
->fs
.fsCsb
[0] = 0;
1917 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1919 if (want_vertical
&& (face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, FALSE
))) return face
;
1923 /* realized font objects */
1925 #define FIRST_FONT_HANDLE 1
1926 #define MAX_FONT_HANDLES 256
1928 struct font_handle_entry
1930 struct gdi_font
*font
;
1931 WORD generation
; /* generation count for reusing handle values */
1934 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
1935 static struct font_handle_entry
*next_free
;
1936 static struct font_handle_entry
*next_unused
= font_handles
;
1938 static struct font_handle_entry
*handle_entry( DWORD handle
)
1940 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
1942 if (idx
< MAX_FONT_HANDLES
)
1944 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
1945 return &font_handles
[idx
];
1947 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
1951 static struct gdi_font
*get_font_from_handle( DWORD handle
)
1953 struct font_handle_entry
*entry
= handle_entry( handle
);
1955 if (entry
) return entry
->font
;
1956 SetLastError( ERROR_INVALID_PARAMETER
);
1960 static DWORD
alloc_font_handle( struct gdi_font
*font
)
1962 struct font_handle_entry
*entry
;
1966 next_free
= (struct font_handle_entry
*)entry
->font
;
1967 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
1968 entry
= next_unused
++;
1971 ERR( "out of realized font handles\n" );
1975 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
1976 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
1979 static void free_font_handle( DWORD handle
)
1981 struct font_handle_entry
*entry
;
1983 if ((entry
= handle_entry( handle
)))
1985 entry
->font
= (struct gdi_font
*)next_free
;
1990 static struct gdi_font
*alloc_gdi_font( const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
)
1992 UINT len
= file
? lstrlenW(file
) : 0;
1993 struct gdi_font
*font
= calloc( 1, offsetof( struct gdi_font
, file
[len
+ 1] ));
1996 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
1998 font
->kern_count
= -1;
1999 list_init( &font
->child_fonts
);
2003 FILE_NETWORK_OPEN_INFORMATION info
;
2004 UNICODE_STRING nt_name
;
2005 OBJECT_ATTRIBUTES attr
;
2007 nt_name
.Buffer
= (WCHAR
*)file
;
2008 nt_name
.Length
= nt_name
.MaximumLength
= len
* sizeof(WCHAR
);
2010 attr
.Length
= sizeof(attr
);
2011 attr
.RootDirectory
= 0;
2012 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2013 attr
.ObjectName
= &nt_name
;
2014 attr
.SecurityDescriptor
= NULL
;
2015 attr
.SecurityQualityOfService
= NULL
;
2017 if (!NtQueryFullAttributesFile( &attr
, &info
))
2019 font
->writetime
.dwLowDateTime
= info
.LastWriteTime
.LowPart
;
2020 font
->writetime
.dwHighDateTime
= info
.LastWriteTime
.HighPart
;
2021 font
->data_size
= info
.EndOfFile
.QuadPart
;
2022 memcpy( font
->file
, file
, len
* sizeof(WCHAR
) );
2027 font
->data_ptr
= data_ptr
;
2028 font
->data_size
= data_size
;
2031 font
->handle
= alloc_font_handle( font
);
2035 static void free_gdi_font( struct gdi_font
*font
)
2038 struct gdi_font
*child
, *child_next
;
2040 if (font
->private) font_funcs
->destroy_font( font
);
2041 free_font_handle( font
->handle
);
2042 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, struct gdi_font
, entry
)
2044 list_remove( &child
->entry
);
2045 free_gdi_font( child
);
2047 for (i
= 0; i
< font
->gm_size
; i
++) free( font
->gm
[i
] );
2048 free( font
->otm
.otmpFamilyName
);
2049 free( font
->otm
.otmpStyleName
);
2050 free( font
->otm
.otmpFaceName
);
2051 free( font
->otm
.otmpFullName
);
2053 free( font
->kern_pairs
);
2054 free( font
->gsub_table
);
2058 static inline const WCHAR
*get_gdi_font_name( struct gdi_font
*font
)
2060 return font
->use_logfont_name
? font
->lf
.lfFaceName
: (WCHAR
*)font
->otm
.otmpFamilyName
;
2063 static struct gdi_font
*create_gdi_font( const struct gdi_font_face
*face
, const WCHAR
*family_name
,
2064 const LOGFONTW
*lf
)
2066 struct gdi_font
*font
;
2068 if (!(font
= alloc_gdi_font( face
->file
, face
->data_ptr
, face
->data_size
))) return NULL
;
2069 font
->fs
= face
->fs
;
2071 font
->fake_italic
= (lf
->lfItalic
&& !(face
->ntmFlags
& NTM_ITALIC
));
2072 font
->fake_bold
= (lf
->lfWeight
> 550 && !(face
->ntmFlags
& NTM_BOLD
));
2073 font
->scalable
= face
->scalable
;
2074 font
->face_index
= face
->face_index
;
2075 font
->ntmFlags
= face
->ntmFlags
;
2076 font
->aa_flags
= HIWORD( face
->flags
);
2077 if (!family_name
) family_name
= face
->family
->family_name
;
2078 font
->otm
.otmpFamilyName
= (char *)strdupW( family_name
);
2079 font
->otm
.otmpStyleName
= (char *)strdupW( face
->style_name
);
2080 font
->otm
.otmpFaceName
= (char *)strdupW( face
->full_name
);
2084 struct glyph_metrics
2087 ABC abc
; /* metrics of the unrotated char */
2091 #define GM_BLOCK_SIZE 128
2093 /* TODO: GGO format support */
2094 static BOOL
get_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
, GLYPHMETRICS
*gm
, ABC
*abc
)
2096 UINT block
= index
/ GM_BLOCK_SIZE
;
2097 UINT entry
= index
% GM_BLOCK_SIZE
;
2099 if (block
< font
->gm_size
&& font
->gm
[block
] && font
->gm
[block
][entry
].init
)
2101 *gm
= font
->gm
[block
][entry
].gm
;
2102 *abc
= font
->gm
[block
][entry
].abc
;
2104 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2105 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point( &gm
->gmptGlyphOrigin
),
2106 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2113 static void set_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
,
2114 const GLYPHMETRICS
*gm
, const ABC
*abc
)
2116 UINT block
= index
/ GM_BLOCK_SIZE
;
2117 UINT entry
= index
% GM_BLOCK_SIZE
;
2119 if (block
>= font
->gm_size
)
2121 struct glyph_metrics
**ptr
;
2123 if (!(ptr
= realloc( font
->gm
, (block
+ 1) * sizeof(*ptr
) ))) return;
2124 memset( ptr
+ font
->gm_size
, 0, (block
+ 1 - font
->gm_size
) * sizeof(*ptr
) );
2125 font
->gm_size
= block
+ 1;
2128 if (!font
->gm
[block
])
2130 font
->gm
[block
] = calloc( sizeof(**font
->gm
), GM_BLOCK_SIZE
);
2131 if (!font
->gm
[block
]) return;
2133 font
->gm
[block
][entry
].gm
= *gm
;
2134 font
->gm
[block
][entry
].abc
= *abc
;
2135 font
->gm
[block
][entry
].init
= TRUE
;
2139 /* GSUB table support */
2153 } GSUB_ScriptRecord
;
2158 GSUB_ScriptRecord ScriptRecord
[1];
2165 } GSUB_LangSysRecord
;
2169 WORD DefaultLangSys
;
2171 GSUB_LangSysRecord LangSysRecord
[1];
2176 WORD LookupOrder
; /* Reserved */
2177 WORD ReqFeatureIndex
;
2179 WORD FeatureIndex
[1];
2186 } GSUB_FeatureRecord
;
2191 GSUB_FeatureRecord FeatureRecord
[1];
2196 WORD FeatureParams
; /* Reserved */
2198 WORD LookupListIndex
[1];
2217 WORD CoverageFormat
;
2220 } GSUB_CoverageFormat1
;
2226 WORD StartCoverageIndex
;
2231 WORD CoverageFormat
;
2233 GSUB_RangeRecord RangeRecord
[1];
2234 } GSUB_CoverageFormat2
;
2238 WORD SubstFormat
; /* = 1 */
2241 } GSUB_SingleSubstFormat1
;
2245 WORD SubstFormat
; /* = 2 */
2249 } GSUB_SingleSubstFormat2
;
2251 static GSUB_Script
*GSUB_get_script_table( GSUB_Header
*header
, const char *tag
)
2253 GSUB_ScriptList
*script
;
2254 GSUB_Script
*deflt
= NULL
;
2257 script
= (GSUB_ScriptList
*)((BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
2258 TRACE("%i scripts in this font\n", GET_BE_WORD(script
->ScriptCount
) );
2259 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
2261 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
2262 GSUB_Script
*scr
= (GSUB_Script
*)((BYTE
*)script
+ offset
);
2263 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, tag
, 4 )) return scr
;
2264 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, "dflt", 4 )) deflt
= scr
;
2269 static GSUB_LangSys
*GSUB_get_lang_table( GSUB_Script
*script
, const char *tag
)
2274 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
2276 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
2278 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
2279 lang
= (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2280 if (!memcmp( script
->LangSysRecord
[i
].LangSysTag
, tag
, 4 )) return lang
;
2282 offset
= GET_BE_WORD(script
->DefaultLangSys
);
2283 if (offset
) return (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2287 static GSUB_Feature
*GSUB_get_feature( GSUB_Header
*header
, GSUB_LangSys
*lang
, const char *tag
)
2290 const GSUB_FeatureList
*feature
;
2292 feature
= (GSUB_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
2293 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
2294 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
2296 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
2297 if (!memcmp( feature
->FeatureRecord
[index
].FeatureTag
, tag
, 4 ))
2298 return (GSUB_Feature
*)((BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
2303 static const char *get_opentype_script( const struct gdi_font
*font
)
2306 * I am not sure if this is the correct way to generate our script tag
2308 switch (font
->charset
)
2310 case ANSI_CHARSET
: return "latn";
2311 case BALTIC_CHARSET
: return "latn"; /* ?? */
2312 case CHINESEBIG5_CHARSET
: return "hani";
2313 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
2314 case GB2312_CHARSET
: return "hani";
2315 case GREEK_CHARSET
: return "grek";
2316 case HANGUL_CHARSET
: return "hang";
2317 case RUSSIAN_CHARSET
: return "cyrl";
2318 case SHIFTJIS_CHARSET
: return "kana";
2319 case TURKISH_CHARSET
: return "latn"; /* ?? */
2320 case VIETNAMESE_CHARSET
: return "latn";
2321 case JOHAB_CHARSET
: return "latn"; /* ?? */
2322 case ARABIC_CHARSET
: return "arab";
2323 case HEBREW_CHARSET
: return "hebr";
2324 case THAI_CHARSET
: return "thai";
2325 default: return "latn";
2329 static void *get_GSUB_vert_feature( struct gdi_font
*font
)
2331 GSUB_Header
*header
;
2332 GSUB_Script
*script
;
2333 GSUB_LangSys
*language
;
2334 GSUB_Feature
*feature
;
2335 DWORD length
= font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, NULL
, 0 );
2337 if (length
== GDI_ERROR
) return NULL
;
2339 header
= malloc( length
);
2340 font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, header
, length
);
2341 TRACE( "Loaded GSUB table of %i bytes\n", length
);
2343 if ((script
= GSUB_get_script_table( header
, get_opentype_script(font
) )))
2345 if ((language
= GSUB_get_lang_table( script
, "xxxx" ))) /* Need to get Lang tag */
2347 feature
= GSUB_get_feature( header
, language
, "vrt2" );
2348 if (!feature
) feature
= GSUB_get_feature( header
, language
, "vert" );
2351 font
->gsub_table
= header
;
2354 TRACE("vrt2/vert feature not found\n");
2356 else TRACE("Language not found\n");
2358 else TRACE("Script not found\n");
2364 static int GSUB_is_glyph_covered( void *table
, UINT glyph
)
2366 GSUB_CoverageFormat1
*cf1
= table
;
2368 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
2370 int i
, count
= GET_BE_WORD(cf1
->GlyphCount
);
2372 TRACE("Coverage Format 1, %i glyphs\n",count
);
2373 for (i
= 0; i
< count
; i
++) if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
])) return i
;
2376 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
2379 GSUB_CoverageFormat2
*cf2
= table
;
2381 count
= GET_BE_WORD(cf2
->RangeCount
);
2382 TRACE("Coverage Format 2, %i ranges\n",count
);
2383 for (i
= 0; i
< count
; i
++)
2385 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) return -1;
2386 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
2387 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
2389 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
2390 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
2395 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
2400 static UINT
GSUB_apply_feature( GSUB_Header
*header
, GSUB_Feature
*feature
, UINT glyph
)
2402 GSUB_LookupList
*lookup
= (GSUB_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2405 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
2406 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
2408 GSUB_LookupTable
*look
;
2409 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
2410 look
= (GSUB_LookupTable
*)((BYTE
*)lookup
+ offset
);
2411 TRACE("type %i, flag %x, subtables %i\n",
2412 GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
2413 if (GET_BE_WORD(look
->LookupType
) == 1)
2415 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
2417 GSUB_SingleSubstFormat1
*ssf1
;
2418 offset
= GET_BE_WORD(look
->SubTable
[j
]);
2419 ssf1
= (GSUB_SingleSubstFormat1
*)((BYTE
*)look
+ offset
);
2420 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
2422 int offset
= GET_BE_WORD(ssf1
->Coverage
);
2423 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
2424 if (GSUB_is_glyph_covered( (BYTE
*) ssf1
+ offset
, glyph
) != -1)
2426 TRACE(" Glyph 0x%x ->",glyph
);
2427 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
2428 TRACE(" 0x%x\n",glyph
);
2433 GSUB_SingleSubstFormat2
*ssf2
;
2436 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
2437 offset
= GET_BE_WORD(ssf1
->Coverage
);
2438 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
2439 index
= GSUB_is_glyph_covered( (BYTE
*)ssf2
+ offset
, glyph
);
2440 TRACE(" Coverage index %i\n",index
);
2443 TRACE(" Glyph is 0x%x ->",glyph
);
2444 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
2445 TRACE("0x%x\n",glyph
);
2450 else FIXME("We only handle SubType 1\n");
2455 static UINT
get_GSUB_vert_glyph( struct gdi_font
*font
, UINT glyph
)
2457 if (!glyph
) return glyph
;
2458 if (!font
->gsub_table
) return glyph
;
2459 return GSUB_apply_feature( font
->gsub_table
, font
->vert_feature
, glyph
);
2462 static void add_child_font( struct gdi_font
*font
, const WCHAR
*family_name
)
2464 FONTSIGNATURE fs
= {{0}};
2465 struct gdi_font
*child
;
2466 struct gdi_font_face
*face
;
2468 if (!(face
= find_matching_face_by_name( family_name
, NULL
, &font
->lf
, fs
, FALSE
, NULL
))) return;
2470 if (!(child
= create_gdi_font( face
, family_name
, &font
->lf
))) return;
2471 child
->matrix
= font
->matrix
;
2472 child
->can_use_bitmap
= font
->can_use_bitmap
;
2473 child
->scale_y
= font
->scale_y
;
2474 child
->aveWidth
= font
->aveWidth
;
2475 child
->charset
= font
->charset
;
2476 child
->codepage
= font
->codepage
;
2477 child
->base_font
= font
;
2478 list_add_tail( &font
->child_fonts
, &child
->entry
);
2479 TRACE( "created child font %p for base %p\n", child
, font
);
2482 static void create_child_font_list( struct gdi_font
*font
)
2484 struct gdi_font_link
*font_link
;
2485 struct gdi_font_link_entry
*entry
;
2486 const WCHAR
* font_name
= (WCHAR
*)font
->otm
.otmpFaceName
;
2488 if ((font_link
= find_gdi_font_link( font_name
)))
2490 TRACE("found entry in system list\n");
2491 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2492 add_child_font( font
, entry
->family_name
);
2495 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2496 * Sans Serif. This is how asian windows get default fallbacks for fonts
2498 if (is_dbcs_ansi_cp(get_acp()) && font
->charset
!= SYMBOL_CHARSET
&& font
->charset
!= OEM_CHARSET
&&
2499 facename_compare( font_name
, microsoft_sans_serifW
, -1 ) != 0)
2501 if ((font_link
= find_gdi_font_link( microsoft_sans_serifW
)))
2503 TRACE("found entry in default fallback list\n");
2504 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2505 add_child_font( font
, entry
->family_name
);
2512 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
2513 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
2514 static unsigned int unused_font_count
;
2515 #define UNUSED_CACHE_SIZE 10
2517 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
2518 const FMAT2
*matrix
, BOOL can_use_bitmap
)
2520 if (font
->hash
!= hash
) return TRUE
;
2521 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
2522 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2523 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
2524 return facename_compare( font
->lf
.lfFaceName
, lf
->lfFaceName
, -1 );
2527 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2529 DWORD hash
= 0, *ptr
, two_chars
;
2533 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
2535 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
2537 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
2540 pwc
= (WCHAR
*)&two_chars
;
2542 *pwc
= towupper(*pwc
);
2544 *pwc
= towupper(*pwc
);
2548 hash
^= !can_use_bitmap
;
2552 static void cache_gdi_font( struct gdi_font
*font
)
2554 static DWORD cache_num
= 1;
2556 font
->cache_num
= cache_num
++;
2557 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
2558 list_add_head( &gdi_font_list
, &font
->entry
);
2559 TRACE( "font %p\n", font
);
2562 static struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2564 struct gdi_font
*font
;
2565 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
2567 /* try the in-use list */
2568 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
2570 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
2571 list_remove( &font
->entry
);
2572 list_add_head( &gdi_font_list
, &font
->entry
);
2573 if (!font
->refcount
++)
2575 list_remove( &font
->unused_entry
);
2576 unused_font_count
--;
2583 static void release_gdi_font( struct gdi_font
*font
)
2587 TRACE( "font %p\n", font
);
2589 /* add it to the unused list */
2590 pthread_mutex_lock( &font_lock
);
2591 if (!--font
->refcount
)
2593 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
2594 if (unused_font_count
> UNUSED_CACHE_SIZE
)
2596 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
2597 TRACE( "freeing %p\n", font
);
2598 list_remove( &font
->entry
);
2599 list_remove( &font
->unused_entry
);
2600 free_gdi_font( font
);
2602 else unused_font_count
++;
2604 pthread_mutex_unlock( &font_lock
);
2607 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
2609 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
2611 set_reg_ascii_value( hkey
, "Courier", fl
->courier
);
2612 set_reg_ascii_value( hkey
, "MS Serif", fl
->serif
);
2613 set_reg_ascii_value( hkey
, "MS Sans Serif", sserif
);
2614 set_reg_ascii_value( hkey
, "Small Fonts", fl
->small
);
2617 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2620 set_reg_ascii_value( hkey
, name
, value
);
2624 asciiz_to_unicode( nameW
, name
);
2625 reg_delete_value( hkey
, nameW
);
2629 static void update_font_association_info(UINT current_ansi_codepage
)
2631 static const WCHAR associated_charsetW
[] =
2632 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
2634 if (is_dbcs_ansi_cp(current_ansi_codepage
))
2637 if ((hkey
= reg_create_key( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
), 0, NULL
)))
2640 if ((hsubkey
= reg_create_key( hkey
, associated_charsetW
, sizeof(associated_charsetW
),
2643 switch (current_ansi_codepage
)
2646 set_value_key(hsubkey
, "ANSI(00)", "NO");
2647 set_value_key(hsubkey
, "OEM(FF)", "NO");
2648 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2653 set_value_key(hsubkey
, "ANSI(00)", "YES");
2654 set_value_key(hsubkey
, "OEM(FF)", "YES");
2655 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2661 /* TODO: Associated DefaultFonts */
2667 reg_delete_tree( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
) );
2670 static void set_multi_value_key( HKEY hkey
, const WCHAR
*name
, const char *value
, DWORD len
)
2673 ascii_to_unicode( valueW
, value
, len
);
2675 set_reg_value( hkey
, name
, REG_MULTI_SZ
, valueW
, len
* sizeof(WCHAR
) );
2677 reg_delete_value( hkey
, name
);
2680 static void update_font_system_link_info(UINT current_ansi_codepage
)
2682 static const char system_link_simplified_chinese
[] =
2683 "SIMSUN.TTC,SimSun\0"
2684 "MINGLIU.TTC,PMingLiu\0"
2685 "MSGOTHIC.TTC,MS UI Gothic\0"
2686 "BATANG.TTC,Batang\0";
2687 static const char system_link_traditional_chinese
[] =
2688 "MINGLIU.TTC,PMingLiu\0"
2689 "SIMSUN.TTC,SimSun\0"
2690 "MSGOTHIC.TTC,MS UI Gothic\0"
2691 "BATANG.TTC,Batang\0";
2692 static const char system_link_japanese
[] =
2693 "MSGOTHIC.TTC,MS UI Gothic\0"
2694 "MINGLIU.TTC,PMingLiU\0"
2695 "SIMSUN.TTC,SimSun\0"
2696 "GULIM.TTC,Gulim\0";
2697 static const char system_link_korean
[] =
2699 "MSGOTHIC.TTC,MS UI Gothic\0"
2700 "MINGLIU.TTC,PMingLiU\0"
2701 "SIMSUN.TTC,SimSun\0";
2702 static const char system_link_non_cjk
[] =
2703 "MSGOTHIC.TTC,MS UI Gothic\0"
2704 "MINGLIU.TTC,PMingLiU\0"
2705 "SIMSUN.TTC,SimSun\0"
2706 "GULIM.TTC,Gulim\0";
2709 if ((hkey
= reg_create_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
), 0, NULL
)))
2714 switch (current_ansi_codepage
)
2717 link
= system_link_japanese
;
2718 len
= sizeof(system_link_japanese
);
2721 link
= system_link_simplified_chinese
;
2722 len
= sizeof(system_link_simplified_chinese
);
2725 link
= system_link_korean
;
2726 len
= sizeof(system_link_korean
);
2729 link
= system_link_traditional_chinese
;
2730 len
= sizeof(system_link_traditional_chinese
);
2733 link
= system_link_non_cjk
;
2734 len
= sizeof(system_link_non_cjk
);
2736 set_multi_value_key(hkey
, lucida_sans_unicodeW
, link
, len
);
2737 set_multi_value_key(hkey
, microsoft_sans_serifW
, link
, len
);
2738 set_multi_value_key(hkey
, tahomaW
, link
, len
);
2743 static void update_codepage( UINT screen_dpi
)
2745 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[40 * sizeof(WCHAR
)])];
2746 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
2751 UINT i
, ansi_cp
, oem_cp
;
2753 BOOL done
= FALSE
, cp_match
= FALSE
;
2755 static const WCHAR log_pixelsW
[] = {'L','o','g','P','i','x','e','l','s',0};
2757 size
= query_reg_value( wine_fonts_key
, log_pixelsW
, info
, sizeof(value_buffer
) );
2758 if (size
== sizeof(DWORD
) && info
->Type
== REG_DWORD
)
2759 font_dpi
= *(DWORD
*)info
->Data
;
2761 ansi_cp
= get_acp();
2762 oem_cp
= get_oemcp();
2763 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2764 asciiz_to_unicode( cpbufW
, cpbuf
);
2766 if (query_reg_ascii_value( wine_fonts_key
, "Codepages", info
, sizeof(value_buffer
) ))
2768 cp_match
= !wcscmp( (const WCHAR
*)info
->Data
, cpbufW
);
2769 if (cp_match
&& screen_dpi
== font_dpi
) return; /* already set correctly */
2770 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2771 debugstr_w((const WCHAR
*)info
->Data
), font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
2773 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2774 ansi_cp
, oem_cp
, screen_dpi
);
2776 set_reg_ascii_value( wine_fonts_key
, "Codepages", cpbuf
);
2777 set_reg_value( wine_fonts_key
, log_pixelsW
, REG_DWORD
, &screen_dpi
, sizeof(screen_dpi
) );
2779 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
2781 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&& nls_update_font_list
[i
].oem_cp
== oem_cp
)
2784 if ((software_hkey
= reg_create_key( NULL
, software_config_keyW
,
2785 sizeof(software_config_keyW
), 0, NULL
)))
2787 static const WCHAR fontsW
[] = {'F','o','n','t','s'};
2788 hkey
= reg_create_key( software_hkey
, fontsW
, sizeof(fontsW
), 0, NULL
);
2789 NtClose( software_hkey
);
2792 set_reg_ascii_value( hkey
, "OEMFONT.FON", nls_update_font_list
[i
].oem
);
2793 set_reg_ascii_value( hkey
, "FIXEDFON.FON", nls_update_font_list
[i
].fixed
);
2794 set_reg_ascii_value( hkey
, "FONTS.FON", nls_update_font_list
[i
].system
);
2798 if ((hkey
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
),
2801 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2804 if ((hkey
= reg_create_key( NULL
, fonts_win9x_config_keyW
,
2805 sizeof(fonts_win9x_config_keyW
), 0, NULL
)))
2807 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2810 /* Only update these if the Codepage changed. */
2812 (hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
2815 set_reg_ascii_value( hkey
, "MS Shell Dlg", nls_update_font_list
[i
].shelldlg
);
2816 set_reg_ascii_value( hkey
, "Tms Rmn", nls_update_font_list
[i
].tmsrmn
);
2818 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2819 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2820 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2821 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2822 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2823 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2824 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2825 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2827 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2828 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2829 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2837 /* Delete the FontSubstitutes from other locales */
2838 if ((hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
2841 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2842 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2843 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2849 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2851 /* update locale dependent font association info and font system link info in registry.
2852 update only when codepages changed, not logpixels. */
2855 update_font_association_info(ansi_cp
);
2856 update_font_system_link_info(ansi_cp
);
2861 /*************************************************************
2864 static BOOL CDECL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR device
, LPCWSTR output
,
2865 const DEVMODEW
*devmode
)
2867 struct font_physdev
*physdev
;
2869 if (!font_funcs
) return TRUE
;
2870 if (!(physdev
= calloc( 1, sizeof(*physdev
) ))) return FALSE
;
2871 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
2876 /*************************************************************
2879 static BOOL CDECL
font_DeleteDC( PHYSDEV dev
)
2881 struct font_physdev
*physdev
= get_font_dev( dev
);
2883 release_gdi_font( physdev
->font
);
2889 struct gdi_font_enum_data
2892 NEWTEXTMETRICEXW ntm
;
2902 static BOOL
is_complex_script_ansi_cp( UINT ansi_cp
)
2904 return (ansi_cp
== 874 /* Thai */
2905 || ansi_cp
== 1255 /* Hebrew */
2906 || ansi_cp
== 1256 /* Arabic */
2910 /***************************************************
2911 * create_enum_charset_list
2913 * This function creates charset enumeration list because in DEFAULT_CHARSET
2914 * case, the ANSI codepage's charset takes precedence over other charsets.
2915 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2916 * This function works as a filter other than DEFAULT_CHARSET case.
2918 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset
*list
)
2920 struct enum_charset
*start
= list
;
2924 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) && csi
.fs
.fsCsb
[0] != 0)
2926 list
->mask
= csi
.fs
.fsCsb
[0];
2927 list
->charset
= csi
.ciCharset
;
2928 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2931 else /* charset is DEFAULT_CHARSET or invalid. */
2933 int acp
= get_acp();
2936 /* Set the current codepage's charset as the first element. */
2937 if (!is_complex_script_ansi_cp(acp
) &&
2938 translate_charset_info( (DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
2939 csi
.fs
.fsCsb
[0] != 0)
2941 list
->mask
= csi
.fs
.fsCsb
[0];
2942 list
->charset
= csi
.ciCharset
;
2943 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2944 mask
|= csi
.fs
.fsCsb
[0];
2948 /* Fill out left elements. */
2949 for (i
= 0; i
< 32; i
++)
2952 fs
.fsCsb
[0] = 1u << i
;
2954 if (fs
.fsCsb
[0] & mask
) continue; /* skip, already added. */
2955 if (!translate_charset_info( fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
2956 continue; /* skip, this is an invalid fsCsb bit. */
2957 list
->mask
= fs
.fsCsb
[0];
2958 list
->charset
= csi
.ciCharset
;
2960 mask
|= fs
.fsCsb
[0];
2963 /* add catch all mask for remaining bits */
2967 list
->charset
= DEFAULT_CHARSET
;
2968 list
->script
= 33; /* other */
2972 return list
- start
;
2975 static UINT
get_font_type( const NEWTEXTMETRICEXW
*ntm
)
2979 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ret
|= TRUETYPE_FONTTYPE
;
2980 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
) ret
|= DEVICE_FONTTYPE
;
2981 if (!(ntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
)) ret
|= RASTER_FONTTYPE
;
2985 static BOOL
get_face_enum_data( struct gdi_font_face
*face
, ENUMLOGFONTEXW
*elf
, NEWTEXTMETRICEXW
*ntm
)
2987 struct gdi_font
*font
;
2988 LOGFONTW lf
= { .lfHeight
= -4096 /* preferable EM Square size */ };
2990 if (!face
->scalable
) lf
.lfHeight
= 0;
2992 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2994 if (!font_funcs
->load_font( font
))
2996 free_gdi_font( font
);
3000 if (font
->scalable
&& -lf
.lfHeight
% font
->otm
.otmEMSquare
!= 0)
3002 /* reload with the original EM Square size */
3003 lf
.lfHeight
= -font
->otm
.otmEMSquare
;
3004 free_gdi_font( font
);
3006 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
3007 if (!font_funcs
->load_font( font
))
3009 free_gdi_font( font
);
3014 if (font_funcs
->set_outline_text_metrics( font
))
3016 static const DWORD ntm_ppem
= 32;
3019 #define TM font->otm.otmTextMetrics
3020 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
3021 cell_height
= TM
.tmHeight
/ ( -lf
.lfHeight
/ font
->otm
.otmEMSquare
);
3022 ntm
->ntmTm
.tmHeight
= muldiv( ntm_ppem
, cell_height
, font
->otm
.otmEMSquare
);
3023 ntm
->ntmTm
.tmAscent
= SCALE_NTM( TM
.tmAscent
);
3024 ntm
->ntmTm
.tmDescent
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmAscent
;
3025 ntm
->ntmTm
.tmInternalLeading
= SCALE_NTM( TM
.tmInternalLeading
);
3026 ntm
->ntmTm
.tmExternalLeading
= SCALE_NTM( TM
.tmExternalLeading
);
3027 ntm
->ntmTm
.tmAveCharWidth
= SCALE_NTM( TM
.tmAveCharWidth
);
3028 ntm
->ntmTm
.tmMaxCharWidth
= SCALE_NTM( TM
.tmMaxCharWidth
);
3030 memcpy((char *)&ntm
->ntmTm
+ offsetof( TEXTMETRICW
, tmWeight
),
3031 (const char *)&TM
+ offsetof( TEXTMETRICW
, tmWeight
),
3032 sizeof(TEXTMETRICW
) - offsetof( TEXTMETRICW
, tmWeight
));
3033 ntm
->ntmTm
.ntmSizeEM
= font
->otm
.otmEMSquare
;
3034 ntm
->ntmTm
.ntmCellHeight
= cell_height
;
3035 ntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
3039 else if (font_funcs
->set_bitmap_text_metrics( font
))
3041 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
3042 ntm
->ntmTm
.ntmSizeEM
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmInternalLeading
;
3043 ntm
->ntmTm
.ntmCellHeight
= ntm
->ntmTm
.tmHeight
;
3044 ntm
->ntmTm
.ntmAvgWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3046 ntm
->ntmTm
.ntmFlags
= font
->ntmFlags
;
3047 ntm
->ntmFontSig
= font
->fs
;
3049 elf
->elfLogFont
.lfEscapement
= 0;
3050 elf
->elfLogFont
.lfOrientation
= 0;
3051 elf
->elfLogFont
.lfHeight
= ntm
->ntmTm
.tmHeight
;
3052 elf
->elfLogFont
.lfWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3053 elf
->elfLogFont
.lfWeight
= ntm
->ntmTm
.tmWeight
;
3054 elf
->elfLogFont
.lfItalic
= ntm
->ntmTm
.tmItalic
;
3055 elf
->elfLogFont
.lfUnderline
= ntm
->ntmTm
.tmUnderlined
;
3056 elf
->elfLogFont
.lfStrikeOut
= ntm
->ntmTm
.tmStruckOut
;
3057 elf
->elfLogFont
.lfCharSet
= ntm
->ntmTm
.tmCharSet
;
3058 elf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3059 elf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3060 elf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3061 elf
->elfLogFont
.lfPitchAndFamily
= (ntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3062 lstrcpynW( elf
->elfLogFont
.lfFaceName
, (WCHAR
*)font
->otm
.otmpFamilyName
, LF_FACESIZE
);
3063 lstrcpynW( elf
->elfFullName
, (WCHAR
*)font
->otm
.otmpFaceName
, LF_FULLFACESIZE
);
3064 lstrcpynW( elf
->elfStyle
, (WCHAR
*)font
->otm
.otmpStyleName
, LF_FACESIZE
);
3066 free_gdi_font( font
);
3070 static BOOL
family_matches( struct gdi_font_family
*family
, const WCHAR
*face_name
)
3072 struct gdi_font_face
*face
;
3074 if (!facename_compare( face_name
, family
->family_name
, LF_FACESIZE
- 1 )) return TRUE
;
3075 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3076 if (!facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 )) return TRUE
;
3080 static BOOL
face_matches( const WCHAR
*family_name
, struct gdi_font_face
*face
, const WCHAR
*face_name
)
3082 if (!facename_compare( face_name
, family_name
, LF_FACESIZE
- 1)) return TRUE
;
3083 return !facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 );
3086 static BOOL
enum_face_charsets( const struct gdi_font_family
*family
, struct gdi_font_face
*face
,
3087 struct enum_charset
*list
, DWORD count
, FONTENUMPROCW proc
, LPARAM lparam
,
3088 const WCHAR
*subst
)
3091 NEWTEXTMETRICEXW ntm
;
3094 if (!face
->cached_enum_data
)
3096 struct gdi_font_enum_data
*data
;
3098 if (!(data
= calloc( 1, sizeof(*data
) )) ||
3099 !get_face_enum_data( face
, &data
->elf
, &data
->ntm
))
3104 face
->cached_enum_data
= data
;
3107 elf
= face
->cached_enum_data
->elf
;
3108 ntm
= face
->cached_enum_data
->ntm
;
3109 type
= get_font_type( &ntm
);
3111 /* font replacement */
3112 if (family
!= face
->family
)
3114 lstrcpynW( elf
.elfLogFont
.lfFaceName
, family
->family_name
, LF_FACESIZE
);
3115 lstrcpynW( elf
.elfFullName
, face
->full_name
, LF_FULLFACESIZE
);
3117 if (subst
) lstrcpynW( elf
.elfLogFont
.lfFaceName
, subst
, LF_FACESIZE
);
3119 for (i
= 0; i
< count
; i
++)
3121 if (face
->fs
.fsCsb
[0] == 0) /* OEM */
3123 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3124 elf
.elfScript
[0] = 32;
3125 i
= count
; /* break out of loop after enumeration */
3129 if (!(face
->fs
.fsCsb
[0] & list
[i
].mask
)) continue;
3130 /* use the DEFAULT_CHARSET case only if no other charset is present */
3131 if (list
[i
].charset
== DEFAULT_CHARSET
&& (face
->fs
.fsCsb
[0] & ~list
[i
].mask
)) continue;
3132 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
[i
].charset
;
3133 /* caller may fill elfScript with the actual string, see load_script_name */
3134 elf
.elfScript
[0] = list
[i
].script
;
3136 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3137 debugstr_w(elf
.elfLogFont
.lfFaceName
), debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3138 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
3139 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
, ntm
.ntmTm
.ntmFlags
);
3140 /* release section before callback (FIXME) */
3141 pthread_mutex_unlock( &font_lock
);
3142 if (!proc( &elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
3143 pthread_mutex_lock( &font_lock
);
3148 /*************************************************************
3151 static BOOL CDECL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, FONTENUMPROCW proc
, LPARAM lparam
)
3153 struct gdi_font_family
*family
;
3154 struct gdi_font_face
*face
;
3155 struct enum_charset enum_charsets
[32];
3156 DWORD count
, charset
;
3158 charset
= lf
? lf
->lfCharSet
: DEFAULT_CHARSET
;
3160 count
= create_enum_charset_list( charset
, enum_charsets
);
3162 pthread_mutex_lock( &font_lock
);
3164 if (lf
&& lf
->lfFaceName
[0])
3166 const WCHAR
*face_name
= get_gdi_font_subst( lf
->lfFaceName
, charset
, NULL
);
3167 const WCHAR
*orig_name
= NULL
;
3169 TRACE( "facename = %s charset %d\n", debugstr_w(lf
->lfFaceName
), charset
);
3172 orig_name
= lf
->lfFaceName
;
3173 TRACE( "substituting %s -> %s\n", debugstr_w(lf
->lfFaceName
), debugstr_w(face_name
) );
3175 else face_name
= lf
->lfFaceName
;
3177 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3179 if (!family_matches(family
, face_name
)) continue;
3180 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3182 if (!face_matches( family
->family_name
, face
, face_name
)) continue;
3183 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, orig_name
))
3190 TRACE( "charset %d\n", charset
);
3191 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3193 face
= LIST_ENTRY( list_head(get_family_face_list(family
)), struct gdi_font_face
, entry
);
3194 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, NULL
))
3198 pthread_mutex_unlock( &font_lock
);
3203 static BOOL
check_unicode_tategaki( WCHAR ch
)
3205 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
3206 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[ch
>> 8]+((ch
>> 4) & 0x0f)]+ (ch
& 0xf)];
3208 /* We only reach this code if typographical substitution did not occur */
3209 /* Type: U or Type: Tu */
3210 return (orientation
== 1 || orientation
== 3);
3213 static UINT
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
3217 if (glyph
< 0x100) glyph
+= 0xf000;
3218 /* there are a number of old pre-Unicode "broken" TTFs, which
3219 do have symbols at U+00XX instead of U+f0XX */
3221 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3224 index
= glyph
- 0xf000;
3225 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3230 CPTABLEINFO
*get_cptable( WORD cp
)
3232 static CPTABLEINFO tables
[100];
3238 for (i
= 0; i
< ARRAY_SIZE(tables
) && tables
[i
].CodePage
; i
++)
3239 if (tables
[i
].CodePage
== cp
) return &tables
[i
];
3240 if (NtGetNlsSectionPtr( 11, cp
, NULL
, (void **)&ptr
, &size
)) return NULL
;
3241 if (i
== ARRAY_SIZE(tables
))
3243 ERR( "too many code pages\n" );
3248 info
->CodePage
= ptr
[1];
3249 info
->MaximumCharacterSize
= ptr
[2];
3250 info
->DefaultChar
= ptr
[3];
3251 info
->UniDefaultChar
= ptr
[4];
3252 info
->TransDefaultChar
= ptr
[5];
3253 info
->TransUniDefaultChar
= ptr
[6];
3254 memcpy( info
->LeadByte
, ptr
+ 7, sizeof(info
->LeadByte
) );
3257 info
->WideCharTable
= ptr
+ ptr
[0] + 1;
3258 info
->MultiByteTable
= ++ptr
;
3260 if (*ptr
++) ptr
+= 256; /* glyph table */
3261 info
->DBCSRanges
= ptr
;
3262 if (*ptr
) /* dbcs ranges */
3264 info
->DBCSCodePage
= 1;
3265 info
->DBCSOffsets
= ptr
+ 1;
3269 info
->DBCSCodePage
= 0;
3270 info
->DBCSOffsets
= NULL
;
3276 DWORD
win32u_wctomb( CPTABLEINFO
*info
, char *dst
, DWORD dstlen
, const WCHAR
*src
, DWORD srclen
)
3280 if (!info
&& !(info
= get_cptable( get_acp() ))) return 0;
3282 srclen
/= sizeof(WCHAR
);
3283 if (info
->DBCSCodePage
)
3285 WCHAR
*uni2cp
= info
->WideCharTable
;
3287 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++)
3289 if (uni2cp
[*src
] & 0xff00)
3291 if (i
== 1) break; /* do not output a partial char */
3293 *dst
++ = uni2cp
[*src
] >> 8;
3295 *dst
++ = (char)uni2cp
[*src
];
3301 char *uni2cp
= info
->WideCharTable
;
3302 ret
= min( srclen
, dstlen
);
3303 for (i
= 0; i
< ret
; i
++) dst
[i
] = uni2cp
[src
[i
]];
3308 DWORD
win32u_mbtowc( CPTABLEINFO
*info
, WCHAR
*dst
, DWORD dstlen
, const char *src
, DWORD srclen
)
3312 if (!info
&& !(info
= get_cptable( get_acp() ))) return 0;
3314 dstlen
/= sizeof(WCHAR
);
3315 if (info
->DBCSOffsets
)
3317 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++, dst
++)
3319 USHORT off
= info
->DBCSOffsets
[(unsigned char)*src
];
3320 if (off
&& srclen
> 1)
3324 *dst
= info
->DBCSOffsets
[off
+ (unsigned char)*src
];
3326 else *dst
= info
->MultiByteTable
[(unsigned char)*src
];
3332 ret
= min( srclen
, dstlen
);
3333 for (i
= 0; i
< ret
; i
++) dst
[i
] = info
->MultiByteTable
[(unsigned char)src
[i
]];
3335 return ret
* sizeof(WCHAR
);
3338 static BOOL
wc_to_index( UINT cp
, WCHAR wc
, unsigned char *dst
, BOOL allow_default
)
3340 const CPTABLEINFO
*info
;
3342 if (!(info
= get_cptable( cp
))) return FALSE
;
3344 if (info
->DBCSCodePage
)
3346 WCHAR
*uni2cp
= info
->WideCharTable
;
3347 if (uni2cp
[wc
] & 0xff00) return FALSE
;
3352 char *uni2cp
= info
->WideCharTable
;
3356 if (info
->MultiByteTable
[*dst
] != wc
)
3358 if (!allow_default
) return FALSE
;
3359 *dst
= info
->DefaultChar
;
3365 static UINT
get_glyph_index( struct gdi_font
*font
, UINT glyph
)
3370 if (font_funcs
->get_glyph_index( font
, &glyph
, TRUE
)) return glyph
;
3372 if (font
->codepage
== CP_SYMBOL
)
3374 glyph
= get_glyph_index_symbol( font
, wc
);
3377 if (wc_to_index( CP_ACP
, wc
, &ch
, TRUE
))
3378 glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
3381 else if (wc_to_index( font
->codepage
, wc
, &ch
, FALSE
))
3383 glyph
= (unsigned char)ch
;
3384 font_funcs
->get_glyph_index( font
, &glyph
, FALSE
);
3391 static UINT
get_glyph_index_linked( struct gdi_font
**font
, UINT glyph
)
3393 struct gdi_font
*child
;
3396 if ((res
= get_glyph_index( *font
, glyph
))) return res
;
3397 if (glyph
< 32) return 0; /* don't check linked fonts for control characters */
3399 LIST_FOR_EACH_ENTRY( child
, &(*font
)->child_fonts
, struct gdi_font
, entry
)
3401 if (!child
->private && !font_funcs
->load_font( child
)) continue;
3402 if ((res
= get_glyph_index( child
, glyph
)))
3411 static DWORD
get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3412 GLYPHMETRICS
*gm_ret
, ABC
*abc_ret
, DWORD buflen
, void *buf
,
3419 BOOL tategaki
= (*get_gdi_font_name( font
) == '@');
3421 if (format
& GGO_GLYPH_INDEX
)
3423 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3424 as glyph index. "Treasure Adventure Game" depends on this. */
3425 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3426 format
&= ~GGO_GLYPH_INDEX
;
3427 /* TODO: Window also turns off tategaki for glyphs passed in by index
3428 if their unicode code points fall outside of the range that is
3433 index
= get_glyph_index_linked( &font
, glyph
);
3437 index
= get_GSUB_vert_glyph( font
, index
);
3438 if (index
== orig
) tategaki
= check_unicode_tategaki( glyph
);
3442 if (mat
&& !memcmp( mat
, &identity
, sizeof(*mat
) )) mat
= NULL
;
3444 if (format
== GGO_METRICS
&& !mat
&& get_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
))
3447 ret
= font_funcs
->get_glyph_outline( font
, index
, format
, &gm
, &abc
, buflen
, buf
, mat
, tategaki
);
3448 if (ret
== GDI_ERROR
) return ret
;
3450 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) && !mat
)
3451 set_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
);
3454 if (gm_ret
) *gm_ret
= gm
;
3455 if (abc_ret
) *abc_ret
= abc
;
3460 /*************************************************************
3463 static BOOL CDECL
font_FontIsLinked( PHYSDEV dev
)
3465 struct font_physdev
*physdev
= get_font_dev( dev
);
3469 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
3470 return dev
->funcs
->pFontIsLinked( dev
);
3472 return !list_empty( &physdev
->font
->child_fonts
);
3476 /*************************************************************
3477 * font_GetCharABCWidths
3479 static BOOL CDECL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT count
,
3480 WCHAR
*chars
, ABC
*buffer
)
3482 struct font_physdev
*physdev
= get_font_dev( dev
);
3487 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
3488 return dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
3491 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3493 pthread_mutex_lock( &font_lock
);
3494 for (i
= 0; i
< count
; i
++)
3496 c
= chars
? chars
[i
] : first
+ i
;
3497 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &buffer
[i
], 0, NULL
, NULL
);
3499 pthread_mutex_unlock( &font_lock
);
3504 /*************************************************************
3505 * font_GetCharABCWidthsI
3507 static BOOL CDECL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
3509 struct font_physdev
*physdev
= get_font_dev( dev
);
3514 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
3515 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
3518 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3520 pthread_mutex_lock( &font_lock
);
3521 for (c
= 0; c
< count
; c
++, buffer
++)
3522 get_glyph_outline( physdev
->font
, gi
? gi
[c
] : first
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3523 NULL
, buffer
, 0, NULL
, NULL
);
3524 pthread_mutex_unlock( &font_lock
);
3529 /*************************************************************
3532 static BOOL CDECL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT count
,
3533 const WCHAR
*chars
, INT
*buffer
)
3535 struct font_physdev
*physdev
= get_font_dev( dev
);
3541 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
3542 return dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buffer
);
3545 TRACE( "%p, %d, %d, %p\n", physdev
->font
, first
, count
, buffer
);
3547 pthread_mutex_lock( &font_lock
);
3548 for (i
= 0; i
< count
; i
++)
3550 c
= chars
? chars
[i
] : i
+ first
;
3551 if (get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
) == GDI_ERROR
)
3554 buffer
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3556 pthread_mutex_unlock( &font_lock
);
3561 /*************************************************************
3562 * font_GetCharWidthInfo
3564 static BOOL CDECL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
3566 struct font_physdev
*physdev
= get_font_dev( dev
);
3567 struct char_width_info
*info
= ptr
;
3571 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
3572 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
3576 if (!physdev
->font
->scalable
|| !font_funcs
->get_char_width_info( physdev
->font
, info
))
3577 info
->lsb
= info
->rsb
= 0;
3583 /*************************************************************
3586 static DWORD CDECL
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
3588 struct font_physdev
*physdev
= get_font_dev( dev
);
3592 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
3593 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
3595 return font_funcs
->get_font_data( physdev
->font
, table
, offset
, buf
, size
);
3599 /*************************************************************
3600 * font_GetFontRealizationInfo
3602 static BOOL CDECL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
3604 struct font_physdev
*physdev
= get_font_dev( dev
);
3605 struct font_realization_info
*info
= ptr
;
3609 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
3610 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
3613 TRACE( "(%p, %p)\n", physdev
->font
, info
);
3616 if (physdev
->font
->scalable
) info
->flags
|= 2;
3618 info
->cache_num
= physdev
->font
->cache_num
;
3619 info
->instance_id
= physdev
->font
->handle
;
3620 if (info
->size
== sizeof(*info
))
3622 info
->file_count
= 1;
3623 info
->face_index
= physdev
->font
->face_index
;
3624 info
->simulations
= 0;
3625 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
3626 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
3632 /*************************************************************
3633 * font_GetFontUnicodeRanges
3635 static DWORD CDECL
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
3637 struct font_physdev
*physdev
= get_font_dev( dev
);
3638 DWORD size
, num_ranges
;
3642 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
3643 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
3646 num_ranges
= font_funcs
->get_unicode_ranges( physdev
->font
, glyphset
);
3647 size
= offsetof( GLYPHSET
, ranges
[num_ranges
] );
3650 glyphset
->cbThis
= size
;
3651 glyphset
->cRanges
= num_ranges
;
3652 glyphset
->flAccel
= 0;
3658 /*************************************************************
3659 * font_GetGlyphIndices
3661 static DWORD CDECL
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
3663 struct font_physdev
*physdev
= get_font_dev( dev
);
3666 BOOL got_default
= FALSE
;
3671 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
3672 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
3675 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
3677 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
3681 pthread_mutex_lock( &font_lock
);
3683 for (i
= 0; i
< count
; i
++)
3685 UINT glyph
= str
[i
];
3687 if (!font_funcs
->get_glyph_index( physdev
->font
, &glyph
, TRUE
))
3690 if (physdev
->font
->codepage
== CP_SYMBOL
)
3692 if (str
[i
] >= 0xf020 && str
[i
] <= 0xf100) glyph
= str
[i
] - 0xf000;
3693 else if (str
[i
] < 0x100) glyph
= str
[i
];
3695 else if (wc_to_index( physdev
->font
->codepage
, str
[i
], &ch
, FALSE
))
3696 glyph
= (unsigned char)ch
;
3702 default_char
= font_funcs
->get_default_glyph( physdev
->font
);
3705 gi
[i
] = default_char
;
3707 else gi
[i
] = get_GSUB_vert_glyph( physdev
->font
, glyph
);
3710 pthread_mutex_unlock( &font_lock
);
3715 /*************************************************************
3716 * font_GetGlyphOutline
3718 static DWORD CDECL
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
3719 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
3721 struct font_physdev
*physdev
= get_font_dev( dev
);
3726 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
3727 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
3729 pthread_mutex_lock( &font_lock
);
3730 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, gm
, NULL
, buflen
, buf
, mat
);
3731 pthread_mutex_unlock( &font_lock
);
3736 /*************************************************************
3737 * font_GetKerningPairs
3739 static DWORD CDECL
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
3741 struct font_physdev
*physdev
= get_font_dev( dev
);
3745 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
3746 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
3749 pthread_mutex_lock( &font_lock
);
3750 if (physdev
->font
->kern_count
== -1)
3751 physdev
->font
->kern_count
= font_funcs
->get_kerning_pairs( physdev
->font
,
3752 &physdev
->font
->kern_pairs
);
3753 pthread_mutex_unlock( &font_lock
);
3757 count
= min( count
, physdev
->font
->kern_count
);
3758 memcpy( pairs
, physdev
->font
->kern_pairs
, count
* sizeof(*pairs
) );
3760 else count
= physdev
->font
->kern_count
;
3766 static void scale_outline_font_metrics( const struct gdi_font
*font
, OUTLINETEXTMETRICW
*otm
)
3768 double scale_x
, scale_y
;
3772 scale_x
= (double)font
->aveWidth
;
3773 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3776 scale_x
= font
->scale_y
;
3778 scale_x
*= fabs(font
->matrix
.eM11
);
3779 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3781 /* Windows scales these values as signed integers even if they are unsigned */
3782 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3783 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3785 SCALE_Y(otm
->otmTextMetrics
.tmHeight
);
3786 SCALE_Y(otm
->otmTextMetrics
.tmAscent
);
3787 SCALE_Y(otm
->otmTextMetrics
.tmDescent
);
3788 SCALE_Y(otm
->otmTextMetrics
.tmInternalLeading
);
3789 SCALE_Y(otm
->otmTextMetrics
.tmExternalLeading
);
3791 SCALE_X(otm
->otmTextMetrics
.tmOverhang
);
3792 if (font
->fake_bold
)
3794 if (!font
->scalable
) otm
->otmTextMetrics
.tmOverhang
++;
3795 otm
->otmTextMetrics
.tmAveCharWidth
++;
3796 otm
->otmTextMetrics
.tmMaxCharWidth
++;
3798 SCALE_X(otm
->otmTextMetrics
.tmAveCharWidth
);
3799 SCALE_X(otm
->otmTextMetrics
.tmMaxCharWidth
);
3801 SCALE_Y(otm
->otmAscent
);
3802 SCALE_Y(otm
->otmDescent
);
3803 SCALE_Y(otm
->otmLineGap
);
3804 SCALE_Y(otm
->otmsCapEmHeight
);
3805 SCALE_Y(otm
->otmsXHeight
);
3806 SCALE_Y(otm
->otmrcFontBox
.top
);
3807 SCALE_Y(otm
->otmrcFontBox
.bottom
);
3808 SCALE_X(otm
->otmrcFontBox
.left
);
3809 SCALE_X(otm
->otmrcFontBox
.right
);
3810 SCALE_Y(otm
->otmMacAscent
);
3811 SCALE_Y(otm
->otmMacDescent
);
3812 SCALE_Y(otm
->otmMacLineGap
);
3813 SCALE_X(otm
->otmptSubscriptSize
.x
);
3814 SCALE_Y(otm
->otmptSubscriptSize
.y
);
3815 SCALE_X(otm
->otmptSubscriptOffset
.x
);
3816 SCALE_Y(otm
->otmptSubscriptOffset
.y
);
3817 SCALE_X(otm
->otmptSuperscriptSize
.x
);
3818 SCALE_Y(otm
->otmptSuperscriptSize
.y
);
3819 SCALE_X(otm
->otmptSuperscriptOffset
.x
);
3820 SCALE_Y(otm
->otmptSuperscriptOffset
.y
);
3821 SCALE_Y(otm
->otmsStrikeoutSize
);
3822 SCALE_Y(otm
->otmsStrikeoutPosition
);
3823 SCALE_Y(otm
->otmsUnderscoreSize
);
3824 SCALE_Y(otm
->otmsUnderscorePosition
);
3830 /*************************************************************
3831 * font_GetOutlineTextMetrics
3833 static UINT CDECL
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
3835 struct font_physdev
*physdev
= get_font_dev( dev
);
3840 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
3841 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
3844 if (!physdev
->font
->scalable
) return 0;
3846 pthread_mutex_lock( &font_lock
);
3847 if (font_funcs
->set_outline_text_metrics( physdev
->font
))
3849 ret
= physdev
->font
->otm
.otmSize
;
3850 if (metrics
&& size
>= physdev
->font
->otm
.otmSize
)
3852 WCHAR
*ptr
= (WCHAR
*)(metrics
+ 1);
3853 *metrics
= physdev
->font
->otm
;
3854 metrics
->otmpFamilyName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3855 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFamilyName
);
3856 ptr
+= lstrlenW(ptr
) + 1;
3857 metrics
->otmpStyleName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3858 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpStyleName
);
3859 ptr
+= lstrlenW(ptr
) + 1;
3860 metrics
->otmpFaceName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3861 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFaceName
);
3862 ptr
+= lstrlenW(ptr
) + 1;
3863 metrics
->otmpFullName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3864 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFullName
);
3865 scale_outline_font_metrics( physdev
->font
, metrics
);
3868 pthread_mutex_unlock( &font_lock
);
3873 /*************************************************************
3874 * font_GetTextCharsetInfo
3876 static UINT CDECL
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
3878 struct font_physdev
*physdev
= get_font_dev( dev
);
3882 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
3883 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
3885 if (fs
) *fs
= physdev
->font
->fs
;
3886 return physdev
->font
->charset
;
3890 /*************************************************************
3891 * font_GetTextExtentExPoint
3893 static BOOL CDECL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
3895 struct font_physdev
*physdev
= get_font_dev( dev
);
3901 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
3902 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
3905 TRACE( "%p, %s, %d\n", physdev
->font
, debugstr_wn(str
, count
), count
);
3907 pthread_mutex_lock( &font_lock
);
3908 for (i
= pos
= 0; i
< count
; i
++)
3910 get_glyph_outline( physdev
->font
, str
[i
], GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
);
3911 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3914 pthread_mutex_unlock( &font_lock
);
3919 /*************************************************************
3920 * font_GetTextExtentExPointI
3922 static BOOL CDECL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
3924 struct font_physdev
*physdev
= get_font_dev( dev
);
3930 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
3931 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
3934 TRACE( "%p, %p, %d\n", physdev
->font
, indices
, count
);
3936 pthread_mutex_lock( &font_lock
);
3937 for (i
= pos
= 0; i
< count
; i
++)
3939 get_glyph_outline( physdev
->font
, indices
[i
], GGO_METRICS
| GGO_GLYPH_INDEX
,
3940 NULL
, &abc
, 0, NULL
, NULL
);
3941 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3944 pthread_mutex_unlock( &font_lock
);
3949 /*************************************************************
3952 static INT CDECL
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
3954 struct font_physdev
*physdev
= get_font_dev( dev
);
3955 const WCHAR
*font_name
;
3960 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
3961 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
3963 font_name
= get_gdi_font_name( physdev
->font
);
3964 len
= lstrlenW( font_name
) + 1;
3967 lstrcpynW( str
, font_name
, count
);
3968 len
= min( count
, len
);
3974 static void scale_font_metrics( struct gdi_font
*font
, TEXTMETRICW
*tm
)
3976 double scale_x
, scale_y
;
3978 /* Make sure that the font has sane width/height ratio */
3979 if (font
->aveWidth
&& (font
->aveWidth
+ tm
->tmHeight
- 1) / tm
->tmHeight
> 100)
3981 WARN( "Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
3987 scale_x
= (double)font
->aveWidth
;
3988 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3991 scale_x
= font
->scale_y
;
3993 scale_x
*= fabs(font
->matrix
.eM11
);
3994 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3996 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3997 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3999 SCALE_Y(tm
->tmHeight
);
4000 SCALE_Y(tm
->tmAscent
);
4001 SCALE_Y(tm
->tmDescent
);
4002 SCALE_Y(tm
->tmInternalLeading
);
4003 SCALE_Y(tm
->tmExternalLeading
);
4005 SCALE_X(tm
->tmOverhang
);
4006 if (font
->fake_bold
)
4008 if (!font
->scalable
) tm
->tmOverhang
++;
4009 tm
->tmAveCharWidth
++;
4010 tm
->tmMaxCharWidth
++;
4012 SCALE_X(tm
->tmAveCharWidth
);
4013 SCALE_X(tm
->tmMaxCharWidth
);
4019 /*************************************************************
4020 * font_GetTextMetrics
4022 static BOOL CDECL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
4024 struct font_physdev
*physdev
= get_font_dev( dev
);
4029 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
4030 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
4033 pthread_mutex_lock( &font_lock
);
4034 if (font_funcs
->set_outline_text_metrics( physdev
->font
) ||
4035 font_funcs
->set_bitmap_text_metrics( physdev
->font
))
4037 *metrics
= physdev
->font
->otm
.otmTextMetrics
;
4038 scale_font_metrics( physdev
->font
, metrics
);
4041 pthread_mutex_unlock( &font_lock
);
4046 static void get_nearest_charset( const WCHAR
*family_name
, struct gdi_font_face
*face
, CHARSETINFO
*csi
)
4048 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4049 a single face with the requested charset. The idea is to check if
4050 the selected font supports the current ANSI codepage, if it does
4051 return the corresponding charset, else return the first charset */
4055 if (translate_charset_info( (DWORD
*)(INT_PTR
)get_acp(), csi
, TCI_SRCCODEPAGE
))
4057 const struct gdi_font_link
*font_link
;
4059 if (csi
->fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return;
4060 font_link
= find_gdi_font_link(family_name
);
4061 if (font_link
&& (csi
->fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])) return;
4063 for (i
= 0; i
< 32; i
++)
4065 DWORD fs0
= 1u << i
;
4066 if (face
->fs
.fsCsb
[0] & fs0
)
4068 if (translate_charset_info(&fs0
, csi
, TCI_SRCFONTSIG
)) return;
4069 FIXME("TCI failing on %x\n", fs0
);
4073 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4074 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4075 csi
->ciACP
= get_acp();
4076 csi
->ciCharset
= DEFAULT_CHARSET
;
4079 static struct gdi_font
*select_font( LOGFONTW
*lf
, FMAT2 dcmat
, BOOL can_use_bitmap
)
4081 struct gdi_font
*font
;
4082 struct gdi_font_face
*face
;
4085 const WCHAR
*orig_name
= NULL
;
4086 BOOL substituted
= FALSE
;
4088 static const WCHAR symbolW
[] = {'S','y','m','b','o','l',0};
4090 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4091 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4092 original value lfCharSet. Note this is a special case for
4093 Symbol and doesn't happen at least for "Wingdings*" */
4094 if (!facename_compare( lf
->lfFaceName
, symbolW
, -1 )) lf
->lfCharSet
= SYMBOL_CHARSET
;
4096 /* check the cache first */
4097 if ((font
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4099 TRACE( "returning cached gdiFont(%p)\n", font
);
4102 if (!(face
= find_matching_face( lf
, &csi
, can_use_bitmap
, &substituted
, &orig_name
)))
4104 FIXME( "can't find a single appropriate font - bailing\n" );
4107 height
= lf
->lfHeight
;
4109 font
= create_gdi_font( face
, orig_name
, lf
);
4110 font
->use_logfont_name
= substituted
;
4111 font
->matrix
= dcmat
;
4112 font
->can_use_bitmap
= can_use_bitmap
;
4113 if (!csi
.fs
.fsCsb
[0]) get_nearest_charset( face
->family
->family_name
, face
, &csi
);
4114 font
->charset
= csi
.ciCharset
;
4115 font
->codepage
= csi
.ciACP
;
4117 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face
->full_name
), debugstr_w(face
->file
),
4118 face
->data_ptr
, face
->face_index
);
4120 font
->aveWidth
= height
? lf
->lfWidth
: 0;
4121 if (!face
->scalable
)
4123 /* Windows uses integer scaling factors for bitmap fonts */
4124 INT scale
, scaled_height
, diff
;
4125 struct gdi_font
*cachedfont
;
4128 diff
= height
- (signed int)face
->size
.height
;
4130 diff
= -height
- ((signed int)face
->size
.height
- face
->size
.internal_leading
);
4132 /* FIXME: rotation of bitmap fonts is ignored */
4133 height
= abs(GDI_ROUND( (double)height
* font
->matrix
.eM22
));
4135 font
->aveWidth
= (double)font
->aveWidth
* font
->matrix
.eM11
;
4136 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
4137 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4138 /* As we changed the matrix, we need to search the cache for the font again,
4139 * otherwise we might explode the cache. */
4140 if ((cachedfont
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4142 TRACE("Found cached font after non-scalable matrix rescale!\n");
4143 free_gdi_font( font
);
4147 if (height
!= 0) height
= diff
;
4148 height
+= face
->size
.height
;
4150 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4151 scaled_height
= scale
* face
->size
.height
;
4152 /* Only jump to the next height if the difference <= 25% original height */
4153 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4154 /* The jump between unscaled and doubled is delayed by 1 */
4155 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4156 font
->scale_y
= scale
;
4157 TRACE("font scale y: %d\n", font
->scale_y
);
4160 if (!font_funcs
->load_font( font
))
4162 free_gdi_font( font
);
4166 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
4167 font
->vert_feature
= get_GSUB_vert_feature( font
);
4169 create_child_font_list( font
);
4171 TRACE( "caching: gdiFont=%p\n", font
);
4172 cache_gdi_font( font
);
4176 /*************************************************************
4179 static HFONT CDECL
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4181 struct font_physdev
*physdev
= get_font_dev( dev
);
4182 struct gdi_font
*font
= NULL
, *prev
= physdev
->font
;
4183 DC
*dc
= get_physdev_dc( dev
);
4189 BOOL can_use_bitmap
= !!(NtGdiGetDeviceCaps( dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
);
4191 NtGdiExtGetObjectW( hfont
, sizeof(lf
), &lf
);
4192 switch (lf
.lfQuality
)
4194 case NONANTIALIASED_QUALITY
:
4195 if (!*aa_flags
) *aa_flags
= GGO_BITMAP
;
4197 case ANTIALIASED_QUALITY
:
4198 if (!*aa_flags
) *aa_flags
= GGO_GRAY4_BITMAP
;
4202 lf
.lfWidth
= abs(lf
.lfWidth
);
4204 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4205 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4206 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4209 if (dc
->attr
->graphics_mode
== GM_ADVANCED
)
4211 memcpy( &dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
) );
4212 /* try to avoid not necessary glyph transformations */
4213 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4215 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4216 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4217 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4222 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4223 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4224 dcmat
.eM21
= dcmat
.eM12
= 0;
4225 lf
.lfOrientation
= lf
.lfEscapement
;
4226 if (dc
->vport2WorldValid
)
4228 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4229 lf
.lfOrientation
= -lf
.lfOrientation
;
4230 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4231 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4234 TRACE( "DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
, dcmat
.eM21
, dcmat
.eM22
);
4236 pthread_mutex_lock( &font_lock
);
4238 font
= select_font( &lf
, dcmat
, can_use_bitmap
);
4242 if (!*aa_flags
) *aa_flags
= font
->aa_flags
;
4245 if (lf
.lfQuality
== CLEARTYPE_QUALITY
|| lf
.lfQuality
== CLEARTYPE_NATURAL_QUALITY
)
4246 *aa_flags
= subpixel_orientation
;
4248 *aa_flags
= font_smoothing
;
4250 *aa_flags
= font_funcs
->get_aa_flags( font
, *aa_flags
, antialias_fakes
);
4252 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
4253 pthread_mutex_unlock( &font_lock
);
4255 physdev
->font
= font
;
4256 if (prev
) release_gdi_font( prev
);
4257 return font
? hfont
: 0;
4261 const struct gdi_dc_funcs font_driver
=
4263 NULL
, /* pAbortDoc */
4264 NULL
, /* pAbortPath */
4265 NULL
, /* pAlphaBlend */
4266 NULL
, /* pAngleArc */
4269 NULL
, /* pBeginPath */
4270 NULL
, /* pBlendImage */
4272 NULL
, /* pCloseFigure */
4273 NULL
, /* pCreateCompatibleDC */
4274 font_CreateDC
, /* pCreateDC */
4275 font_DeleteDC
, /* pDeleteDC */
4276 NULL
, /* pDeleteObject */
4277 NULL
, /* pEllipse */
4279 NULL
, /* pEndPage */
4280 NULL
, /* pEndPath */
4281 font_EnumFonts
, /* pEnumFonts */
4282 NULL
, /* pExtEscape */
4283 NULL
, /* pExtFloodFill */
4284 NULL
, /* pExtTextOut */
4285 NULL
, /* pFillPath */
4286 NULL
, /* pFillRgn */
4287 font_FontIsLinked
, /* pFontIsLinked */
4288 NULL
, /* pFrameRgn */
4289 NULL
, /* pGetBoundsRect */
4290 font_GetCharABCWidths
, /* pGetCharABCWidths */
4291 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
4292 font_GetCharWidth
, /* pGetCharWidth */
4293 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
4294 NULL
, /* pGetDeviceCaps */
4295 NULL
, /* pGetDeviceGammaRamp */
4296 font_GetFontData
, /* pGetFontData */
4297 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
4298 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
4299 font_GetGlyphIndices
, /* pGetGlyphIndices */
4300 font_GetGlyphOutline
, /* pGetGlyphOutline */
4301 NULL
, /* pGetICMProfile */
4302 NULL
, /* pGetImage */
4303 font_GetKerningPairs
, /* pGetKerningPairs */
4304 NULL
, /* pGetNearestColor */
4305 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
4306 NULL
, /* pGetPixel */
4307 NULL
, /* pGetSystemPaletteEntries */
4308 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
4309 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
4310 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
4311 font_GetTextFace
, /* pGetTextFace */
4312 font_GetTextMetrics
, /* pGetTextMetrics */
4313 NULL
, /* pGradientFill */
4314 NULL
, /* pInvertRgn */
4317 NULL
, /* pPaintRgn */
4320 NULL
, /* pPolyBezier */
4321 NULL
, /* pPolyBezierTo */
4322 NULL
, /* pPolyDraw */
4323 NULL
, /* pPolyPolygon */
4324 NULL
, /* pPolyPolyline */
4325 NULL
, /* pPolylineTo */
4326 NULL
, /* pPutImage */
4327 NULL
, /* pRealizeDefaultPalette */
4328 NULL
, /* pRealizePalette */
4329 NULL
, /* pRectangle */
4330 NULL
, /* pResetDC */
4331 NULL
, /* pRoundRect */
4332 NULL
, /* pSelectBitmap */
4333 NULL
, /* pSelectBrush */
4334 font_SelectFont
, /* pSelectFont */
4335 NULL
, /* pSelectPen */
4336 NULL
, /* pSetBkColor */
4337 NULL
, /* pSetBoundsRect */
4338 NULL
, /* pSetDCBrushColor */
4339 NULL
, /* pSetDCPenColor */
4340 NULL
, /* pSetDIBitsToDevice */
4341 NULL
, /* pSetDeviceClipping */
4342 NULL
, /* pSetDeviceGammaRamp */
4343 NULL
, /* pSetPixel */
4344 NULL
, /* pSetTextColor */
4345 NULL
, /* pStartDoc */
4346 NULL
, /* pStartPage */
4347 NULL
, /* pStretchBlt */
4348 NULL
, /* pStretchDIBits */
4349 NULL
, /* pStrokeAndFillPath */
4350 NULL
, /* pStrokePath */
4351 NULL
, /* pUnrealizePalette */
4352 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
4353 NULL
, /* pD3DKMTSetVidPnSourceOwner */
4354 NULL
, /* wine_get_wgl_driver */
4355 NULL
, /* wine_get_vulkan_driver */
4356 GDI_PRIORITY_FONT_DRV
/* priority */
4359 static BOOL
get_key_value( HKEY key
, const char *name
, DWORD
*value
)
4361 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[12 * sizeof(WCHAR
)])];
4362 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4365 count
= query_reg_ascii_value( key
, name
, info
, sizeof(value_buffer
) );
4368 if (info
->Type
== REG_DWORD
) memcpy( value
, info
->Data
, sizeof(*value
) );
4369 else *value
= wcstol( (const WCHAR
*)info
->Data
, NULL
, 10 );
4374 static UINT
init_font_options(void)
4376 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[20 * sizeof(WCHAR
)])];
4377 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4379 DWORD i
, val
, gamma
= 1400;
4382 if (query_reg_ascii_value( wine_fonts_key
, "AntialiasFakeBoldOrItalic",
4383 info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
4385 static const WCHAR valsW
[] = {'y','Y','t','T','1',0};
4386 antialias_fakes
= (wcschr( valsW
, *(const WCHAR
*)info
->Data
) != NULL
);
4389 if ((key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
4391 /* FIXME: handle vertical orientations even though Windows doesn't */
4392 if (get_key_value( key
, "FontSmoothingOrientation", &val
))
4396 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4397 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
4399 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4400 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
4404 if (get_key_value( key
, "FontSmoothing", &val
) && val
/* enabled */)
4406 if (get_key_value( key
, "FontSmoothingType", &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4407 font_smoothing
= subpixel_orientation
;
4409 font_smoothing
= GGO_GRAY4_BITMAP
;
4411 if (get_key_value( key
, "FontSmoothingGamma", &val
) && val
)
4413 gamma
= min( max( val
, 1000 ), 2200 );
4415 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4419 /* Calibrating the difference between the registry value and the Wine gamma value.
4420 This looks roughly similar to Windows Native with the same registry value.
4421 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4422 gamma
= 1000 * gamma
/ 1400;
4425 for (i
= 0; i
< 256; i
++)
4427 font_gamma_ramp
.encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
4428 font_gamma_ramp
.decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
4432 if (!dpi
&& (key
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) )))
4434 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4439 font_gamma_ramp
.gamma
= gamma
;
4440 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp
.gamma
, dpi
);
4445 /* compute positions for text rendering, in device coords */
4446 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
4451 size
->cx
= size
->cy
= 0;
4452 if (!count
) return TRUE
;
4454 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4455 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4457 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
4458 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
4460 if (dc
->breakExtra
|| dc
->breakRem
)
4462 int i
, space
= 0, rem
= dc
->breakRem
;
4464 for (i
= 0; i
< count
; i
++)
4466 if (str
[i
] == tm
.tmBreakChar
)
4468 space
+= dc
->breakExtra
;
4478 size
->cx
= dx
[count
- 1];
4479 size
->cy
= tm
.tmHeight
;
4483 /* compute positions for text rendering, in device coords */
4484 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
4489 size
->cx
= size
->cy
= 0;
4490 if (!count
) return TRUE
;
4492 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4493 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4495 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
4496 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
4498 if (dc
->breakExtra
|| dc
->breakRem
)
4501 int i
, space
= 0, rem
= dc
->breakRem
;
4503 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4504 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
4506 for (i
= 0; i
< count
; i
++)
4508 if (indices
[i
] == space_index
)
4510 space
+= dc
->breakExtra
;
4520 size
->cx
= dx
[count
- 1];
4521 size
->cy
= tm
.tmHeight
;
4525 /***********************************************************************
4526 * get_text_charset_info
4528 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4530 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
4532 UINT ret
= DEFAULT_CHARSET
;
4535 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
4536 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4538 if (ret
== DEFAULT_CHARSET
&& fs
)
4539 memset(fs
, 0, sizeof(FONTSIGNATURE
));
4543 /***********************************************************************
4544 * NtGdiGetTextCharsetInfo (win32u.@)
4546 UINT WINAPI
NtGdiGetTextCharsetInfo( HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
4548 UINT ret
= DEFAULT_CHARSET
;
4549 DC
*dc
= get_dc_ptr(hdc
);
4553 ret
= get_text_charset_info( dc
, fs
, flags
);
4554 release_dc_ptr( dc
);
4559 /***********************************************************************
4560 * NtGdiHfontCreate (win32u.@)
4562 HFONT WINAPI
NtGdiHfontCreate( const ENUMLOGFONTEXDVW
*penumex
, ULONG size
, ULONG type
,
4563 ULONG flags
, void *data
)
4567 const LOGFONTW
*plf
;
4569 if (!penumex
) return 0;
4571 if (penumex
->elfEnumLogfontEx
.elfFullName
[0] ||
4572 penumex
->elfEnumLogfontEx
.elfStyle
[0] ||
4573 penumex
->elfEnumLogfontEx
.elfScript
[0])
4575 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4576 debugstr_w(penumex
->elfEnumLogfontEx
.elfFullName
),
4577 debugstr_w(penumex
->elfEnumLogfontEx
.elfStyle
),
4578 debugstr_w(penumex
->elfEnumLogfontEx
.elfScript
));
4581 plf
= &penumex
->elfEnumLogfontEx
.elfLogFont
;
4582 if (!(fontPtr
= malloc( sizeof(*fontPtr
) ))) return 0;
4584 fontPtr
->logfont
= *plf
;
4586 if (!(hFont
= alloc_gdi_handle( &fontPtr
->obj
, NTGDI_OBJ_FONT
, &fontobj_funcs
)))
4592 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4593 plf
->lfHeight
, plf
->lfWidth
,
4594 plf
->lfEscapement
, plf
->lfOrientation
,
4595 plf
->lfPitchAndFamily
,
4596 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
4597 plf
->lfQuality
, plf
->lfCharSet
,
4598 debugstr_w(plf
->lfFaceName
),
4599 plf
->lfWeight
> 400 ? "Bold" : "",
4600 plf
->lfItalic
? "Italic" : "",
4601 plf
->lfUnderline
? "Underline" : "", hFont
);
4606 #define ASSOC_CHARSET_OEM 1
4607 #define ASSOC_CHARSET_ANSI 2
4608 #define ASSOC_CHARSET_SYMBOL 4
4610 static DWORD
get_associated_charset_info(void)
4612 static DWORD associated_charset
= -1;
4614 if (associated_charset
== -1)
4616 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[32 * sizeof(WCHAR
)])];
4617 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4620 static const WCHAR yesW
[] = {'y','e','s',0};
4622 associated_charset
= 0;
4624 if (!(hkey
= reg_open_key( NULL
, associated_charset_keyW
, sizeof(associated_charset_keyW
) )))
4627 if (query_reg_ascii_value( hkey
, "ANSI(00)", info
, sizeof(value_buffer
) ) &&
4628 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4629 associated_charset
|= ASSOC_CHARSET_ANSI
;
4631 if (query_reg_ascii_value( hkey
, "OEM(FF)", info
, sizeof(value_buffer
) ) &&
4632 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4633 associated_charset
|= ASSOC_CHARSET_OEM
;
4635 if (query_reg_ascii_value( hkey
, "SYMBOL(02)", info
, sizeof(value_buffer
) ) &&
4636 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4637 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
4641 TRACE("associated_charset = %d\n", associated_charset
);
4644 return associated_charset
;
4647 static void update_font_code_page( DC
*dc
, HANDLE font
)
4650 int charset
= get_text_charset_info( dc
, NULL
, 0 );
4652 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
4656 NtGdiExtGetObjectW( font
, sizeof(lf
), &lf
);
4657 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
4658 charset
= DEFAULT_CHARSET
;
4661 /* Hmm, nicely designed api this one! */
4662 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
4663 dc
->attr
->font_code_page
= csi
.ciACP
;
4667 dc
->attr
->font_code_page
= get_oemcp();
4669 case DEFAULT_CHARSET
:
4670 dc
->attr
->font_code_page
= get_acp();
4673 case VISCII_CHARSET
:
4679 case CELTIC_CHARSET
:
4680 /* FIXME: These have no place here, but because x11drv
4681 enumerates fonts with these (made up) charsets some apps
4682 might use them and then the FIXME below would become
4683 annoying. Now we could pick the intended codepage for
4684 each of these, but since it's broken anyway we'll just
4685 use CP_ACP and hope it'll go away...
4687 dc
->attr
->font_code_page
= CP_ACP
;
4691 FIXME("Can't find codepage for charset %d\n", charset
);
4692 dc
->attr
->font_code_page
= CP_ACP
;
4697 TRACE( "charset %d => cp %d\n", charset
, dc
->attr
->font_code_page
);
4700 /***********************************************************************
4701 * NtGdiSelectFont (win32u.@)
4703 HGDIOBJ WINAPI
NtGdiSelectFont( HDC hdc
, HGDIOBJ handle
)
4706 DC
*dc
= get_dc_ptr( hdc
);
4712 if (!GDI_inc_ref_count( handle
))
4714 release_dc_ptr( dc
);
4718 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
4719 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
4723 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
4724 update_font_code_page( dc
, handle
);
4725 if (dc
->font_gamma_ramp
== NULL
)
4726 dc
->font_gamma_ramp
= &font_gamma_ramp
;
4727 GDI_dec_ref_count( ret
);
4729 else GDI_dec_ref_count( handle
);
4731 release_dc_ptr( dc
);
4736 /***********************************************************************
4739 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
4741 FONTOBJ
*font
= GDI_GetObjPtr( handle
, NTGDI_OBJ_FONT
);
4743 if (!font
) return 0;
4746 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
4747 memcpy( buffer
, &font
->logfont
, count
);
4749 else count
= sizeof(LOGFONTW
);
4750 GDI_ReleaseObj( handle
);
4755 /***********************************************************************
4758 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
4762 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
4771 struct font_enum_entry
*buf
;
4777 static INT WINAPI
font_enum_proc( const LOGFONTW
*lf
, const TEXTMETRICW
*tm
,
4778 DWORD type
, LPARAM lp
)
4780 struct font_enum
*fe
= (struct font_enum
*)lp
;
4782 if (fe
->charset
!= DEFAULT_CHARSET
&& lf
->lfCharSet
!= fe
->charset
) return 1;
4783 if ((type
& RASTER_FONTTYPE
) && !(NtGdiGetDeviceCaps( fe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
))
4786 if (fe
->buf
&& fe
->count
< fe
->size
)
4788 fe
->buf
[fe
->count
].type
= type
;
4789 fe
->buf
[fe
->count
].lf
= *(const ENUMLOGFONTEXW
*)lf
;
4790 fe
->buf
[fe
->count
].tm
= *(const NEWTEXTMETRICEXW
*)tm
;
4796 /***********************************************************************
4797 * NtGdiEnumFonts (win32u.@)
4799 BOOL WINAPI
NtGdiEnumFonts( HDC hdc
, ULONG type
, ULONG win32_compat
, ULONG face_name_len
,
4800 const WCHAR
*face_name
, ULONG charset
, ULONG
*count
, void *buf
)
4802 struct font_enum fe
;
4808 if (!(dc
= get_dc_ptr( hdc
))) return 0;
4810 memset( &lf
, 0, sizeof(lf
) );
4811 lf
.lfCharSet
= charset
;
4812 if (face_name_len
) memcpy( lf
.lfFaceName
, face_name
, face_name_len
* sizeof(WCHAR
) );
4816 fe
.size
= *count
/ sizeof(*fe
.buf
);
4818 fe
.charset
= charset
;
4820 physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
4821 ret
= physdev
->funcs
->pEnumFonts( physdev
, &lf
, font_enum_proc
, (LPARAM
)&fe
);
4822 if (ret
&& buf
) ret
= fe
.count
<= fe
.size
;
4823 *count
= fe
.count
* sizeof(*fe
.buf
);
4825 release_dc_ptr( dc
);
4830 /***********************************************************************
4831 * NtGdiSetTextJustification (win32u.@)
4833 BOOL WINAPI
NtGdiSetTextJustification( HDC hdc
, INT extra
, INT breaks
)
4837 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
4839 extra
= abs( (extra
* dc
->attr
->vport_ext
.cx
+ dc
->attr
->wnd_ext
.cx
/ 2) /
4840 dc
->attr
->wnd_ext
.cx
);
4841 if (!extra
) breaks
= 0;
4844 dc
->breakExtra
= extra
/ breaks
;
4845 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
4853 release_dc_ptr( dc
);
4858 /***********************************************************************
4859 * NtGdiGetTextFaceW (win32u.@)
4861 INT WINAPI
NtGdiGetTextFaceW( HDC hdc
, INT count
, WCHAR
*name
, BOOL alias_name
)
4866 DC
* dc
= get_dc_ptr( hdc
);
4869 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
4870 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
4871 release_dc_ptr( dc
);
4876 /***********************************************************************
4877 * NtGdiGetTextExtentExW (win32u.@)
4879 * Return the size of the string as it would be if it was output properly by
4882 BOOL WINAPI
NtGdiGetTextExtentExW( HDC hdc
, const WCHAR
*str
, INT count
, INT max_ext
,
4883 INT
*nfit
, INT
*dxs
, SIZE
*size
, UINT flags
)
4888 INT buffer
[256], *pos
= dxs
;
4890 if (count
< 0) return FALSE
;
4892 dc
= get_dc_ptr(hdc
);
4893 if (!dc
) return FALSE
;
4898 if (count
> 256 && !(pos
= malloc( count
* sizeof(*pos
) )))
4900 release_dc_ptr( dc
);
4907 ret
= get_char_positions_indices( dc
, str
, count
, pos
, size
);
4909 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
4914 for (i
= 0; i
< count
; i
++)
4916 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) +
4917 (i
+ 1) * dc
->attr
->char_extra
;
4918 if (nfit
&& dx
> (unsigned int)max_ext
) break;
4919 if (dxs
) dxs
[i
] = dx
;
4921 if (nfit
) *nfit
= i
;
4924 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->attr
->char_extra
;
4925 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
4928 if (pos
!= buffer
&& pos
!= dxs
) free( pos
);
4929 release_dc_ptr( dc
);
4931 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
4935 /***********************************************************************
4936 * NtGdiGetTextMetricsW (win32u.@)
4938 BOOL WINAPI
NtGdiGetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
, ULONG flags
)
4942 DC
* dc
= get_dc_ptr( hdc
);
4943 if (!dc
) return FALSE
;
4945 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4946 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
4950 /* device layer returns values in device units
4951 * therefore we have to convert them to logical */
4953 metrics
->tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
4954 metrics
->tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
4955 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
4956 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
4957 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
4958 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
4959 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
4960 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
4961 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
4962 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
4965 TRACE("text metrics:\n"
4966 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
4967 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
4968 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
4969 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
4970 " PitchAndFamily = %02x\n"
4971 " --------------------\n"
4972 " InternalLeading = %i\n"
4976 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
4977 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
4978 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
4979 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
4980 metrics
->tmPitchAndFamily
,
4981 metrics
->tmInternalLeading
,
4984 metrics
->tmHeight
);
4986 release_dc_ptr( dc
);
4991 /***********************************************************************
4992 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
4994 UINT WINAPI
NtGdiGetOutlineTextMetricsInternalW( HDC hdc
, UINT cbData
,
4995 OUTLINETEXTMETRICW
*lpOTM
, ULONG opts
)
4997 DC
*dc
= get_dc_ptr( hdc
);
4998 OUTLINETEXTMETRICW
*output
= lpOTM
;
5002 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
5005 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
5006 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
5008 if (lpOTM
&& ret
> cbData
)
5010 output
= malloc( ret
);
5011 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
5016 output
->otmTextMetrics
.tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
5017 output
->otmTextMetrics
.tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
5018 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
5019 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
5020 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
5021 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
5022 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
5023 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
5024 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
5025 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
5026 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
5027 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
5028 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
5029 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
5030 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
5031 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
5032 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
5033 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
5034 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
5035 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
5036 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
5037 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
5038 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
5039 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
5040 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
5041 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
5042 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
5043 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
5044 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
5045 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
5046 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
5047 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
5048 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
5049 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
5053 memcpy(lpOTM
, output
, cbData
);
5062 /***********************************************************************
5063 * NtGdiGetCharWidthW (win32u.@)
5065 BOOL WINAPI
NtGdiGetCharWidthW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5066 ULONG flags
, void *buf
)
5068 UINT i
, count
= last
;
5073 if (flags
& NTGDI_GETCHARWIDTH_INDICES
)
5078 if (!(abc
= malloc( count
* sizeof(ABC
) )))
5081 if (!NtGdiGetCharABCWidthsW( hdc
, first
, last
, chars
,
5082 NTGDI_GETCHARABCWIDTHS_INT
| NTGDI_GETCHARABCWIDTHS_INDICES
,
5089 for (i
= 0; i
< count
; i
++)
5090 ((INT
*)buf
)[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
5096 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
5098 if (!chars
) count
= last
- first
+ 1;
5099 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
5100 ret
= dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buf
);
5104 if (flags
& NTGDI_GETCHARWIDTH_INT
)
5107 /* convert device units to logical */
5108 for (i
= 0; i
< count
; i
++)
5109 buffer
[i
] = width_to_LP( dc
, buffer
[i
] );
5113 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
5114 for (i
= 0; i
< count
; i
++)
5115 ((float *)buf
)[i
] = ((int *)buf
)[i
] * scale
;
5118 release_dc_ptr( dc
);
5123 /* helper for nulldrv_ExtTextOut */
5124 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
5125 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
5127 UINT indices
[3] = {0, 0, 0x20};
5133 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
5135 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
5138 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
, FALSE
);
5139 if (ret
!= GDI_ERROR
) break;
5142 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
5143 if (!image
) return ERROR_SUCCESS
;
5147 if (!ret
) /* empty glyph */
5149 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
5150 return ERROR_SUCCESS
;
5153 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5154 size
= metrics
->gmBlackBoxY
* stride
;
5156 if (!(image
->ptr
= malloc( size
))) return ERROR_OUTOFMEMORY
;
5157 image
->is_copy
= TRUE
;
5158 image
->free
= free_heap_bits
;
5160 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
,
5162 if (ret
== GDI_ERROR
)
5165 return ERROR_NOT_FOUND
;
5167 return ERROR_SUCCESS
;
5170 /* helper for nulldrv_ExtTextOut */
5171 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
5172 LPCWSTR str
, UINT count
, const INT
*dx
)
5177 reset_bounds( &bounds
);
5178 for (i
= 0; i
< count
; i
++)
5180 GLYPHMETRICS metrics
;
5182 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
5184 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
5185 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
5186 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
5187 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
5188 add_bounds_rect( &bounds
, &rect
);
5192 if (flags
& ETO_PDY
)
5195 y
+= dx
[ i
* 2 + 1];
5201 x
+= metrics
.gmCellIncX
;
5202 y
+= metrics
.gmCellIncY
;
5208 /* helper for nulldrv_ExtTextOut */
5209 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
5210 const struct gdi_image_bits
*image
, const RECT
*clip
)
5212 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5213 UINT i
, count
, max_count
;
5215 BYTE
*ptr
= image
->ptr
;
5216 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5218 RECT rect
, clipped_rect
;
5220 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
5221 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
5222 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
5223 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
5224 if (!clip
) clipped_rect
= rect
;
5225 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
5227 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
5228 pts
= malloc( max_count
* sizeof(*pts
) );
5232 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
5233 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
5235 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
5237 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5238 pts
[count
].x
= rect
.left
+ x
;
5239 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5240 pts
[count
+ 1].x
= rect
.left
+ x
;
5241 if (pts
[count
+ 1].x
> pts
[count
].x
)
5243 pts
[count
].y
= pts
[count
+ 1].y
= y
;
5248 assert( count
<= max_count
);
5249 dp_to_lp( dc
, pts
, count
);
5250 for (i
= 0; i
< count
; i
+= 2)
5252 const UINT pts_count
= 2;
5253 NtGdiPolyPolyDraw( dc
->hSelf
, pts
+ i
, &pts_count
, 1, NtGdiPolyPolyline
);
5258 /***********************************************************************
5259 * nulldrv_ExtTextOut
5261 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5262 LPCWSTR str
, UINT count
, const INT
*dx
)
5264 DC
*dc
= get_nulldrv_dc( dev
);
5270 if (flags
& ETO_OPAQUE
)
5273 COLORREF brush_color
= NtGdiGetNearestColor( dev
->hdc
, dc
->attr
->background_color
);
5274 HBRUSH brush
= NtGdiCreateSolidBrush( brush_color
, NULL
);
5278 orig
= NtGdiSelectBrush( dev
->hdc
, brush
);
5279 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5280 NtGdiPatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5281 NtGdiSelectBrush( dev
->hdc
, orig
);
5282 NtGdiDeleteObjectApp( brush
);
5286 if (!count
) return TRUE
;
5288 if (dc
->aa_flags
!= GGO_BITMAP
)
5290 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5291 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5292 struct gdi_image_bits bits
;
5293 struct bitblt_coords src
, dst
;
5295 /* FIXME Subpixel modes */
5296 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5298 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5299 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5300 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5301 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5303 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5304 src
.x
= src
.visrect
.left
;
5305 src
.y
= src
.visrect
.top
;
5306 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5307 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5309 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5310 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5312 /* we can avoid the GetImage, just query the needed format */
5313 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5314 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5315 info
->bmiHeader
.biWidth
= src
.width
;
5316 info
->bmiHeader
.biHeight
= -src
.height
;
5317 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5318 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5319 if (!err
|| err
== ERROR_BAD_FORMAT
)
5321 /* make the source rectangle relative to the source bits */
5323 src
.visrect
.left
= src
.visrect
.top
= 0;
5324 src
.visrect
.right
= src
.width
;
5325 src
.visrect
.bottom
= src
.height
;
5327 bits
.ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5328 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5329 bits
.is_copy
= TRUE
;
5330 bits
.free
= free_heap_bits
;
5331 err
= ERROR_SUCCESS
;
5336 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5337 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5338 if (!err
&& !bits
.is_copy
)
5340 void *ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5343 if (bits
.free
) bits
.free( &bits
);
5344 return ERROR_OUTOFMEMORY
;
5346 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5347 if (bits
.free
) bits
.free( &bits
);
5349 bits
.is_copy
= TRUE
;
5350 bits
.free
= free_heap_bits
;
5355 /* make x,y relative to the image bits */
5356 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5357 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5358 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5359 aa_flags
, str
, count
, dx
);
5360 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5361 if (bits
.free
) bits
.free( &bits
);
5366 pen
= NtGdiCreatePen( PS_SOLID
, 1, dc
->attr
->text_color
, NULL
);
5367 orig
= NtGdiSelectPen( dev
->hdc
, pen
);
5369 for (i
= 0; i
< count
; i
++)
5371 GLYPHMETRICS metrics
;
5372 struct gdi_image_bits image
;
5374 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5377 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5378 if (image
.free
) image
.free( &image
);
5382 if (flags
& ETO_PDY
)
5385 y
+= dx
[ i
* 2 + 1];
5391 x
+= metrics
.gmCellIncX
;
5392 y
+= metrics
.gmCellIncY
;
5396 NtGdiSelectPen( dev
->hdc
, orig
);
5397 NtGdiDeleteObjectApp( pen
);
5401 /***********************************************************************
5404 * Scale the underline / strikeout line width.
5406 static inline int get_line_width( DC
*dc
, int metric_size
)
5408 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5409 if (width
== 0) width
= 1;
5410 if (metric_size
< 0) width
= -width
;
5414 /***********************************************************************
5415 * NtGdiExtTextOutW (win32u.@)
5417 * Draws text using the currently selected font, background color, and text color.
5421 * x,y [I] coordinates of string
5423 * ETO_GRAYED - undocumented on MSDN
5424 * ETO_OPAQUE - use background color for fill the rectangle
5425 * ETO_CLIPPED - clipping text to the rectangle
5426 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5427 * than encoded characters. Implies ETO_IGNORELANGUAGE
5428 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5429 * Affects BiDi ordering
5430 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5431 * ETO_PDY - unimplemented
5432 * ETO_NUMERICSLATIN - unimplemented always assumed -
5433 * do not translate numbers into locale representations
5434 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5435 * lprect [I] dimensions for clipping or/and opaquing
5436 * str [I] text string
5437 * count [I] number of symbols in string
5438 * lpDx [I] optional parameter with distance between drawing characters
5444 BOOL WINAPI
NtGdiExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
, const RECT
*lprect
,
5445 const WCHAR
*str
, UINT count
, const INT
*lpDx
, DWORD cp
)
5453 double cosEsc
, sinEsc
;
5457 POINT
*deltas
= NULL
, width
= {0, 0};
5458 DC
* dc
= get_dc_ptr( hdc
);
5461 static int quietfixme
= 0;
5463 if (!dc
) return FALSE
;
5464 if (count
> INT_MAX
) return FALSE
;
5466 align
= dc
->attr
->text_align
;
5467 breakRem
= dc
->breakRem
;
5468 layout
= dc
->attr
->layout
;
5470 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5472 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5477 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5479 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5480 if (layout
& LAYOUT_RTL
)
5482 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5483 align
^= TA_RTLREADING
;
5486 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
5487 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
5488 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->attr
->background_mode
,
5489 dc
->attr
->map_mode
);
5491 if(align
& TA_UPDATECP
)
5493 pt
= dc
->attr
->cur_pos
;
5498 NtGdiGetTextMetricsW( hdc
, &tm
, 0 );
5499 NtGdiExtGetObjectW( dc
->hFont
, sizeof(lf
), &lf
);
5501 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
5502 lf
.lfEscapement
= 0;
5504 if ((dc
->attr
->graphics_mode
== GM_COMPATIBLE
) &&
5505 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
5507 lf
.lfEscapement
= -lf
.lfEscapement
;
5510 if(lf
.lfEscapement
!= 0)
5512 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
5513 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
5521 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
5524 lp_to_dp(dc
, (POINT
*)&rc
, 2);
5526 if (flags
& ETO_OPAQUE
)
5527 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
5529 else flags
&= ~ETO_CLIPPED
;
5539 lp_to_dp(dc
, &pt
, 1);
5543 char_extra
= dc
->attr
->char_extra
;
5544 if (char_extra
&& lpDx
&& NtGdiGetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
5545 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5547 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
5550 POINT total
= {0, 0}, desired
[2];
5552 deltas
= malloc( count
* sizeof(*deltas
) );
5555 if (flags
& ETO_PDY
)
5557 for (i
= 0; i
< count
; i
++)
5559 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
5560 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
5565 for (i
= 0; i
< count
; i
++)
5567 deltas
[i
].x
= lpDx
[i
] + char_extra
;
5574 INT
*dx
= malloc( count
* sizeof(*dx
) );
5576 NtGdiGetTextExtentExW( hdc
, str
, count
, -1, NULL
, dx
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5578 deltas
[0].x
= dx
[0];
5580 for (i
= 1; i
< count
; i
++)
5582 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
5588 for(i
= 0; i
< count
; i
++)
5590 total
.x
+= deltas
[i
].x
;
5591 total
.y
+= deltas
[i
].y
;
5593 desired
[0].x
= desired
[0].y
= 0;
5595 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
5596 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
5598 lp_to_dp(dc
, desired
, 2);
5599 desired
[1].x
-= desired
[0].x
;
5600 desired
[1].y
-= desired
[0].y
;
5602 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5604 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5605 desired
[1].x
= -desired
[1].x
;
5606 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5607 desired
[1].y
= -desired
[1].y
;
5610 deltas
[i
].x
= desired
[1].x
- width
.x
;
5611 deltas
[i
].y
= desired
[1].y
- width
.y
;
5621 NtGdiGetTextExtentExW( hdc
, str
, count
, 0, NULL
, NULL
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5622 desired
[0].x
= desired
[0].y
= 0;
5623 desired
[1].x
= sz
.cx
;
5625 lp_to_dp(dc
, desired
, 2);
5626 desired
[1].x
-= desired
[0].x
;
5627 desired
[1].y
-= desired
[0].y
;
5629 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5631 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5632 desired
[1].x
= -desired
[1].x
;
5633 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5634 desired
[1].y
= -desired
[1].y
;
5639 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
5640 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
5641 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
5644 if (align
& TA_UPDATECP
)
5648 dp_to_lp(dc
, &pt
, 1);
5649 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5661 if (align
& TA_UPDATECP
)
5665 dp_to_lp(dc
, &pt
, 1);
5666 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5671 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
5674 y
+= tm
.tmAscent
* cosEsc
;
5675 x
+= tm
.tmAscent
* sinEsc
;
5679 y
-= tm
.tmDescent
* cosEsc
;
5680 x
-= tm
.tmDescent
* sinEsc
;
5687 if (dc
->attr
->background_mode
!= TRANSPARENT
)
5689 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
5691 if(!(flags
& ETO_OPAQUE
) || !lprect
||
5692 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
5693 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
5697 text_box
.right
= x
+ width
.x
;
5698 text_box
.top
= y
- tm
.tmAscent
;
5699 text_box
.bottom
= y
+ tm
.tmDescent
;
5701 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
5702 if (!is_rect_empty( &text_box
))
5703 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
5708 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
5709 str
, count
, (INT
*)deltas
);
5714 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
5716 int underlinePos
, strikeoutPos
;
5717 int underlineWidth
, strikeoutWidth
;
5718 UINT size
= NtGdiGetOutlineTextMetricsInternalW( hdc
, 0, NULL
, 0 );
5719 OUTLINETEXTMETRICW
* otm
= NULL
;
5721 HPEN hpen
= NtGdiSelectPen( hdc
, get_stock_object(NULL_PEN
) );
5722 HBRUSH hbrush
= NtGdiCreateSolidBrush( dc
->attr
->text_color
, NULL
);
5724 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
5729 underlineWidth
= tm
.tmAscent
/ 20 + 1;
5730 strikeoutPos
= tm
.tmAscent
/ 2;
5731 strikeoutWidth
= underlineWidth
;
5735 otm
= malloc( size
);
5736 NtGdiGetOutlineTextMetricsInternalW( hdc
, size
, otm
, 0 );
5737 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
5738 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
5739 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
5740 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
5741 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
5742 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
5750 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5751 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5752 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5753 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5754 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
5755 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
5756 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
5757 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
5758 pts
[4].x
= pts
[0].x
;
5759 pts
[4].y
= pts
[0].y
;
5760 dp_to_lp(dc
, pts
, 5);
5761 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
5767 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5768 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5769 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5770 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5771 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
5772 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
5773 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
5774 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
5775 pts
[4].x
= pts
[0].x
;
5776 pts
[4].y
= pts
[0].y
;
5777 dp_to_lp(dc
, pts
, 5);
5778 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
5781 NtGdiSelectPen(hdc
, hpen
);
5782 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
5783 NtGdiDeleteObjectApp( hbrush
);
5786 release_dc_ptr( dc
);
5792 /******************************************************************************
5793 * NtGdiGetCharABCWidthsW (win32u.@)
5795 * Retrieves widths of characters in range.
5798 * hdc [I] Handle of device context
5799 * firstChar [I] First character in range to query
5800 * lastChar [I] Last character in range to query
5801 * abc [O] Address of character-width structure
5804 * Only works with TrueType fonts
5806 BOOL WINAPI
NtGdiGetCharABCWidthsW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5807 ULONG flags
, void *buffer
)
5809 DC
*dc
= get_dc_ptr(hdc
);
5811 unsigned int i
, count
= last
;
5815 if (!dc
) return FALSE
;
5819 release_dc_ptr( dc
);
5823 if (flags
& NTGDI_GETCHARABCWIDTHS_INDICES
)
5825 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
5826 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, chars
, buffer
);
5830 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
5832 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
5833 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5834 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
5836 release_dc_ptr( dc
);
5841 if (!chars
) count
= last
- first
+ 1;
5842 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
5843 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
5849 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
5851 /* convert device units to logical */
5852 for (i
= 0; i
< count
; i
++)
5854 abc
[i
].abcA
= width_to_LP( dc
, abc
[i
].abcA
);
5855 abc
[i
].abcB
= width_to_LP( dc
, abc
[i
].abcB
);
5856 abc
[i
].abcC
= width_to_LP( dc
, abc
[i
].abcC
);
5861 /* convert device units to logical */
5862 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
5863 ABCFLOAT
*abcf
= buffer
;
5865 for (i
= 0; i
< count
; i
++)
5867 abcf
[i
].abcfA
= abc
[i
].abcA
* scale
;
5868 abcf
[i
].abcfB
= abc
[i
].abcB
* scale
;
5869 abcf
[i
].abcfC
= abc
[i
].abcC
* scale
;
5874 release_dc_ptr( dc
);
5879 /***********************************************************************
5880 * NtGdiGetGlyphOutline (win32u.@)
5882 DWORD WINAPI
NtGdiGetGlyphOutline( HDC hdc
, UINT ch
, UINT format
, GLYPHMETRICS
*metrics
,
5883 DWORD size
, void *buffer
, const MAT2
*mat2
,
5884 BOOL ignore_rotation
)
5890 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc
, ch
, format
, metrics
, size
, buffer
, mat2
);
5892 if (!mat2
) return GDI_ERROR
;
5894 dc
= get_dc_ptr(hdc
);
5895 if(!dc
) return GDI_ERROR
;
5897 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
5898 ret
= dev
->funcs
->pGetGlyphOutline( dev
, ch
& 0xffff, format
, metrics
, size
, buffer
, mat2
);
5899 release_dc_ptr( dc
);
5904 /**********************************************************************
5905 * __wine_get_file_outline_text_metric (win32u.@)
5907 BOOL CDECL
__wine_get_file_outline_text_metric( const WCHAR
*path
, OUTLINETEXTMETRICW
*otm
)
5909 struct gdi_font
*font
= NULL
;
5911 if (!path
|| !font_funcs
) return FALSE
;
5913 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
5914 font
->lf
.lfHeight
= 100;
5915 if (!font_funcs
->load_font( font
)) goto done
;
5916 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
5918 free_gdi_font( font
);
5922 if (font
) free_gdi_font( font
);
5923 SetLastError( ERROR_INVALID_PARAMETER
);
5927 /*************************************************************************
5928 * NtGdiGetKerningPairs (win32u.@)
5930 DWORD WINAPI
NtGdiGetKerningPairs( HDC hdc
, DWORD count
, KERNINGPAIR
*kern_pair
)
5936 TRACE( "(%p,%d,%p)\n", hdc
, count
, kern_pair
);
5938 if (!count
&& kern_pair
)
5940 SetLastError( ERROR_INVALID_PARAMETER
);
5944 dc
= get_dc_ptr( hdc
);
5947 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
5948 ret
= dev
->funcs
->pGetKerningPairs( dev
, count
, kern_pair
);
5949 release_dc_ptr( dc
);
5953 /*************************************************************************
5954 * NtGdiGetFontData (win32u.@)
5956 * Retrieve data for TrueType font.
5960 * success: Number of bytes returned
5961 * failure: GDI_ERROR
5965 * Calls SetLastError()
5968 DWORD WINAPI
NtGdiGetFontData( HDC hdc
, DWORD table
, DWORD offset
, void *buffer
, DWORD length
)
5970 DC
*dc
= get_dc_ptr(hdc
);
5974 if(!dc
) return GDI_ERROR
;
5976 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
5977 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
5978 release_dc_ptr( dc
);
5982 /*************************************************************************
5983 * NtGdiGetGlyphIndicesW (win32u.@)
5985 DWORD WINAPI
NtGdiGetGlyphIndicesW( HDC hdc
, const WCHAR
*str
, INT count
,
5986 WORD
*indices
, DWORD flags
)
5988 DC
*dc
= get_dc_ptr(hdc
);
5992 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc
, debugstr_wn(str
, count
), count
, indices
, flags
);
5994 if(!dc
) return GDI_ERROR
;
5996 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
5997 ret
= dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, indices
, flags
);
5998 release_dc_ptr( dc
);
6002 /***********************************************************************
6004 * Font Resource API *
6006 ***********************************************************************/
6009 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
6011 WCHAR path
[MAX_PATH
];
6014 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6015 get_fonts_win_dir_path( file
, path
);
6016 pthread_mutex_lock( &font_lock
);
6017 ret
= font_funcs
->add_font( path
, flags
);
6018 pthread_mutex_unlock( &font_lock
);
6019 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6022 get_fonts_data_dir_path( file
, path
);
6023 pthread_mutex_lock( &font_lock
);
6024 ret
= font_funcs
->add_font( path
, flags
);
6025 pthread_mutex_unlock( &font_lock
);
6030 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
6032 WCHAR path
[MAX_PATH
];
6035 get_fonts_win_dir_path( file
, path
);
6036 if (!(ret
= remove_font( path
, flags
)))
6038 get_fonts_data_dir_path( file
, path
);
6039 ret
= remove_font( path
, flags
);
6044 static int add_font_resource( LPCWSTR file
, DWORD flags
)
6050 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6052 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6053 pthread_mutex_lock( &font_lock
);
6054 ret
= font_funcs
->add_font( file
, addfont_flags
);
6055 pthread_mutex_unlock( &font_lock
);
6057 else if (!wcschr( file
, '\\' ))
6058 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6063 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
6069 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6071 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6072 ret
= remove_font( file
, addfont_flags
);
6074 else if (!wcschr( file
, '\\' ))
6075 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6080 static void load_system_bitmap_fonts(void)
6082 static const char * const fonts
[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6083 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6084 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6088 if (!(hkey
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) ))) return;
6089 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
6091 if (query_reg_ascii_value( hkey
, fonts
[i
], info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
6092 add_system_font_resource( (const WCHAR
*)info
->Data
, ADDFONT_ALLOW_BITMAP
);
6097 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
6099 OBJECT_ATTRIBUTES attr
;
6100 UNICODE_STRING nt_name
;
6106 len
= lstrlenW( path
);
6107 while (len
&& path
[len
- 1] == '\\') len
--;
6109 nt_name
.Buffer
= path
;
6110 nt_name
.MaximumLength
= nt_name
.Length
= len
* sizeof(WCHAR
);
6112 attr
.Length
= sizeof(attr
);
6113 attr
.RootDirectory
= 0;
6114 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
6115 attr
.ObjectName
= &nt_name
;
6116 attr
.SecurityDescriptor
= NULL
;
6117 attr
.SecurityQualityOfService
= NULL
;
6119 if (NtOpenFile( &handle
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
,
6120 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
6121 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
))
6126 while (!NtQueryDirectoryFile( handle
, 0, NULL
, NULL
, &io
, buf
, sizeof(buf
),
6127 FileBothDirectoryInformation
, FALSE
, NULL
, FALSE
) &&
6130 FILE_BOTH_DIR_INFORMATION
*info
= (FILE_BOTH_DIR_INFORMATION
*)buf
;
6133 if (!(info
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
6135 memcpy( path
+ len
, info
->FileName
, info
->FileNameLength
);
6136 path
[len
+ info
->FileNameLength
/ sizeof(WCHAR
)] = 0;
6137 font_funcs
->add_font( path
, flags
);
6139 if (!info
->NextEntryOffset
) break;
6140 info
= (FILE_BOTH_DIR_INFORMATION
*)((char *)info
+ info
->NextEntryOffset
);
6147 static void load_file_system_fonts(void)
6149 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024 * sizeof(WCHAR
)])];
6150 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6151 WCHAR
*ptr
, *next
, path
[MAX_PATH
];
6153 /* Windows directory */
6154 get_fonts_win_dir_path( NULL
, path
);
6155 load_directory_fonts( path
, 0 );
6157 /* Wine data directory */
6158 get_fonts_data_dir_path( NULL
, path
);
6159 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6162 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6163 if (query_reg_ascii_value( wine_fonts_key
, "Path", info
, sizeof(value_buffer
) ) &&
6164 info
->Type
== REG_SZ
)
6166 for (ptr
= (WCHAR
*)info
->Data
; ptr
; ptr
= next
)
6168 if ((next
= wcschr( ptr
, ';' ))) *next
++ = 0;
6169 if (next
&& next
- ptr
< 2) continue;
6170 lstrcpynW( path
, ptr
, MAX_PATH
);
6173 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, (lstrlenW( path
) + 1) * sizeof(WCHAR
) );
6174 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6176 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6184 WCHAR value
[LF_FULLFACESIZE
+ 12];
6187 static void update_external_font_keys(void)
6189 struct list external_keys
= LIST_INIT(external_keys
);
6190 HKEY winnt_key
= 0, win9x_key
= 0;
6191 struct gdi_font_family
*family
;
6192 struct external_key
*key
, *next
;
6193 struct gdi_font_face
*face
;
6195 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6197 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
6201 static const WCHAR external_fontsW
[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6203 winnt_key
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
), 0, NULL
);
6204 win9x_key
= reg_create_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
), 0, NULL
);
6206 /* enumerate the fonts and add external ones to the two keys */
6208 if (!(hkey
= reg_create_key( wine_fonts_key
, external_fontsW
, sizeof(external_fontsW
), 0, NULL
)))
6211 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
) - sizeof(nt_prefixW
),
6212 value
, LF_FULLFACESIZE
* sizeof(WCHAR
) ))
6214 if (info
->Type
!= REG_SZ
) continue;
6216 path
= (WCHAR
*)(buffer
+ info
->DataOffset
);
6217 if (path
[0] && path
[1] == ':')
6219 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, info
->DataLength
);
6220 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6223 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6224 if ((face
= find_face_from_full_name( value
)) && !wcsicmp( face
->file
, path
))
6226 face
->flags
|= ADDFONT_EXTERNAL_FOUND
;
6229 if (tmp
&& !*tmp
) *tmp
= ' ';
6230 if (!(key
= malloc( sizeof(*key
) ))) break;
6231 lstrcpyW( key
->value
, value
);
6232 list_add_tail( &external_keys
, &key
->entry
);
6235 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
6237 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
6239 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
6240 if ((face
->flags
& ADDFONT_EXTERNAL_FOUND
)) continue;
6242 lstrcpyW( value
, face
->full_name
);
6243 if (face
->scalable
) lstrcatW( value
, true_type_suffixW
);
6245 if (face
->file
[0] == '\\')
6248 if (file
[5] == ':') file
+= ARRAYSIZE(nt_prefixW
);
6250 else if ((file
= wcsrchr( face
->file
, '\\' )))
6255 len
= (lstrlenW(file
) + 1) * sizeof(WCHAR
);
6256 set_reg_value( winnt_key
, value
, REG_SZ
, file
, len
);
6257 set_reg_value( win9x_key
, value
, REG_SZ
, file
, len
);
6258 set_reg_value( hkey
, value
, REG_SZ
, file
, len
);
6261 LIST_FOR_EACH_ENTRY_SAFE( key
, next
, &external_keys
, struct external_key
, entry
)
6263 reg_delete_value( win9x_key
, key
->value
);
6264 reg_delete_value( winnt_key
, key
->value
);
6265 reg_delete_value( hkey
, key
->value
);
6266 list_remove( &key
->entry
);
6269 NtClose( win9x_key
);
6270 NtClose( winnt_key
);
6274 static void load_registry_fonts(void)
6276 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6277 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6278 KEY_VALUE_FULL_INFORMATION
*enum_info
= (KEY_VALUE_FULL_INFORMATION
*)value_buffer
;
6279 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6283 static const WCHAR dot_fonW
[] = {'.','f','o','n',0};
6285 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6286 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6287 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6290 hkey
= reg_open_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
) );
6292 hkey
= reg_open_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
) );
6295 while (reg_enum_value( hkey
, i
++, enum_info
, sizeof(value_buffer
), value
, sizeof(value
) ))
6297 if (enum_info
->Type
!= REG_SZ
) continue;
6298 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6299 if (find_face_from_full_name( value
)) continue;
6300 if (tmp
&& !*tmp
) *tmp
= ' ';
6302 if (!(dlen
= query_reg_value( hkey
, value
, info
, sizeof(value_buffer
) - sizeof(nt_prefixW
) )) ||
6303 info
->Type
!= REG_SZ
)
6305 WARN( "Unable to get face path %s\n", debugstr_w(value
) );
6309 path
= (WCHAR
*)info
->Data
;
6310 if (path
[0] && path
[1] == ':')
6312 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, dlen
);
6313 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6314 dlen
+= sizeof(nt_prefixW
);
6317 dlen
/= sizeof(WCHAR
);
6319 add_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6320 else if (dlen
>= 6 && !wcsicmp( path
+ dlen
- 5, dot_fonW
))
6321 add_system_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6326 static HKEY
open_hkcu(void)
6330 DWORD_PTR sid_data
[(sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
) / sizeof(DWORD_PTR
)];
6331 DWORD i
, len
= sizeof(sid_data
);
6334 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser
, sid_data
, len
, &len
))
6337 sid
= ((TOKEN_USER
*)sid_data
)->User
.Sid
;
6338 len
= sprintf( buffer
, "\\Registry\\User\\S-%u-%u", sid
->Revision
,
6339 MAKELONG( MAKEWORD( sid
->IdentifierAuthority
.Value
[5], sid
->IdentifierAuthority
.Value
[4] ),
6340 MAKEWORD( sid
->IdentifierAuthority
.Value
[3], sid
->IdentifierAuthority
.Value
[2] )));
6341 for (i
= 0; i
< sid
->SubAuthorityCount
; i
++)
6342 len
+= sprintf( buffer
+ len
, "-%u", sid
->SubAuthority
[i
] );
6343 ascii_to_unicode( bufferW
, buffer
, len
+ 1 );
6345 return reg_open_key( NULL
, bufferW
, len
* sizeof(WCHAR
) );
6348 /***********************************************************************
6351 UINT
font_init(void)
6353 OBJECT_ATTRIBUTES attr
= { sizeof(attr
) };
6354 UNICODE_STRING name
;
6359 static WCHAR wine_font_mutexW
[] =
6360 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6361 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6362 static const WCHAR wine_fonts_keyW
[] =
6363 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6364 static const WCHAR cacheW
[] = {'C','a','c','h','e'};
6366 if (!(hkcu_key
= open_hkcu())) return 0;
6367 wine_fonts_key
= reg_create_key( hkcu_key
, wine_fonts_keyW
, sizeof(wine_fonts_keyW
), 0, NULL
);
6368 if (wine_fonts_key
) dpi
= init_font_options();
6369 if (!dpi
) return 96;
6370 update_codepage( dpi
);
6372 if (!(font_funcs
= init_freetype_lib()))
6375 load_system_bitmap_fonts();
6376 load_file_system_fonts();
6377 font_funcs
->load_fonts();
6379 attr
.Attributes
= OBJ_OPENIF
;
6380 attr
.ObjectName
= &name
;
6381 name
.Buffer
= wine_font_mutexW
;
6382 name
.Length
= name
.MaximumLength
= sizeof(wine_font_mutexW
);
6384 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return dpi
;
6385 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
6387 wine_fonts_cache_key
= reg_create_key( wine_fonts_key
, cacheW
, sizeof(cacheW
),
6388 REG_OPTION_VOLATILE
, &disposition
);
6390 if (disposition
== REG_CREATED_NEW_KEY
)
6392 load_registry_fonts();
6393 update_external_font_keys();
6396 NtReleaseMutant( mutex
, NULL
);
6398 if (disposition
!= REG_CREATED_NEW_KEY
)
6400 load_registry_fonts();
6401 load_font_list_from_cache();
6404 reorder_font_list();
6405 load_gdi_font_subst();
6406 load_gdi_font_replacements();
6407 load_system_links();
6408 dump_gdi_font_list();
6409 dump_gdi_font_subst();
6413 /***********************************************************************
6414 * NtGdiAddFontResourceW (win32u.@)
6416 INT WINAPI
NtGdiAddFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6417 DWORD tid
, void *dv
)
6419 if (!font_funcs
) return 1;
6420 return add_font_resource( str
, flags
);
6423 /***********************************************************************
6424 * NtGdiAddFontMemResourceEx (win32u.@)
6426 HANDLE WINAPI
NtGdiAddFontMemResourceEx( void *ptr
, DWORD size
, void *dv
, ULONG dv_size
,
6433 if (!ptr
|| !size
|| !count
)
6435 SetLastError(ERROR_INVALID_PARAMETER
);
6438 if (!font_funcs
) return NULL
;
6439 if (!(copy
= malloc( size
))) return NULL
;
6440 memcpy( copy
, ptr
, size
);
6442 pthread_mutex_lock( &font_lock
);
6443 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6444 pthread_mutex_unlock( &font_lock
);
6452 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6453 * For now return something unique but quite random
6455 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
6463 WARN( "page fault while writing to *count (%p)\n", count
);
6464 NtGdiRemoveFontMemResourceEx( ret
);
6468 TRACE( "Returning handle %p\n", ret
);
6472 /***********************************************************************
6473 * NtGdiRemoveFontMemResourceEx (win32u.@)
6475 BOOL WINAPI
NtGdiRemoveFontMemResourceEx( HANDLE handle
)
6477 FIXME( "(%p) stub\n", handle
);
6481 /***********************************************************************
6482 * NtGdiRemoveFontResourceW (win32u.@)
6484 BOOL WINAPI
NtGdiRemoveFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6485 DWORD tid
, void *dv
)
6487 if (!font_funcs
) return TRUE
;
6488 return remove_font_resource( str
, flags
);
6491 /***********************************************************************
6492 * NtGdiGetFontUnicodeRanges (win32u.@)
6494 * Retrieve a list of supported Unicode characters in a font.
6497 * hdc [I] Handle to a device context.
6498 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6501 * Success: Number of bytes written to the buffer pointed to by lpgs.
6505 DWORD WINAPI
NtGdiGetFontUnicodeRanges( HDC hdc
, GLYPHSET
*lpgs
)
6509 DC
*dc
= get_dc_ptr(hdc
);
6511 TRACE("(%p, %p)\n", hdc
, lpgs
);
6515 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
6516 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
6522 /*************************************************************
6523 * NtGdiFontIsLinked (win32u.@)
6525 BOOL WINAPI
NtGdiFontIsLinked( HDC hdc
)
6527 DC
*dc
= get_dc_ptr(hdc
);
6531 if (!dc
) return FALSE
;
6532 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
6533 ret
= dev
->funcs
->pFontIsLinked( dev
);
6535 TRACE("returning %d\n", ret
);
6539 /*************************************************************
6540 * NtGdiGetRealizationInfo (win32u.@)
6542 BOOL WINAPI
NtGdiGetRealizationInfo( HDC hdc
, struct font_realization_info
*info
)
6544 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, file_count
);
6549 if (info
->size
!= sizeof(*info
) && !is_v0
)
6552 dc
= get_dc_ptr(hdc
);
6553 if (!dc
) return FALSE
;
6554 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
6555 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
6560 /*************************************************************************
6561 * NtGdiGetRasterizerCaps (win32u.@)
6563 BOOL WINAPI
NtGdiGetRasterizerCaps( RASTERIZER_STATUS
*status
, UINT size
)
6565 status
->nSize
= sizeof(RASTERIZER_STATUS
);
6566 status
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
6567 status
->nLanguageID
= 0;
6571 /*************************************************************************
6572 * NtGdiGetFontFileData (win32u.@)
6574 BOOL WINAPI
NtGdiGetFontFileData( DWORD instance_id
, DWORD file_index
, UINT64
*offset
,
6575 void *buff
, DWORD buff_size
)
6577 struct gdi_font
*font
;
6578 DWORD tag
= 0, size
;
6581 if (!font_funcs
) return FALSE
;
6582 pthread_mutex_lock( &font_lock
);
6583 if ((font
= get_font_from_handle( instance_id
)))
6585 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
6586 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
6587 if (size
!= GDI_ERROR
&& size
>= buff_size
&& *offset
<= size
- buff_size
)
6588 ret
= font_funcs
->get_font_data( font
, tag
, *offset
, buff
, buff_size
) != GDI_ERROR
;
6590 SetLastError( ERROR_INVALID_PARAMETER
);
6592 pthread_mutex_unlock( &font_lock
);
6596 /*************************************************************************
6597 * NtGdiGetFontFileInfo (win32u.@)
6599 BOOL WINAPI
NtGdiGetFontFileInfo( DWORD instance_id
, DWORD file_index
, struct font_fileinfo
*info
,
6600 SIZE_T size
, SIZE_T
*needed
)
6602 SIZE_T required_size
= 0;
6603 struct gdi_font
*font
;
6606 pthread_mutex_lock( &font_lock
);
6608 if ((font
= get_font_from_handle( instance_id
)))
6610 required_size
= sizeof(*info
) + lstrlenW( font
->file
) * sizeof(WCHAR
);
6611 if (required_size
<= size
)
6613 info
->writetime
= font
->writetime
;
6614 info
->size
.QuadPart
= font
->data_size
;
6615 lstrcpyW( info
->path
, font
->file
);
6618 else SetLastError( ERROR_INSUFFICIENT_BUFFER
);
6621 pthread_mutex_unlock( &font_lock
);
6622 if (needed
) *needed
= required_size
;
6626 /*************************************************************
6627 * NtGdiGetCharWidthInfo (win32u.@)
6629 BOOL WINAPI
NtGdiGetCharWidthInfo( HDC hdc
, struct char_width_info
*info
)
6635 dc
= get_dc_ptr(hdc
);
6636 if (!dc
) return FALSE
;
6637 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
6638 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
6642 info
->lsb
= width_to_LP( dc
, info
->lsb
);
6643 info
->rsb
= width_to_LP( dc
, info
->rsb
);