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
);
202 static CPTABLEINFO utf8_cp
;
203 static CPTABLEINFO oem_cp
;
204 CPTABLEINFO ansi_cp
= { 0 };
206 static inline WCHAR
facename_tolower( WCHAR c
)
208 if (c
>= 'A' && c
<= 'Z') return c
- 'A' + 'a';
209 else if (c
> 127) return RtlDowncaseUnicodeChar( c
);
213 static inline int facename_compare( const WCHAR
*str1
, const WCHAR
*str2
, SIZE_T len
)
217 WCHAR c1
= facename_tolower( *str1
++ ), c2
= facename_tolower( *str2
++ );
218 if (c1
!= c2
) return c1
- c2
;
219 else if (!c1
) return 0;
224 /* Device -> World size conversion */
226 /* Performs a device to world transformation on the specified width (which
227 * is in integer format).
229 static inline INT
INTERNAL_XDSTOWS(DC
*dc
, INT width
)
233 /* Perform operation with floating point */
234 floatWidth
= (double)width
* dc
->xformVport2World
.eM11
;
235 /* Round to integers */
236 return GDI_ROUND(floatWidth
);
239 /* Performs a device to world transformation on the specified size (which
240 * is in integer format).
242 static inline INT
INTERNAL_YDSTOWS(DC
*dc
, INT height
)
246 /* Perform operation with floating point */
247 floatHeight
= (double)height
* dc
->xformVport2World
.eM22
;
248 /* Round to integers */
249 return GDI_ROUND(floatHeight
);
252 /* scale width and height but don't mirror them */
254 static inline INT
width_to_LP( DC
*dc
, INT width
)
256 return GDI_ROUND( (double)width
* fabs( dc
->xformVport2World
.eM11
));
259 static inline INT
height_to_LP( DC
*dc
, INT height
)
261 return GDI_ROUND( (double)height
* fabs( dc
->xformVport2World
.eM22
));
264 static inline INT
INTERNAL_YWSTODS(DC
*dc
, INT height
)
267 pt
[0].x
= pt
[0].y
= 0;
271 return pt
[1].y
- pt
[0].y
;
274 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
);
275 static BOOL
FONT_DeleteObject( HGDIOBJ handle
);
277 static const struct gdi_obj_funcs fontobj_funcs
=
279 FONT_GetObjectW
, /* pGetObjectW */
280 NULL
, /* pUnrealizeObject */
281 FONT_DeleteObject
/* pDeleteObject */
286 struct gdi_obj_header obj
;
290 /* for translate_charset_info */
291 static const CHARSETINFO charset_info
[] =
293 { ANSI_CHARSET
, 1252, { {0}, { FS_LATIN1
}}},
294 { EASTEUROPE_CHARSET
, 1250, { {0}, { FS_LATIN2
}}},
295 { RUSSIAN_CHARSET
, 1251, { {0}, { FS_CYRILLIC
}}},
296 { GREEK_CHARSET
, 1253, { {0}, { FS_GREEK
}}},
297 { TURKISH_CHARSET
, 1254, { {0}, { FS_TURKISH
}}},
298 { HEBREW_CHARSET
, 1255, { {0}, { FS_HEBREW
}}},
299 { ARABIC_CHARSET
, 1256, { {0}, { FS_ARABIC
}}},
300 { BALTIC_CHARSET
, 1257, { {0}, { FS_BALTIC
}}},
301 { VIETNAMESE_CHARSET
, 1258, { {0}, { FS_VIETNAMESE
}}},
302 { THAI_CHARSET
, 874, { {0}, { FS_THAI
}}},
303 { SHIFTJIS_CHARSET
, 932, { {0}, { FS_JISJAPAN
}}},
304 { GB2312_CHARSET
, 936, { {0}, { FS_CHINESESIMP
}}},
305 { HANGEUL_CHARSET
, 949, { {0}, { FS_WANSUNG
}}},
306 { CHINESEBIG5_CHARSET
, 950, { {0}, { FS_CHINESETRAD
}}},
307 { JOHAB_CHARSET
, 1361, { {0}, { FS_JOHAB
}}},
308 { 254, CP_UTF8
, { {0}, { 0x04000000 }}},
309 { SYMBOL_CHARSET
, CP_SYMBOL
, { {0}, { FS_SYMBOL
}}}
312 static const char * const default_serif_list
[3] =
316 "Bitstream Vera Serif"
318 static const char * const default_fixed_list
[3] =
322 "Bitstream Vera Sans Mono"
324 static const char * const default_sans_list
[3] =
328 "Bitstream Vera Sans"
330 static WCHAR ff_roman_default
[LF_FACESIZE
];
331 static WCHAR ff_modern_default
[LF_FACESIZE
];
332 static WCHAR ff_swiss_default
[LF_FACESIZE
];
334 static const struct nls_update_font_list
336 UINT ansi_cp
, oem_cp
;
337 const char *oem
, *fixed
, *system
;
338 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
339 /* these are for font substitutes */
340 const char *shelldlg
, *tmsrmn
;
341 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
, *helv_0
, *tmsrmn_0
;
342 struct subst
{ const char *from
, *to
; } arial_0
, courier_new_0
, times_new_roman_0
;
343 } nls_update_font_list
[] =
345 /* Latin 1 (United States) */
346 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
347 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
348 "Tahoma","Times New Roman"
350 /* Latin 1 (Multilingual) */
351 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
352 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
353 "Tahoma","Times New Roman" /* FIXME unverified */
356 { CP_UTF8
, CP_UTF8
, "vga850.fon", "vgafix.fon", "vgasys.fon",
357 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
358 "Tahoma", "Times New Roman" /* FIXME unverified */
361 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
362 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
363 "Tahoma","Times New Roman", /* FIXME unverified */
364 "Fixedsys,238", "System,238",
365 "Courier New,238", "MS Serif,238", "Small Fonts,238",
366 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
367 { "Arial CE,0", "Arial,238" },
368 { "Courier New CE,0", "Courier New,238" },
369 { "Times New Roman CE,0", "Times New Roman,238" }
372 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
373 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
374 "Tahoma","Times New Roman", /* FIXME unverified */
375 "Fixedsys,204", "System,204",
376 "Courier New,204", "MS Serif,204", "Small Fonts,204",
377 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
378 { "Arial Cyr,0", "Arial,204" },
379 { "Courier New Cyr,0", "Courier New,204" },
380 { "Times New Roman Cyr,0", "Times New Roman,204" }
383 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
384 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
385 "Tahoma","Times New Roman", /* FIXME unverified */
386 "Fixedsys,161", "System,161",
387 "Courier New,161", "MS Serif,161", "Small Fonts,161",
388 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
389 { "Arial Greek,0", "Arial,161" },
390 { "Courier New Greek,0", "Courier New,161" },
391 { "Times New Roman Greek,0", "Times New Roman,161" }
394 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
395 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
396 "Tahoma","Times New Roman", /* FIXME unverified */
397 "Fixedsys,162", "System,162",
398 "Courier New,162", "MS Serif,162", "Small Fonts,162",
399 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
400 { "Arial Tur,0", "Arial,162" },
401 { "Courier New Tur,0", "Courier New,162" },
402 { "Times New Roman Tur,0", "Times New Roman,162" }
405 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
406 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
407 "Tahoma","Times New Roman", /* FIXME unverified */
408 "Fixedsys,177", "System,177",
409 "Courier New,177", "MS Serif,177", "Small Fonts,177",
410 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
413 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
414 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
415 "Microsoft Sans Serif","Times New Roman",
416 "Fixedsys,178", "System,178",
417 "Courier New,178", "MS Serif,178", "Small Fonts,178",
418 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
421 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
422 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
423 "Tahoma","Times New Roman", /* FIXME unverified */
424 "Fixedsys,186", "System,186",
425 "Courier New,186", "MS Serif,186", "Small Fonts,186",
426 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
427 { "Arial Baltic,0", "Arial,186" },
428 { "Courier New Baltic,0", "Courier New,186" },
429 { "Times New Roman Baltic,0", "Times New Roman,186" }
432 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
433 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
434 "Tahoma","Times New Roman" /* FIXME unverified */
437 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
438 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
439 "Tahoma","Times New Roman" /* FIXME unverified */
442 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
443 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
444 "MS UI Gothic","MS Serif"
446 /* Chinese Simplified */
447 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
452 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
453 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
456 /* Chinese Traditional */
457 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
458 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
459 "PMingLiU", "MingLiU"
463 static pthread_mutex_t font_lock
= PTHREAD_MUTEX_INITIALIZER
;
465 #ifndef WINE_FONT_DIR
466 #define WINE_FONT_DIR "fonts"
469 #ifdef WORDS_BIGENDIAN
470 #define GET_BE_WORD(x) (x)
471 #define GET_BE_DWORD(x) (x)
473 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
474 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
477 static void get_fonts_data_dir_path( const WCHAR
*file
, WCHAR
*path
)
480 ULONG len
= MAX_PATH
;
482 if ((dir
= ntdll_get_data_dir()))
484 wine_unix_to_nt_file_name( dir
, path
, &len
);
485 asciiz_to_unicode( path
+ len
- 1, "\\" WINE_FONT_DIR
"\\" );
487 else if ((dir
= ntdll_get_build_dir()))
489 wine_unix_to_nt_file_name( dir
, path
, &len
);
490 asciiz_to_unicode( path
+ len
- 1, "\\fonts\\" );
493 if (file
) lstrcatW( path
, file
);
496 static void get_fonts_win_dir_path( const WCHAR
*file
, WCHAR
*path
)
498 asciiz_to_unicode( path
, "\\??\\C:\\windows\\fonts\\" );
499 if (file
) lstrcatW( path
, file
);
502 HKEY
reg_open_key( HKEY root
, const WCHAR
*name
, ULONG name_len
)
504 UNICODE_STRING nameW
= { name_len
, name_len
, (WCHAR
*)name
};
505 OBJECT_ATTRIBUTES attr
;
508 attr
.Length
= sizeof(attr
);
509 attr
.RootDirectory
= root
;
510 attr
.ObjectName
= &nameW
;
512 attr
.SecurityDescriptor
= NULL
;
513 attr
.SecurityQualityOfService
= NULL
;
515 if (NtOpenKeyEx( &ret
, MAXIMUM_ALLOWED
, &attr
, 0 )) return 0;
519 /* wrapper for NtCreateKey that creates the key recursively if necessary */
520 HKEY
reg_create_key( HKEY root
, const WCHAR
*name
, ULONG name_len
,
521 DWORD options
, DWORD
*disposition
)
523 UNICODE_STRING nameW
= { name_len
, name_len
, (WCHAR
*)name
};
524 OBJECT_ATTRIBUTES attr
;
528 attr
.Length
= sizeof(attr
);
529 attr
.RootDirectory
= root
;
530 attr
.ObjectName
= &nameW
;
532 attr
.SecurityDescriptor
= NULL
;
533 attr
.SecurityQualityOfService
= NULL
;
535 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, options
, disposition
);
536 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
538 static const WCHAR registry_rootW
[] = { '\\','R','e','g','i','s','t','r','y','\\' };
539 DWORD pos
= 0, i
= 0, len
= name_len
/ sizeof(WCHAR
);
541 /* don't try to create registry root */
542 if (!root
&& len
> ARRAY_SIZE(registry_rootW
) &&
543 !memcmp( name
, registry_rootW
, sizeof(registry_rootW
) ))
544 i
+= ARRAY_SIZE(registry_rootW
);
546 while (i
< len
&& name
[i
] != '\\') i
++;
547 if (i
== len
) return 0;
550 unsigned int subkey_options
= options
;
551 if (i
< len
) subkey_options
&= ~(REG_OPTION_CREATE_LINK
| REG_OPTION_OPEN_LINK
);
552 nameW
.Buffer
= (WCHAR
*)name
+ pos
;
553 nameW
.Length
= (i
- pos
) * sizeof(WCHAR
);
554 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, subkey_options
, disposition
);
556 if (attr
.RootDirectory
!= root
) NtClose( attr
.RootDirectory
);
557 if (!NT_SUCCESS(status
)) return 0;
559 attr
.RootDirectory
= ret
;
560 while (i
< len
&& name
[i
] == '\\') i
++;
562 while (i
< len
&& name
[i
] != '\\') i
++;
568 HKEY
reg_open_hkcu_key( const char *name
)
571 return reg_open_key( hkcu_key
, nameW
, asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
) );
574 BOOL
set_reg_value( HKEY hkey
, const WCHAR
*name
, UINT type
, const void *value
, DWORD count
)
576 unsigned int name_size
= name
? lstrlenW( name
) * sizeof(WCHAR
) : 0;
577 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
578 return !NtSetValueKey( hkey
, &nameW
, 0, type
, value
, count
);
581 void set_reg_ascii_value( HKEY hkey
, const char *name
, const char *value
)
583 WCHAR nameW
[64], valueW
[128];
584 asciiz_to_unicode( nameW
, name
);
585 set_reg_value( hkey
, nameW
, REG_SZ
, valueW
, asciiz_to_unicode( valueW
, value
));
588 ULONG
query_reg_value( HKEY hkey
, const WCHAR
*name
,
589 KEY_VALUE_PARTIAL_INFORMATION
*info
, ULONG size
)
591 unsigned int name_size
= name
? lstrlenW( name
) * sizeof(WCHAR
) : 0;
592 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
594 if (NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
598 return size
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
601 ULONG
query_reg_ascii_value( HKEY hkey
, const char *name
,
602 KEY_VALUE_PARTIAL_INFORMATION
*info
, ULONG size
)
605 asciiz_to_unicode( nameW
, name
);
606 return query_reg_value( hkey
, nameW
, info
, size
);
609 static BOOL
reg_enum_value( HKEY hkey
, unsigned int index
, KEY_VALUE_FULL_INFORMATION
*info
,
610 ULONG size
, WCHAR
*name
, ULONG name_size
)
614 if (NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
615 info
, size
, &full_size
))
620 if (name_size
< info
->NameLength
+ sizeof(WCHAR
)) return FALSE
;
621 memcpy( name
, info
->Name
, info
->NameLength
);
622 name
[info
->NameLength
/ sizeof(WCHAR
)] = 0;
627 void reg_delete_value( HKEY hkey
, const WCHAR
*name
)
629 unsigned int name_size
= lstrlenW( name
) * sizeof(WCHAR
);
630 UNICODE_STRING nameW
= { name_size
, name_size
, (WCHAR
*)name
};
631 NtDeleteValueKey( hkey
, &nameW
);
634 BOOL
reg_delete_tree( HKEY parent
, const WCHAR
*name
, ULONG name_len
)
637 KEY_NODE_INFORMATION
*key_info
= (KEY_NODE_INFORMATION
*)buffer
;
642 if (!(key
= reg_open_key( parent
, name
, name_len
))) return FALSE
;
644 while (ret
&& !NtEnumerateKey( key
, 0, KeyNodeInformation
, key_info
, sizeof(buffer
), &size
))
645 ret
= reg_delete_tree( key
, key_info
->Name
, key_info
->NameLength
);
647 if (ret
) ret
= !NtDeleteKey( key
);
652 /* font substitutions */
654 struct gdi_font_subst
662 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
664 static inline WCHAR
*get_subst_to_name( struct gdi_font_subst
*subst
)
666 return subst
->names
+ lstrlenW( subst
->names
) + 1;
669 static void dump_gdi_font_subst(void)
671 struct gdi_font_subst
*subst
;
673 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
675 if (subst
->from_charset
!= -1 || subst
->to_charset
!= -1)
676 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst
->names
),
677 subst
->from_charset
, debugstr_w(get_subst_to_name(subst
)), subst
->to_charset
);
679 TRACE("%s -> %s\n", debugstr_w(subst
->names
), debugstr_w(get_subst_to_name(subst
)));
683 static const WCHAR
*get_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, int *to_charset
)
685 struct gdi_font_subst
*subst
;
687 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
689 if (!facename_compare( subst
->names
, from_name
, -1 ) &&
690 (subst
->from_charset
== from_charset
|| subst
->from_charset
== -1))
692 if (to_charset
) *to_charset
= subst
->to_charset
;
693 return get_subst_to_name( subst
);
699 static BOOL
add_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, const WCHAR
*to_name
, int to_charset
)
701 struct gdi_font_subst
*subst
;
702 int len
= lstrlenW( from_name
) + lstrlenW( to_name
) + 2;
704 if (get_gdi_font_subst( from_name
, from_charset
, NULL
)) return FALSE
; /* already exists */
706 if (!(subst
= malloc( offsetof( struct gdi_font_subst
, names
[len
] ) )))
708 lstrcpyW( subst
->names
, from_name
);
709 lstrcpyW( get_subst_to_name(subst
), to_name
);
710 subst
->from_charset
= from_charset
;
711 subst
->to_charset
= to_charset
;
712 list_add_tail( &font_subst_list
, &subst
->entry
);
716 static void load_gdi_font_subst(void)
719 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
722 WCHAR
*data
, *p
, value
[64];
724 if (!(hkey
= reg_open_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
) )))
727 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
729 int from_charset
= -1, to_charset
= -1;
731 if (info
->Type
!= REG_SZ
) continue;
732 data
= (WCHAR
*)((char *)info
+ info
->DataOffset
);
734 TRACE( "Got %s=%s\n", debugstr_w(value
), debugstr_w(data
) );
735 if ((p
= wcsrchr( value
, ',' )) && p
[1])
738 from_charset
= wcstol( p
, NULL
, 10 );
740 if ((p
= wcsrchr( data
, ',' )) && p
[1])
743 to_charset
= wcstol( p
, NULL
, 10 );
746 /* Win 2000 doesn't allow mapping between different charsets
747 or mapping of DEFAULT_CHARSET */
748 if ((!from_charset
|| to_charset
== from_charset
) && to_charset
!= DEFAULT_CHARSET
)
749 add_gdi_font_subst( value
, from_charset
, data
, to_charset
);
756 static int family_namecmp( const WCHAR
*str1
, const WCHAR
*str2
)
758 int prio1
, prio2
, vert1
= (str1
[0] == '@' ? 1 : 0), vert2
= (str2
[0] == '@' ? 1 : 0);
760 if (!facename_compare( str1
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio1
= 0;
761 else if (!facename_compare( str1
, ff_modern_default
, LF_FACESIZE
- 1 )) prio1
= 1;
762 else if (!facename_compare( str1
, ff_roman_default
, LF_FACESIZE
- 1 )) prio1
= 2;
765 if (!facename_compare( str2
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio2
= 0;
766 else if (!facename_compare( str2
, ff_modern_default
, LF_FACESIZE
- 1 )) prio2
= 1;
767 else if (!facename_compare( str2
, ff_roman_default
, LF_FACESIZE
- 1 )) prio2
= 2;
770 if (prio1
!= prio2
) return prio1
- prio2
;
771 if (vert1
!= vert2
) return vert1
- vert2
;
772 return facename_compare( str1
+ vert1
, str2
+ vert2
, LF_FACESIZE
- 1 );
775 static int family_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
777 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, name_entry
);
778 return family_namecmp( (const WCHAR
*)key
, family
->family_name
);
781 static int family_second_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
783 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, second_name_entry
);
784 return family_namecmp( (const WCHAR
*)key
, family
->second_name
);
787 static int face_full_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
789 const struct gdi_font_face
*face
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_face
, full_name_entry
);
790 return facename_compare( (const WCHAR
*)key
, face
->full_name
, LF_FULLFACESIZE
- 1 );
793 static struct wine_rb_tree family_name_tree
= { family_name_compare
};
794 static struct wine_rb_tree family_second_name_tree
= { family_second_name_compare
};
795 static struct wine_rb_tree face_full_name_tree
= { face_full_name_compare
};
797 static int face_is_in_full_name_tree( const struct gdi_font_face
*face
)
799 return face
->full_name_entry
.parent
|| face_full_name_tree
.root
== &face
->full_name_entry
;
802 static struct gdi_font_family
*create_family( const WCHAR
*name
, const WCHAR
*second_name
)
804 struct gdi_font_family
*family
= malloc( sizeof(*family
) );
806 family
->refcount
= 1;
807 lstrcpynW( family
->family_name
, name
, LF_FACESIZE
);
808 if (second_name
&& second_name
[0] && wcsicmp( name
, second_name
))
810 lstrcpynW( family
->second_name
, second_name
, LF_FACESIZE
);
811 add_gdi_font_subst( second_name
, -1, name
, -1 );
813 else family
->second_name
[0] = 0;
814 list_init( &family
->faces
);
815 family
->replacement
= NULL
;
816 wine_rb_put( &family_name_tree
, family
->family_name
, &family
->name_entry
);
817 if (family
->second_name
[0]) wine_rb_put( &family_second_name_tree
, family
->second_name
, &family
->second_name_entry
);
821 static void release_family( struct gdi_font_family
*family
)
823 if (--family
->refcount
) return;
824 assert( list_empty( &family
->faces
));
825 wine_rb_remove( &family_name_tree
, &family
->name_entry
);
826 if (family
->second_name
[0]) wine_rb_remove( &family_second_name_tree
, &family
->second_name_entry
);
827 if (family
->replacement
) release_family( family
->replacement
);
831 static struct gdi_font_family
*find_family_from_name( const WCHAR
*name
)
833 struct wine_rb_entry
*entry
;
834 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) return NULL
;
835 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, name_entry
);
838 static struct gdi_font_family
*find_family_from_any_name( const WCHAR
*name
)
840 struct wine_rb_entry
*entry
;
841 struct gdi_font_family
*family
;
842 if ((family
= find_family_from_name( name
))) return family
;
843 if (!(entry
= wine_rb_get( &family_second_name_tree
, name
))) return NULL
;
844 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, second_name_entry
);
847 static struct gdi_font_face
*find_face_from_full_name( const WCHAR
*full_name
)
849 struct wine_rb_entry
*entry
;
850 if (!(entry
= wine_rb_get( &face_full_name_tree
, full_name
))) return NULL
;
851 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_face
, full_name_entry
);
854 static const struct list
*get_family_face_list( const struct gdi_font_family
*family
)
856 return family
->replacement
? &family
->replacement
->faces
: &family
->faces
;
859 static struct gdi_font_face
*family_find_face_from_filename( struct gdi_font_family
*family
, const WCHAR
*file_name
)
861 struct gdi_font_face
*face
;
863 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
865 if (!face
->file
) continue;
866 file
= wcsrchr(face
->file
, '\\');
867 if (!file
) file
= face
->file
;
869 if (wcsicmp( file
, file_name
)) continue;
876 static struct gdi_font_face
*find_face_from_filename( const WCHAR
*file_name
, const WCHAR
*family_name
)
878 struct gdi_font_family
*family
;
879 struct gdi_font_face
*face
;
881 TRACE( "looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(family_name
) );
885 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
886 if ((face
= family_find_face_from_filename( family
, file_name
))) return face
;
890 if (!(family
= find_family_from_name( family_name
))) return NULL
;
891 return family_find_face_from_filename( family
, file_name
);
894 static BOOL
add_family_replacement( const WCHAR
*new_name
, const WCHAR
*replace
)
896 struct gdi_font_family
*new_family
, *family
;
897 struct gdi_font_face
*face
;
898 WCHAR new_name_vert
[LF_FACESIZE
], replace_vert
[LF_FACESIZE
];
900 if (!(family
= find_family_from_any_name( replace
)))
902 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace
) );
906 if (family
->replacement
)
908 TRACE( "%s is replaced by another font, skipping.\n", debugstr_w(replace
) );
912 if (!(new_family
= create_family( new_name
, NULL
))) return FALSE
;
913 new_family
->replacement
= family
;
915 TRACE( "mapping %s to %s\n", debugstr_w(replace
), debugstr_w(new_name
) );
917 /* also add replacement for vertical font if necessary */
918 if (replace
[0] == '@') return TRUE
;
919 if (list_empty( &family
->faces
)) return TRUE
;
920 face
= LIST_ENTRY( list_head(&family
->faces
), struct gdi_font_face
, entry
);
921 if (!(face
->fs
.fsCsb
[0] & FS_DBCS_MASK
)) return TRUE
;
923 new_name_vert
[0] = '@';
924 lstrcpynW( new_name_vert
+ 1, new_name
, LF_FACESIZE
- 1 );
925 if (find_family_from_any_name( new_name_vert
)) return TRUE
; /* already exists */
927 replace_vert
[0] = '@';
928 lstrcpynW( replace_vert
+ 1, replace
, LF_FACESIZE
- 1 );
929 add_family_replacement( new_name_vert
, replace_vert
);
934 * The replacement list is a way to map an entire font
935 * family onto another family. For example adding
937 * [HKCU\Software\Wine\Fonts\Replacements]
938 * "Wingdings"="Winedings"
940 * would enumerate the Winedings font both as Winedings and
941 * Wingdings. However if a real Wingdings font is present the
942 * replacement does not take place.
944 static void load_gdi_font_replacements(void)
947 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
950 WCHAR value
[LF_FACESIZE
];
952 static const WCHAR replacementsW
[] = {'R','e','p','l','a','c','e','m','e','n','t','s'};
954 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
955 if (!(hkey
= reg_open_key( wine_fonts_key
, replacementsW
, sizeof(replacementsW
) ))) return;
957 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
959 WCHAR
*data
= (WCHAR
*)((char *)info
+ info
->DataOffset
);
960 /* "NewName"="Oldname" */
961 if (!find_family_from_any_name( value
))
963 if (info
->Type
== REG_MULTI_SZ
)
965 WCHAR
*replace
= data
;
968 if (add_family_replacement( value
, replace
)) break;
969 replace
+= lstrlenW(replace
) + 1;
972 else if (info
->Type
== REG_SZ
) add_family_replacement( value
, data
);
974 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
979 static void dump_gdi_font_list(void)
981 struct gdi_font_family
*family
;
982 struct gdi_font_face
*face
;
984 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
986 TRACE( "Family: %s\n", debugstr_w(family
->family_name
) );
987 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
989 TRACE( "\t%s\t%s\t%08x", debugstr_w(face
->style_name
), debugstr_w(face
->full_name
),
991 if (!face
->scalable
) TRACE(" %d", face
->size
.height
);
997 static BOOL
enum_fallbacks( DWORD pitch_and_family
, int index
, WCHAR buffer
[LF_FACESIZE
] )
1001 const char * const *defaults
;
1003 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
)
1004 defaults
= default_fixed_list
;
1005 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
)
1006 defaults
= default_serif_list
;
1008 defaults
= default_sans_list
;
1009 asciiz_to_unicode( buffer
, defaults
[index
] );
1012 return font_funcs
->enum_family_fallbacks( pitch_and_family
, index
- 3, buffer
);
1015 static void set_default_family( DWORD pitch_and_family
, WCHAR
*default_name
)
1017 struct wine_rb_entry
*entry
;
1018 WCHAR name
[LF_FACESIZE
];
1021 while (enum_fallbacks( pitch_and_family
, i
++, name
))
1023 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) continue;
1024 wine_rb_remove( &family_name_tree
, entry
);
1025 lstrcpynW( default_name
, name
, LF_FACESIZE
- 1 );
1026 wine_rb_put( &family_name_tree
, name
, entry
);
1031 static void reorder_font_list(void)
1033 set_default_family( FF_ROMAN
, ff_roman_default
);
1034 set_default_family( FF_MODERN
, ff_modern_default
);
1035 set_default_family( FF_SWISS
, ff_swiss_default
);
1038 static void release_face( struct gdi_font_face
*face
)
1040 if (--face
->refcount
) return;
1043 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1044 list_remove( &face
->entry
);
1045 release_family( face
->family
);
1047 if (face_is_in_full_name_tree( face
)) wine_rb_remove( &face_full_name_tree
, &face
->full_name_entry
);
1049 free( face
->style_name
);
1050 free( face
->full_name
);
1051 free( face
->cached_enum_data
);
1055 static int remove_font( const WCHAR
*file
, DWORD flags
)
1057 struct gdi_font_family
*family
, *family_next
;
1058 struct gdi_font_face
*face
, *face_next
;
1061 pthread_mutex_lock( &font_lock
);
1062 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family
, family_next
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1065 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, struct gdi_font_face
, entry
)
1067 if (!face
->file
) continue;
1068 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
1069 if (!wcsicmp( face
->file
, file
))
1071 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
1072 release_face( face
);
1076 release_family( family
);
1078 pthread_mutex_unlock( &font_lock
);
1082 static inline BOOL
faces_equal( const struct gdi_font_face
*f1
, const struct gdi_font_face
*f2
)
1084 if (facename_compare( f1
->full_name
, f2
->full_name
, -1 )) return FALSE
;
1085 if (f1
->scalable
) return TRUE
;
1086 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1087 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1090 static inline int style_order( const struct gdi_font_face
*face
)
1092 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1100 case NTM_BOLD
| NTM_ITALIC
:
1103 WARN( "Don't know how to order face %s with flags 0x%08x\n",
1104 debugstr_w(face
->full_name
), face
->ntmFlags
);
1109 static BOOL
insert_face_in_family_list( struct gdi_font_face
*face
, struct gdi_font_family
*family
)
1111 struct gdi_font_face
*cursor
;
1113 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, struct gdi_font_face
, entry
)
1115 if (faces_equal( face
, cursor
))
1117 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
1118 debugstr_w(face
->full_name
), debugstr_w(family
->family_name
),
1119 cursor
->version
, face
->version
);
1121 if (face
->file
&& cursor
->file
&& !wcsicmp( face
->file
, cursor
->file
))
1124 TRACE("Font %s already in list, refcount now %d\n",
1125 debugstr_w(face
->file
), cursor
->refcount
);
1128 if (face
->version
<= cursor
->version
)
1130 TRACE("Original font %s is newer so skipping %s\n",
1131 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1136 TRACE("Replacing original %s with %s\n",
1137 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1138 list_add_before( &cursor
->entry
, &face
->entry
);
1139 face
->family
= family
;
1142 if (face_is_in_full_name_tree( cursor
))
1144 wine_rb_replace( &face_full_name_tree
, &cursor
->full_name_entry
, &face
->full_name_entry
);
1145 memset( &cursor
->full_name_entry
, 0, sizeof(cursor
->full_name_entry
) );
1147 release_face( cursor
);
1151 if (style_order( face
) < style_order( cursor
)) break;
1154 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face
->full_name
),
1155 debugstr_w(family
->family_name
), debugstr_w(face
->file
) );
1156 list_add_before( &cursor
->entry
, &face
->entry
);
1157 if (face
->scalable
) wine_rb_put( &face_full_name_tree
, face
->full_name
, &face
->full_name_entry
);
1158 face
->family
= family
;
1164 static struct gdi_font_face
*create_face( struct gdi_font_family
*family
, const WCHAR
*style
,
1165 const WCHAR
*fullname
, const WCHAR
*file
,
1166 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
1167 DWORD ntmflags
, DWORD version
, DWORD flags
,
1168 const struct bitmap_font_size
*size
)
1170 struct gdi_font_face
*face
= calloc( 1, sizeof(*face
) );
1173 face
->style_name
= wcsdup( style
);
1174 face
->full_name
= wcsdup( fullname
);
1175 face
->face_index
= index
;
1177 face
->ntmFlags
= ntmflags
;
1178 face
->version
= version
;
1179 face
->flags
= flags
;
1180 face
->data_ptr
= data_ptr
;
1181 face
->data_size
= data_size
;
1182 if (file
) face
->file
= wcsdup( file
);
1183 if (size
) face
->size
= *size
;
1184 else face
->scalable
= TRUE
;
1185 if (insert_face_in_family_list( face
, family
)) return face
;
1186 release_face( face
);
1190 int add_gdi_face( const WCHAR
*family_name
, const WCHAR
*second_name
,
1191 const WCHAR
*style
, const WCHAR
*fullname
, const WCHAR
*file
,
1192 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
1193 DWORD ntmflags
, DWORD version
, DWORD flags
,
1194 const struct bitmap_font_size
*size
)
1196 struct gdi_font_face
*face
;
1197 struct gdi_font_family
*family
;
1200 if ((family
= find_family_from_name( family_name
))) family
->refcount
++;
1201 else if (!(family
= create_family( family_name
, second_name
))) return ret
;
1203 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1204 index
, fs
, ntmflags
, version
, flags
, size
)))
1206 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1207 release_face( face
);
1209 release_family( family
);
1212 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
1214 WCHAR vert_family
[LF_FACESIZE
], vert_second
[LF_FACESIZE
], vert_full
[LF_FULLFACESIZE
];
1216 vert_family
[0] = '@';
1217 lstrcpynW( vert_family
+ 1, family_name
, LF_FACESIZE
- 1 );
1219 if (second_name
&& second_name
[0])
1221 vert_second
[0] = '@';
1222 lstrcpynW( vert_second
+ 1, second_name
, LF_FACESIZE
- 1 );
1224 else vert_second
[0] = 0;
1229 lstrcpynW( vert_full
+ 1, fullname
, LF_FULLFACESIZE
- 1 );
1230 fullname
= vert_full
;
1233 if ((family
= find_family_from_name( vert_family
))) family
->refcount
++;
1234 else if (!(family
= create_family( vert_family
, vert_second
))) return ret
;
1236 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1237 index
, fs
, ntmflags
, version
, flags
| ADDFONT_VERTICAL_FONT
, size
)))
1239 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1240 release_face( face
);
1242 release_family( family
);
1256 struct bitmap_font_size size
;
1259 /* WCHAR file_name[]; */
1262 static void load_face_from_cache( HKEY hkey_family
, struct gdi_font_family
*family
,
1263 void *buffer
, DWORD buffer_size
, BOOL scalable
)
1265 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1266 KEY_NODE_INFORMATION
*node_info
= (KEY_NODE_INFORMATION
*)buffer
;
1267 DWORD index
= 0, total_size
;
1268 struct gdi_font_face
*face
;
1271 struct cached_face
*cached
;
1273 while (reg_enum_value( hkey_family
, index
++, info
,
1274 buffer_size
- sizeof(DWORD
), name
, sizeof(name
) ))
1276 cached
= (struct cached_face
*)((char *)info
+ info
->DataOffset
);
1277 if (info
->Type
== REG_BINARY
&& info
->DataLength
> sizeof(*cached
))
1279 ((DWORD
*)cached
)[info
->DataLength
/ sizeof(DWORD
)] = 0;
1280 if ((face
= create_face( family
, name
, cached
->full_name
,
1281 cached
->full_name
+ lstrlenW(cached
->full_name
) + 1,
1282 NULL
, 0, cached
->index
, cached
->fs
, cached
->ntmflags
, cached
->version
,
1283 cached
->flags
, scalable
? NULL
: &cached
->size
)))
1286 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1287 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1288 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1290 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1291 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1292 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1293 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1295 release_face( face
);
1300 /* load bitmap strikes */
1303 while (!NtEnumerateKey( hkey_family
, index
++, KeyNodeInformation
, node_info
,
1304 buffer_size
, &total_size
))
1306 if ((hkey_strike
= reg_open_key( hkey_family
, node_info
->Name
, node_info
->NameLength
)))
1308 load_face_from_cache( hkey_strike
, family
, buffer
, buffer_size
, FALSE
);
1309 NtClose( hkey_strike
);
1314 static void load_font_list_from_cache(void)
1317 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)buffer
;
1318 KEY_NODE_INFORMATION
*enum_info
= (KEY_NODE_INFORMATION
*)buffer
;
1319 DWORD family_index
= 0, total_size
;
1320 struct gdi_font_family
*family
;
1322 WCHAR
*second_name
= (WCHAR
*)info
->Data
;
1324 while (!NtEnumerateKey( wine_fonts_cache_key
, family_index
++, KeyNodeInformation
, enum_info
,
1325 sizeof(buffer
), &total_size
))
1327 if (!(hkey_family
= reg_open_key( wine_fonts_cache_key
, enum_info
->Name
,
1328 enum_info
->NameLength
)))
1330 TRACE( "opened family key %s\n", debugstr_wn(enum_info
->Name
, enum_info
->NameLength
/ sizeof(WCHAR
)) );
1331 if (!query_reg_value( hkey_family
, NULL
, info
, sizeof(buffer
) ))
1334 family
= create_family( buffer
, second_name
);
1336 load_face_from_cache( hkey_family
, family
, buffer
, sizeof(buffer
), TRUE
);
1338 NtClose( hkey_family
);
1339 release_family( family
);
1343 static void add_face_to_cache( struct gdi_font_face
*face
)
1345 HKEY hkey_family
, hkey_face
;
1346 DWORD len
, buffer
[1024];
1347 struct cached_face
*cached
= (struct cached_face
*)buffer
;
1349 if (!(hkey_family
= reg_create_key( wine_fonts_cache_key
, face
->family
->family_name
,
1350 lstrlenW( face
->family
->family_name
) * sizeof(WCHAR
),
1351 REG_OPTION_VOLATILE
, NULL
)))
1354 if (face
->family
->second_name
[0])
1355 set_reg_value( hkey_family
, NULL
, REG_SZ
, face
->family
->second_name
,
1356 (lstrlenW( face
->family
->second_name
) + 1) * sizeof(WCHAR
) );
1358 if (!face
->scalable
)
1363 sprintf( name
, "%d", face
->size
.y_ppem
);
1364 hkey_face
= reg_create_key( hkey_family
, nameW
,
1365 asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
),
1366 REG_OPTION_VOLATILE
, NULL
);
1368 else hkey_face
= hkey_family
;
1370 memset( cached
, 0, sizeof(*cached
) );
1371 cached
->index
= face
->face_index
;
1372 cached
->flags
= face
->flags
;
1373 cached
->ntmflags
= face
->ntmFlags
;
1374 cached
->version
= face
->version
;
1375 cached
->fs
= face
->fs
;
1376 if (!face
->scalable
) cached
->size
= face
->size
;
1377 lstrcpyW( cached
->full_name
, face
->full_name
);
1378 len
= lstrlenW( face
->full_name
) + 1;
1379 lstrcpyW( cached
->full_name
+ len
, face
->file
);
1380 len
+= lstrlenW( face
->file
) + 1;
1382 set_reg_value( hkey_face
, face
->style_name
, REG_BINARY
, cached
,
1383 offsetof( struct cached_face
, full_name
[len
] ));
1385 if (hkey_face
!= hkey_family
) NtClose( hkey_face
);
1386 NtClose( hkey_family
);
1389 static void remove_face_from_cache( struct gdi_font_face
*face
)
1391 HKEY hkey_family
, hkey
;
1393 if (!(hkey_family
= reg_open_key( wine_fonts_cache_key
, face
->family
->family_name
,
1394 lstrlenW( face
->family
->family_name
) * sizeof(WCHAR
) )))
1397 if (!face
->scalable
)
1401 sprintf( name
, "%d", face
->size
.y_ppem
);
1402 if ((hkey
= reg_open_key( hkey_family
, nameW
,
1403 asciiz_to_unicode( nameW
, name
) - sizeof(WCHAR
) )))
1405 NtDeleteKey( hkey
);
1409 else reg_delete_value( hkey_family
, face
->style_name
);
1411 NtClose( hkey_family
);
1416 struct gdi_font_link
1420 WCHAR name
[LF_FACESIZE
];
1424 struct gdi_font_link_entry
1428 WCHAR family_name
[LF_FACESIZE
];
1431 static struct list font_links
= LIST_INIT(font_links
);
1433 static struct gdi_font_link
*find_gdi_font_link( const WCHAR
*name
)
1435 struct gdi_font_link
*link
;
1437 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1438 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 )) return link
;
1442 static struct gdi_font_family
*find_family_from_font_links( const WCHAR
*name
, const WCHAR
*subst
,
1445 struct gdi_font_link
*link
;
1446 struct gdi_font_link_entry
*entry
;
1447 struct gdi_font_family
*family
;
1449 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1451 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 ) ||
1452 (subst
&& !facename_compare( link
->name
, subst
, LF_FACESIZE
- 1 )))
1454 TRACE("found entry in system list\n");
1455 LIST_FOR_EACH_ENTRY( entry
, &link
->links
, struct gdi_font_link_entry
, entry
)
1457 const struct gdi_font_link
*links
;
1459 family
= find_family_from_name( entry
->family_name
);
1460 if (!fs
.fsCsb
[0]) return family
;
1461 if (fs
.fsCsb
[0] & entry
->fs
.fsCsb
[0]) return family
;
1462 if ((links
= find_gdi_font_link( family
->family_name
)) && fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
1470 static struct gdi_font_link
*add_gdi_font_link( const WCHAR
*name
)
1472 struct gdi_font_link
*link
= find_gdi_font_link( name
);
1474 if (link
) return link
;
1475 if ((link
= malloc( sizeof(*link
) )))
1477 lstrcpynW( link
->name
, name
, LF_FACESIZE
);
1478 memset( &link
->fs
, 0, sizeof(link
->fs
) );
1479 list_init( &link
->links
);
1480 list_add_tail( &font_links
, &link
->entry
);
1485 static void add_gdi_font_link_entry( struct gdi_font_link
*link
, const WCHAR
*family_name
, FONTSIGNATURE fs
)
1487 struct gdi_font_link_entry
*entry
;
1489 entry
= malloc( sizeof(*entry
) );
1490 lstrcpynW( entry
->family_name
, family_name
, LF_FACESIZE
);
1492 link
->fs
.fsCsb
[0] |= fs
.fsCsb
[0];
1493 link
->fs
.fsCsb
[1] |= fs
.fsCsb
[1];
1494 list_add_tail( &link
->links
, &entry
->entry
);
1497 static const WCHAR lucida_sans_unicodeW
[] =
1498 {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
1499 static const WCHAR microsoft_sans_serifW
[] =
1500 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1501 static const WCHAR tahomaW
[] =
1502 {'T','a','h','o','m','a',0};
1503 static const WCHAR ms_ui_gothicW
[] =
1504 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1505 static const WCHAR sim_sunW
[] =
1506 {'S','i','m','S','u','n',0};
1507 static const WCHAR gulimW
[] =
1508 {'G','u','l','i','m',0};
1509 static const WCHAR p_ming_li_uW
[] =
1510 {'P','M','i','n','g','L','i','U',0};
1511 static const WCHAR batangW
[] =
1512 {'B','a','t','a','n','g',0};
1514 static const WCHAR
* const font_links_list
[] =
1516 lucida_sans_unicodeW
,
1517 microsoft_sans_serifW
,
1521 static const struct font_links_defaults_list
1523 /* Keyed off substitution for "MS Shell Dlg" */
1524 const WCHAR
*shelldlg
;
1525 /* Maximum of four substitutes, plus terminating NULL pointer */
1526 const WCHAR
*substitutes
[5];
1527 } font_links_defaults_list
[] =
1529 /* Non East-Asian */
1530 { tahomaW
, /* FIXME unverified ordering */
1531 { ms_ui_gothicW
, sim_sunW
, gulimW
, p_ming_li_uW
, NULL
}
1533 /* Below lists are courtesy of
1534 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1538 { ms_ui_gothicW
, p_ming_li_uW
, sim_sunW
, gulimW
, NULL
}
1540 /* Chinese Simplified */
1542 { sim_sunW
, p_ming_li_uW
, ms_ui_gothicW
, batangW
, NULL
}
1546 { gulimW
, p_ming_li_uW
, ms_ui_gothicW
, sim_sunW
, NULL
}
1548 /* Chinese Traditional */
1550 { p_ming_li_uW
, sim_sunW
, ms_ui_gothicW
, batangW
, NULL
}
1554 static void populate_system_links( const WCHAR
*name
, const WCHAR
* const *values
)
1556 struct gdi_font_family
*family
;
1557 struct gdi_font_face
*face
;
1558 struct gdi_font_link
*font_link
;
1559 const WCHAR
*file
, *value
;
1561 /* Don't store fonts that are only substitutes for other fonts */
1562 if (get_gdi_font_subst( name
, -1, NULL
))
1564 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
) );
1567 font_link
= add_gdi_font_link( name
);
1568 for ( ; *values
; values
++)
1570 if (!facename_compare( name
, *values
, -1 )) continue;
1571 if (!(value
= get_gdi_font_subst( *values
, -1, NULL
))) value
= *values
;
1572 if (!(family
= find_family_from_name( value
))) continue;
1573 /* use first extant filename for this Family */
1574 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1576 if (!face
->file
) continue;
1577 file
= wcsrchr(face
->file
, '\\');
1578 if (!file
) file
= face
->file
;
1580 if ((face
= find_face_from_filename( file
, value
)))
1582 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1583 TRACE( "added internal SystemLink for %s to %s in %s\n",
1584 debugstr_w(name
), debugstr_w(value
), debugstr_w(file
) );
1586 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
) );
1592 static void load_system_links(void)
1596 const WCHAR
*shelldlg_name
;
1597 struct gdi_font_link
*font_link
, *system_font_link
;
1598 struct gdi_font_face
*face
;
1600 static const WCHAR ms_shell_dlgW
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
1601 static const WCHAR systemW
[] = {'S','y','s','t','e','m',0};
1602 static const WCHAR tahoma_ttfW
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1604 if ((hkey
= reg_open_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
) )))
1607 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1608 WCHAR value
[MAX_PATH
];
1609 WCHAR
*entry
, *next
;
1612 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
1614 /* Don't store fonts that are only substitutes for other fonts */
1615 if (!get_gdi_font_subst( value
, -1, NULL
))
1617 char *data
= (char *)info
+ info
->DataOffset
;
1618 font_link
= add_gdi_font_link( value
);
1619 for (entry
= (WCHAR
*)data
; (char *)entry
< data
+ info
->DataLength
&& *entry
; entry
= next
)
1621 const WCHAR
*family_name
= NULL
;
1624 TRACE( "%s: %s\n", debugstr_w(value
), debugstr_w(entry
) );
1626 next
= entry
+ lstrlenW(entry
) + 1;
1627 if ((p
= wcschr( entry
, ',' )))
1630 while (*p
== ' ' || *p
== '\t') p
++;
1631 if (!(family_name
= get_gdi_font_subst( p
, -1, NULL
))) family_name
= p
;
1633 if ((face
= find_face_from_filename( entry
, family_name
)))
1635 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1636 TRACE("Adding file %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1638 else TRACE( "Unable to find file %s family %s\n",
1639 debugstr_w(entry
), debugstr_w(family_name
) );
1642 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1647 if ((shelldlg_name
= get_gdi_font_subst( ms_shell_dlgW
, -1, NULL
)))
1649 for (i
= 0; i
< ARRAY_SIZE(font_links_defaults_list
); i
++)
1651 const WCHAR
*subst
= get_gdi_font_subst( font_links_defaults_list
[i
].shelldlg
, -1, NULL
);
1653 if ((!facename_compare( font_links_defaults_list
[i
].shelldlg
, shelldlg_name
, -1 ) ||
1654 (subst
&& !facename_compare( subst
, shelldlg_name
, -1 ))))
1656 for (j
= 0; j
< ARRAY_SIZE(font_links_list
); j
++)
1657 populate_system_links( font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
1658 if (!facename_compare(shelldlg_name
, font_links_defaults_list
[i
].substitutes
[0], -1))
1659 populate_system_links( shelldlg_name
, font_links_defaults_list
[i
].substitutes
);
1663 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1665 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1668 system_font_link
= add_gdi_font_link( systemW
);
1669 if ((face
= find_face_from_filename( tahoma_ttfW
, tahomaW
)))
1671 add_gdi_font_link_entry( system_font_link
, face
->family
->family_name
, face
->fs
);
1672 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1674 if ((font_link
= find_gdi_font_link( tahomaW
)))
1676 struct gdi_font_link_entry
*entry
;
1677 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1678 add_gdi_font_link_entry( system_font_link
, entry
->family_name
, entry
->fs
);
1682 /* see TranslateCharsetInfo */
1683 BOOL
translate_charset_info( DWORD
*src
, CHARSETINFO
*cs
, DWORD flags
)
1689 case TCI_SRCFONTSIG
:
1690 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
1691 if (charset_info
[i
].fs
.fsCsb
[0] & src
[0]) goto found
;
1693 case TCI_SRCCODEPAGE
:
1694 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
1695 if (PtrToUlong(src
) == charset_info
[i
].ciACP
) goto found
;
1697 case TCI_SRCCHARSET
:
1698 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
1699 if (PtrToUlong(src
) == charset_info
[i
].ciCharset
) goto found
;
1705 *cs
= charset_info
[i
];
1711 static BOOL
can_select_face( const struct gdi_font_face
*face
, FONTSIGNATURE fs
, BOOL can_use_bitmap
)
1713 struct gdi_font_link
*font_link
;
1715 if (!face
->scalable
&& !can_use_bitmap
) return FALSE
;
1716 if (!fs
.fsCsb
[0]) return TRUE
;
1717 if (fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return TRUE
;
1718 if (!(font_link
= find_gdi_font_link( face
->family
->family_name
))) return FALSE
;
1719 if (fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) return TRUE
;
1723 static struct gdi_font_face
*find_best_matching_face( const struct gdi_font_family
*family
,
1724 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1725 BOOL can_use_bitmap
)
1727 struct gdi_font_face
*face
= NULL
, *best
= NULL
, *best_bitmap
= NULL
;
1728 unsigned int best_score
= 4;
1730 int it
= !!lf
->lfItalic
;
1731 int bd
= lf
->lfWeight
> 550;
1732 int height
= lf
->lfHeight
;
1734 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1736 int italic
= !!(face
->ntmFlags
& NTM_ITALIC
);
1737 int bold
= !!(face
->ntmFlags
& NTM_BOLD
);
1738 int score
= (italic
^ it
) + (bold
^ bd
);
1740 if (!can_select_face( face
, fs
, can_use_bitmap
)) continue;
1741 if (score
> best_score
) continue;
1742 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic
, bold
, it
, bd
);
1745 if (best
->scalable
&& best_score
== 0) break;
1746 if (!best
->scalable
)
1750 diff
= height
- (signed int)best
->size
.height
;
1752 diff
= -height
- ((signed int)best
->size
.height
- best
->size
.internal_leading
);
1754 (best_diff
> 0 && diff
>= 0 && diff
< best_diff
) ||
1755 (best_diff
< 0 && diff
> best_diff
))
1757 TRACE( "%d is better for %d diff was %d\n", best
->size
.height
, height
, best_diff
);
1760 if (best_score
== 0 && best_diff
== 0) break;
1764 if (!best
) return NULL
;
1765 return best
->scalable
? best
: best_bitmap
;
1768 static struct gdi_font_face
*find_matching_face_by_name( const WCHAR
*name
, const WCHAR
*subst
,
1769 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1770 BOOL can_use_bitmap
, const WCHAR
**orig_name
)
1772 struct gdi_font_family
*family
;
1773 struct gdi_font_face
*face
;
1775 family
= find_family_from_any_name( name
);
1776 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
1779 family
= find_family_from_any_name( subst
);
1780 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
1783 /* search by full face name */
1784 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1785 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1786 if (!facename_compare( face
->full_name
, name
, LF_FACESIZE
- 1 ) &&
1787 can_select_face( face
, fs
, can_use_bitmap
))
1790 if ((family
= find_family_from_font_links( name
, subst
, fs
)))
1792 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1797 if (orig_name
&& family
!= face
->family
)
1798 *orig_name
= family
->family_name
;
1802 static struct gdi_font_face
*find_any_face( const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1803 BOOL can_use_bitmap
, BOOL want_vertical
)
1805 struct gdi_font_family
*family
;
1806 struct gdi_font_face
*face
;
1807 WCHAR name
[LF_FACESIZE
+ 1];
1810 /* first try the family fallbacks */
1811 while (enum_fallbacks( lf
->lfPitchAndFamily
, i
++, name
))
1815 memmove(name
+ 1, name
, min(lstrlenW(name
), LF_FACESIZE
));
1819 if (!(family
= find_family_from_any_name(name
))) continue;
1820 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1822 /* otherwise try only scalable */
1823 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1825 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1826 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1828 if (!can_use_bitmap
) return NULL
;
1829 /* then also bitmap fonts */
1830 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1832 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1833 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1838 static struct gdi_font_face
*find_matching_face( const LOGFONTW
*lf
, CHARSETINFO
*csi
, BOOL can_use_bitmap
,
1839 BOOL
*substituted
, const WCHAR
**orig_name
)
1841 BOOL want_vertical
= (lf
->lfFaceName
[0] == '@');
1842 struct gdi_font_face
*face
;
1844 if (!translate_charset_info( (DWORD
*)(INT_PTR
)lf
->lfCharSet
, csi
, TCI_SRCCHARSET
))
1846 if (lf
->lfCharSet
!= DEFAULT_CHARSET
) FIXME( "Untranslated charset %d\n", lf
->lfCharSet
);
1847 csi
->fs
.fsCsb
[0] = 0;
1850 if (lf
->lfFaceName
[0])
1853 const WCHAR
*subst
= get_gdi_font_subst( lf
->lfFaceName
, lf
->lfCharSet
, &subst_charset
);
1857 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf
->lfFaceName
), lf
->lfCharSet
,
1858 debugstr_w(subst
), (subst_charset
!= -1) ? subst_charset
: lf
->lfCharSet
);
1859 if (subst_charset
!= -1)
1860 translate_charset_info( (DWORD
*)(INT_PTR
)subst_charset
, csi
, TCI_SRCCHARSET
);
1861 *substituted
= TRUE
;
1864 if ((face
= find_matching_face_by_name( lf
->lfFaceName
, subst
, lf
, csi
->fs
, can_use_bitmap
, orig_name
)))
1867 *substituted
= FALSE
; /* substitution is no longer relevant */
1869 /* If requested charset was DEFAULT_CHARSET then try using charset
1870 corresponding to the current ansi codepage */
1871 if (!csi
->fs
.fsCsb
[0])
1873 if (!translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, csi
, TCI_SRCCODEPAGE
))
1875 FIXME( "TCI failed on codepage %d\n", ansi_cp
.CodePage
);
1876 csi
->fs
.fsCsb
[0] = 0;
1880 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1881 if (csi
->fs
.fsCsb
[0])
1883 csi
->fs
.fsCsb
[0] = 0;
1884 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1886 if (want_vertical
&& (face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, FALSE
))) return face
;
1890 /* realized font objects */
1892 #define FIRST_FONT_HANDLE 1
1893 #define MAX_FONT_HANDLES 256
1895 struct font_handle_entry
1897 struct gdi_font
*font
;
1898 WORD generation
; /* generation count for reusing handle values */
1901 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
1902 static struct font_handle_entry
*next_free
;
1903 static struct font_handle_entry
*next_unused
= font_handles
;
1905 static struct font_handle_entry
*handle_entry( DWORD handle
)
1907 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
1909 if (idx
< MAX_FONT_HANDLES
)
1911 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
1912 return &font_handles
[idx
];
1914 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
1918 static struct gdi_font
*get_font_from_handle( DWORD handle
)
1920 struct font_handle_entry
*entry
= handle_entry( handle
);
1922 if (entry
) return entry
->font
;
1923 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1927 static DWORD
alloc_font_handle( struct gdi_font
*font
)
1929 struct font_handle_entry
*entry
;
1933 next_free
= (struct font_handle_entry
*)entry
->font
;
1934 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
1935 entry
= next_unused
++;
1938 ERR( "out of realized font handles\n" );
1942 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
1943 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
1946 static void free_font_handle( DWORD handle
)
1948 struct font_handle_entry
*entry
;
1950 if ((entry
= handle_entry( handle
)))
1952 entry
->font
= (struct gdi_font
*)next_free
;
1957 static struct gdi_font
*alloc_gdi_font( const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
)
1959 UINT len
= file
? lstrlenW(file
) : 0;
1960 struct gdi_font
*font
= calloc( 1, offsetof( struct gdi_font
, file
[len
+ 1] ));
1963 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
1965 font
->kern_count
= -1;
1966 list_init( &font
->child_fonts
);
1970 FILE_NETWORK_OPEN_INFORMATION info
;
1971 UNICODE_STRING nt_name
;
1972 OBJECT_ATTRIBUTES attr
;
1974 nt_name
.Buffer
= (WCHAR
*)file
;
1975 nt_name
.Length
= nt_name
.MaximumLength
= len
* sizeof(WCHAR
);
1977 attr
.Length
= sizeof(attr
);
1978 attr
.RootDirectory
= 0;
1979 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
1980 attr
.ObjectName
= &nt_name
;
1981 attr
.SecurityDescriptor
= NULL
;
1982 attr
.SecurityQualityOfService
= NULL
;
1984 if (!NtQueryFullAttributesFile( &attr
, &info
))
1986 font
->writetime
.dwLowDateTime
= info
.LastWriteTime
.LowPart
;
1987 font
->writetime
.dwHighDateTime
= info
.LastWriteTime
.HighPart
;
1988 font
->data_size
= info
.EndOfFile
.QuadPart
;
1989 memcpy( font
->file
, file
, len
* sizeof(WCHAR
) );
1994 font
->data_ptr
= data_ptr
;
1995 font
->data_size
= data_size
;
1998 font
->handle
= alloc_font_handle( font
);
2002 static void free_gdi_font( struct gdi_font
*font
)
2005 struct gdi_font
*child
, *child_next
;
2007 if (font
->private) font_funcs
->destroy_font( font
);
2008 free_font_handle( font
->handle
);
2009 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, struct gdi_font
, entry
)
2011 list_remove( &child
->entry
);
2012 free_gdi_font( child
);
2014 for (i
= 0; i
< font
->gm_size
; i
++) free( font
->gm
[i
] );
2015 free( font
->otm
.otmpFamilyName
);
2016 free( font
->otm
.otmpStyleName
);
2017 free( font
->otm
.otmpFaceName
);
2018 free( font
->otm
.otmpFullName
);
2020 free( font
->kern_pairs
);
2021 free( font
->gsub_table
);
2025 static inline const WCHAR
*get_gdi_font_name( struct gdi_font
*font
)
2027 return font
->use_logfont_name
? font
->lf
.lfFaceName
: (WCHAR
*)font
->otm
.otmpFamilyName
;
2030 static struct gdi_font
*create_gdi_font( const struct gdi_font_face
*face
, const WCHAR
*family_name
,
2031 const LOGFONTW
*lf
)
2033 struct gdi_font
*font
;
2035 if (!(font
= alloc_gdi_font( face
->file
, face
->data_ptr
, face
->data_size
))) return NULL
;
2036 font
->fs
= face
->fs
;
2038 font
->fake_italic
= (lf
->lfItalic
&& !(face
->ntmFlags
& NTM_ITALIC
));
2039 font
->fake_bold
= (lf
->lfWeight
> 550 && !(face
->ntmFlags
& NTM_BOLD
));
2040 font
->scalable
= face
->scalable
;
2041 font
->face_index
= face
->face_index
;
2042 font
->ntmFlags
= face
->ntmFlags
;
2043 font
->aa_flags
= HIWORD( face
->flags
);
2044 if (!family_name
) family_name
= face
->family
->family_name
;
2045 font
->otm
.otmpFamilyName
= (char *)wcsdup( family_name
);
2046 font
->otm
.otmpStyleName
= (char *)wcsdup( face
->style_name
);
2047 font
->otm
.otmpFaceName
= (char *)wcsdup( face
->full_name
);
2051 struct glyph_metrics
2054 ABC abc
; /* metrics of the unrotated char */
2058 #define GM_BLOCK_SIZE 128
2060 /* TODO: GGO format support */
2061 static BOOL
get_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
, GLYPHMETRICS
*gm
, ABC
*abc
)
2063 UINT block
= index
/ GM_BLOCK_SIZE
;
2064 UINT entry
= index
% GM_BLOCK_SIZE
;
2066 if (block
< font
->gm_size
&& font
->gm
[block
] && font
->gm
[block
][entry
].init
)
2068 *gm
= font
->gm
[block
][entry
].gm
;
2069 *abc
= font
->gm
[block
][entry
].abc
;
2071 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2072 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point( &gm
->gmptGlyphOrigin
),
2073 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2080 static void set_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
,
2081 const GLYPHMETRICS
*gm
, const ABC
*abc
)
2083 UINT block
= index
/ GM_BLOCK_SIZE
;
2084 UINT entry
= index
% GM_BLOCK_SIZE
;
2086 if (block
>= font
->gm_size
)
2088 struct glyph_metrics
**ptr
;
2090 if (!(ptr
= realloc( font
->gm
, (block
+ 1) * sizeof(*ptr
) ))) return;
2091 memset( ptr
+ font
->gm_size
, 0, (block
+ 1 - font
->gm_size
) * sizeof(*ptr
) );
2092 font
->gm_size
= block
+ 1;
2095 if (!font
->gm
[block
])
2097 font
->gm
[block
] = calloc( sizeof(**font
->gm
), GM_BLOCK_SIZE
);
2098 if (!font
->gm
[block
]) return;
2100 font
->gm
[block
][entry
].gm
= *gm
;
2101 font
->gm
[block
][entry
].abc
= *abc
;
2102 font
->gm
[block
][entry
].init
= TRUE
;
2106 /* GSUB table support */
2120 } GSUB_ScriptRecord
;
2125 GSUB_ScriptRecord ScriptRecord
[1];
2132 } GSUB_LangSysRecord
;
2136 WORD DefaultLangSys
;
2138 GSUB_LangSysRecord LangSysRecord
[1];
2143 WORD LookupOrder
; /* Reserved */
2144 WORD ReqFeatureIndex
;
2146 WORD FeatureIndex
[1];
2153 } GSUB_FeatureRecord
;
2158 GSUB_FeatureRecord FeatureRecord
[1];
2163 WORD FeatureParams
; /* Reserved */
2165 WORD LookupListIndex
[1];
2184 WORD CoverageFormat
;
2187 } GSUB_CoverageFormat1
;
2193 WORD StartCoverageIndex
;
2198 WORD CoverageFormat
;
2200 GSUB_RangeRecord RangeRecord
[1];
2201 } GSUB_CoverageFormat2
;
2205 WORD SubstFormat
; /* = 1 */
2208 } GSUB_SingleSubstFormat1
;
2212 WORD SubstFormat
; /* = 2 */
2216 } GSUB_SingleSubstFormat2
;
2218 static GSUB_Script
*GSUB_get_script_table( GSUB_Header
*header
, const char *tag
)
2220 GSUB_ScriptList
*script
;
2221 GSUB_Script
*deflt
= NULL
;
2224 script
= (GSUB_ScriptList
*)((BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
2225 TRACE("%i scripts in this font\n", GET_BE_WORD(script
->ScriptCount
) );
2226 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
2228 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
2229 GSUB_Script
*scr
= (GSUB_Script
*)((BYTE
*)script
+ offset
);
2230 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, tag
, 4 )) return scr
;
2231 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, "dflt", 4 )) deflt
= scr
;
2236 static GSUB_LangSys
*GSUB_get_lang_table( GSUB_Script
*script
, const char *tag
)
2241 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
2243 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
2245 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
2246 lang
= (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2247 if (!memcmp( script
->LangSysRecord
[i
].LangSysTag
, tag
, 4 )) return lang
;
2249 offset
= GET_BE_WORD(script
->DefaultLangSys
);
2250 if (offset
) return (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2254 static GSUB_Feature
*GSUB_get_feature( GSUB_Header
*header
, GSUB_LangSys
*lang
, const char *tag
)
2257 const GSUB_FeatureList
*feature
;
2259 feature
= (GSUB_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
2260 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
2261 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
2263 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
2264 if (!memcmp( feature
->FeatureRecord
[index
].FeatureTag
, tag
, 4 ))
2265 return (GSUB_Feature
*)((BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
2270 static const char *get_opentype_script( const struct gdi_font
*font
)
2273 * I am not sure if this is the correct way to generate our script tag
2275 switch (font
->charset
)
2277 case ANSI_CHARSET
: return "latn";
2278 case BALTIC_CHARSET
: return "latn"; /* ?? */
2279 case CHINESEBIG5_CHARSET
: return "hani";
2280 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
2281 case GB2312_CHARSET
: return "hani";
2282 case GREEK_CHARSET
: return "grek";
2283 case HANGUL_CHARSET
: return "hang";
2284 case RUSSIAN_CHARSET
: return "cyrl";
2285 case SHIFTJIS_CHARSET
: return "kana";
2286 case TURKISH_CHARSET
: return "latn"; /* ?? */
2287 case VIETNAMESE_CHARSET
: return "latn";
2288 case JOHAB_CHARSET
: return "latn"; /* ?? */
2289 case ARABIC_CHARSET
: return "arab";
2290 case HEBREW_CHARSET
: return "hebr";
2291 case THAI_CHARSET
: return "thai";
2292 default: return "latn";
2296 static void *get_GSUB_vert_feature( struct gdi_font
*font
)
2298 GSUB_Header
*header
;
2299 GSUB_Script
*script
;
2300 GSUB_LangSys
*language
;
2301 GSUB_Feature
*feature
;
2302 DWORD length
= font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, NULL
, 0 );
2304 if (length
== GDI_ERROR
) return NULL
;
2306 header
= malloc( length
);
2307 font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, header
, length
);
2308 TRACE( "Loaded GSUB table of %i bytes\n", length
);
2310 if ((script
= GSUB_get_script_table( header
, get_opentype_script(font
) )))
2312 if ((language
= GSUB_get_lang_table( script
, "xxxx" ))) /* Need to get Lang tag */
2314 feature
= GSUB_get_feature( header
, language
, "vrt2" );
2315 if (!feature
) feature
= GSUB_get_feature( header
, language
, "vert" );
2318 font
->gsub_table
= header
;
2321 TRACE("vrt2/vert feature not found\n");
2323 else TRACE("Language not found\n");
2325 else TRACE("Script not found\n");
2331 static int GSUB_is_glyph_covered( void *table
, UINT glyph
)
2333 GSUB_CoverageFormat1
*cf1
= table
;
2335 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
2337 int i
, count
= GET_BE_WORD(cf1
->GlyphCount
);
2339 TRACE("Coverage Format 1, %i glyphs\n",count
);
2340 for (i
= 0; i
< count
; i
++) if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
])) return i
;
2343 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
2346 GSUB_CoverageFormat2
*cf2
= table
;
2348 count
= GET_BE_WORD(cf2
->RangeCount
);
2349 TRACE("Coverage Format 2, %i ranges\n",count
);
2350 for (i
= 0; i
< count
; i
++)
2352 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) return -1;
2353 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
2354 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
2356 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
2357 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
2362 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
2367 static UINT
GSUB_apply_feature( GSUB_Header
*header
, GSUB_Feature
*feature
, UINT glyph
)
2369 GSUB_LookupList
*lookup
= (GSUB_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2372 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
2373 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
2375 GSUB_LookupTable
*look
;
2376 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
2377 look
= (GSUB_LookupTable
*)((BYTE
*)lookup
+ offset
);
2378 TRACE("type %i, flag %x, subtables %i\n",
2379 GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
2380 if (GET_BE_WORD(look
->LookupType
) == 1)
2382 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
2384 GSUB_SingleSubstFormat1
*ssf1
;
2385 offset
= GET_BE_WORD(look
->SubTable
[j
]);
2386 ssf1
= (GSUB_SingleSubstFormat1
*)((BYTE
*)look
+ offset
);
2387 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
2389 int offset
= GET_BE_WORD(ssf1
->Coverage
);
2390 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
2391 if (GSUB_is_glyph_covered( (BYTE
*) ssf1
+ offset
, glyph
) != -1)
2393 TRACE(" Glyph 0x%x ->",glyph
);
2394 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
2395 TRACE(" 0x%x\n",glyph
);
2400 GSUB_SingleSubstFormat2
*ssf2
;
2403 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
2404 offset
= GET_BE_WORD(ssf1
->Coverage
);
2405 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
2406 index
= GSUB_is_glyph_covered( (BYTE
*)ssf2
+ offset
, glyph
);
2407 TRACE(" Coverage index %i\n",index
);
2410 TRACE(" Glyph is 0x%x ->",glyph
);
2411 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
2412 TRACE("0x%x\n",glyph
);
2417 else FIXME("We only handle SubType 1\n");
2422 static UINT
get_GSUB_vert_glyph( struct gdi_font
*font
, UINT glyph
)
2424 if (!glyph
) return glyph
;
2425 if (!font
->gsub_table
) return glyph
;
2426 return GSUB_apply_feature( font
->gsub_table
, font
->vert_feature
, glyph
);
2429 static void add_child_font( struct gdi_font
*font
, const WCHAR
*family_name
)
2431 FONTSIGNATURE fs
= {{0}};
2432 struct gdi_font
*child
;
2433 struct gdi_font_face
*face
;
2435 if (!(face
= find_matching_face_by_name( family_name
, NULL
, &font
->lf
, fs
, FALSE
, NULL
))) return;
2437 if (!(child
= create_gdi_font( face
, family_name
, &font
->lf
))) return;
2438 child
->matrix
= font
->matrix
;
2439 child
->can_use_bitmap
= font
->can_use_bitmap
;
2440 child
->scale_y
= font
->scale_y
;
2441 child
->aveWidth
= font
->aveWidth
;
2442 child
->charset
= font
->charset
;
2443 child
->codepage
= font
->codepage
;
2444 child
->base_font
= font
;
2445 list_add_tail( &font
->child_fonts
, &child
->entry
);
2446 TRACE( "created child font %p for base %p\n", child
, font
);
2449 static void create_child_font_list( struct gdi_font
*font
)
2451 struct gdi_font_link
*font_link
;
2452 struct gdi_font_link_entry
*entry
;
2453 const WCHAR
* font_name
= (WCHAR
*)font
->otm
.otmpFaceName
;
2455 if ((font_link
= find_gdi_font_link( font_name
)))
2457 TRACE("found entry in system list\n");
2458 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2459 add_child_font( font
, entry
->family_name
);
2462 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2463 * Sans Serif. This is how asian windows get default fallbacks for fonts
2465 if (ansi_cp
.MaximumCharacterSize
== 2 && font
->charset
!= SYMBOL_CHARSET
&& font
->charset
!= OEM_CHARSET
&&
2466 facename_compare( font_name
, microsoft_sans_serifW
, -1 ) != 0)
2468 if ((font_link
= find_gdi_font_link( microsoft_sans_serifW
)))
2470 TRACE("found entry in default fallback list\n");
2471 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2472 add_child_font( font
, entry
->family_name
);
2479 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
2480 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
2481 static unsigned int unused_font_count
;
2482 #define UNUSED_CACHE_SIZE 10
2484 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
2485 const FMAT2
*matrix
, BOOL can_use_bitmap
)
2487 if (font
->hash
!= hash
) return TRUE
;
2488 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
2489 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2490 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
2491 return facename_compare( font
->lf
.lfFaceName
, lf
->lfFaceName
, -1 );
2494 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2496 DWORD hash
= 0, *ptr
, two_chars
;
2500 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
2502 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
2504 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
2507 pwc
= (WCHAR
*)&two_chars
;
2509 *pwc
= towupper(*pwc
);
2511 *pwc
= towupper(*pwc
);
2515 hash
^= !can_use_bitmap
;
2519 static void cache_gdi_font( struct gdi_font
*font
)
2521 static DWORD cache_num
= 1;
2523 font
->cache_num
= cache_num
++;
2524 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
2525 list_add_head( &gdi_font_list
, &font
->entry
);
2526 TRACE( "font %p\n", font
);
2529 static struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2531 struct gdi_font
*font
;
2532 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
2534 /* try the in-use list */
2535 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
2537 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
2538 list_remove( &font
->entry
);
2539 list_add_head( &gdi_font_list
, &font
->entry
);
2540 if (!font
->refcount
++)
2542 list_remove( &font
->unused_entry
);
2543 unused_font_count
--;
2550 static void release_gdi_font( struct gdi_font
*font
)
2554 TRACE( "font %p\n", font
);
2556 /* add it to the unused list */
2557 pthread_mutex_lock( &font_lock
);
2558 if (!--font
->refcount
)
2560 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
2561 if (unused_font_count
> UNUSED_CACHE_SIZE
)
2563 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
2564 TRACE( "freeing %p\n", font
);
2565 list_remove( &font
->entry
);
2566 list_remove( &font
->unused_entry
);
2567 free_gdi_font( font
);
2569 else unused_font_count
++;
2571 pthread_mutex_unlock( &font_lock
);
2574 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
2576 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
2578 set_reg_ascii_value( hkey
, "Courier", fl
->courier
);
2579 set_reg_ascii_value( hkey
, "MS Serif", fl
->serif
);
2580 set_reg_ascii_value( hkey
, "MS Sans Serif", sserif
);
2581 set_reg_ascii_value( hkey
, "Small Fonts", fl
->small
);
2584 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2587 set_reg_ascii_value( hkey
, name
, value
);
2591 asciiz_to_unicode( nameW
, name
);
2592 reg_delete_value( hkey
, nameW
);
2596 static void update_font_association_info(void)
2598 static const WCHAR associated_charsetW
[] =
2599 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
2601 if (ansi_cp
.MaximumCharacterSize
== 2)
2604 if ((hkey
= reg_create_key( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
), 0, NULL
)))
2607 if ((hsubkey
= reg_create_key( hkey
, associated_charsetW
, sizeof(associated_charsetW
),
2610 switch (ansi_cp
.CodePage
)
2613 set_value_key(hsubkey
, "ANSI(00)", "NO");
2614 set_value_key(hsubkey
, "OEM(FF)", "NO");
2615 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2620 set_value_key(hsubkey
, "ANSI(00)", "YES");
2621 set_value_key(hsubkey
, "OEM(FF)", "YES");
2622 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2628 /* TODO: Associated DefaultFonts */
2634 reg_delete_tree( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
) );
2637 static void set_multi_value_key( HKEY hkey
, const WCHAR
*name
, const char *value
, DWORD len
)
2640 ascii_to_unicode( valueW
, value
, len
);
2642 set_reg_value( hkey
, name
, REG_MULTI_SZ
, valueW
, len
* sizeof(WCHAR
) );
2644 reg_delete_value( hkey
, name
);
2647 static void update_font_system_link_info(void)
2649 static const char system_link_simplified_chinese
[] =
2650 "SIMSUN.TTC,SimSun\0"
2651 "MINGLIU.TTC,PMingLiu\0"
2652 "MSGOTHIC.TTC,MS UI Gothic\0"
2653 "BATANG.TTC,Batang\0";
2654 static const char system_link_traditional_chinese
[] =
2655 "MINGLIU.TTC,PMingLiu\0"
2656 "SIMSUN.TTC,SimSun\0"
2657 "MSGOTHIC.TTC,MS UI Gothic\0"
2658 "BATANG.TTC,Batang\0";
2659 static const char system_link_japanese
[] =
2660 "MSGOTHIC.TTC,MS UI Gothic\0"
2661 "MINGLIU.TTC,PMingLiU\0"
2662 "SIMSUN.TTC,SimSun\0"
2663 "GULIM.TTC,Gulim\0";
2664 static const char system_link_korean
[] =
2666 "MSGOTHIC.TTC,MS UI Gothic\0"
2667 "MINGLIU.TTC,PMingLiU\0"
2668 "SIMSUN.TTC,SimSun\0";
2669 static const char system_link_non_cjk
[] =
2670 "MSGOTHIC.TTC,MS UI Gothic\0"
2671 "MINGLIU.TTC,PMingLiU\0"
2672 "SIMSUN.TTC,SimSun\0"
2673 "GULIM.TTC,Gulim\0";
2676 if ((hkey
= reg_create_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
), 0, NULL
)))
2681 switch (ansi_cp
.CodePage
)
2684 link
= system_link_japanese
;
2685 len
= sizeof(system_link_japanese
);
2688 link
= system_link_simplified_chinese
;
2689 len
= sizeof(system_link_simplified_chinese
);
2692 link
= system_link_korean
;
2693 len
= sizeof(system_link_korean
);
2696 link
= system_link_traditional_chinese
;
2697 len
= sizeof(system_link_traditional_chinese
);
2700 link
= system_link_non_cjk
;
2701 len
= sizeof(system_link_non_cjk
);
2703 set_multi_value_key(hkey
, lucida_sans_unicodeW
, link
, len
);
2704 set_multi_value_key(hkey
, microsoft_sans_serifW
, link
, len
);
2705 set_multi_value_key(hkey
, tahomaW
, link
, len
);
2710 static void update_codepage( UINT screen_dpi
)
2712 USHORT utf8_hdr
[2] = { 0, CP_UTF8
};
2713 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[40 * sizeof(WCHAR
)])];
2714 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
2721 BOOL done
= FALSE
, cp_match
= FALSE
;
2723 static const WCHAR log_pixelsW
[] = {'L','o','g','P','i','x','e','l','s',0};
2725 size
= query_reg_value( wine_fonts_key
, log_pixelsW
, info
, sizeof(value_buffer
) );
2726 if (size
== sizeof(DWORD
) && info
->Type
== REG_DWORD
)
2727 font_dpi
= *(DWORD
*)info
->Data
;
2729 RtlInitCodePageTable( utf8_hdr
, &utf8_cp
);
2730 if (NtCurrentTeb()->Peb
->AnsiCodePageData
)
2731 RtlInitCodePageTable( NtCurrentTeb()->Peb
->AnsiCodePageData
, &ansi_cp
);
2734 if (NtCurrentTeb()->Peb
->OemCodePageData
)
2735 RtlInitCodePageTable( NtCurrentTeb()->Peb
->OemCodePageData
, &oem_cp
);
2738 sprintf( cpbuf
, "%u,%u", ansi_cp
.CodePage
, oem_cp
.CodePage
);
2739 asciiz_to_unicode( cpbufW
, cpbuf
);
2741 if (query_reg_ascii_value( wine_fonts_key
, "Codepages", info
, sizeof(value_buffer
) ))
2743 cp_match
= !wcscmp( (const WCHAR
*)info
->Data
, cpbufW
);
2744 if (cp_match
&& screen_dpi
== font_dpi
) return; /* already set correctly */
2745 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2746 debugstr_w((const WCHAR
*)info
->Data
), font_dpi
, ansi_cp
.CodePage
, oem_cp
.CodePage
, screen_dpi
);
2748 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2749 ansi_cp
.CodePage
, oem_cp
.CodePage
, screen_dpi
);
2751 set_reg_ascii_value( wine_fonts_key
, "Codepages", cpbuf
);
2752 set_reg_value( wine_fonts_key
, log_pixelsW
, REG_DWORD
, &screen_dpi
, sizeof(screen_dpi
) );
2754 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
2756 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
.CodePage
&&
2757 nls_update_font_list
[i
].oem_cp
== oem_cp
.CodePage
)
2760 if ((software_hkey
= reg_create_key( NULL
, software_config_keyW
,
2761 sizeof(software_config_keyW
), 0, NULL
)))
2763 static const WCHAR fontsW
[] = {'F','o','n','t','s'};
2764 hkey
= reg_create_key( software_hkey
, fontsW
, sizeof(fontsW
), 0, NULL
);
2765 NtClose( software_hkey
);
2768 set_reg_ascii_value( hkey
, "OEMFONT.FON", nls_update_font_list
[i
].oem
);
2769 set_reg_ascii_value( hkey
, "FIXEDFON.FON", nls_update_font_list
[i
].fixed
);
2770 set_reg_ascii_value( hkey
, "FONTS.FON", nls_update_font_list
[i
].system
);
2774 if ((hkey
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
),
2777 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2780 if ((hkey
= reg_create_key( NULL
, fonts_win9x_config_keyW
,
2781 sizeof(fonts_win9x_config_keyW
), 0, NULL
)))
2783 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2786 /* Only update these if the Codepage changed. */
2788 (hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
2791 set_reg_ascii_value( hkey
, "MS Shell Dlg", nls_update_font_list
[i
].shelldlg
);
2792 set_reg_ascii_value( hkey
, "Tms Rmn", nls_update_font_list
[i
].tmsrmn
);
2794 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2795 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2796 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2797 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2798 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2799 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2800 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2801 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2803 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2804 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2805 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2813 /* Delete the FontSubstitutes from other locales */
2814 if ((hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
2817 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2818 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2819 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2825 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
.CodePage
, oem_cp
.CodePage
);
2827 /* update locale dependent font association info and font system link info in registry.
2828 update only when codepages changed, not logpixels. */
2831 update_font_association_info();
2832 update_font_system_link_info();
2837 /*************************************************************
2840 static BOOL CDECL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR device
, LPCWSTR output
,
2841 const DEVMODEW
*devmode
)
2843 struct font_physdev
*physdev
;
2845 if (!font_funcs
) return TRUE
;
2846 if (!(physdev
= calloc( 1, sizeof(*physdev
) ))) return FALSE
;
2847 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
2852 /*************************************************************
2855 static BOOL CDECL
font_DeleteDC( PHYSDEV dev
)
2857 struct font_physdev
*physdev
= get_font_dev( dev
);
2859 release_gdi_font( physdev
->font
);
2865 struct gdi_font_enum_data
2868 NEWTEXTMETRICEXW ntm
;
2878 static BOOL
is_complex_script_ansi_cp(void)
2880 return (ansi_cp
.CodePage
== 874 /* Thai */
2881 || ansi_cp
.CodePage
== 1255 /* Hebrew */
2882 || ansi_cp
.CodePage
== 1256 /* Arabic */
2886 /***************************************************
2887 * create_enum_charset_list
2889 * This function creates charset enumeration list because in DEFAULT_CHARSET
2890 * case, the ANSI codepage's charset takes precedence over other charsets.
2891 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2892 * This function works as a filter other than DEFAULT_CHARSET case.
2894 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset
*list
)
2896 struct enum_charset
*start
= list
;
2900 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) && csi
.fs
.fsCsb
[0] != 0)
2902 list
->mask
= csi
.fs
.fsCsb
[0];
2903 list
->charset
= csi
.ciCharset
;
2904 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2907 else /* charset is DEFAULT_CHARSET or invalid. */
2911 /* Set the current codepage's charset as the first element. */
2912 if (!is_complex_script_ansi_cp() &&
2913 translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, &csi
, TCI_SRCCODEPAGE
) &&
2914 csi
.fs
.fsCsb
[0] != 0)
2916 list
->mask
= csi
.fs
.fsCsb
[0];
2917 list
->charset
= csi
.ciCharset
;
2918 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2919 mask
|= csi
.fs
.fsCsb
[0];
2923 /* Fill out left elements. */
2924 for (i
= 0; i
< 32; i
++)
2927 fs
.fsCsb
[0] = 1u << i
;
2929 if (fs
.fsCsb
[0] & mask
) continue; /* skip, already added. */
2930 if (!translate_charset_info( fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
2931 continue; /* skip, this is an invalid fsCsb bit. */
2932 list
->mask
= fs
.fsCsb
[0];
2933 list
->charset
= csi
.ciCharset
;
2935 mask
|= fs
.fsCsb
[0];
2938 /* add catch all mask for remaining bits */
2942 list
->charset
= DEFAULT_CHARSET
;
2943 list
->script
= 33; /* other */
2947 return list
- start
;
2950 static UINT
get_font_type( const NEWTEXTMETRICEXW
*ntm
)
2954 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ret
|= TRUETYPE_FONTTYPE
;
2955 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
) ret
|= DEVICE_FONTTYPE
;
2956 if (!(ntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
)) ret
|= RASTER_FONTTYPE
;
2960 static BOOL
get_face_enum_data( struct gdi_font_face
*face
, ENUMLOGFONTEXW
*elf
, NEWTEXTMETRICEXW
*ntm
)
2962 struct gdi_font
*font
;
2963 LOGFONTW lf
= { .lfHeight
= -4096 /* preferable EM Square size */ };
2965 if (!face
->scalable
) lf
.lfHeight
= 0;
2967 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2969 if (!font_funcs
->load_font( font
))
2971 free_gdi_font( font
);
2975 if (font
->scalable
&& -lf
.lfHeight
% font
->otm
.otmEMSquare
!= 0)
2977 /* reload with the original EM Square size */
2978 lf
.lfHeight
= -font
->otm
.otmEMSquare
;
2979 free_gdi_font( font
);
2981 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2982 if (!font_funcs
->load_font( font
))
2984 free_gdi_font( font
);
2989 if (font_funcs
->set_outline_text_metrics( font
))
2991 static const DWORD ntm_ppem
= 32;
2994 #define TM font->otm.otmTextMetrics
2995 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
2996 cell_height
= TM
.tmHeight
/ ( -lf
.lfHeight
/ font
->otm
.otmEMSquare
);
2997 ntm
->ntmTm
.tmHeight
= muldiv( ntm_ppem
, cell_height
, font
->otm
.otmEMSquare
);
2998 ntm
->ntmTm
.tmAscent
= SCALE_NTM( TM
.tmAscent
);
2999 ntm
->ntmTm
.tmDescent
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmAscent
;
3000 ntm
->ntmTm
.tmInternalLeading
= SCALE_NTM( TM
.tmInternalLeading
);
3001 ntm
->ntmTm
.tmExternalLeading
= SCALE_NTM( TM
.tmExternalLeading
);
3002 ntm
->ntmTm
.tmAveCharWidth
= SCALE_NTM( TM
.tmAveCharWidth
);
3003 ntm
->ntmTm
.tmMaxCharWidth
= SCALE_NTM( TM
.tmMaxCharWidth
);
3005 memcpy((char *)&ntm
->ntmTm
+ offsetof( TEXTMETRICW
, tmWeight
),
3006 (const char *)&TM
+ offsetof( TEXTMETRICW
, tmWeight
),
3007 sizeof(TEXTMETRICW
) - offsetof( TEXTMETRICW
, tmWeight
));
3008 ntm
->ntmTm
.ntmSizeEM
= font
->otm
.otmEMSquare
;
3009 ntm
->ntmTm
.ntmCellHeight
= cell_height
;
3010 ntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
3014 else if (font_funcs
->set_bitmap_text_metrics( font
))
3016 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
3017 ntm
->ntmTm
.ntmSizeEM
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmInternalLeading
;
3018 ntm
->ntmTm
.ntmCellHeight
= ntm
->ntmTm
.tmHeight
;
3019 ntm
->ntmTm
.ntmAvgWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3021 ntm
->ntmTm
.ntmFlags
= font
->ntmFlags
;
3022 ntm
->ntmFontSig
= font
->fs
;
3024 elf
->elfLogFont
.lfEscapement
= 0;
3025 elf
->elfLogFont
.lfOrientation
= 0;
3026 elf
->elfLogFont
.lfHeight
= ntm
->ntmTm
.tmHeight
;
3027 elf
->elfLogFont
.lfWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3028 elf
->elfLogFont
.lfWeight
= ntm
->ntmTm
.tmWeight
;
3029 elf
->elfLogFont
.lfItalic
= ntm
->ntmTm
.tmItalic
;
3030 elf
->elfLogFont
.lfUnderline
= ntm
->ntmTm
.tmUnderlined
;
3031 elf
->elfLogFont
.lfStrikeOut
= ntm
->ntmTm
.tmStruckOut
;
3032 elf
->elfLogFont
.lfCharSet
= ntm
->ntmTm
.tmCharSet
;
3033 elf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3034 elf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3035 elf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3036 elf
->elfLogFont
.lfPitchAndFamily
= (ntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3037 lstrcpynW( elf
->elfLogFont
.lfFaceName
, (WCHAR
*)font
->otm
.otmpFamilyName
, LF_FACESIZE
);
3038 lstrcpynW( elf
->elfFullName
, (WCHAR
*)font
->otm
.otmpFaceName
, LF_FULLFACESIZE
);
3039 lstrcpynW( elf
->elfStyle
, (WCHAR
*)font
->otm
.otmpStyleName
, LF_FACESIZE
);
3041 free_gdi_font( font
);
3045 static BOOL
family_matches( struct gdi_font_family
*family
, const WCHAR
*face_name
)
3047 struct gdi_font_face
*face
;
3049 if (!facename_compare( face_name
, family
->family_name
, LF_FACESIZE
- 1 )) return TRUE
;
3050 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3051 if (!facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 )) return TRUE
;
3055 static BOOL
face_matches( const WCHAR
*family_name
, struct gdi_font_face
*face
, const WCHAR
*face_name
)
3057 if (!facename_compare( face_name
, family_name
, LF_FACESIZE
- 1)) return TRUE
;
3058 return !facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 );
3061 static BOOL
enum_face_charsets( const struct gdi_font_family
*family
, struct gdi_font_face
*face
,
3062 struct enum_charset
*list
, DWORD count
, FONTENUMPROCW proc
, LPARAM lparam
,
3063 const WCHAR
*subst
)
3066 NEWTEXTMETRICEXW ntm
;
3069 if (!face
->cached_enum_data
)
3071 struct gdi_font_enum_data
*data
;
3073 if (!(data
= calloc( 1, sizeof(*data
) )) ||
3074 !get_face_enum_data( face
, &data
->elf
, &data
->ntm
))
3079 face
->cached_enum_data
= data
;
3082 elf
= face
->cached_enum_data
->elf
;
3083 ntm
= face
->cached_enum_data
->ntm
;
3084 type
= get_font_type( &ntm
);
3086 /* font replacement */
3087 if (family
!= face
->family
)
3089 lstrcpynW( elf
.elfLogFont
.lfFaceName
, family
->family_name
, LF_FACESIZE
);
3090 lstrcpynW( elf
.elfFullName
, face
->full_name
, LF_FULLFACESIZE
);
3092 if (subst
) lstrcpynW( elf
.elfLogFont
.lfFaceName
, subst
, LF_FACESIZE
);
3094 for (i
= 0; i
< count
; i
++)
3096 if (face
->fs
.fsCsb
[0] == 0) /* OEM */
3098 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3099 elf
.elfScript
[0] = 32;
3100 i
= count
; /* break out of loop after enumeration */
3104 if (!(face
->fs
.fsCsb
[0] & list
[i
].mask
)) continue;
3105 /* use the DEFAULT_CHARSET case only if no other charset is present */
3106 if (list
[i
].charset
== DEFAULT_CHARSET
&& (face
->fs
.fsCsb
[0] & ~list
[i
].mask
)) continue;
3107 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
[i
].charset
;
3108 /* caller may fill elfScript with the actual string, see load_script_name */
3109 elf
.elfScript
[0] = list
[i
].script
;
3111 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3112 debugstr_w(elf
.elfLogFont
.lfFaceName
), debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3113 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
3114 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
, ntm
.ntmTm
.ntmFlags
);
3115 /* release section before callback (FIXME) */
3116 pthread_mutex_unlock( &font_lock
);
3117 if (!proc( &elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
3118 pthread_mutex_lock( &font_lock
);
3123 /*************************************************************
3126 static BOOL CDECL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, FONTENUMPROCW proc
, LPARAM lparam
)
3128 struct gdi_font_family
*family
;
3129 struct gdi_font_face
*face
;
3130 struct enum_charset enum_charsets
[32];
3131 DWORD count
, charset
;
3133 charset
= lf
? lf
->lfCharSet
: DEFAULT_CHARSET
;
3135 count
= create_enum_charset_list( charset
, enum_charsets
);
3137 pthread_mutex_lock( &font_lock
);
3139 if (lf
&& lf
->lfFaceName
[0])
3141 const WCHAR
*face_name
= get_gdi_font_subst( lf
->lfFaceName
, charset
, NULL
);
3142 const WCHAR
*orig_name
= NULL
;
3144 TRACE( "facename = %s charset %d\n", debugstr_w(lf
->lfFaceName
), charset
);
3147 orig_name
= lf
->lfFaceName
;
3148 TRACE( "substituting %s -> %s\n", debugstr_w(lf
->lfFaceName
), debugstr_w(face_name
) );
3150 else face_name
= lf
->lfFaceName
;
3152 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3154 if (!family_matches(family
, face_name
)) continue;
3155 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3157 if (!face_matches( family
->family_name
, face
, face_name
)) continue;
3158 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, orig_name
))
3165 TRACE( "charset %d\n", charset
);
3166 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3168 face
= LIST_ENTRY( list_head(get_family_face_list(family
)), struct gdi_font_face
, entry
);
3169 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, NULL
))
3173 pthread_mutex_unlock( &font_lock
);
3178 static BOOL
check_unicode_tategaki( WCHAR ch
)
3180 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
3181 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[ch
>> 8]+((ch
>> 4) & 0x0f)]+ (ch
& 0xf)];
3183 /* We only reach this code if typographical substitution did not occur */
3184 /* Type: U or Type: Tu */
3185 return (orientation
== 1 || orientation
== 3);
3188 static UINT
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
3192 if (glyph
< 0x100) glyph
+= 0xf000;
3193 /* there are a number of old pre-Unicode "broken" TTFs, which
3194 do have symbols at U+00XX instead of U+f0XX */
3196 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3199 index
= glyph
- 0xf000;
3200 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3205 CPTABLEINFO
*get_cptable( WORD cp
)
3207 static CPTABLEINFO tables
[100];
3212 if (cp
== CP_ACP
) return &ansi_cp
;
3213 if (cp
== CP_UTF8
) return &utf8_cp
;
3215 for (i
= 0; i
< ARRAY_SIZE(tables
) && tables
[i
].CodePage
; i
++)
3216 if (tables
[i
].CodePage
== cp
) return &tables
[i
];
3217 if (NtGetNlsSectionPtr( 11, cp
, NULL
, (void **)&ptr
, &size
)) return NULL
;
3218 if (i
== ARRAY_SIZE(tables
))
3220 ERR( "too many code pages\n" );
3223 RtlInitCodePageTable( ptr
, &tables
[i
] );
3227 DWORD
win32u_wctomb( CPTABLEINFO
*info
, char *dst
, DWORD dstlen
, const WCHAR
*src
, DWORD srclen
)
3231 if (info
->CodePage
== CP_UTF8
)
3232 RtlUnicodeToUTF8N( dst
, dstlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
3234 RtlUnicodeToCustomCPN( info
, dst
, dstlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
3239 DWORD
win32u_wctomb_size( CPTABLEINFO
*info
, const WCHAR
*src
, DWORD srclen
)
3243 if (info
->CodePage
== CP_UTF8
)
3245 RtlUnicodeToUTF8N( NULL
, 0, &ret
, src
, srclen
* sizeof(WCHAR
) );
3247 else if(info
->DBCSCodePage
)
3249 WCHAR
*uni2cp
= info
->WideCharTable
;
3250 for (ret
= srclen
; srclen
; srclen
--, src
++)
3251 if (uni2cp
[*src
] & 0xff00) ret
++;
3261 DWORD
win32u_mbtowc( CPTABLEINFO
*info
, WCHAR
*dst
, DWORD dstlen
, const char *src
, DWORD srclen
)
3265 if (info
->CodePage
== CP_UTF8
)
3266 RtlUTF8ToUnicodeN( dst
, dstlen
* sizeof(WCHAR
), &ret
, src
, srclen
);
3268 RtlCustomCPToUnicodeN( info
, dst
, dstlen
* sizeof(WCHAR
), &ret
, src
, srclen
);
3270 return ret
/ sizeof(WCHAR
);
3273 static BOOL
wc_to_index( UINT cp
, WCHAR wc
, unsigned char *dst
, BOOL allow_default
)
3275 const CPTABLEINFO
*info
;
3277 if (!(info
= get_cptable( cp
))) return FALSE
;
3279 if (info
->CodePage
== CP_UTF8
)
3286 if (!allow_default
) return FALSE
;
3287 *dst
= info
->DefaultChar
;
3290 else if (info
->DBCSCodePage
)
3292 WCHAR
*uni2cp
= info
->WideCharTable
;
3293 if (uni2cp
[wc
] & 0xff00) return FALSE
;
3298 char *uni2cp
= info
->WideCharTable
;
3302 if (info
->MultiByteTable
[*dst
] != wc
)
3304 if (!allow_default
) return FALSE
;
3305 *dst
= info
->DefaultChar
;
3311 static UINT
get_glyph_index( struct gdi_font
*font
, UINT glyph
)
3316 if (font_funcs
->get_glyph_index( font
, &glyph
, TRUE
)) return glyph
;
3318 if (font
->codepage
== CP_SYMBOL
)
3320 glyph
= get_glyph_index_symbol( font
, wc
);
3323 if (wc_to_index( CP_ACP
, wc
, &ch
, TRUE
))
3324 glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
3327 else if (wc_to_index( font
->codepage
, wc
, &ch
, FALSE
))
3329 glyph
= (unsigned char)ch
;
3330 font_funcs
->get_glyph_index( font
, &glyph
, FALSE
);
3337 static UINT
get_glyph_index_linked( struct gdi_font
**font
, UINT glyph
)
3339 struct gdi_font
*child
;
3342 if ((res
= get_glyph_index( *font
, glyph
))) return res
;
3343 if (glyph
< 32) return 0; /* don't check linked fonts for control characters */
3345 LIST_FOR_EACH_ENTRY( child
, &(*font
)->child_fonts
, struct gdi_font
, entry
)
3347 if (!child
->private && !font_funcs
->load_font( child
)) continue;
3348 if ((res
= get_glyph_index( child
, glyph
)))
3357 static DWORD
get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3358 GLYPHMETRICS
*gm_ret
, ABC
*abc_ret
, DWORD buflen
, void *buf
,
3365 BOOL tategaki
= (*get_gdi_font_name( font
) == '@');
3367 if (format
& GGO_GLYPH_INDEX
)
3369 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3370 as glyph index. "Treasure Adventure Game" depends on this. */
3371 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3372 format
&= ~GGO_GLYPH_INDEX
;
3373 /* TODO: Window also turns off tategaki for glyphs passed in by index
3374 if their unicode code points fall outside of the range that is
3379 index
= get_glyph_index_linked( &font
, glyph
);
3383 index
= get_GSUB_vert_glyph( font
, index
);
3384 if (index
== orig
) tategaki
= check_unicode_tategaki( glyph
);
3388 if (mat
&& !memcmp( mat
, &identity
, sizeof(*mat
) )) mat
= NULL
;
3390 if (format
== GGO_METRICS
&& !mat
&& get_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
))
3393 ret
= font_funcs
->get_glyph_outline( font
, index
, format
, &gm
, &abc
, buflen
, buf
, mat
, tategaki
);
3394 if (ret
== GDI_ERROR
) return ret
;
3396 if (format
== GGO_METRICS
&& !mat
)
3397 set_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
);
3400 if (gm_ret
) *gm_ret
= gm
;
3401 if (abc_ret
) *abc_ret
= abc
;
3406 /*************************************************************
3409 static BOOL CDECL
font_FontIsLinked( PHYSDEV dev
)
3411 struct font_physdev
*physdev
= get_font_dev( dev
);
3415 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
3416 return dev
->funcs
->pFontIsLinked( dev
);
3418 return !list_empty( &physdev
->font
->child_fonts
);
3422 /*************************************************************
3423 * font_GetCharABCWidths
3425 static BOOL CDECL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT count
,
3426 WCHAR
*chars
, ABC
*buffer
)
3428 struct font_physdev
*physdev
= get_font_dev( dev
);
3433 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
3434 return dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
3437 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3439 pthread_mutex_lock( &font_lock
);
3440 for (i
= 0; i
< count
; i
++)
3442 c
= chars
? chars
[i
] : first
+ i
;
3443 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &buffer
[i
], 0, NULL
, NULL
);
3445 pthread_mutex_unlock( &font_lock
);
3450 /*************************************************************
3451 * font_GetCharABCWidthsI
3453 static BOOL CDECL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
3455 struct font_physdev
*physdev
= get_font_dev( dev
);
3460 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
3461 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
3464 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3466 pthread_mutex_lock( &font_lock
);
3467 for (c
= 0; c
< count
; c
++, buffer
++)
3468 get_glyph_outline( physdev
->font
, gi
? gi
[c
] : first
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3469 NULL
, buffer
, 0, NULL
, NULL
);
3470 pthread_mutex_unlock( &font_lock
);
3475 /*************************************************************
3478 static BOOL CDECL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT count
,
3479 const WCHAR
*chars
, INT
*buffer
)
3481 struct font_physdev
*physdev
= get_font_dev( dev
);
3487 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
3488 return dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buffer
);
3491 TRACE( "%p, %d, %d, %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
] : i
+ first
;
3497 if (get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
) == GDI_ERROR
)
3500 buffer
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3502 pthread_mutex_unlock( &font_lock
);
3507 /*************************************************************
3508 * font_GetCharWidthInfo
3510 static BOOL CDECL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
3512 struct font_physdev
*physdev
= get_font_dev( dev
);
3513 struct char_width_info
*info
= ptr
;
3517 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
3518 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
3522 if (!physdev
->font
->scalable
|| !font_funcs
->get_char_width_info( physdev
->font
, info
))
3523 info
->lsb
= info
->rsb
= 0;
3529 /*************************************************************
3532 static DWORD CDECL
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
3534 struct font_physdev
*physdev
= get_font_dev( dev
);
3538 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
3539 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
3541 return font_funcs
->get_font_data( physdev
->font
, table
, offset
, buf
, size
);
3545 /*************************************************************
3546 * font_GetFontRealizationInfo
3548 static BOOL CDECL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
3550 struct font_physdev
*physdev
= get_font_dev( dev
);
3551 struct font_realization_info
*info
= ptr
;
3555 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
3556 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
3559 TRACE( "(%p, %p)\n", physdev
->font
, info
);
3562 if (physdev
->font
->scalable
) info
->flags
|= 2;
3564 info
->cache_num
= physdev
->font
->cache_num
;
3565 info
->instance_id
= physdev
->font
->handle
;
3566 if (info
->size
== sizeof(*info
))
3568 info
->file_count
= 1;
3569 info
->face_index
= physdev
->font
->face_index
;
3570 info
->simulations
= 0;
3571 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
3572 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
3578 /*************************************************************
3579 * font_GetFontUnicodeRanges
3581 static DWORD CDECL
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
3583 struct font_physdev
*physdev
= get_font_dev( dev
);
3584 DWORD size
, num_ranges
;
3588 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
3589 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
3592 num_ranges
= font_funcs
->get_unicode_ranges( physdev
->font
, glyphset
);
3593 size
= offsetof( GLYPHSET
, ranges
[num_ranges
] );
3596 glyphset
->cbThis
= size
;
3597 glyphset
->cRanges
= num_ranges
;
3598 glyphset
->flAccel
= 0;
3604 /*************************************************************
3605 * font_GetGlyphIndices
3607 static DWORD CDECL
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
3609 struct font_physdev
*physdev
= get_font_dev( dev
);
3612 BOOL got_default
= FALSE
;
3617 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
3618 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
3621 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
3623 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
3627 pthread_mutex_lock( &font_lock
);
3629 for (i
= 0; i
< count
; i
++)
3631 UINT glyph
= str
[i
];
3633 if (!font_funcs
->get_glyph_index( physdev
->font
, &glyph
, TRUE
))
3636 if (physdev
->font
->codepage
== CP_SYMBOL
)
3638 if (str
[i
] >= 0xf020 && str
[i
] <= 0xf100) glyph
= str
[i
] - 0xf000;
3639 else if (str
[i
] < 0x100) glyph
= str
[i
];
3641 else if (wc_to_index( physdev
->font
->codepage
, str
[i
], &ch
, FALSE
))
3642 glyph
= (unsigned char)ch
;
3648 default_char
= font_funcs
->get_default_glyph( physdev
->font
);
3651 gi
[i
] = default_char
;
3653 else gi
[i
] = get_GSUB_vert_glyph( physdev
->font
, glyph
);
3656 pthread_mutex_unlock( &font_lock
);
3661 /*************************************************************
3662 * font_GetGlyphOutline
3664 static DWORD CDECL
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
3665 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
3667 struct font_physdev
*physdev
= get_font_dev( dev
);
3672 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
3673 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
3675 pthread_mutex_lock( &font_lock
);
3676 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, gm
, NULL
, buflen
, buf
, mat
);
3677 pthread_mutex_unlock( &font_lock
);
3682 /*************************************************************
3683 * font_GetKerningPairs
3685 static DWORD CDECL
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
3687 struct font_physdev
*physdev
= get_font_dev( dev
);
3691 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
3692 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
3695 pthread_mutex_lock( &font_lock
);
3696 if (physdev
->font
->kern_count
== -1)
3697 physdev
->font
->kern_count
= font_funcs
->get_kerning_pairs( physdev
->font
,
3698 &physdev
->font
->kern_pairs
);
3699 pthread_mutex_unlock( &font_lock
);
3703 count
= min( count
, physdev
->font
->kern_count
);
3704 memcpy( pairs
, physdev
->font
->kern_pairs
, count
* sizeof(*pairs
) );
3706 else count
= physdev
->font
->kern_count
;
3712 static void scale_outline_font_metrics( const struct gdi_font
*font
, OUTLINETEXTMETRICW
*otm
)
3714 double scale_x
, scale_y
;
3718 scale_x
= (double)font
->aveWidth
;
3719 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3722 scale_x
= font
->scale_y
;
3724 scale_x
*= fabs(font
->matrix
.eM11
);
3725 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3727 /* Windows scales these values as signed integers even if they are unsigned */
3728 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3729 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3731 SCALE_Y(otm
->otmTextMetrics
.tmHeight
);
3732 SCALE_Y(otm
->otmTextMetrics
.tmAscent
);
3733 SCALE_Y(otm
->otmTextMetrics
.tmDescent
);
3734 SCALE_Y(otm
->otmTextMetrics
.tmInternalLeading
);
3735 SCALE_Y(otm
->otmTextMetrics
.tmExternalLeading
);
3737 SCALE_X(otm
->otmTextMetrics
.tmOverhang
);
3738 if (font
->fake_bold
)
3740 if (!font
->scalable
) otm
->otmTextMetrics
.tmOverhang
++;
3741 otm
->otmTextMetrics
.tmAveCharWidth
++;
3742 otm
->otmTextMetrics
.tmMaxCharWidth
++;
3744 SCALE_X(otm
->otmTextMetrics
.tmAveCharWidth
);
3745 SCALE_X(otm
->otmTextMetrics
.tmMaxCharWidth
);
3747 SCALE_Y(otm
->otmAscent
);
3748 SCALE_Y(otm
->otmDescent
);
3749 SCALE_Y(otm
->otmLineGap
);
3750 SCALE_Y(otm
->otmsCapEmHeight
);
3751 SCALE_Y(otm
->otmsXHeight
);
3752 SCALE_Y(otm
->otmrcFontBox
.top
);
3753 SCALE_Y(otm
->otmrcFontBox
.bottom
);
3754 SCALE_X(otm
->otmrcFontBox
.left
);
3755 SCALE_X(otm
->otmrcFontBox
.right
);
3756 SCALE_Y(otm
->otmMacAscent
);
3757 SCALE_Y(otm
->otmMacDescent
);
3758 SCALE_Y(otm
->otmMacLineGap
);
3759 SCALE_X(otm
->otmptSubscriptSize
.x
);
3760 SCALE_Y(otm
->otmptSubscriptSize
.y
);
3761 SCALE_X(otm
->otmptSubscriptOffset
.x
);
3762 SCALE_Y(otm
->otmptSubscriptOffset
.y
);
3763 SCALE_X(otm
->otmptSuperscriptSize
.x
);
3764 SCALE_Y(otm
->otmptSuperscriptSize
.y
);
3765 SCALE_X(otm
->otmptSuperscriptOffset
.x
);
3766 SCALE_Y(otm
->otmptSuperscriptOffset
.y
);
3767 SCALE_Y(otm
->otmsStrikeoutSize
);
3768 SCALE_Y(otm
->otmsStrikeoutPosition
);
3769 SCALE_Y(otm
->otmsUnderscoreSize
);
3770 SCALE_Y(otm
->otmsUnderscorePosition
);
3776 /*************************************************************
3777 * font_GetOutlineTextMetrics
3779 static UINT CDECL
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
3781 struct font_physdev
*physdev
= get_font_dev( dev
);
3786 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
3787 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
3790 if (!physdev
->font
->scalable
) return 0;
3792 pthread_mutex_lock( &font_lock
);
3793 if (font_funcs
->set_outline_text_metrics( physdev
->font
))
3795 ret
= physdev
->font
->otm
.otmSize
;
3796 if (metrics
&& size
>= physdev
->font
->otm
.otmSize
)
3798 WCHAR
*ptr
= (WCHAR
*)(metrics
+ 1);
3799 *metrics
= physdev
->font
->otm
;
3800 metrics
->otmpFamilyName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3801 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFamilyName
);
3802 ptr
+= lstrlenW(ptr
) + 1;
3803 metrics
->otmpStyleName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3804 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpStyleName
);
3805 ptr
+= lstrlenW(ptr
) + 1;
3806 metrics
->otmpFaceName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3807 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFaceName
);
3808 ptr
+= lstrlenW(ptr
) + 1;
3809 metrics
->otmpFullName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3810 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFullName
);
3811 scale_outline_font_metrics( physdev
->font
, metrics
);
3814 pthread_mutex_unlock( &font_lock
);
3819 /*************************************************************
3820 * font_GetTextCharsetInfo
3822 static UINT CDECL
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
3824 struct font_physdev
*physdev
= get_font_dev( dev
);
3828 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
3829 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
3831 if (fs
) *fs
= physdev
->font
->fs
;
3832 return physdev
->font
->charset
;
3836 /*************************************************************
3837 * font_GetTextExtentExPoint
3839 static BOOL CDECL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
3841 struct font_physdev
*physdev
= get_font_dev( dev
);
3847 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
3848 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
3851 TRACE( "%p, %s, %d\n", physdev
->font
, debugstr_wn(str
, count
), count
);
3853 pthread_mutex_lock( &font_lock
);
3854 for (i
= pos
= 0; i
< count
; i
++)
3856 get_glyph_outline( physdev
->font
, str
[i
], GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
);
3857 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3860 pthread_mutex_unlock( &font_lock
);
3865 /*************************************************************
3866 * font_GetTextExtentExPointI
3868 static BOOL CDECL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
3870 struct font_physdev
*physdev
= get_font_dev( dev
);
3876 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
3877 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
3880 TRACE( "%p, %p, %d\n", physdev
->font
, indices
, count
);
3882 pthread_mutex_lock( &font_lock
);
3883 for (i
= pos
= 0; i
< count
; i
++)
3885 get_glyph_outline( physdev
->font
, indices
[i
], GGO_METRICS
| GGO_GLYPH_INDEX
,
3886 NULL
, &abc
, 0, NULL
, NULL
);
3887 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3890 pthread_mutex_unlock( &font_lock
);
3895 /*************************************************************
3898 static INT CDECL
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
3900 struct font_physdev
*physdev
= get_font_dev( dev
);
3901 const WCHAR
*font_name
;
3906 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
3907 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
3909 font_name
= get_gdi_font_name( physdev
->font
);
3910 len
= lstrlenW( font_name
) + 1;
3913 lstrcpynW( str
, font_name
, count
);
3914 len
= min( count
, len
);
3920 static void scale_font_metrics( struct gdi_font
*font
, TEXTMETRICW
*tm
)
3922 double scale_x
, scale_y
;
3924 /* Make sure that the font has sane width/height ratio */
3925 if (font
->aveWidth
&& (font
->aveWidth
+ tm
->tmHeight
- 1) / tm
->tmHeight
> 100)
3927 WARN( "Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
3933 scale_x
= (double)font
->aveWidth
;
3934 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3937 scale_x
= font
->scale_y
;
3939 scale_x
*= fabs(font
->matrix
.eM11
);
3940 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3942 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3943 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3945 SCALE_Y(tm
->tmHeight
);
3946 SCALE_Y(tm
->tmAscent
);
3947 SCALE_Y(tm
->tmDescent
);
3948 SCALE_Y(tm
->tmInternalLeading
);
3949 SCALE_Y(tm
->tmExternalLeading
);
3951 SCALE_X(tm
->tmOverhang
);
3952 if (font
->fake_bold
)
3954 if (!font
->scalable
) tm
->tmOverhang
++;
3955 tm
->tmAveCharWidth
++;
3956 tm
->tmMaxCharWidth
++;
3958 SCALE_X(tm
->tmAveCharWidth
);
3959 SCALE_X(tm
->tmMaxCharWidth
);
3965 /*************************************************************
3966 * font_GetTextMetrics
3968 static BOOL CDECL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
3970 struct font_physdev
*physdev
= get_font_dev( dev
);
3975 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
3976 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
3979 pthread_mutex_lock( &font_lock
);
3980 if (font_funcs
->set_outline_text_metrics( physdev
->font
) ||
3981 font_funcs
->set_bitmap_text_metrics( physdev
->font
))
3983 *metrics
= physdev
->font
->otm
.otmTextMetrics
;
3984 scale_font_metrics( physdev
->font
, metrics
);
3987 pthread_mutex_unlock( &font_lock
);
3992 static void get_nearest_charset( const WCHAR
*family_name
, struct gdi_font_face
*face
, CHARSETINFO
*csi
)
3994 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3995 a single face with the requested charset. The idea is to check if
3996 the selected font supports the current ANSI codepage, if it does
3997 return the corresponding charset, else return the first charset */
4001 if (translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, csi
, TCI_SRCCODEPAGE
))
4003 const struct gdi_font_link
*font_link
;
4005 if (csi
->fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return;
4006 font_link
= find_gdi_font_link(family_name
);
4007 if (font_link
&& (csi
->fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])) return;
4009 for (i
= 0; i
< 32; i
++)
4011 DWORD fs0
= 1u << i
;
4012 if (face
->fs
.fsCsb
[0] & fs0
)
4014 if (translate_charset_info(&fs0
, csi
, TCI_SRCFONTSIG
)) return;
4015 FIXME("TCI failing on %x\n", fs0
);
4019 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4020 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4021 csi
->ciACP
= ansi_cp
.CodePage
;
4022 csi
->ciCharset
= DEFAULT_CHARSET
;
4025 static struct gdi_font
*select_font( LOGFONTW
*lf
, FMAT2 dcmat
, BOOL can_use_bitmap
)
4027 struct gdi_font
*font
;
4028 struct gdi_font_face
*face
;
4031 const WCHAR
*orig_name
= NULL
;
4032 BOOL substituted
= FALSE
;
4034 static const WCHAR symbolW
[] = {'S','y','m','b','o','l',0};
4036 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4037 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4038 original value lfCharSet. Note this is a special case for
4039 Symbol and doesn't happen at least for "Wingdings*" */
4040 if (!facename_compare( lf
->lfFaceName
, symbolW
, -1 )) lf
->lfCharSet
= SYMBOL_CHARSET
;
4042 /* check the cache first */
4043 if ((font
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4045 TRACE( "returning cached gdiFont(%p)\n", font
);
4048 if (!(face
= find_matching_face( lf
, &csi
, can_use_bitmap
, &substituted
, &orig_name
)))
4050 FIXME( "can't find a single appropriate font - bailing\n" );
4053 height
= lf
->lfHeight
;
4055 font
= create_gdi_font( face
, orig_name
, lf
);
4056 font
->use_logfont_name
= substituted
;
4057 font
->matrix
= dcmat
;
4058 font
->can_use_bitmap
= can_use_bitmap
;
4059 if (!csi
.fs
.fsCsb
[0]) get_nearest_charset( face
->family
->family_name
, face
, &csi
);
4060 font
->charset
= csi
.ciCharset
;
4061 font
->codepage
= csi
.ciACP
;
4063 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face
->full_name
), debugstr_w(face
->file
),
4064 face
->data_ptr
, face
->face_index
);
4066 font
->aveWidth
= height
? lf
->lfWidth
: 0;
4067 if (!face
->scalable
)
4069 /* Windows uses integer scaling factors for bitmap fonts */
4070 INT scale
, scaled_height
, diff
;
4071 struct gdi_font
*cachedfont
;
4074 diff
= height
- (signed int)face
->size
.height
;
4076 diff
= -height
- ((signed int)face
->size
.height
- face
->size
.internal_leading
);
4078 /* FIXME: rotation of bitmap fonts is ignored */
4079 height
= abs(GDI_ROUND( (double)height
* font
->matrix
.eM22
));
4081 font
->aveWidth
= (double)font
->aveWidth
* font
->matrix
.eM11
;
4082 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
4083 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4084 /* As we changed the matrix, we need to search the cache for the font again,
4085 * otherwise we might explode the cache. */
4086 if ((cachedfont
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4088 TRACE("Found cached font after non-scalable matrix rescale!\n");
4089 free_gdi_font( font
);
4093 if (height
!= 0) height
= diff
;
4094 height
+= face
->size
.height
;
4096 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4097 scaled_height
= scale
* face
->size
.height
;
4098 /* Only jump to the next height if the difference <= 25% original height */
4099 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4100 /* The jump between unscaled and doubled is delayed by 1 */
4101 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4102 font
->scale_y
= scale
;
4103 TRACE("font scale y: %d\n", font
->scale_y
);
4106 if (!font_funcs
->load_font( font
))
4108 free_gdi_font( font
);
4112 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
4113 font
->vert_feature
= get_GSUB_vert_feature( font
);
4115 create_child_font_list( font
);
4117 TRACE( "caching: gdiFont=%p\n", font
);
4118 cache_gdi_font( font
);
4122 /*************************************************************
4125 static HFONT CDECL
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4127 struct font_physdev
*physdev
= get_font_dev( dev
);
4128 struct gdi_font
*font
= NULL
, *prev
= physdev
->font
;
4129 DC
*dc
= get_physdev_dc( dev
);
4135 BOOL can_use_bitmap
= !!(NtGdiGetDeviceCaps( dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
);
4137 NtGdiExtGetObjectW( hfont
, sizeof(lf
), &lf
);
4138 switch (lf
.lfQuality
)
4140 case NONANTIALIASED_QUALITY
:
4141 if (!*aa_flags
) *aa_flags
= GGO_BITMAP
;
4143 case ANTIALIASED_QUALITY
:
4144 if (!*aa_flags
) *aa_flags
= GGO_GRAY4_BITMAP
;
4148 lf
.lfWidth
= abs(lf
.lfWidth
);
4150 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4151 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4152 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4155 if (dc
->attr
->graphics_mode
== GM_ADVANCED
)
4157 memcpy( &dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
) );
4158 /* try to avoid not necessary glyph transformations */
4159 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4161 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4162 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4163 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4168 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4169 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4170 dcmat
.eM21
= dcmat
.eM12
= 0;
4171 lf
.lfOrientation
= lf
.lfEscapement
;
4172 if (dc
->vport2WorldValid
)
4174 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4175 lf
.lfOrientation
= -lf
.lfOrientation
;
4176 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4177 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4180 TRACE( "DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
, dcmat
.eM21
, dcmat
.eM22
);
4182 pthread_mutex_lock( &font_lock
);
4184 font
= select_font( &lf
, dcmat
, can_use_bitmap
);
4188 if (!*aa_flags
) *aa_flags
= font
->aa_flags
;
4191 if (lf
.lfQuality
== CLEARTYPE_QUALITY
|| lf
.lfQuality
== CLEARTYPE_NATURAL_QUALITY
)
4192 *aa_flags
= subpixel_orientation
;
4194 *aa_flags
= font_smoothing
;
4196 *aa_flags
= font_funcs
->get_aa_flags( font
, *aa_flags
, antialias_fakes
);
4198 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
4199 pthread_mutex_unlock( &font_lock
);
4201 physdev
->font
= font
;
4202 if (prev
) release_gdi_font( prev
);
4203 return font
? hfont
: 0;
4207 const struct gdi_dc_funcs font_driver
=
4209 NULL
, /* pAbortDoc */
4210 NULL
, /* pAbortPath */
4211 NULL
, /* pAlphaBlend */
4212 NULL
, /* pAngleArc */
4215 NULL
, /* pBeginPath */
4216 NULL
, /* pBlendImage */
4218 NULL
, /* pCloseFigure */
4219 NULL
, /* pCreateCompatibleDC */
4220 font_CreateDC
, /* pCreateDC */
4221 font_DeleteDC
, /* pDeleteDC */
4222 NULL
, /* pDeleteObject */
4223 NULL
, /* pEllipse */
4225 NULL
, /* pEndPage */
4226 NULL
, /* pEndPath */
4227 font_EnumFonts
, /* pEnumFonts */
4228 NULL
, /* pExtEscape */
4229 NULL
, /* pExtFloodFill */
4230 NULL
, /* pExtTextOut */
4231 NULL
, /* pFillPath */
4232 NULL
, /* pFillRgn */
4233 font_FontIsLinked
, /* pFontIsLinked */
4234 NULL
, /* pFrameRgn */
4235 NULL
, /* pGetBoundsRect */
4236 font_GetCharABCWidths
, /* pGetCharABCWidths */
4237 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
4238 font_GetCharWidth
, /* pGetCharWidth */
4239 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
4240 NULL
, /* pGetDeviceCaps */
4241 NULL
, /* pGetDeviceGammaRamp */
4242 font_GetFontData
, /* pGetFontData */
4243 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
4244 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
4245 font_GetGlyphIndices
, /* pGetGlyphIndices */
4246 font_GetGlyphOutline
, /* pGetGlyphOutline */
4247 NULL
, /* pGetICMProfile */
4248 NULL
, /* pGetImage */
4249 font_GetKerningPairs
, /* pGetKerningPairs */
4250 NULL
, /* pGetNearestColor */
4251 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
4252 NULL
, /* pGetPixel */
4253 NULL
, /* pGetSystemPaletteEntries */
4254 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
4255 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
4256 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
4257 font_GetTextFace
, /* pGetTextFace */
4258 font_GetTextMetrics
, /* pGetTextMetrics */
4259 NULL
, /* pGradientFill */
4260 NULL
, /* pInvertRgn */
4263 NULL
, /* pPaintRgn */
4266 NULL
, /* pPolyBezier */
4267 NULL
, /* pPolyBezierTo */
4268 NULL
, /* pPolyDraw */
4269 NULL
, /* pPolyPolygon */
4270 NULL
, /* pPolyPolyline */
4271 NULL
, /* pPolylineTo */
4272 NULL
, /* pPutImage */
4273 NULL
, /* pRealizeDefaultPalette */
4274 NULL
, /* pRealizePalette */
4275 NULL
, /* pRectangle */
4276 NULL
, /* pResetDC */
4277 NULL
, /* pRoundRect */
4278 NULL
, /* pSelectBitmap */
4279 NULL
, /* pSelectBrush */
4280 font_SelectFont
, /* pSelectFont */
4281 NULL
, /* pSelectPen */
4282 NULL
, /* pSetBkColor */
4283 NULL
, /* pSetBoundsRect */
4284 NULL
, /* pSetDCBrushColor */
4285 NULL
, /* pSetDCPenColor */
4286 NULL
, /* pSetDIBitsToDevice */
4287 NULL
, /* pSetDeviceClipping */
4288 NULL
, /* pSetDeviceGammaRamp */
4289 NULL
, /* pSetPixel */
4290 NULL
, /* pSetTextColor */
4291 NULL
, /* pStartDoc */
4292 NULL
, /* pStartPage */
4293 NULL
, /* pStretchBlt */
4294 NULL
, /* pStretchDIBits */
4295 NULL
, /* pStrokeAndFillPath */
4296 NULL
, /* pStrokePath */
4297 NULL
, /* pUnrealizePalette */
4298 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
4299 NULL
, /* pD3DKMTCloseAdapter */
4300 NULL
, /* pD3DKMTOpenAdapterFromLuid */
4301 NULL
, /* pD3DKMTQueryVideoMemoryInfo */
4302 NULL
, /* pD3DKMTSetVidPnSourceOwner */
4303 GDI_PRIORITY_FONT_DRV
/* priority */
4306 static BOOL
get_key_value( HKEY key
, const char *name
, DWORD
*value
)
4308 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[12 * sizeof(WCHAR
)])];
4309 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4312 count
= query_reg_ascii_value( key
, name
, info
, sizeof(value_buffer
) );
4315 if (info
->Type
== REG_DWORD
) memcpy( value
, info
->Data
, sizeof(*value
) );
4316 else *value
= wcstol( (const WCHAR
*)info
->Data
, NULL
, 10 );
4321 static UINT
init_font_options(void)
4323 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[20 * sizeof(WCHAR
)])];
4324 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4326 DWORD i
, val
, gamma
= 1400;
4329 if (query_reg_ascii_value( wine_fonts_key
, "AntialiasFakeBoldOrItalic",
4330 info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
4332 static const WCHAR valsW
[] = {'y','Y','t','T','1',0};
4333 antialias_fakes
= (wcschr( valsW
, *(const WCHAR
*)info
->Data
) != NULL
);
4336 if ((key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
4338 /* FIXME: handle vertical orientations even though Windows doesn't */
4339 if (get_key_value( key
, "FontSmoothingOrientation", &val
))
4343 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4344 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
4346 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4347 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
4351 if (get_key_value( key
, "FontSmoothing", &val
) && val
/* enabled */)
4353 if (get_key_value( key
, "FontSmoothingType", &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4354 font_smoothing
= subpixel_orientation
;
4356 font_smoothing
= GGO_GRAY4_BITMAP
;
4358 if (get_key_value( key
, "FontSmoothingGamma", &val
) && val
)
4360 gamma
= min( max( val
, 1000 ), 2200 );
4362 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4366 /* Calibrating the difference between the registry value and the Wine gamma value.
4367 This looks roughly similar to Windows Native with the same registry value.
4368 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4369 gamma
= 1000 * gamma
/ 1400;
4372 for (i
= 0; i
< 256; i
++)
4374 font_gamma_ramp
.encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
4375 font_gamma_ramp
.decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
4379 if (!dpi
&& (key
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) )))
4381 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4386 font_gamma_ramp
.gamma
= gamma
;
4387 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp
.gamma
, dpi
);
4392 /* compute positions for text rendering, in device coords */
4393 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
4398 size
->cx
= size
->cy
= 0;
4399 if (!count
) return TRUE
;
4401 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4402 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4404 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
4405 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
4407 if (dc
->breakExtra
|| dc
->breakRem
)
4409 int i
, space
= 0, rem
= dc
->breakRem
;
4411 for (i
= 0; i
< count
; i
++)
4413 if (str
[i
] == tm
.tmBreakChar
)
4415 space
+= dc
->breakExtra
;
4425 size
->cx
= dx
[count
- 1];
4426 size
->cy
= tm
.tmHeight
;
4430 /* compute positions for text rendering, in device coords */
4431 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
4436 size
->cx
= size
->cy
= 0;
4437 if (!count
) return TRUE
;
4439 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4440 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4442 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
4443 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
4445 if (dc
->breakExtra
|| dc
->breakRem
)
4448 int i
, space
= 0, rem
= dc
->breakRem
;
4450 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4451 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
4453 for (i
= 0; i
< count
; i
++)
4455 if (indices
[i
] == space_index
)
4457 space
+= dc
->breakExtra
;
4467 size
->cx
= dx
[count
- 1];
4468 size
->cy
= tm
.tmHeight
;
4472 /***********************************************************************
4473 * get_text_charset_info
4475 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4477 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
4479 UINT ret
= DEFAULT_CHARSET
;
4482 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
4483 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4485 if (ret
== DEFAULT_CHARSET
&& fs
)
4486 memset(fs
, 0, sizeof(FONTSIGNATURE
));
4490 /***********************************************************************
4491 * NtGdiGetTextCharsetInfo (win32u.@)
4493 UINT WINAPI
NtGdiGetTextCharsetInfo( HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
4495 UINT ret
= DEFAULT_CHARSET
;
4496 DC
*dc
= get_dc_ptr(hdc
);
4500 ret
= get_text_charset_info( dc
, fs
, flags
);
4501 release_dc_ptr( dc
);
4506 /***********************************************************************
4507 * NtGdiHfontCreate (win32u.@)
4509 HFONT WINAPI
NtGdiHfontCreate( const void *logfont
, ULONG size
, ULONG type
,
4510 ULONG flags
, void *data
)
4514 const LOGFONTW
*plf
;
4516 if (!logfont
) return 0;
4518 if (size
== sizeof(ENUMLOGFONTEXDVW
) || size
== sizeof(ENUMLOGFONTEXW
))
4520 const ENUMLOGFONTEXW
*lfex
= logfont
;
4522 if (lfex
->elfFullName
[0] || lfex
->elfStyle
[0] || lfex
->elfScript
[0])
4524 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
4525 debugstr_w( lfex
->elfFullName
), debugstr_w( lfex
->elfStyle
),
4526 debugstr_w( lfex
->elfScript
));
4529 plf
= &lfex
->elfLogFont
;
4531 else if (size
!= sizeof(LOGFONTW
))
4533 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4538 if (!(fontPtr
= malloc( sizeof(*fontPtr
) ))) return 0;
4540 fontPtr
->logfont
= *plf
;
4542 if (!(hFont
= alloc_gdi_handle( &fontPtr
->obj
, NTGDI_OBJ_FONT
, &fontobj_funcs
)))
4548 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4549 plf
->lfHeight
, plf
->lfWidth
,
4550 plf
->lfEscapement
, plf
->lfOrientation
,
4551 plf
->lfPitchAndFamily
,
4552 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
4553 plf
->lfQuality
, plf
->lfCharSet
,
4554 debugstr_w(plf
->lfFaceName
),
4555 plf
->lfWeight
> 400 ? "Bold" : "",
4556 plf
->lfItalic
? "Italic" : "",
4557 plf
->lfUnderline
? "Underline" : "", hFont
);
4562 #define ASSOC_CHARSET_OEM 1
4563 #define ASSOC_CHARSET_ANSI 2
4564 #define ASSOC_CHARSET_SYMBOL 4
4566 static DWORD
get_associated_charset_info(void)
4568 static DWORD associated_charset
= -1;
4570 if (associated_charset
== -1)
4572 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[32 * sizeof(WCHAR
)])];
4573 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4576 static const WCHAR yesW
[] = {'y','e','s',0};
4578 associated_charset
= 0;
4580 if (!(hkey
= reg_open_key( NULL
, associated_charset_keyW
, sizeof(associated_charset_keyW
) )))
4583 if (query_reg_ascii_value( hkey
, "ANSI(00)", info
, sizeof(value_buffer
) ) &&
4584 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4585 associated_charset
|= ASSOC_CHARSET_ANSI
;
4587 if (query_reg_ascii_value( hkey
, "OEM(FF)", info
, sizeof(value_buffer
) ) &&
4588 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4589 associated_charset
|= ASSOC_CHARSET_OEM
;
4591 if (query_reg_ascii_value( hkey
, "SYMBOL(02)", info
, sizeof(value_buffer
) ) &&
4592 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4593 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
4597 TRACE("associated_charset = %d\n", associated_charset
);
4600 return associated_charset
;
4603 static void update_font_code_page( DC
*dc
, HANDLE font
)
4606 int charset
= get_text_charset_info( dc
, NULL
, 0 );
4608 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
4612 NtGdiExtGetObjectW( font
, sizeof(lf
), &lf
);
4613 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
4614 charset
= DEFAULT_CHARSET
;
4617 /* Hmm, nicely designed api this one! */
4618 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
4619 dc
->attr
->font_code_page
= csi
.ciACP
;
4623 dc
->attr
->font_code_page
= oem_cp
.CodePage
;
4625 case DEFAULT_CHARSET
:
4626 dc
->attr
->font_code_page
= ansi_cp
.CodePage
;
4629 case VISCII_CHARSET
:
4635 case CELTIC_CHARSET
:
4636 /* FIXME: These have no place here, but because x11drv
4637 enumerates fonts with these (made up) charsets some apps
4638 might use them and then the FIXME below would become
4639 annoying. Now we could pick the intended codepage for
4640 each of these, but since it's broken anyway we'll just
4641 use CP_ACP and hope it'll go away...
4643 dc
->attr
->font_code_page
= CP_ACP
;
4647 FIXME("Can't find codepage for charset %d\n", charset
);
4648 dc
->attr
->font_code_page
= CP_ACP
;
4653 TRACE( "charset %d => cp %d\n", charset
, dc
->attr
->font_code_page
);
4656 /***********************************************************************
4657 * NtGdiSelectFont (win32u.@)
4659 HGDIOBJ WINAPI
NtGdiSelectFont( HDC hdc
, HGDIOBJ handle
)
4662 DC
*dc
= get_dc_ptr( hdc
);
4668 if (!GDI_inc_ref_count( handle
))
4670 release_dc_ptr( dc
);
4674 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
4675 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
4679 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
4680 update_font_code_page( dc
, handle
);
4681 if (dc
->font_gamma_ramp
== NULL
)
4682 dc
->font_gamma_ramp
= &font_gamma_ramp
;
4683 GDI_dec_ref_count( ret
);
4685 else GDI_dec_ref_count( handle
);
4687 release_dc_ptr( dc
);
4692 /***********************************************************************
4695 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
4697 FONTOBJ
*font
= GDI_GetObjPtr( handle
, NTGDI_OBJ_FONT
);
4699 if (!font
) return 0;
4702 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
4703 memcpy( buffer
, &font
->logfont
, count
);
4705 else count
= sizeof(LOGFONTW
);
4706 GDI_ReleaseObj( handle
);
4711 /***********************************************************************
4714 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
4718 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
4727 struct font_enum_entry
*buf
;
4733 static INT WINAPI
font_enum_proc( const LOGFONTW
*lf
, const TEXTMETRICW
*tm
,
4734 DWORD type
, LPARAM lp
)
4736 struct font_enum
*fe
= (struct font_enum
*)lp
;
4738 if (fe
->charset
!= DEFAULT_CHARSET
&& lf
->lfCharSet
!= fe
->charset
) return 1;
4739 if ((type
& RASTER_FONTTYPE
) && !(NtGdiGetDeviceCaps( fe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
))
4742 if (fe
->buf
&& fe
->count
< fe
->size
)
4744 fe
->buf
[fe
->count
].type
= type
;
4745 fe
->buf
[fe
->count
].lf
= *(const ENUMLOGFONTEXW
*)lf
;
4746 fe
->buf
[fe
->count
].tm
= *(const NEWTEXTMETRICEXW
*)tm
;
4752 /***********************************************************************
4753 * NtGdiEnumFonts (win32u.@)
4755 BOOL WINAPI
NtGdiEnumFonts( HDC hdc
, ULONG type
, ULONG win32_compat
, ULONG face_name_len
,
4756 const WCHAR
*face_name
, ULONG charset
, ULONG
*count
, void *buf
)
4758 struct font_enum fe
;
4764 if (!(dc
= get_dc_ptr( hdc
))) return 0;
4766 memset( &lf
, 0, sizeof(lf
) );
4767 lf
.lfCharSet
= charset
;
4768 if (face_name_len
) memcpy( lf
.lfFaceName
, face_name
, face_name_len
* sizeof(WCHAR
) );
4772 fe
.size
= *count
/ sizeof(*fe
.buf
);
4774 fe
.charset
= charset
;
4776 physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
4777 ret
= physdev
->funcs
->pEnumFonts( physdev
, &lf
, font_enum_proc
, (LPARAM
)&fe
);
4778 if (ret
&& buf
) ret
= fe
.count
<= fe
.size
;
4779 *count
= fe
.count
* sizeof(*fe
.buf
);
4781 release_dc_ptr( dc
);
4786 /***********************************************************************
4787 * NtGdiSetTextJustification (win32u.@)
4789 BOOL WINAPI
NtGdiSetTextJustification( HDC hdc
, INT extra
, INT breaks
)
4793 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
4795 extra
= abs( (extra
* dc
->attr
->vport_ext
.cx
+ dc
->attr
->wnd_ext
.cx
/ 2) /
4796 dc
->attr
->wnd_ext
.cx
);
4797 if (!extra
) breaks
= 0;
4800 dc
->breakExtra
= extra
/ breaks
;
4801 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
4809 release_dc_ptr( dc
);
4814 /***********************************************************************
4815 * NtGdiGetTextFaceW (win32u.@)
4817 INT WINAPI
NtGdiGetTextFaceW( HDC hdc
, INT count
, WCHAR
*name
, BOOL alias_name
)
4822 DC
* dc
= get_dc_ptr( hdc
);
4825 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
4826 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
4827 release_dc_ptr( dc
);
4832 /***********************************************************************
4833 * NtGdiGetTextExtentExW (win32u.@)
4835 * Return the size of the string as it would be if it was output properly by
4838 BOOL WINAPI
NtGdiGetTextExtentExW( HDC hdc
, const WCHAR
*str
, INT count
, INT max_ext
,
4839 INT
*nfit
, INT
*dxs
, SIZE
*size
, UINT flags
)
4844 INT buffer
[256], *pos
= dxs
;
4846 if (count
< 0) return FALSE
;
4848 dc
= get_dc_ptr(hdc
);
4849 if (!dc
) return FALSE
;
4854 if (count
> 256 && !(pos
= malloc( count
* sizeof(*pos
) )))
4856 release_dc_ptr( dc
);
4863 ret
= get_char_positions_indices( dc
, str
, count
, pos
, size
);
4865 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
4870 for (i
= 0; i
< count
; i
++)
4872 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) +
4873 (i
+ 1) * dc
->attr
->char_extra
;
4874 if (nfit
&& dx
> (unsigned int)max_ext
) break;
4875 if (dxs
) dxs
[i
] = dx
;
4877 if (nfit
) *nfit
= i
;
4880 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->attr
->char_extra
;
4881 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
4884 if (pos
!= buffer
&& pos
!= dxs
) free( pos
);
4885 release_dc_ptr( dc
);
4887 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
4891 /***********************************************************************
4892 * NtGdiGetTextMetricsW (win32u.@)
4894 BOOL WINAPI
NtGdiGetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
, ULONG flags
)
4898 DC
* dc
= get_dc_ptr( hdc
);
4899 if (!dc
) return FALSE
;
4901 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4902 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
4906 /* device layer returns values in device units
4907 * therefore we have to convert them to logical */
4909 metrics
->tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
4910 metrics
->tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
4911 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
4912 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
4913 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
4914 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
4915 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
4916 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
4917 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
4918 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
4921 TRACE("text metrics:\n"
4922 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
4923 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
4924 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
4925 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
4926 " PitchAndFamily = %02x\n"
4927 " --------------------\n"
4928 " InternalLeading = %i\n"
4932 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
4933 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
4934 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
4935 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
4936 metrics
->tmPitchAndFamily
,
4937 metrics
->tmInternalLeading
,
4940 metrics
->tmHeight
);
4942 release_dc_ptr( dc
);
4947 /***********************************************************************
4948 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
4950 UINT WINAPI
NtGdiGetOutlineTextMetricsInternalW( HDC hdc
, UINT cbData
,
4951 OUTLINETEXTMETRICW
*lpOTM
, ULONG opts
)
4953 DC
*dc
= get_dc_ptr( hdc
);
4954 OUTLINETEXTMETRICW
*output
= lpOTM
;
4958 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
4961 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
4962 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
4964 if (lpOTM
&& ret
> cbData
)
4966 output
= malloc( ret
);
4967 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
4972 output
->otmTextMetrics
.tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
4973 output
->otmTextMetrics
.tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
4974 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
4975 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
4976 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
4977 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
4978 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
4979 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
4980 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
4981 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
4982 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
4983 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
4984 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
4985 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
4986 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
4987 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
4988 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
4989 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
4990 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
4991 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
4992 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
4993 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
4994 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
4995 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
4996 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
4997 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
4998 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
4999 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
5000 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
5001 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
5002 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
5003 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
5004 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
5005 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
5009 memcpy(lpOTM
, output
, cbData
);
5018 /***********************************************************************
5019 * NtGdiGetCharWidthW (win32u.@)
5021 BOOL WINAPI
NtGdiGetCharWidthW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5022 ULONG flags
, void *buf
)
5024 UINT i
, count
= last
;
5029 if (flags
& NTGDI_GETCHARWIDTH_INDICES
)
5034 if (!(abc
= malloc( count
* sizeof(ABC
) )))
5037 if (!NtGdiGetCharABCWidthsW( hdc
, first
, last
, chars
,
5038 NTGDI_GETCHARABCWIDTHS_INT
| NTGDI_GETCHARABCWIDTHS_INDICES
,
5045 for (i
= 0; i
< count
; i
++)
5046 ((INT
*)buf
)[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
5052 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
5054 if (!chars
) count
= last
- first
+ 1;
5055 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
5056 ret
= dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buf
);
5060 if (flags
& NTGDI_GETCHARWIDTH_INT
)
5063 /* convert device units to logical */
5064 for (i
= 0; i
< count
; i
++)
5065 buffer
[i
] = width_to_LP( dc
, buffer
[i
] );
5069 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
5070 for (i
= 0; i
< count
; i
++)
5071 ((float *)buf
)[i
] = ((int *)buf
)[i
] * scale
;
5074 release_dc_ptr( dc
);
5079 /* helper for nulldrv_ExtTextOut */
5080 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
5081 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
5083 UINT indices
[3] = {0, 0, 0x20};
5089 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
5091 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
5094 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
, FALSE
);
5095 if (ret
!= GDI_ERROR
) break;
5098 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
5099 if (!image
) return ERROR_SUCCESS
;
5103 if (!ret
) /* empty glyph */
5105 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
5106 return ERROR_SUCCESS
;
5109 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5110 size
= metrics
->gmBlackBoxY
* stride
;
5112 if (!(image
->ptr
= malloc( size
))) return ERROR_OUTOFMEMORY
;
5113 image
->is_copy
= TRUE
;
5114 image
->free
= free_heap_bits
;
5116 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
,
5118 if (ret
== GDI_ERROR
)
5121 return ERROR_NOT_FOUND
;
5123 return ERROR_SUCCESS
;
5126 /* helper for nulldrv_ExtTextOut */
5127 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
5128 LPCWSTR str
, UINT count
, const INT
*dx
)
5133 reset_bounds( &bounds
);
5134 for (i
= 0; i
< count
; i
++)
5136 GLYPHMETRICS metrics
;
5138 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
5140 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
5141 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
5142 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
5143 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
5144 add_bounds_rect( &bounds
, &rect
);
5148 if (flags
& ETO_PDY
)
5151 y
+= dx
[ i
* 2 + 1];
5157 x
+= metrics
.gmCellIncX
;
5158 y
+= metrics
.gmCellIncY
;
5164 /* helper for nulldrv_ExtTextOut */
5165 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
5166 const struct gdi_image_bits
*image
, const RECT
*clip
)
5168 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5169 UINT i
, count
, max_count
;
5171 BYTE
*ptr
= image
->ptr
;
5172 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5174 RECT rect
, clipped_rect
;
5176 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
5177 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
5178 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
5179 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
5180 if (!clip
) clipped_rect
= rect
;
5181 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
5183 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
5184 pts
= malloc( max_count
* sizeof(*pts
) );
5188 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
5189 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
5191 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
5193 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5194 pts
[count
].x
= rect
.left
+ x
;
5195 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5196 pts
[count
+ 1].x
= rect
.left
+ x
;
5197 if (pts
[count
+ 1].x
> pts
[count
].x
)
5199 pts
[count
].y
= pts
[count
+ 1].y
= y
;
5204 assert( count
<= max_count
);
5205 dp_to_lp( dc
, pts
, count
);
5206 for (i
= 0; i
< count
; i
+= 2)
5208 const ULONG pts_count
= 2;
5209 NtGdiPolyPolyDraw( dc
->hSelf
, pts
+ i
, &pts_count
, 1, NtGdiPolyPolyline
);
5214 /***********************************************************************
5215 * nulldrv_ExtTextOut
5217 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5218 LPCWSTR str
, UINT count
, const INT
*dx
)
5220 DC
*dc
= get_nulldrv_dc( dev
);
5226 if (flags
& ETO_OPAQUE
)
5229 COLORREF brush_color
= NtGdiGetNearestColor( dev
->hdc
, dc
->attr
->background_color
);
5230 HBRUSH brush
= NtGdiCreateSolidBrush( brush_color
, NULL
);
5234 orig
= NtGdiSelectBrush( dev
->hdc
, brush
);
5235 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5236 NtGdiPatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5237 NtGdiSelectBrush( dev
->hdc
, orig
);
5238 NtGdiDeleteObjectApp( brush
);
5242 if (!count
) return TRUE
;
5244 if (dc
->aa_flags
!= GGO_BITMAP
)
5246 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5247 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5248 struct gdi_image_bits bits
;
5249 struct bitblt_coords src
, dst
;
5251 /* FIXME Subpixel modes */
5252 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5254 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5255 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5256 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5257 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5259 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5260 src
.x
= src
.visrect
.left
;
5261 src
.y
= src
.visrect
.top
;
5262 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5263 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5265 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5266 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5268 /* we can avoid the GetImage, just query the needed format */
5269 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5270 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5271 info
->bmiHeader
.biWidth
= src
.width
;
5272 info
->bmiHeader
.biHeight
= -src
.height
;
5273 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5274 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5275 if (!err
|| err
== ERROR_BAD_FORMAT
)
5277 /* make the source rectangle relative to the source bits */
5279 src
.visrect
.left
= src
.visrect
.top
= 0;
5280 src
.visrect
.right
= src
.width
;
5281 src
.visrect
.bottom
= src
.height
;
5283 bits
.ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5284 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5285 bits
.is_copy
= TRUE
;
5286 bits
.free
= free_heap_bits
;
5287 err
= ERROR_SUCCESS
;
5292 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5293 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5294 if (!err
&& !bits
.is_copy
)
5296 void *ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5299 if (bits
.free
) bits
.free( &bits
);
5300 return ERROR_OUTOFMEMORY
;
5302 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5303 if (bits
.free
) bits
.free( &bits
);
5305 bits
.is_copy
= TRUE
;
5306 bits
.free
= free_heap_bits
;
5311 /* make x,y relative to the image bits */
5312 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5313 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5314 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5315 aa_flags
, str
, count
, dx
);
5316 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5317 if (bits
.free
) bits
.free( &bits
);
5322 pen
= NtGdiCreatePen( PS_SOLID
, 1, dc
->attr
->text_color
, NULL
);
5323 orig
= NtGdiSelectPen( dev
->hdc
, pen
);
5325 for (i
= 0; i
< count
; i
++)
5327 GLYPHMETRICS metrics
;
5328 struct gdi_image_bits image
;
5330 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5333 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5334 if (image
.free
) image
.free( &image
);
5338 if (flags
& ETO_PDY
)
5341 y
+= dx
[ i
* 2 + 1];
5347 x
+= metrics
.gmCellIncX
;
5348 y
+= metrics
.gmCellIncY
;
5352 NtGdiSelectPen( dev
->hdc
, orig
);
5353 NtGdiDeleteObjectApp( pen
);
5357 /***********************************************************************
5360 * Scale the underline / strikeout line width.
5362 static inline int get_line_width( DC
*dc
, int metric_size
)
5364 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5365 if (width
== 0) width
= 1;
5366 if (metric_size
< 0) width
= -width
;
5370 /***********************************************************************
5371 * NtGdiExtTextOutW (win32u.@)
5373 * Draws text using the currently selected font, background color, and text color.
5377 * x,y [I] coordinates of string
5379 * ETO_GRAYED - undocumented on MSDN
5380 * ETO_OPAQUE - use background color for fill the rectangle
5381 * ETO_CLIPPED - clipping text to the rectangle
5382 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5383 * than encoded characters. Implies ETO_IGNORELANGUAGE
5384 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5385 * Affects BiDi ordering
5386 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5387 * ETO_PDY - unimplemented
5388 * ETO_NUMERICSLATIN - unimplemented always assumed -
5389 * do not translate numbers into locale representations
5390 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5391 * lprect [I] dimensions for clipping or/and opaquing
5392 * str [I] text string
5393 * count [I] number of symbols in string
5394 * lpDx [I] optional parameter with distance between drawing characters
5400 BOOL WINAPI
NtGdiExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
, const RECT
*lprect
,
5401 const WCHAR
*str
, UINT count
, const INT
*lpDx
, DWORD cp
)
5409 double cosEsc
, sinEsc
;
5413 POINT
*deltas
= NULL
, width
= {0, 0};
5414 DC
* dc
= get_dc_ptr( hdc
);
5417 static int quietfixme
= 0;
5419 if (!dc
) return FALSE
;
5420 if (count
> INT_MAX
) return FALSE
;
5422 align
= dc
->attr
->text_align
;
5423 breakRem
= dc
->breakRem
;
5424 layout
= dc
->attr
->layout
;
5426 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5428 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5433 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5435 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5436 if (layout
& LAYOUT_RTL
)
5438 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5439 align
^= TA_RTLREADING
;
5442 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
5443 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
5444 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->attr
->background_mode
,
5445 dc
->attr
->map_mode
);
5447 if(align
& TA_UPDATECP
)
5449 pt
= dc
->attr
->cur_pos
;
5454 NtGdiGetTextMetricsW( hdc
, &tm
, 0 );
5455 NtGdiExtGetObjectW( dc
->hFont
, sizeof(lf
), &lf
);
5457 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
5458 lf
.lfEscapement
= 0;
5460 if ((dc
->attr
->graphics_mode
== GM_COMPATIBLE
) &&
5461 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
5463 lf
.lfEscapement
= -lf
.lfEscapement
;
5466 if(lf
.lfEscapement
!= 0)
5468 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
5469 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
5477 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
5480 lp_to_dp(dc
, (POINT
*)&rc
, 2);
5482 if (flags
& ETO_OPAQUE
)
5483 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
5485 else flags
&= ~ETO_CLIPPED
;
5495 lp_to_dp(dc
, &pt
, 1);
5499 char_extra
= dc
->attr
->char_extra
;
5500 if (char_extra
&& lpDx
&& NtGdiGetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
5501 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5503 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
5506 POINT total
= {0, 0}, desired
[2];
5508 deltas
= malloc( count
* sizeof(*deltas
) );
5511 if (flags
& ETO_PDY
)
5513 for (i
= 0; i
< count
; i
++)
5515 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
5516 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
5521 for (i
= 0; i
< count
; i
++)
5523 deltas
[i
].x
= lpDx
[i
] + char_extra
;
5530 INT
*dx
= malloc( count
* sizeof(*dx
) );
5532 NtGdiGetTextExtentExW( hdc
, str
, count
, -1, NULL
, dx
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5534 deltas
[0].x
= dx
[0];
5536 for (i
= 1; i
< count
; i
++)
5538 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
5544 for(i
= 0; i
< count
; i
++)
5546 total
.x
+= deltas
[i
].x
;
5547 total
.y
+= deltas
[i
].y
;
5549 desired
[0].x
= desired
[0].y
= 0;
5551 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
5552 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
5554 lp_to_dp(dc
, desired
, 2);
5555 desired
[1].x
-= desired
[0].x
;
5556 desired
[1].y
-= desired
[0].y
;
5558 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5560 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5561 desired
[1].x
= -desired
[1].x
;
5562 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5563 desired
[1].y
= -desired
[1].y
;
5566 deltas
[i
].x
= desired
[1].x
- width
.x
;
5567 deltas
[i
].y
= desired
[1].y
- width
.y
;
5577 NtGdiGetTextExtentExW( hdc
, str
, count
, 0, NULL
, NULL
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5578 desired
[0].x
= desired
[0].y
= 0;
5579 desired
[1].x
= sz
.cx
;
5581 lp_to_dp(dc
, desired
, 2);
5582 desired
[1].x
-= desired
[0].x
;
5583 desired
[1].y
-= desired
[0].y
;
5585 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5587 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5588 desired
[1].x
= -desired
[1].x
;
5589 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5590 desired
[1].y
= -desired
[1].y
;
5595 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
5596 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
5597 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
5600 if (align
& TA_UPDATECP
)
5604 dp_to_lp(dc
, &pt
, 1);
5605 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5617 if (align
& TA_UPDATECP
)
5621 dp_to_lp(dc
, &pt
, 1);
5622 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5627 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
5630 y
+= tm
.tmAscent
* cosEsc
;
5631 x
+= tm
.tmAscent
* sinEsc
;
5635 y
-= tm
.tmDescent
* cosEsc
;
5636 x
-= tm
.tmDescent
* sinEsc
;
5643 if (dc
->attr
->background_mode
!= TRANSPARENT
)
5645 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
5647 if(!(flags
& ETO_OPAQUE
) || !lprect
||
5648 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
5649 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
5653 text_box
.right
= x
+ width
.x
;
5654 text_box
.top
= y
- tm
.tmAscent
;
5655 text_box
.bottom
= y
+ tm
.tmDescent
;
5657 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
5658 if (!IsRectEmpty( &text_box
))
5659 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
5664 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
5665 str
, count
, (INT
*)deltas
);
5670 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
5672 int underlinePos
, strikeoutPos
;
5673 int underlineWidth
, strikeoutWidth
;
5674 UINT size
= NtGdiGetOutlineTextMetricsInternalW( hdc
, 0, NULL
, 0 );
5675 OUTLINETEXTMETRICW
* otm
= NULL
;
5677 HPEN hpen
= NtGdiSelectPen( hdc
, GetStockObject(NULL_PEN
) );
5678 HBRUSH hbrush
= NtGdiCreateSolidBrush( dc
->attr
->text_color
, NULL
);
5680 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
5685 underlineWidth
= tm
.tmAscent
/ 20 + 1;
5686 strikeoutPos
= tm
.tmAscent
/ 2;
5687 strikeoutWidth
= underlineWidth
;
5691 otm
= malloc( size
);
5692 NtGdiGetOutlineTextMetricsInternalW( hdc
, size
, otm
, 0 );
5693 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
5694 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
5695 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
5696 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
5697 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
5698 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
5705 const ULONG cnt
= 5;
5706 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5707 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5708 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5709 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5710 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
5711 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
5712 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
5713 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
5714 pts
[4].x
= pts
[0].x
;
5715 pts
[4].y
= pts
[0].y
;
5716 dp_to_lp(dc
, pts
, 5);
5717 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
5722 const ULONG cnt
= 5;
5723 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5724 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5725 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5726 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5727 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
5728 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
5729 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
5730 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
5731 pts
[4].x
= pts
[0].x
;
5732 pts
[4].y
= pts
[0].y
;
5733 dp_to_lp(dc
, pts
, 5);
5734 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
5737 NtGdiSelectPen(hdc
, hpen
);
5738 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
5739 NtGdiDeleteObjectApp( hbrush
);
5742 release_dc_ptr( dc
);
5748 /******************************************************************************
5749 * NtGdiGetCharABCWidthsW (win32u.@)
5751 * Retrieves widths of characters in range.
5754 * hdc [I] Handle of device context
5755 * firstChar [I] First character in range to query
5756 * lastChar [I] Last character in range to query
5757 * abc [O] Address of character-width structure
5760 * Only works with TrueType fonts
5762 BOOL WINAPI
NtGdiGetCharABCWidthsW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5763 ULONG flags
, void *buffer
)
5765 DC
*dc
= get_dc_ptr(hdc
);
5767 unsigned int i
, count
= last
;
5771 if (!dc
) return FALSE
;
5775 release_dc_ptr( dc
);
5779 if (flags
& NTGDI_GETCHARABCWIDTHS_INDICES
)
5781 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
5782 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, chars
, buffer
);
5786 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
5788 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
5789 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5790 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
5792 release_dc_ptr( dc
);
5797 if (!chars
) count
= last
- first
+ 1;
5798 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
5799 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
5805 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
5807 /* convert device units to logical */
5808 for (i
= 0; i
< count
; i
++)
5810 abc
[i
].abcA
= width_to_LP( dc
, abc
[i
].abcA
);
5811 abc
[i
].abcB
= width_to_LP( dc
, abc
[i
].abcB
);
5812 abc
[i
].abcC
= width_to_LP( dc
, abc
[i
].abcC
);
5817 /* convert device units to logical */
5818 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
5819 ABCFLOAT
*abcf
= buffer
;
5821 for (i
= 0; i
< count
; i
++)
5823 abcf
[i
].abcfA
= abc
[i
].abcA
* scale
;
5824 abcf
[i
].abcfB
= abc
[i
].abcB
* scale
;
5825 abcf
[i
].abcfC
= abc
[i
].abcC
* scale
;
5830 release_dc_ptr( dc
);
5835 /***********************************************************************
5836 * NtGdiGetGlyphOutline (win32u.@)
5838 DWORD WINAPI
NtGdiGetGlyphOutline( HDC hdc
, UINT ch
, UINT format
, GLYPHMETRICS
*metrics
,
5839 DWORD size
, void *buffer
, const MAT2
*mat2
,
5840 BOOL ignore_rotation
)
5846 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc
, ch
, format
, metrics
, size
, buffer
, mat2
);
5848 if (!mat2
) return GDI_ERROR
;
5850 dc
= get_dc_ptr(hdc
);
5851 if(!dc
) return GDI_ERROR
;
5853 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
5854 ret
= dev
->funcs
->pGetGlyphOutline( dev
, ch
& 0xffff, format
, metrics
, size
, buffer
, mat2
);
5855 release_dc_ptr( dc
);
5860 /**********************************************************************
5861 * __wine_get_file_outline_text_metric (win32u.@)
5863 BOOL CDECL
__wine_get_file_outline_text_metric( const WCHAR
*path
, OUTLINETEXTMETRICW
*otm
)
5865 struct gdi_font
*font
= NULL
;
5867 if (!path
|| !font_funcs
) return FALSE
;
5869 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
5870 font
->lf
.lfHeight
= 100;
5871 if (!font_funcs
->load_font( font
)) goto done
;
5872 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
5874 free_gdi_font( font
);
5878 if (font
) free_gdi_font( font
);
5879 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
5883 /*************************************************************************
5884 * NtGdiGetKerningPairs (win32u.@)
5886 DWORD WINAPI
NtGdiGetKerningPairs( HDC hdc
, DWORD count
, KERNINGPAIR
*kern_pair
)
5892 TRACE( "(%p,%d,%p)\n", hdc
, count
, kern_pair
);
5894 if (!count
&& kern_pair
)
5896 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
5900 dc
= get_dc_ptr( hdc
);
5903 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
5904 ret
= dev
->funcs
->pGetKerningPairs( dev
, count
, kern_pair
);
5905 release_dc_ptr( dc
);
5909 /*************************************************************************
5910 * NtGdiGetFontData (win32u.@)
5912 * Retrieve data for TrueType font.
5916 * success: Number of bytes returned
5917 * failure: GDI_ERROR
5921 * Calls RtlSetLastWin32Error()
5924 DWORD WINAPI
NtGdiGetFontData( HDC hdc
, DWORD table
, DWORD offset
, void *buffer
, DWORD length
)
5926 DC
*dc
= get_dc_ptr(hdc
);
5930 if(!dc
) return GDI_ERROR
;
5932 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
5933 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
5934 release_dc_ptr( dc
);
5938 /*************************************************************************
5939 * NtGdiGetGlyphIndicesW (win32u.@)
5941 DWORD WINAPI
NtGdiGetGlyphIndicesW( HDC hdc
, const WCHAR
*str
, INT count
,
5942 WORD
*indices
, DWORD flags
)
5944 DC
*dc
= get_dc_ptr(hdc
);
5948 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc
, debugstr_wn(str
, count
), count
, indices
, flags
);
5950 if(!dc
) return GDI_ERROR
;
5952 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
5953 ret
= dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, indices
, flags
);
5954 release_dc_ptr( dc
);
5958 /***********************************************************************
5960 * Font Resource API *
5962 ***********************************************************************/
5965 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
5967 WCHAR path
[MAX_PATH
];
5970 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
5971 get_fonts_win_dir_path( file
, path
);
5972 pthread_mutex_lock( &font_lock
);
5973 ret
= font_funcs
->add_font( path
, flags
);
5974 pthread_mutex_unlock( &font_lock
);
5975 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
5978 get_fonts_data_dir_path( file
, path
);
5979 pthread_mutex_lock( &font_lock
);
5980 ret
= font_funcs
->add_font( path
, flags
);
5981 pthread_mutex_unlock( &font_lock
);
5986 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
5988 WCHAR path
[MAX_PATH
];
5991 get_fonts_win_dir_path( file
, path
);
5992 if (!(ret
= remove_font( path
, flags
)))
5994 get_fonts_data_dir_path( file
, path
);
5995 ret
= remove_font( path
, flags
);
6000 static int add_font_resource( LPCWSTR file
, DWORD flags
)
6006 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6008 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6009 pthread_mutex_lock( &font_lock
);
6010 ret
= font_funcs
->add_font( file
, addfont_flags
);
6011 pthread_mutex_unlock( &font_lock
);
6013 else if (!wcschr( file
, '\\' ))
6014 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6019 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
6025 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6027 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6028 ret
= remove_font( file
, addfont_flags
);
6030 else if (!wcschr( file
, '\\' ))
6031 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6036 static void load_system_bitmap_fonts(void)
6038 static const char * const fonts
[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6039 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6040 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6044 if (!(hkey
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) ))) return;
6045 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
6047 if (query_reg_ascii_value( hkey
, fonts
[i
], info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
6048 add_system_font_resource( (const WCHAR
*)info
->Data
, ADDFONT_ALLOW_BITMAP
);
6053 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
6055 OBJECT_ATTRIBUTES attr
;
6056 UNICODE_STRING nt_name
;
6062 len
= lstrlenW( path
);
6063 while (len
&& path
[len
- 1] == '\\') len
--;
6065 nt_name
.Buffer
= path
;
6066 nt_name
.MaximumLength
= nt_name
.Length
= len
* sizeof(WCHAR
);
6068 attr
.Length
= sizeof(attr
);
6069 attr
.RootDirectory
= 0;
6070 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
6071 attr
.ObjectName
= &nt_name
;
6072 attr
.SecurityDescriptor
= NULL
;
6073 attr
.SecurityQualityOfService
= NULL
;
6075 if (NtOpenFile( &handle
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
,
6076 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
6077 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
))
6082 while (!NtQueryDirectoryFile( handle
, 0, NULL
, NULL
, &io
, buf
, sizeof(buf
),
6083 FileBothDirectoryInformation
, FALSE
, NULL
, FALSE
) &&
6086 FILE_BOTH_DIR_INFORMATION
*info
= (FILE_BOTH_DIR_INFORMATION
*)buf
;
6089 if (!(info
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
6091 memcpy( path
+ len
, info
->FileName
, info
->FileNameLength
);
6092 path
[len
+ info
->FileNameLength
/ sizeof(WCHAR
)] = 0;
6093 font_funcs
->add_font( path
, flags
);
6095 if (!info
->NextEntryOffset
) break;
6096 info
= (FILE_BOTH_DIR_INFORMATION
*)((char *)info
+ info
->NextEntryOffset
);
6103 static void load_file_system_fonts(void)
6105 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024 * sizeof(WCHAR
)])];
6106 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6107 WCHAR
*ptr
, *next
, path
[MAX_PATH
];
6109 /* Windows directory */
6110 get_fonts_win_dir_path( NULL
, path
);
6111 load_directory_fonts( path
, 0 );
6113 /* Wine data directory */
6114 get_fonts_data_dir_path( NULL
, path
);
6115 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6118 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6119 if (query_reg_ascii_value( wine_fonts_key
, "Path", info
, sizeof(value_buffer
) ) &&
6120 info
->Type
== REG_SZ
)
6122 for (ptr
= (WCHAR
*)info
->Data
; ptr
; ptr
= next
)
6124 if ((next
= wcschr( ptr
, ';' ))) *next
++ = 0;
6125 if (next
&& next
- ptr
< 2) continue;
6126 lstrcpynW( path
, ptr
, MAX_PATH
);
6129 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, (lstrlenW( path
) + 1) * sizeof(WCHAR
) );
6130 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6132 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6140 WCHAR value
[LF_FULLFACESIZE
+ 12];
6143 static void update_external_font_keys(void)
6145 struct list external_keys
= LIST_INIT(external_keys
);
6146 HKEY winnt_key
= 0, win9x_key
= 0;
6147 struct gdi_font_family
*family
;
6148 struct external_key
*key
, *next
;
6149 struct gdi_font_face
*face
;
6151 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6153 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
6157 static const WCHAR external_fontsW
[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6159 winnt_key
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
), 0, NULL
);
6160 win9x_key
= reg_create_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
), 0, NULL
);
6162 /* enumerate the fonts and add external ones to the two keys */
6164 if (!(hkey
= reg_create_key( wine_fonts_key
, external_fontsW
, sizeof(external_fontsW
), 0, NULL
)))
6167 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
) - sizeof(nt_prefixW
),
6168 value
, LF_FULLFACESIZE
* sizeof(WCHAR
) ))
6170 if (info
->Type
!= REG_SZ
) continue;
6172 path
= (WCHAR
*)(buffer
+ info
->DataOffset
);
6173 if (path
[0] && path
[1] == ':')
6175 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, info
->DataLength
);
6176 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6179 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6180 if ((face
= find_face_from_full_name( value
)) && !wcsicmp( face
->file
, path
))
6182 face
->flags
|= ADDFONT_EXTERNAL_FOUND
;
6185 if (tmp
&& !*tmp
) *tmp
= ' ';
6186 if (!(key
= malloc( sizeof(*key
) ))) break;
6187 lstrcpyW( key
->value
, value
);
6188 list_add_tail( &external_keys
, &key
->entry
);
6191 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
6193 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
6195 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
6196 if ((face
->flags
& ADDFONT_EXTERNAL_FOUND
)) continue;
6198 lstrcpyW( value
, face
->full_name
);
6199 if (face
->scalable
) lstrcatW( value
, true_type_suffixW
);
6201 if (face
->file
[0] == '\\')
6204 if (file
[5] == ':') file
+= ARRAYSIZE(nt_prefixW
);
6206 else if ((file
= wcsrchr( face
->file
, '\\' )))
6211 len
= (lstrlenW(file
) + 1) * sizeof(WCHAR
);
6212 set_reg_value( winnt_key
, value
, REG_SZ
, file
, len
);
6213 set_reg_value( win9x_key
, value
, REG_SZ
, file
, len
);
6214 set_reg_value( hkey
, value
, REG_SZ
, file
, len
);
6217 LIST_FOR_EACH_ENTRY_SAFE( key
, next
, &external_keys
, struct external_key
, entry
)
6219 reg_delete_value( win9x_key
, key
->value
);
6220 reg_delete_value( winnt_key
, key
->value
);
6221 reg_delete_value( hkey
, key
->value
);
6222 list_remove( &key
->entry
);
6225 NtClose( win9x_key
);
6226 NtClose( winnt_key
);
6230 static void load_registry_fonts(void)
6232 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6233 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6234 KEY_VALUE_FULL_INFORMATION
*enum_info
= (KEY_VALUE_FULL_INFORMATION
*)value_buffer
;
6235 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6239 static const WCHAR dot_fonW
[] = {'.','f','o','n',0};
6241 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6242 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6243 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6246 hkey
= reg_open_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
) );
6248 hkey
= reg_open_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
) );
6251 while (reg_enum_value( hkey
, i
++, enum_info
, sizeof(value_buffer
), value
, sizeof(value
) ))
6253 if (enum_info
->Type
!= REG_SZ
) continue;
6254 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6255 if (find_face_from_full_name( value
)) continue;
6256 if (tmp
&& !*tmp
) *tmp
= ' ';
6258 if (!(dlen
= query_reg_value( hkey
, value
, info
, sizeof(value_buffer
) - sizeof(nt_prefixW
) )) ||
6259 info
->Type
!= REG_SZ
)
6261 WARN( "Unable to get face path %s\n", debugstr_w(value
) );
6265 path
= (WCHAR
*)info
->Data
;
6266 if (path
[0] && path
[1] == ':')
6268 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, dlen
);
6269 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6270 dlen
+= sizeof(nt_prefixW
);
6273 dlen
/= sizeof(WCHAR
);
6275 add_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6276 else if (dlen
>= 6 && !wcsicmp( path
+ dlen
- 5, dot_fonW
))
6277 add_system_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6282 static HKEY
open_hkcu(void)
6286 DWORD_PTR sid_data
[(sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
) / sizeof(DWORD_PTR
)];
6287 DWORD i
, len
= sizeof(sid_data
);
6290 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser
, sid_data
, len
, &len
))
6293 sid
= ((TOKEN_USER
*)sid_data
)->User
.Sid
;
6294 len
= sprintf( buffer
, "\\Registry\\User\\S-%u-%u", sid
->Revision
,
6295 MAKELONG( MAKEWORD( sid
->IdentifierAuthority
.Value
[5], sid
->IdentifierAuthority
.Value
[4] ),
6296 MAKEWORD( sid
->IdentifierAuthority
.Value
[3], sid
->IdentifierAuthority
.Value
[2] )));
6297 for (i
= 0; i
< sid
->SubAuthorityCount
; i
++)
6298 len
+= sprintf( buffer
+ len
, "-%u", sid
->SubAuthority
[i
] );
6299 ascii_to_unicode( bufferW
, buffer
, len
+ 1 );
6301 return reg_open_key( NULL
, bufferW
, len
* sizeof(WCHAR
) );
6304 /***********************************************************************
6307 UINT
font_init(void)
6309 OBJECT_ATTRIBUTES attr
= { sizeof(attr
) };
6310 UNICODE_STRING name
;
6315 static WCHAR wine_font_mutexW
[] =
6316 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6317 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6318 static const WCHAR wine_fonts_keyW
[] =
6319 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6320 static const WCHAR cacheW
[] = {'C','a','c','h','e'};
6322 if (!(hkcu_key
= open_hkcu())) return 0;
6323 wine_fonts_key
= reg_create_key( hkcu_key
, wine_fonts_keyW
, sizeof(wine_fonts_keyW
), 0, NULL
);
6324 if (wine_fonts_key
) dpi
= init_font_options();
6325 if (!dpi
) return 96;
6326 update_codepage( dpi
);
6328 if (!(font_funcs
= init_freetype_lib()))
6331 load_system_bitmap_fonts();
6332 load_file_system_fonts();
6333 font_funcs
->load_fonts();
6335 attr
.Attributes
= OBJ_OPENIF
;
6336 attr
.ObjectName
= &name
;
6337 name
.Buffer
= wine_font_mutexW
;
6338 name
.Length
= name
.MaximumLength
= sizeof(wine_font_mutexW
);
6340 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return dpi
;
6341 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
6343 wine_fonts_cache_key
= reg_create_key( wine_fonts_key
, cacheW
, sizeof(cacheW
),
6344 REG_OPTION_VOLATILE
, &disposition
);
6346 if (disposition
== REG_CREATED_NEW_KEY
)
6348 load_registry_fonts();
6349 update_external_font_keys();
6352 NtReleaseMutant( mutex
, NULL
);
6354 if (disposition
!= REG_CREATED_NEW_KEY
)
6356 load_registry_fonts();
6357 load_font_list_from_cache();
6360 reorder_font_list();
6361 load_gdi_font_subst();
6362 load_gdi_font_replacements();
6363 load_system_links();
6364 dump_gdi_font_list();
6365 dump_gdi_font_subst();
6369 /***********************************************************************
6370 * NtGdiAddFontResourceW (win32u.@)
6372 INT WINAPI
NtGdiAddFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6373 DWORD tid
, void *dv
)
6375 if (!font_funcs
) return 1;
6376 return add_font_resource( str
, flags
);
6379 /***********************************************************************
6380 * NtGdiAddFontMemResourceEx (win32u.@)
6382 HANDLE WINAPI
NtGdiAddFontMemResourceEx( void *ptr
, DWORD size
, void *dv
, ULONG dv_size
,
6389 if (!ptr
|| !size
|| !count
)
6391 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER
);
6394 if (!font_funcs
) return NULL
;
6395 if (!(copy
= malloc( size
))) return NULL
;
6396 memcpy( copy
, ptr
, size
);
6398 pthread_mutex_lock( &font_lock
);
6399 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6400 pthread_mutex_unlock( &font_lock
);
6408 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6409 * For now return something unique but quite random
6411 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
6419 WARN( "page fault while writing to *count (%p)\n", count
);
6420 NtGdiRemoveFontMemResourceEx( ret
);
6424 TRACE( "Returning handle %p\n", ret
);
6428 /***********************************************************************
6429 * NtGdiRemoveFontMemResourceEx (win32u.@)
6431 BOOL WINAPI
NtGdiRemoveFontMemResourceEx( HANDLE handle
)
6433 FIXME( "(%p) stub\n", handle
);
6437 /***********************************************************************
6438 * NtGdiRemoveFontResourceW (win32u.@)
6440 BOOL WINAPI
NtGdiRemoveFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6441 DWORD tid
, void *dv
)
6443 if (!font_funcs
) return TRUE
;
6444 return remove_font_resource( str
, flags
);
6447 /***********************************************************************
6448 * NtGdiGetFontUnicodeRanges (win32u.@)
6450 * Retrieve a list of supported Unicode characters in a font.
6453 * hdc [I] Handle to a device context.
6454 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6457 * Success: Number of bytes written to the buffer pointed to by lpgs.
6461 DWORD WINAPI
NtGdiGetFontUnicodeRanges( HDC hdc
, GLYPHSET
*lpgs
)
6465 DC
*dc
= get_dc_ptr(hdc
);
6467 TRACE("(%p, %p)\n", hdc
, lpgs
);
6471 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
6472 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
6478 /*************************************************************
6479 * NtGdiFontIsLinked (win32u.@)
6481 BOOL WINAPI
NtGdiFontIsLinked( HDC hdc
)
6483 DC
*dc
= get_dc_ptr(hdc
);
6487 if (!dc
) return FALSE
;
6488 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
6489 ret
= dev
->funcs
->pFontIsLinked( dev
);
6491 TRACE("returning %d\n", ret
);
6495 /*************************************************************
6496 * NtGdiGetRealizationInfo (win32u.@)
6498 BOOL WINAPI
NtGdiGetRealizationInfo( HDC hdc
, struct font_realization_info
*info
)
6500 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, file_count
);
6505 if (info
->size
!= sizeof(*info
) && !is_v0
)
6508 dc
= get_dc_ptr(hdc
);
6509 if (!dc
) return FALSE
;
6510 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
6511 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
6516 /*************************************************************************
6517 * NtGdiGetRasterizerCaps (win32u.@)
6519 BOOL WINAPI
NtGdiGetRasterizerCaps( RASTERIZER_STATUS
*status
, UINT size
)
6521 status
->nSize
= sizeof(RASTERIZER_STATUS
);
6522 status
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
6523 status
->nLanguageID
= 0;
6527 /*************************************************************************
6528 * NtGdiGetFontFileData (win32u.@)
6530 BOOL WINAPI
NtGdiGetFontFileData( DWORD instance_id
, DWORD file_index
, UINT64
*offset
,
6531 void *buff
, DWORD buff_size
)
6533 struct gdi_font
*font
;
6534 DWORD tag
= 0, size
;
6537 if (!font_funcs
) return FALSE
;
6538 pthread_mutex_lock( &font_lock
);
6539 if ((font
= get_font_from_handle( instance_id
)))
6541 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
6542 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
6543 if (size
!= GDI_ERROR
&& size
>= buff_size
&& *offset
<= size
- buff_size
)
6544 ret
= font_funcs
->get_font_data( font
, tag
, *offset
, buff
, buff_size
) != GDI_ERROR
;
6546 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
6548 pthread_mutex_unlock( &font_lock
);
6552 /*************************************************************************
6553 * NtGdiGetFontFileInfo (win32u.@)
6555 BOOL WINAPI
NtGdiGetFontFileInfo( DWORD instance_id
, DWORD file_index
, struct font_fileinfo
*info
,
6556 SIZE_T size
, SIZE_T
*needed
)
6558 SIZE_T required_size
= 0;
6559 struct gdi_font
*font
;
6562 pthread_mutex_lock( &font_lock
);
6564 if ((font
= get_font_from_handle( instance_id
)))
6566 required_size
= sizeof(*info
) + lstrlenW( font
->file
) * sizeof(WCHAR
);
6567 if (required_size
<= size
)
6569 info
->writetime
= font
->writetime
;
6570 info
->size
.QuadPart
= font
->data_size
;
6571 lstrcpyW( info
->path
, font
->file
);
6574 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
6577 pthread_mutex_unlock( &font_lock
);
6578 if (needed
) *needed
= required_size
;
6582 /*************************************************************
6583 * NtGdiGetCharWidthInfo (win32u.@)
6585 BOOL WINAPI
NtGdiGetCharWidthInfo( HDC hdc
, struct char_width_info
*info
)
6591 dc
= get_dc_ptr(hdc
);
6592 if (!dc
) return FALSE
;
6593 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
6594 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
6598 info
->lsb
= width_to_LP( dc
, info
->lsb
);
6599 info
->rsb
= width_to_LP( dc
, info
->rsb
);
6605 /***********************************************************************
6606 * DrawTextW (win32u.so)
6608 INT WINAPI
DrawTextW( HDC hdc
, const WCHAR
*str
, INT count
, RECT
*rect
, UINT flags
)
6610 struct draw_text_params
*params
;
6611 ULONG ret_len
, size
;
6615 if (count
== -1) count
= wcslen( str
);
6616 size
= FIELD_OFFSET( struct draw_text_params
, str
[count
] );
6617 if (!(params
= malloc( size
))) return 0;
6619 params
->rect
= *rect
;
6620 params
->ret_rect
= rect
;
6621 params
->flags
= flags
;
6622 if (count
) memcpy( params
->str
, str
, count
* sizeof(WCHAR
) );
6623 ret
= KeUserModeCallback( NtUserDrawText
, params
, size
, &ret_ptr
, &ret_len
);
6624 if (ret_len
== sizeof(*rect
)) *rect
= *(const RECT
*)ret_ptr
;