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 GDI_PRIORITY_FONT_DRV
/* priority */
4358 static BOOL
get_key_value( HKEY key
, const char *name
, DWORD
*value
)
4360 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[12 * sizeof(WCHAR
)])];
4361 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4364 count
= query_reg_ascii_value( key
, name
, info
, sizeof(value_buffer
) );
4367 if (info
->Type
== REG_DWORD
) memcpy( value
, info
->Data
, sizeof(*value
) );
4368 else *value
= wcstol( (const WCHAR
*)info
->Data
, NULL
, 10 );
4373 static UINT
init_font_options(void)
4375 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[20 * sizeof(WCHAR
)])];
4376 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4378 DWORD i
, val
, gamma
= 1400;
4381 if (query_reg_ascii_value( wine_fonts_key
, "AntialiasFakeBoldOrItalic",
4382 info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
4384 static const WCHAR valsW
[] = {'y','Y','t','T','1',0};
4385 antialias_fakes
= (wcschr( valsW
, *(const WCHAR
*)info
->Data
) != NULL
);
4388 if ((key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
4390 /* FIXME: handle vertical orientations even though Windows doesn't */
4391 if (get_key_value( key
, "FontSmoothingOrientation", &val
))
4395 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4396 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
4398 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4399 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
4403 if (get_key_value( key
, "FontSmoothing", &val
) && val
/* enabled */)
4405 if (get_key_value( key
, "FontSmoothingType", &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4406 font_smoothing
= subpixel_orientation
;
4408 font_smoothing
= GGO_GRAY4_BITMAP
;
4410 if (get_key_value( key
, "FontSmoothingGamma", &val
) && val
)
4412 gamma
= min( max( val
, 1000 ), 2200 );
4414 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4418 /* Calibrating the difference between the registry value and the Wine gamma value.
4419 This looks roughly similar to Windows Native with the same registry value.
4420 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4421 gamma
= 1000 * gamma
/ 1400;
4424 for (i
= 0; i
< 256; i
++)
4426 font_gamma_ramp
.encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
4427 font_gamma_ramp
.decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
4431 if (!dpi
&& (key
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) )))
4433 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4438 font_gamma_ramp
.gamma
= gamma
;
4439 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp
.gamma
, dpi
);
4444 /* compute positions for text rendering, in device coords */
4445 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
4450 size
->cx
= size
->cy
= 0;
4451 if (!count
) return TRUE
;
4453 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4454 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4456 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
4457 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
4459 if (dc
->breakExtra
|| dc
->breakRem
)
4461 int i
, space
= 0, rem
= dc
->breakRem
;
4463 for (i
= 0; i
< count
; i
++)
4465 if (str
[i
] == tm
.tmBreakChar
)
4467 space
+= dc
->breakExtra
;
4477 size
->cx
= dx
[count
- 1];
4478 size
->cy
= tm
.tmHeight
;
4482 /* compute positions for text rendering, in device coords */
4483 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
4488 size
->cx
= size
->cy
= 0;
4489 if (!count
) return TRUE
;
4491 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4492 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4494 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
4495 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
4497 if (dc
->breakExtra
|| dc
->breakRem
)
4500 int i
, space
= 0, rem
= dc
->breakRem
;
4502 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4503 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
4505 for (i
= 0; i
< count
; i
++)
4507 if (indices
[i
] == space_index
)
4509 space
+= dc
->breakExtra
;
4519 size
->cx
= dx
[count
- 1];
4520 size
->cy
= tm
.tmHeight
;
4524 /***********************************************************************
4525 * get_text_charset_info
4527 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4529 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
4531 UINT ret
= DEFAULT_CHARSET
;
4534 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
4535 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4537 if (ret
== DEFAULT_CHARSET
&& fs
)
4538 memset(fs
, 0, sizeof(FONTSIGNATURE
));
4542 /***********************************************************************
4543 * NtGdiGetTextCharsetInfo (win32u.@)
4545 UINT WINAPI
NtGdiGetTextCharsetInfo( HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
4547 UINT ret
= DEFAULT_CHARSET
;
4548 DC
*dc
= get_dc_ptr(hdc
);
4552 ret
= get_text_charset_info( dc
, fs
, flags
);
4553 release_dc_ptr( dc
);
4558 /***********************************************************************
4559 * NtGdiHfontCreate (win32u.@)
4561 HFONT WINAPI
NtGdiHfontCreate( const ENUMLOGFONTEXDVW
*penumex
, ULONG size
, ULONG type
,
4562 ULONG flags
, void *data
)
4566 const LOGFONTW
*plf
;
4568 if (!penumex
) return 0;
4570 if (penumex
->elfEnumLogfontEx
.elfFullName
[0] ||
4571 penumex
->elfEnumLogfontEx
.elfStyle
[0] ||
4572 penumex
->elfEnumLogfontEx
.elfScript
[0])
4574 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4575 debugstr_w(penumex
->elfEnumLogfontEx
.elfFullName
),
4576 debugstr_w(penumex
->elfEnumLogfontEx
.elfStyle
),
4577 debugstr_w(penumex
->elfEnumLogfontEx
.elfScript
));
4580 plf
= &penumex
->elfEnumLogfontEx
.elfLogFont
;
4581 if (!(fontPtr
= malloc( sizeof(*fontPtr
) ))) return 0;
4583 fontPtr
->logfont
= *plf
;
4585 if (!(hFont
= alloc_gdi_handle( &fontPtr
->obj
, NTGDI_OBJ_FONT
, &fontobj_funcs
)))
4591 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4592 plf
->lfHeight
, plf
->lfWidth
,
4593 plf
->lfEscapement
, plf
->lfOrientation
,
4594 plf
->lfPitchAndFamily
,
4595 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
4596 plf
->lfQuality
, plf
->lfCharSet
,
4597 debugstr_w(plf
->lfFaceName
),
4598 plf
->lfWeight
> 400 ? "Bold" : "",
4599 plf
->lfItalic
? "Italic" : "",
4600 plf
->lfUnderline
? "Underline" : "", hFont
);
4605 #define ASSOC_CHARSET_OEM 1
4606 #define ASSOC_CHARSET_ANSI 2
4607 #define ASSOC_CHARSET_SYMBOL 4
4609 static DWORD
get_associated_charset_info(void)
4611 static DWORD associated_charset
= -1;
4613 if (associated_charset
== -1)
4615 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[32 * sizeof(WCHAR
)])];
4616 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4619 static const WCHAR yesW
[] = {'y','e','s',0};
4621 associated_charset
= 0;
4623 if (!(hkey
= reg_open_key( NULL
, associated_charset_keyW
, sizeof(associated_charset_keyW
) )))
4626 if (query_reg_ascii_value( hkey
, "ANSI(00)", info
, sizeof(value_buffer
) ) &&
4627 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4628 associated_charset
|= ASSOC_CHARSET_ANSI
;
4630 if (query_reg_ascii_value( hkey
, "OEM(FF)", info
, sizeof(value_buffer
) ) &&
4631 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4632 associated_charset
|= ASSOC_CHARSET_OEM
;
4634 if (query_reg_ascii_value( hkey
, "SYMBOL(02)", info
, sizeof(value_buffer
) ) &&
4635 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4636 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
4640 TRACE("associated_charset = %d\n", associated_charset
);
4643 return associated_charset
;
4646 static void update_font_code_page( DC
*dc
, HANDLE font
)
4649 int charset
= get_text_charset_info( dc
, NULL
, 0 );
4651 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
4655 NtGdiExtGetObjectW( font
, sizeof(lf
), &lf
);
4656 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
4657 charset
= DEFAULT_CHARSET
;
4660 /* Hmm, nicely designed api this one! */
4661 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
4662 dc
->attr
->font_code_page
= csi
.ciACP
;
4666 dc
->attr
->font_code_page
= get_oemcp();
4668 case DEFAULT_CHARSET
:
4669 dc
->attr
->font_code_page
= get_acp();
4672 case VISCII_CHARSET
:
4678 case CELTIC_CHARSET
:
4679 /* FIXME: These have no place here, but because x11drv
4680 enumerates fonts with these (made up) charsets some apps
4681 might use them and then the FIXME below would become
4682 annoying. Now we could pick the intended codepage for
4683 each of these, but since it's broken anyway we'll just
4684 use CP_ACP and hope it'll go away...
4686 dc
->attr
->font_code_page
= CP_ACP
;
4690 FIXME("Can't find codepage for charset %d\n", charset
);
4691 dc
->attr
->font_code_page
= CP_ACP
;
4696 TRACE( "charset %d => cp %d\n", charset
, dc
->attr
->font_code_page
);
4699 /***********************************************************************
4700 * NtGdiSelectFont (win32u.@)
4702 HGDIOBJ WINAPI
NtGdiSelectFont( HDC hdc
, HGDIOBJ handle
)
4705 DC
*dc
= get_dc_ptr( hdc
);
4711 if (!GDI_inc_ref_count( handle
))
4713 release_dc_ptr( dc
);
4717 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
4718 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
4722 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
4723 update_font_code_page( dc
, handle
);
4724 if (dc
->font_gamma_ramp
== NULL
)
4725 dc
->font_gamma_ramp
= &font_gamma_ramp
;
4726 GDI_dec_ref_count( ret
);
4728 else GDI_dec_ref_count( handle
);
4730 release_dc_ptr( dc
);
4735 /***********************************************************************
4738 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
4740 FONTOBJ
*font
= GDI_GetObjPtr( handle
, NTGDI_OBJ_FONT
);
4742 if (!font
) return 0;
4745 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
4746 memcpy( buffer
, &font
->logfont
, count
);
4748 else count
= sizeof(LOGFONTW
);
4749 GDI_ReleaseObj( handle
);
4754 /***********************************************************************
4757 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
4761 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
4770 struct font_enum_entry
*buf
;
4776 static INT WINAPI
font_enum_proc( const LOGFONTW
*lf
, const TEXTMETRICW
*tm
,
4777 DWORD type
, LPARAM lp
)
4779 struct font_enum
*fe
= (struct font_enum
*)lp
;
4781 if (fe
->charset
!= DEFAULT_CHARSET
&& lf
->lfCharSet
!= fe
->charset
) return 1;
4782 if ((type
& RASTER_FONTTYPE
) && !(NtGdiGetDeviceCaps( fe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
))
4785 if (fe
->buf
&& fe
->count
< fe
->size
)
4787 fe
->buf
[fe
->count
].type
= type
;
4788 fe
->buf
[fe
->count
].lf
= *(const ENUMLOGFONTEXW
*)lf
;
4789 fe
->buf
[fe
->count
].tm
= *(const NEWTEXTMETRICEXW
*)tm
;
4795 /***********************************************************************
4796 * NtGdiEnumFonts (win32u.@)
4798 BOOL WINAPI
NtGdiEnumFonts( HDC hdc
, ULONG type
, ULONG win32_compat
, ULONG face_name_len
,
4799 const WCHAR
*face_name
, ULONG charset
, ULONG
*count
, void *buf
)
4801 struct font_enum fe
;
4807 if (!(dc
= get_dc_ptr( hdc
))) return 0;
4809 memset( &lf
, 0, sizeof(lf
) );
4810 lf
.lfCharSet
= charset
;
4811 if (face_name_len
) memcpy( lf
.lfFaceName
, face_name
, face_name_len
* sizeof(WCHAR
) );
4815 fe
.size
= *count
/ sizeof(*fe
.buf
);
4817 fe
.charset
= charset
;
4819 physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
4820 ret
= physdev
->funcs
->pEnumFonts( physdev
, &lf
, font_enum_proc
, (LPARAM
)&fe
);
4821 if (ret
&& buf
) ret
= fe
.count
<= fe
.size
;
4822 *count
= fe
.count
* sizeof(*fe
.buf
);
4824 release_dc_ptr( dc
);
4829 /***********************************************************************
4830 * NtGdiSetTextJustification (win32u.@)
4832 BOOL WINAPI
NtGdiSetTextJustification( HDC hdc
, INT extra
, INT breaks
)
4836 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
4838 extra
= abs( (extra
* dc
->attr
->vport_ext
.cx
+ dc
->attr
->wnd_ext
.cx
/ 2) /
4839 dc
->attr
->wnd_ext
.cx
);
4840 if (!extra
) breaks
= 0;
4843 dc
->breakExtra
= extra
/ breaks
;
4844 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
4852 release_dc_ptr( dc
);
4857 /***********************************************************************
4858 * NtGdiGetTextFaceW (win32u.@)
4860 INT WINAPI
NtGdiGetTextFaceW( HDC hdc
, INT count
, WCHAR
*name
, BOOL alias_name
)
4865 DC
* dc
= get_dc_ptr( hdc
);
4868 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
4869 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
4870 release_dc_ptr( dc
);
4875 /***********************************************************************
4876 * NtGdiGetTextExtentExW (win32u.@)
4878 * Return the size of the string as it would be if it was output properly by
4881 BOOL WINAPI
NtGdiGetTextExtentExW( HDC hdc
, const WCHAR
*str
, INT count
, INT max_ext
,
4882 INT
*nfit
, INT
*dxs
, SIZE
*size
, UINT flags
)
4887 INT buffer
[256], *pos
= dxs
;
4889 if (count
< 0) return FALSE
;
4891 dc
= get_dc_ptr(hdc
);
4892 if (!dc
) return FALSE
;
4897 if (count
> 256 && !(pos
= malloc( count
* sizeof(*pos
) )))
4899 release_dc_ptr( dc
);
4906 ret
= get_char_positions_indices( dc
, str
, count
, pos
, size
);
4908 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
4913 for (i
= 0; i
< count
; i
++)
4915 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) +
4916 (i
+ 1) * dc
->attr
->char_extra
;
4917 if (nfit
&& dx
> (unsigned int)max_ext
) break;
4918 if (dxs
) dxs
[i
] = dx
;
4920 if (nfit
) *nfit
= i
;
4923 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->attr
->char_extra
;
4924 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
4927 if (pos
!= buffer
&& pos
!= dxs
) free( pos
);
4928 release_dc_ptr( dc
);
4930 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
4934 /***********************************************************************
4935 * NtGdiGetTextMetricsW (win32u.@)
4937 BOOL WINAPI
NtGdiGetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
, ULONG flags
)
4941 DC
* dc
= get_dc_ptr( hdc
);
4942 if (!dc
) return FALSE
;
4944 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4945 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
4949 /* device layer returns values in device units
4950 * therefore we have to convert them to logical */
4952 metrics
->tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
4953 metrics
->tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
4954 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
4955 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
4956 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
4957 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
4958 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
4959 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
4960 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
4961 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
4964 TRACE("text metrics:\n"
4965 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
4966 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
4967 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
4968 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
4969 " PitchAndFamily = %02x\n"
4970 " --------------------\n"
4971 " InternalLeading = %i\n"
4975 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
4976 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
4977 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
4978 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
4979 metrics
->tmPitchAndFamily
,
4980 metrics
->tmInternalLeading
,
4983 metrics
->tmHeight
);
4985 release_dc_ptr( dc
);
4990 /***********************************************************************
4991 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
4993 UINT WINAPI
NtGdiGetOutlineTextMetricsInternalW( HDC hdc
, UINT cbData
,
4994 OUTLINETEXTMETRICW
*lpOTM
, ULONG opts
)
4996 DC
*dc
= get_dc_ptr( hdc
);
4997 OUTLINETEXTMETRICW
*output
= lpOTM
;
5001 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
5004 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
5005 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
5007 if (lpOTM
&& ret
> cbData
)
5009 output
= malloc( ret
);
5010 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
5015 output
->otmTextMetrics
.tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
5016 output
->otmTextMetrics
.tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
5017 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
5018 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
5019 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
5020 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
5021 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
5022 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
5023 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
5024 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
5025 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
5026 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
5027 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
5028 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
5029 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
5030 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
5031 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
5032 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
5033 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
5034 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
5035 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
5036 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
5037 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
5038 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
5039 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
5040 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
5041 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
5042 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
5043 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
5044 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
5045 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
5046 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
5047 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
5048 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
5052 memcpy(lpOTM
, output
, cbData
);
5061 /***********************************************************************
5062 * NtGdiGetCharWidthW (win32u.@)
5064 BOOL WINAPI
NtGdiGetCharWidthW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5065 ULONG flags
, void *buf
)
5067 UINT i
, count
= last
;
5072 if (flags
& NTGDI_GETCHARWIDTH_INDICES
)
5077 if (!(abc
= malloc( count
* sizeof(ABC
) )))
5080 if (!NtGdiGetCharABCWidthsW( hdc
, first
, last
, chars
,
5081 NTGDI_GETCHARABCWIDTHS_INT
| NTGDI_GETCHARABCWIDTHS_INDICES
,
5088 for (i
= 0; i
< count
; i
++)
5089 ((INT
*)buf
)[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
5095 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
5097 if (!chars
) count
= last
- first
+ 1;
5098 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
5099 ret
= dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buf
);
5103 if (flags
& NTGDI_GETCHARWIDTH_INT
)
5106 /* convert device units to logical */
5107 for (i
= 0; i
< count
; i
++)
5108 buffer
[i
] = width_to_LP( dc
, buffer
[i
] );
5112 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
5113 for (i
= 0; i
< count
; i
++)
5114 ((float *)buf
)[i
] = ((int *)buf
)[i
] * scale
;
5117 release_dc_ptr( dc
);
5122 /* helper for nulldrv_ExtTextOut */
5123 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
5124 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
5126 UINT indices
[3] = {0, 0, 0x20};
5132 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
5134 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
5137 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
, FALSE
);
5138 if (ret
!= GDI_ERROR
) break;
5141 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
5142 if (!image
) return ERROR_SUCCESS
;
5146 if (!ret
) /* empty glyph */
5148 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
5149 return ERROR_SUCCESS
;
5152 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5153 size
= metrics
->gmBlackBoxY
* stride
;
5155 if (!(image
->ptr
= malloc( size
))) return ERROR_OUTOFMEMORY
;
5156 image
->is_copy
= TRUE
;
5157 image
->free
= free_heap_bits
;
5159 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
,
5161 if (ret
== GDI_ERROR
)
5164 return ERROR_NOT_FOUND
;
5166 return ERROR_SUCCESS
;
5169 /* helper for nulldrv_ExtTextOut */
5170 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
5171 LPCWSTR str
, UINT count
, const INT
*dx
)
5176 reset_bounds( &bounds
);
5177 for (i
= 0; i
< count
; i
++)
5179 GLYPHMETRICS metrics
;
5181 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
5183 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
5184 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
5185 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
5186 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
5187 add_bounds_rect( &bounds
, &rect
);
5191 if (flags
& ETO_PDY
)
5194 y
+= dx
[ i
* 2 + 1];
5200 x
+= metrics
.gmCellIncX
;
5201 y
+= metrics
.gmCellIncY
;
5207 /* helper for nulldrv_ExtTextOut */
5208 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
5209 const struct gdi_image_bits
*image
, const RECT
*clip
)
5211 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5212 UINT i
, count
, max_count
;
5214 BYTE
*ptr
= image
->ptr
;
5215 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5217 RECT rect
, clipped_rect
;
5219 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
5220 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
5221 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
5222 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
5223 if (!clip
) clipped_rect
= rect
;
5224 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
5226 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
5227 pts
= malloc( max_count
* sizeof(*pts
) );
5231 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
5232 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
5234 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
5236 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5237 pts
[count
].x
= rect
.left
+ x
;
5238 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5239 pts
[count
+ 1].x
= rect
.left
+ x
;
5240 if (pts
[count
+ 1].x
> pts
[count
].x
)
5242 pts
[count
].y
= pts
[count
+ 1].y
= y
;
5247 assert( count
<= max_count
);
5248 dp_to_lp( dc
, pts
, count
);
5249 for (i
= 0; i
< count
; i
+= 2)
5251 const ULONG pts_count
= 2;
5252 NtGdiPolyPolyDraw( dc
->hSelf
, pts
+ i
, &pts_count
, 1, NtGdiPolyPolyline
);
5257 /***********************************************************************
5258 * nulldrv_ExtTextOut
5260 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5261 LPCWSTR str
, UINT count
, const INT
*dx
)
5263 DC
*dc
= get_nulldrv_dc( dev
);
5269 if (flags
& ETO_OPAQUE
)
5272 COLORREF brush_color
= NtGdiGetNearestColor( dev
->hdc
, dc
->attr
->background_color
);
5273 HBRUSH brush
= NtGdiCreateSolidBrush( brush_color
, NULL
);
5277 orig
= NtGdiSelectBrush( dev
->hdc
, brush
);
5278 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5279 NtGdiPatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5280 NtGdiSelectBrush( dev
->hdc
, orig
);
5281 NtGdiDeleteObjectApp( brush
);
5285 if (!count
) return TRUE
;
5287 if (dc
->aa_flags
!= GGO_BITMAP
)
5289 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5290 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5291 struct gdi_image_bits bits
;
5292 struct bitblt_coords src
, dst
;
5294 /* FIXME Subpixel modes */
5295 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5297 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5298 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5299 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5300 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5302 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5303 src
.x
= src
.visrect
.left
;
5304 src
.y
= src
.visrect
.top
;
5305 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5306 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5308 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5309 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5311 /* we can avoid the GetImage, just query the needed format */
5312 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5313 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5314 info
->bmiHeader
.biWidth
= src
.width
;
5315 info
->bmiHeader
.biHeight
= -src
.height
;
5316 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5317 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5318 if (!err
|| err
== ERROR_BAD_FORMAT
)
5320 /* make the source rectangle relative to the source bits */
5322 src
.visrect
.left
= src
.visrect
.top
= 0;
5323 src
.visrect
.right
= src
.width
;
5324 src
.visrect
.bottom
= src
.height
;
5326 bits
.ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5327 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5328 bits
.is_copy
= TRUE
;
5329 bits
.free
= free_heap_bits
;
5330 err
= ERROR_SUCCESS
;
5335 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5336 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5337 if (!err
&& !bits
.is_copy
)
5339 void *ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5342 if (bits
.free
) bits
.free( &bits
);
5343 return ERROR_OUTOFMEMORY
;
5345 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5346 if (bits
.free
) bits
.free( &bits
);
5348 bits
.is_copy
= TRUE
;
5349 bits
.free
= free_heap_bits
;
5354 /* make x,y relative to the image bits */
5355 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5356 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5357 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5358 aa_flags
, str
, count
, dx
);
5359 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5360 if (bits
.free
) bits
.free( &bits
);
5365 pen
= NtGdiCreatePen( PS_SOLID
, 1, dc
->attr
->text_color
, NULL
);
5366 orig
= NtGdiSelectPen( dev
->hdc
, pen
);
5368 for (i
= 0; i
< count
; i
++)
5370 GLYPHMETRICS metrics
;
5371 struct gdi_image_bits image
;
5373 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5376 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5377 if (image
.free
) image
.free( &image
);
5381 if (flags
& ETO_PDY
)
5384 y
+= dx
[ i
* 2 + 1];
5390 x
+= metrics
.gmCellIncX
;
5391 y
+= metrics
.gmCellIncY
;
5395 NtGdiSelectPen( dev
->hdc
, orig
);
5396 NtGdiDeleteObjectApp( pen
);
5400 /***********************************************************************
5403 * Scale the underline / strikeout line width.
5405 static inline int get_line_width( DC
*dc
, int metric_size
)
5407 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5408 if (width
== 0) width
= 1;
5409 if (metric_size
< 0) width
= -width
;
5413 /***********************************************************************
5414 * NtGdiExtTextOutW (win32u.@)
5416 * Draws text using the currently selected font, background color, and text color.
5420 * x,y [I] coordinates of string
5422 * ETO_GRAYED - undocumented on MSDN
5423 * ETO_OPAQUE - use background color for fill the rectangle
5424 * ETO_CLIPPED - clipping text to the rectangle
5425 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5426 * than encoded characters. Implies ETO_IGNORELANGUAGE
5427 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5428 * Affects BiDi ordering
5429 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5430 * ETO_PDY - unimplemented
5431 * ETO_NUMERICSLATIN - unimplemented always assumed -
5432 * do not translate numbers into locale representations
5433 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5434 * lprect [I] dimensions for clipping or/and opaquing
5435 * str [I] text string
5436 * count [I] number of symbols in string
5437 * lpDx [I] optional parameter with distance between drawing characters
5443 BOOL WINAPI
NtGdiExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
, const RECT
*lprect
,
5444 const WCHAR
*str
, UINT count
, const INT
*lpDx
, DWORD cp
)
5452 double cosEsc
, sinEsc
;
5456 POINT
*deltas
= NULL
, width
= {0, 0};
5457 DC
* dc
= get_dc_ptr( hdc
);
5460 static int quietfixme
= 0;
5462 if (!dc
) return FALSE
;
5463 if (count
> INT_MAX
) return FALSE
;
5465 align
= dc
->attr
->text_align
;
5466 breakRem
= dc
->breakRem
;
5467 layout
= dc
->attr
->layout
;
5469 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5471 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5476 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5478 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5479 if (layout
& LAYOUT_RTL
)
5481 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5482 align
^= TA_RTLREADING
;
5485 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
5486 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
5487 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->attr
->background_mode
,
5488 dc
->attr
->map_mode
);
5490 if(align
& TA_UPDATECP
)
5492 pt
= dc
->attr
->cur_pos
;
5497 NtGdiGetTextMetricsW( hdc
, &tm
, 0 );
5498 NtGdiExtGetObjectW( dc
->hFont
, sizeof(lf
), &lf
);
5500 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
5501 lf
.lfEscapement
= 0;
5503 if ((dc
->attr
->graphics_mode
== GM_COMPATIBLE
) &&
5504 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
5506 lf
.lfEscapement
= -lf
.lfEscapement
;
5509 if(lf
.lfEscapement
!= 0)
5511 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
5512 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
5520 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
5523 lp_to_dp(dc
, (POINT
*)&rc
, 2);
5525 if (flags
& ETO_OPAQUE
)
5526 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
5528 else flags
&= ~ETO_CLIPPED
;
5538 lp_to_dp(dc
, &pt
, 1);
5542 char_extra
= dc
->attr
->char_extra
;
5543 if (char_extra
&& lpDx
&& NtGdiGetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
5544 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5546 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
5549 POINT total
= {0, 0}, desired
[2];
5551 deltas
= malloc( count
* sizeof(*deltas
) );
5554 if (flags
& ETO_PDY
)
5556 for (i
= 0; i
< count
; i
++)
5558 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
5559 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
5564 for (i
= 0; i
< count
; i
++)
5566 deltas
[i
].x
= lpDx
[i
] + char_extra
;
5573 INT
*dx
= malloc( count
* sizeof(*dx
) );
5575 NtGdiGetTextExtentExW( hdc
, str
, count
, -1, NULL
, dx
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5577 deltas
[0].x
= dx
[0];
5579 for (i
= 1; i
< count
; i
++)
5581 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
5587 for(i
= 0; i
< count
; i
++)
5589 total
.x
+= deltas
[i
].x
;
5590 total
.y
+= deltas
[i
].y
;
5592 desired
[0].x
= desired
[0].y
= 0;
5594 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
5595 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
5597 lp_to_dp(dc
, desired
, 2);
5598 desired
[1].x
-= desired
[0].x
;
5599 desired
[1].y
-= desired
[0].y
;
5601 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5603 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5604 desired
[1].x
= -desired
[1].x
;
5605 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5606 desired
[1].y
= -desired
[1].y
;
5609 deltas
[i
].x
= desired
[1].x
- width
.x
;
5610 deltas
[i
].y
= desired
[1].y
- width
.y
;
5620 NtGdiGetTextExtentExW( hdc
, str
, count
, 0, NULL
, NULL
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5621 desired
[0].x
= desired
[0].y
= 0;
5622 desired
[1].x
= sz
.cx
;
5624 lp_to_dp(dc
, desired
, 2);
5625 desired
[1].x
-= desired
[0].x
;
5626 desired
[1].y
-= desired
[0].y
;
5628 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5630 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5631 desired
[1].x
= -desired
[1].x
;
5632 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5633 desired
[1].y
= -desired
[1].y
;
5638 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
5639 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
5640 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
5643 if (align
& TA_UPDATECP
)
5647 dp_to_lp(dc
, &pt
, 1);
5648 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5660 if (align
& TA_UPDATECP
)
5664 dp_to_lp(dc
, &pt
, 1);
5665 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5670 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
5673 y
+= tm
.tmAscent
* cosEsc
;
5674 x
+= tm
.tmAscent
* sinEsc
;
5678 y
-= tm
.tmDescent
* cosEsc
;
5679 x
-= tm
.tmDescent
* sinEsc
;
5686 if (dc
->attr
->background_mode
!= TRANSPARENT
)
5688 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
5690 if(!(flags
& ETO_OPAQUE
) || !lprect
||
5691 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
5692 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
5696 text_box
.right
= x
+ width
.x
;
5697 text_box
.top
= y
- tm
.tmAscent
;
5698 text_box
.bottom
= y
+ tm
.tmDescent
;
5700 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
5701 if (!is_rect_empty( &text_box
))
5702 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
5707 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
5708 str
, count
, (INT
*)deltas
);
5713 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
5715 int underlinePos
, strikeoutPos
;
5716 int underlineWidth
, strikeoutWidth
;
5717 UINT size
= NtGdiGetOutlineTextMetricsInternalW( hdc
, 0, NULL
, 0 );
5718 OUTLINETEXTMETRICW
* otm
= NULL
;
5720 HPEN hpen
= NtGdiSelectPen( hdc
, get_stock_object(NULL_PEN
) );
5721 HBRUSH hbrush
= NtGdiCreateSolidBrush( dc
->attr
->text_color
, NULL
);
5723 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
5728 underlineWidth
= tm
.tmAscent
/ 20 + 1;
5729 strikeoutPos
= tm
.tmAscent
/ 2;
5730 strikeoutWidth
= underlineWidth
;
5734 otm
= malloc( size
);
5735 NtGdiGetOutlineTextMetricsInternalW( hdc
, size
, otm
, 0 );
5736 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
5737 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
5738 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
5739 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
5740 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
5741 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
5748 const ULONG cnt
= 5;
5749 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5750 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5751 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5752 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5753 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
5754 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
5755 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
5756 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
5757 pts
[4].x
= pts
[0].x
;
5758 pts
[4].y
= pts
[0].y
;
5759 dp_to_lp(dc
, pts
, 5);
5760 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
5765 const ULONG cnt
= 5;
5766 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5767 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5768 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5769 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5770 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
5771 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
5772 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
5773 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
5774 pts
[4].x
= pts
[0].x
;
5775 pts
[4].y
= pts
[0].y
;
5776 dp_to_lp(dc
, pts
, 5);
5777 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
5780 NtGdiSelectPen(hdc
, hpen
);
5781 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
5782 NtGdiDeleteObjectApp( hbrush
);
5785 release_dc_ptr( dc
);
5791 /******************************************************************************
5792 * NtGdiGetCharABCWidthsW (win32u.@)
5794 * Retrieves widths of characters in range.
5797 * hdc [I] Handle of device context
5798 * firstChar [I] First character in range to query
5799 * lastChar [I] Last character in range to query
5800 * abc [O] Address of character-width structure
5803 * Only works with TrueType fonts
5805 BOOL WINAPI
NtGdiGetCharABCWidthsW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5806 ULONG flags
, void *buffer
)
5808 DC
*dc
= get_dc_ptr(hdc
);
5810 unsigned int i
, count
= last
;
5814 if (!dc
) return FALSE
;
5818 release_dc_ptr( dc
);
5822 if (flags
& NTGDI_GETCHARABCWIDTHS_INDICES
)
5824 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
5825 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, chars
, buffer
);
5829 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
5831 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
5832 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5833 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
5835 release_dc_ptr( dc
);
5840 if (!chars
) count
= last
- first
+ 1;
5841 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
5842 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
5848 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
5850 /* convert device units to logical */
5851 for (i
= 0; i
< count
; i
++)
5853 abc
[i
].abcA
= width_to_LP( dc
, abc
[i
].abcA
);
5854 abc
[i
].abcB
= width_to_LP( dc
, abc
[i
].abcB
);
5855 abc
[i
].abcC
= width_to_LP( dc
, abc
[i
].abcC
);
5860 /* convert device units to logical */
5861 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
5862 ABCFLOAT
*abcf
= buffer
;
5864 for (i
= 0; i
< count
; i
++)
5866 abcf
[i
].abcfA
= abc
[i
].abcA
* scale
;
5867 abcf
[i
].abcfB
= abc
[i
].abcB
* scale
;
5868 abcf
[i
].abcfC
= abc
[i
].abcC
* scale
;
5873 release_dc_ptr( dc
);
5878 /***********************************************************************
5879 * NtGdiGetGlyphOutline (win32u.@)
5881 DWORD WINAPI
NtGdiGetGlyphOutline( HDC hdc
, UINT ch
, UINT format
, GLYPHMETRICS
*metrics
,
5882 DWORD size
, void *buffer
, const MAT2
*mat2
,
5883 BOOL ignore_rotation
)
5889 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc
, ch
, format
, metrics
, size
, buffer
, mat2
);
5891 if (!mat2
) return GDI_ERROR
;
5893 dc
= get_dc_ptr(hdc
);
5894 if(!dc
) return GDI_ERROR
;
5896 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
5897 ret
= dev
->funcs
->pGetGlyphOutline( dev
, ch
& 0xffff, format
, metrics
, size
, buffer
, mat2
);
5898 release_dc_ptr( dc
);
5903 /**********************************************************************
5904 * __wine_get_file_outline_text_metric (win32u.@)
5906 BOOL CDECL
__wine_get_file_outline_text_metric( const WCHAR
*path
, OUTLINETEXTMETRICW
*otm
)
5908 struct gdi_font
*font
= NULL
;
5910 if (!path
|| !font_funcs
) return FALSE
;
5912 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
5913 font
->lf
.lfHeight
= 100;
5914 if (!font_funcs
->load_font( font
)) goto done
;
5915 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
5917 free_gdi_font( font
);
5921 if (font
) free_gdi_font( font
);
5922 SetLastError( ERROR_INVALID_PARAMETER
);
5926 /*************************************************************************
5927 * NtGdiGetKerningPairs (win32u.@)
5929 DWORD WINAPI
NtGdiGetKerningPairs( HDC hdc
, DWORD count
, KERNINGPAIR
*kern_pair
)
5935 TRACE( "(%p,%d,%p)\n", hdc
, count
, kern_pair
);
5937 if (!count
&& kern_pair
)
5939 SetLastError( ERROR_INVALID_PARAMETER
);
5943 dc
= get_dc_ptr( hdc
);
5946 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
5947 ret
= dev
->funcs
->pGetKerningPairs( dev
, count
, kern_pair
);
5948 release_dc_ptr( dc
);
5952 /*************************************************************************
5953 * NtGdiGetFontData (win32u.@)
5955 * Retrieve data for TrueType font.
5959 * success: Number of bytes returned
5960 * failure: GDI_ERROR
5964 * Calls SetLastError()
5967 DWORD WINAPI
NtGdiGetFontData( HDC hdc
, DWORD table
, DWORD offset
, void *buffer
, DWORD length
)
5969 DC
*dc
= get_dc_ptr(hdc
);
5973 if(!dc
) return GDI_ERROR
;
5975 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
5976 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
5977 release_dc_ptr( dc
);
5981 /*************************************************************************
5982 * NtGdiGetGlyphIndicesW (win32u.@)
5984 DWORD WINAPI
NtGdiGetGlyphIndicesW( HDC hdc
, const WCHAR
*str
, INT count
,
5985 WORD
*indices
, DWORD flags
)
5987 DC
*dc
= get_dc_ptr(hdc
);
5991 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc
, debugstr_wn(str
, count
), count
, indices
, flags
);
5993 if(!dc
) return GDI_ERROR
;
5995 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
5996 ret
= dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, indices
, flags
);
5997 release_dc_ptr( dc
);
6001 /***********************************************************************
6003 * Font Resource API *
6005 ***********************************************************************/
6008 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
6010 WCHAR path
[MAX_PATH
];
6013 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6014 get_fonts_win_dir_path( file
, path
);
6015 pthread_mutex_lock( &font_lock
);
6016 ret
= font_funcs
->add_font( path
, flags
);
6017 pthread_mutex_unlock( &font_lock
);
6018 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6021 get_fonts_data_dir_path( file
, path
);
6022 pthread_mutex_lock( &font_lock
);
6023 ret
= font_funcs
->add_font( path
, flags
);
6024 pthread_mutex_unlock( &font_lock
);
6029 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
6031 WCHAR path
[MAX_PATH
];
6034 get_fonts_win_dir_path( file
, path
);
6035 if (!(ret
= remove_font( path
, flags
)))
6037 get_fonts_data_dir_path( file
, path
);
6038 ret
= remove_font( path
, flags
);
6043 static int add_font_resource( LPCWSTR file
, DWORD flags
)
6049 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6051 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6052 pthread_mutex_lock( &font_lock
);
6053 ret
= font_funcs
->add_font( file
, addfont_flags
);
6054 pthread_mutex_unlock( &font_lock
);
6056 else if (!wcschr( file
, '\\' ))
6057 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6062 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
6068 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6070 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6071 ret
= remove_font( file
, addfont_flags
);
6073 else if (!wcschr( file
, '\\' ))
6074 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6079 static void load_system_bitmap_fonts(void)
6081 static const char * const fonts
[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6082 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6083 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6087 if (!(hkey
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) ))) return;
6088 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
6090 if (query_reg_ascii_value( hkey
, fonts
[i
], info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
6091 add_system_font_resource( (const WCHAR
*)info
->Data
, ADDFONT_ALLOW_BITMAP
);
6096 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
6098 OBJECT_ATTRIBUTES attr
;
6099 UNICODE_STRING nt_name
;
6105 len
= lstrlenW( path
);
6106 while (len
&& path
[len
- 1] == '\\') len
--;
6108 nt_name
.Buffer
= path
;
6109 nt_name
.MaximumLength
= nt_name
.Length
= len
* sizeof(WCHAR
);
6111 attr
.Length
= sizeof(attr
);
6112 attr
.RootDirectory
= 0;
6113 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
6114 attr
.ObjectName
= &nt_name
;
6115 attr
.SecurityDescriptor
= NULL
;
6116 attr
.SecurityQualityOfService
= NULL
;
6118 if (NtOpenFile( &handle
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
,
6119 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
6120 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
))
6125 while (!NtQueryDirectoryFile( handle
, 0, NULL
, NULL
, &io
, buf
, sizeof(buf
),
6126 FileBothDirectoryInformation
, FALSE
, NULL
, FALSE
) &&
6129 FILE_BOTH_DIR_INFORMATION
*info
= (FILE_BOTH_DIR_INFORMATION
*)buf
;
6132 if (!(info
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
6134 memcpy( path
+ len
, info
->FileName
, info
->FileNameLength
);
6135 path
[len
+ info
->FileNameLength
/ sizeof(WCHAR
)] = 0;
6136 font_funcs
->add_font( path
, flags
);
6138 if (!info
->NextEntryOffset
) break;
6139 info
= (FILE_BOTH_DIR_INFORMATION
*)((char *)info
+ info
->NextEntryOffset
);
6146 static void load_file_system_fonts(void)
6148 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024 * sizeof(WCHAR
)])];
6149 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6150 WCHAR
*ptr
, *next
, path
[MAX_PATH
];
6152 /* Windows directory */
6153 get_fonts_win_dir_path( NULL
, path
);
6154 load_directory_fonts( path
, 0 );
6156 /* Wine data directory */
6157 get_fonts_data_dir_path( NULL
, path
);
6158 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6161 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6162 if (query_reg_ascii_value( wine_fonts_key
, "Path", info
, sizeof(value_buffer
) ) &&
6163 info
->Type
== REG_SZ
)
6165 for (ptr
= (WCHAR
*)info
->Data
; ptr
; ptr
= next
)
6167 if ((next
= wcschr( ptr
, ';' ))) *next
++ = 0;
6168 if (next
&& next
- ptr
< 2) continue;
6169 lstrcpynW( path
, ptr
, MAX_PATH
);
6172 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, (lstrlenW( path
) + 1) * sizeof(WCHAR
) );
6173 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6175 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6183 WCHAR value
[LF_FULLFACESIZE
+ 12];
6186 static void update_external_font_keys(void)
6188 struct list external_keys
= LIST_INIT(external_keys
);
6189 HKEY winnt_key
= 0, win9x_key
= 0;
6190 struct gdi_font_family
*family
;
6191 struct external_key
*key
, *next
;
6192 struct gdi_font_face
*face
;
6194 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6196 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
6200 static const WCHAR external_fontsW
[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6202 winnt_key
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
), 0, NULL
);
6203 win9x_key
= reg_create_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
), 0, NULL
);
6205 /* enumerate the fonts and add external ones to the two keys */
6207 if (!(hkey
= reg_create_key( wine_fonts_key
, external_fontsW
, sizeof(external_fontsW
), 0, NULL
)))
6210 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
) - sizeof(nt_prefixW
),
6211 value
, LF_FULLFACESIZE
* sizeof(WCHAR
) ))
6213 if (info
->Type
!= REG_SZ
) continue;
6215 path
= (WCHAR
*)(buffer
+ info
->DataOffset
);
6216 if (path
[0] && path
[1] == ':')
6218 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, info
->DataLength
);
6219 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6222 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6223 if ((face
= find_face_from_full_name( value
)) && !wcsicmp( face
->file
, path
))
6225 face
->flags
|= ADDFONT_EXTERNAL_FOUND
;
6228 if (tmp
&& !*tmp
) *tmp
= ' ';
6229 if (!(key
= malloc( sizeof(*key
) ))) break;
6230 lstrcpyW( key
->value
, value
);
6231 list_add_tail( &external_keys
, &key
->entry
);
6234 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
6236 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
6238 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
6239 if ((face
->flags
& ADDFONT_EXTERNAL_FOUND
)) continue;
6241 lstrcpyW( value
, face
->full_name
);
6242 if (face
->scalable
) lstrcatW( value
, true_type_suffixW
);
6244 if (face
->file
[0] == '\\')
6247 if (file
[5] == ':') file
+= ARRAYSIZE(nt_prefixW
);
6249 else if ((file
= wcsrchr( face
->file
, '\\' )))
6254 len
= (lstrlenW(file
) + 1) * sizeof(WCHAR
);
6255 set_reg_value( winnt_key
, value
, REG_SZ
, file
, len
);
6256 set_reg_value( win9x_key
, value
, REG_SZ
, file
, len
);
6257 set_reg_value( hkey
, value
, REG_SZ
, file
, len
);
6260 LIST_FOR_EACH_ENTRY_SAFE( key
, next
, &external_keys
, struct external_key
, entry
)
6262 reg_delete_value( win9x_key
, key
->value
);
6263 reg_delete_value( winnt_key
, key
->value
);
6264 reg_delete_value( hkey
, key
->value
);
6265 list_remove( &key
->entry
);
6268 NtClose( win9x_key
);
6269 NtClose( winnt_key
);
6273 static void load_registry_fonts(void)
6275 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6276 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6277 KEY_VALUE_FULL_INFORMATION
*enum_info
= (KEY_VALUE_FULL_INFORMATION
*)value_buffer
;
6278 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6282 static const WCHAR dot_fonW
[] = {'.','f','o','n',0};
6284 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6285 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6286 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6289 hkey
= reg_open_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
) );
6291 hkey
= reg_open_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
) );
6294 while (reg_enum_value( hkey
, i
++, enum_info
, sizeof(value_buffer
), value
, sizeof(value
) ))
6296 if (enum_info
->Type
!= REG_SZ
) continue;
6297 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6298 if (find_face_from_full_name( value
)) continue;
6299 if (tmp
&& !*tmp
) *tmp
= ' ';
6301 if (!(dlen
= query_reg_value( hkey
, value
, info
, sizeof(value_buffer
) - sizeof(nt_prefixW
) )) ||
6302 info
->Type
!= REG_SZ
)
6304 WARN( "Unable to get face path %s\n", debugstr_w(value
) );
6308 path
= (WCHAR
*)info
->Data
;
6309 if (path
[0] && path
[1] == ':')
6311 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, dlen
);
6312 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6313 dlen
+= sizeof(nt_prefixW
);
6316 dlen
/= sizeof(WCHAR
);
6318 add_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6319 else if (dlen
>= 6 && !wcsicmp( path
+ dlen
- 5, dot_fonW
))
6320 add_system_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6325 static HKEY
open_hkcu(void)
6329 DWORD_PTR sid_data
[(sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
) / sizeof(DWORD_PTR
)];
6330 DWORD i
, len
= sizeof(sid_data
);
6333 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser
, sid_data
, len
, &len
))
6336 sid
= ((TOKEN_USER
*)sid_data
)->User
.Sid
;
6337 len
= sprintf( buffer
, "\\Registry\\User\\S-%u-%u", sid
->Revision
,
6338 MAKELONG( MAKEWORD( sid
->IdentifierAuthority
.Value
[5], sid
->IdentifierAuthority
.Value
[4] ),
6339 MAKEWORD( sid
->IdentifierAuthority
.Value
[3], sid
->IdentifierAuthority
.Value
[2] )));
6340 for (i
= 0; i
< sid
->SubAuthorityCount
; i
++)
6341 len
+= sprintf( buffer
+ len
, "-%u", sid
->SubAuthority
[i
] );
6342 ascii_to_unicode( bufferW
, buffer
, len
+ 1 );
6344 return reg_open_key( NULL
, bufferW
, len
* sizeof(WCHAR
) );
6347 /***********************************************************************
6350 UINT
font_init(void)
6352 OBJECT_ATTRIBUTES attr
= { sizeof(attr
) };
6353 UNICODE_STRING name
;
6358 static WCHAR wine_font_mutexW
[] =
6359 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6360 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6361 static const WCHAR wine_fonts_keyW
[] =
6362 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6363 static const WCHAR cacheW
[] = {'C','a','c','h','e'};
6365 if (!(hkcu_key
= open_hkcu())) return 0;
6366 wine_fonts_key
= reg_create_key( hkcu_key
, wine_fonts_keyW
, sizeof(wine_fonts_keyW
), 0, NULL
);
6367 if (wine_fonts_key
) dpi
= init_font_options();
6368 if (!dpi
) return 96;
6369 update_codepage( dpi
);
6371 if (!(font_funcs
= init_freetype_lib()))
6374 load_system_bitmap_fonts();
6375 load_file_system_fonts();
6376 font_funcs
->load_fonts();
6378 attr
.Attributes
= OBJ_OPENIF
;
6379 attr
.ObjectName
= &name
;
6380 name
.Buffer
= wine_font_mutexW
;
6381 name
.Length
= name
.MaximumLength
= sizeof(wine_font_mutexW
);
6383 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return dpi
;
6384 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
6386 wine_fonts_cache_key
= reg_create_key( wine_fonts_key
, cacheW
, sizeof(cacheW
),
6387 REG_OPTION_VOLATILE
, &disposition
);
6389 if (disposition
== REG_CREATED_NEW_KEY
)
6391 load_registry_fonts();
6392 update_external_font_keys();
6395 NtReleaseMutant( mutex
, NULL
);
6397 if (disposition
!= REG_CREATED_NEW_KEY
)
6399 load_registry_fonts();
6400 load_font_list_from_cache();
6403 reorder_font_list();
6404 load_gdi_font_subst();
6405 load_gdi_font_replacements();
6406 load_system_links();
6407 dump_gdi_font_list();
6408 dump_gdi_font_subst();
6412 /***********************************************************************
6413 * NtGdiAddFontResourceW (win32u.@)
6415 INT WINAPI
NtGdiAddFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6416 DWORD tid
, void *dv
)
6418 if (!font_funcs
) return 1;
6419 return add_font_resource( str
, flags
);
6422 /***********************************************************************
6423 * NtGdiAddFontMemResourceEx (win32u.@)
6425 HANDLE WINAPI
NtGdiAddFontMemResourceEx( void *ptr
, DWORD size
, void *dv
, ULONG dv_size
,
6432 if (!ptr
|| !size
|| !count
)
6434 SetLastError(ERROR_INVALID_PARAMETER
);
6437 if (!font_funcs
) return NULL
;
6438 if (!(copy
= malloc( size
))) return NULL
;
6439 memcpy( copy
, ptr
, size
);
6441 pthread_mutex_lock( &font_lock
);
6442 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6443 pthread_mutex_unlock( &font_lock
);
6451 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6452 * For now return something unique but quite random
6454 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
6462 WARN( "page fault while writing to *count (%p)\n", count
);
6463 NtGdiRemoveFontMemResourceEx( ret
);
6467 TRACE( "Returning handle %p\n", ret
);
6471 /***********************************************************************
6472 * NtGdiRemoveFontMemResourceEx (win32u.@)
6474 BOOL WINAPI
NtGdiRemoveFontMemResourceEx( HANDLE handle
)
6476 FIXME( "(%p) stub\n", handle
);
6480 /***********************************************************************
6481 * NtGdiRemoveFontResourceW (win32u.@)
6483 BOOL WINAPI
NtGdiRemoveFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6484 DWORD tid
, void *dv
)
6486 if (!font_funcs
) return TRUE
;
6487 return remove_font_resource( str
, flags
);
6490 /***********************************************************************
6491 * NtGdiGetFontUnicodeRanges (win32u.@)
6493 * Retrieve a list of supported Unicode characters in a font.
6496 * hdc [I] Handle to a device context.
6497 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6500 * Success: Number of bytes written to the buffer pointed to by lpgs.
6504 DWORD WINAPI
NtGdiGetFontUnicodeRanges( HDC hdc
, GLYPHSET
*lpgs
)
6508 DC
*dc
= get_dc_ptr(hdc
);
6510 TRACE("(%p, %p)\n", hdc
, lpgs
);
6514 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
6515 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
6521 /*************************************************************
6522 * NtGdiFontIsLinked (win32u.@)
6524 BOOL WINAPI
NtGdiFontIsLinked( HDC hdc
)
6526 DC
*dc
= get_dc_ptr(hdc
);
6530 if (!dc
) return FALSE
;
6531 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
6532 ret
= dev
->funcs
->pFontIsLinked( dev
);
6534 TRACE("returning %d\n", ret
);
6538 /*************************************************************
6539 * NtGdiGetRealizationInfo (win32u.@)
6541 BOOL WINAPI
NtGdiGetRealizationInfo( HDC hdc
, struct font_realization_info
*info
)
6543 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, file_count
);
6548 if (info
->size
!= sizeof(*info
) && !is_v0
)
6551 dc
= get_dc_ptr(hdc
);
6552 if (!dc
) return FALSE
;
6553 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
6554 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
6559 /*************************************************************************
6560 * NtGdiGetRasterizerCaps (win32u.@)
6562 BOOL WINAPI
NtGdiGetRasterizerCaps( RASTERIZER_STATUS
*status
, UINT size
)
6564 status
->nSize
= sizeof(RASTERIZER_STATUS
);
6565 status
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
6566 status
->nLanguageID
= 0;
6570 /*************************************************************************
6571 * NtGdiGetFontFileData (win32u.@)
6573 BOOL WINAPI
NtGdiGetFontFileData( DWORD instance_id
, DWORD file_index
, UINT64
*offset
,
6574 void *buff
, DWORD buff_size
)
6576 struct gdi_font
*font
;
6577 DWORD tag
= 0, size
;
6580 if (!font_funcs
) return FALSE
;
6581 pthread_mutex_lock( &font_lock
);
6582 if ((font
= get_font_from_handle( instance_id
)))
6584 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
6585 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
6586 if (size
!= GDI_ERROR
&& size
>= buff_size
&& *offset
<= size
- buff_size
)
6587 ret
= font_funcs
->get_font_data( font
, tag
, *offset
, buff
, buff_size
) != GDI_ERROR
;
6589 SetLastError( ERROR_INVALID_PARAMETER
);
6591 pthread_mutex_unlock( &font_lock
);
6595 /*************************************************************************
6596 * NtGdiGetFontFileInfo (win32u.@)
6598 BOOL WINAPI
NtGdiGetFontFileInfo( DWORD instance_id
, DWORD file_index
, struct font_fileinfo
*info
,
6599 SIZE_T size
, SIZE_T
*needed
)
6601 SIZE_T required_size
= 0;
6602 struct gdi_font
*font
;
6605 pthread_mutex_lock( &font_lock
);
6607 if ((font
= get_font_from_handle( instance_id
)))
6609 required_size
= sizeof(*info
) + lstrlenW( font
->file
) * sizeof(WCHAR
);
6610 if (required_size
<= size
)
6612 info
->writetime
= font
->writetime
;
6613 info
->size
.QuadPart
= font
->data_size
;
6614 lstrcpyW( info
->path
, font
->file
);
6617 else SetLastError( ERROR_INSUFFICIENT_BUFFER
);
6620 pthread_mutex_unlock( &font_lock
);
6621 if (needed
) *needed
= required_size
;
6625 /*************************************************************
6626 * NtGdiGetCharWidthInfo (win32u.@)
6628 BOOL WINAPI
NtGdiGetCharWidthInfo( HDC hdc
, struct char_width_info
*info
)
6634 dc
= get_dc_ptr(hdc
);
6635 if (!dc
) return FALSE
;
6636 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
6637 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
6641 info
->lsb
= width_to_LP( dc
, info
->lsb
);
6642 info
->rsb
= width_to_LP( dc
, info
->rsb
);