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_gothicW
[] =
1504 {'M','S',' ','G','o','t','h','i','c',0};
1505 static const WCHAR ms_p_gothicW
[] =
1506 {'M','S',' ','P','G','o','t','h','i','c',0};
1507 static const WCHAR ms_ui_gothicW
[] =
1508 {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
1509 static const WCHAR sim_sunW
[] =
1510 {'S','i','m','S','u','n',0};
1511 static const WCHAR gulimW
[] =
1512 {'G','u','l','i','m',0};
1513 static const WCHAR ming_li_uW
[] =
1514 {'M','i','n','g','L','i','U',0};
1515 static const WCHAR p_ming_li_uW
[] =
1516 {'P','M','i','n','g','L','i','U',0};
1517 static const WCHAR ming_li_u_hkscsW
[] =
1518 {'M','i','n','g','L','i','U','_','H','K','S','C','S',0};
1519 static const WCHAR ming_li_u_ext_bW
[] =
1520 {'M','i','n','g','L','i','U','-','E','x','t','B',0};
1521 static const WCHAR p_ming_li_u_ext_bW
[] =
1522 {'P','M','i','n','g','L','i','U','-','E','x','t','B',0};
1523 static const WCHAR ming_li_u_hkscs_ext_bW
[] =
1524 {'M','i','n','g','L','i','U','_','H','K','S','C','S','-','E','x','t','B',0};
1525 static const WCHAR batangW
[] =
1526 {'B','a','t','a','n','g',0};
1527 static const WCHAR microsoft_jheng_heiW
[] =
1528 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',0};
1529 static const WCHAR microsoft_jheng_hei_boldW
[] =
1530 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','B','o','l','d',0};
1531 static const WCHAR microsoft_jheng_hei_uiW
[] =
1532 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',0};
1533 static const WCHAR microsoft_jheng_hei_ui_boldW
[] =
1534 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','B','o','l','d',0};
1535 static const WCHAR microsoft_jheng_hei_ui_lightW
[] =
1536 {'M','i','c','r','o','s','o','f','t',' ','J','h','e','n','g','H','e','i',' ','U','I',' ','L','i','g','h','t',0};
1538 static const WCHAR
* const font_links_list
[] =
1540 lucida_sans_unicodeW
,
1541 microsoft_sans_serifW
,
1545 static const struct font_links_defaults_list
1547 /* Keyed off substitution for "MS Shell Dlg" */
1548 const WCHAR
*shelldlg
;
1549 /* Maximum of four substitutes, plus terminating NULL pointer */
1550 const WCHAR
*substitutes
[5];
1551 } font_links_defaults_list
[] =
1553 /* Non East-Asian */
1554 { tahomaW
, /* FIXME unverified ordering */
1555 { ms_ui_gothicW
, sim_sunW
, gulimW
, p_ming_li_uW
, NULL
}
1557 /* Below lists are courtesy of
1558 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1562 { ms_ui_gothicW
, p_ming_li_uW
, sim_sunW
, gulimW
, NULL
}
1564 /* Chinese Simplified */
1566 { sim_sunW
, p_ming_li_uW
, ms_ui_gothicW
, batangW
, NULL
}
1570 { gulimW
, p_ming_li_uW
, ms_ui_gothicW
, sim_sunW
, NULL
}
1572 /* Chinese Traditional */
1574 { p_ming_li_uW
, sim_sunW
, ms_ui_gothicW
, batangW
, NULL
}
1578 static const char system_link_tahoma_sc
[] =
1579 "SIMSUN.TTC,SimSun\0"
1580 "MINGLIU.TTC,PMingLiu\0"
1581 "MSGOTHIC.TTC,MS UI Gothic\0"
1582 "BATANG.TTC,Batang\0"
1583 "MSYH.TTC,Microsoft YaHei UI\0"
1584 "MSJH.TTC,Microsoft JhengHei UI\0"
1585 "YUGOTHM.TTC,Yu Gothic UI\0"
1586 "MALGUN.TTF,Malgun Gothic\0"
1587 "SEGUISYM.TTF,Segoe UI Symbol\0";
1589 static const char system_link_tahoma_tc
[] =
1590 "MINGLIU.TTC,PMingLiu\0"
1591 "SIMSUN.TTC,SimSun\0"
1592 "MSGOTHIC.TTC,MS UI Gothic\0"
1593 "BATANG.TTC,Batang\0"
1594 "MSJH.TTC,Microsoft JhengHei UI\0"
1595 "MSYH.TTC,Microsoft YaHei UI\0"
1596 "YUGOTHM.TTC,Yu Gothic UI\0"
1597 "MALGUN.TTF,Malgun Gothic\0"
1598 "SEGUISYM.TTF,Segoe UI Symbol\0";
1600 static const char system_link_tahoma_jp
[] =
1601 "MSGOTHIC.TTC,MS UI Gothic\0"
1602 "MINGLIU.TTC,PMingLiU\0"
1603 "SIMSUN.TTC,SimSun\0"
1605 "YUGOTHM.TTC,Yu Gothic UI\0"
1606 "MSJH.TTC,Microsoft JhengHei UI\0"
1607 "MSYH.TTC,Microsoft YaHei UI\0"
1608 "MALGUN.TTF,Malgun Gothic\0"
1609 "SEGUISYM.TTF,Segoe UI Symbol\0";
1611 static const char system_link_tahoma_kr
[] =
1613 "MSGOTHIC.TTC,MS UI Gothic\0"
1614 "MINGLIU.TTC,PMingLiU\0"
1615 "SIMSUN.TTC,SimSun\0"
1616 "MALGUN.TTF,Malgun Gothic\0"
1617 "YUGOTHM.TTC,Yu Gothic UI\0"
1618 "MSJH.TTC,Microsoft JhengHei UI\0"
1619 "MSYH.TTC,Microsoft YaHei UI\0"
1620 "SEGUISYM.TTF,Segoe UI Symbol\0";
1622 static const char system_link_tahoma_non_cjk
[] =
1623 "MSGOTHIC.TTC,MS UI Gothic\0"
1624 "MINGLIU.TTC,PMingLiU\0"
1625 "SIMSUN.TTC,SimSun\0"
1627 "YUGOTHM.TTC,Yu Gothic UI\0"
1628 "MSJH.TTC,Microsoft JhengHei UI\0"
1629 "MSYH.TTC,Microsoft YaHei UI\0"
1630 "MALGUN.TTF,Malgun Gothic\0"
1631 "SEGUISYM.TTF,Segoe UI Symbol\0";
1633 static const char system_link_ms_gothic
[] =
1634 "MINGLIU.TTC,MingLiU\0"
1635 "SIMSUN.TTC,SimSun\0"
1636 "GULIM.TTC,GulimChe\0"
1637 "YUGOTHM.TTC,Yu Gothic UI\0"
1638 "MSJH.TTC,Microsoft JhengHei UI\0"
1639 "MSYH.TTC,Microsoft YaHei UI\0"
1640 "MALGUN.TTF,Malgun Gothic\0"
1641 "SEGUISYM.TTF,Segoe UI Symbol\0";
1643 static const char system_link_ms_p_gothic
[] =
1644 "MINGLIU.TTC,PMingLiU\0"
1645 "SIMSUN.TTC,SimSun\0"
1647 "YUGOTHM.TTC,Yu Gothic UI\0"
1648 "MSJH.TTC,Microsoft JhengHei UI\0"
1649 "MSYH.TTC,Microsoft YaHei UI\0"
1650 "MALGUN.TTF,Malgun Gothic\0"
1651 "SEGUISYM.TTF,Segoe UI Symbol\0";
1653 static const char system_link_ms_ui_gothic
[] =
1654 "MICROSS.TTF,Microsoft Sans Serif\0"
1655 "MINGLIU.TTC,PMingLiU\0"
1656 "SIMSUN.TTC,SimSun\0"
1658 "YUGOTHM.TTC,Yu Gothic UI\0"
1659 "MSJH.TTC,Microsoft JhengHei UI\0"
1660 "MSYH.TTC,Microsoft YaHei UI\0"
1661 "MALGUN.TTF,Malgun Gothic\0"
1662 "SEGUISYM.TTF,Segoe UI Symbol\0";
1664 static const char system_link_microsoft_jheng_hei
[] =
1665 "SEGOEUI.TTF,Segoe UI\0"
1666 "MINGLIU.TTC,MingLiU\0"
1667 "MSYH.TTC,Microsoft YaHei\0"
1668 "MEIRYO.TTC,Meiryo\0"
1669 "MALGUN.TTF,Malgun Gothic\0"
1670 "YUGOTHM.TTC,Yu Gothic UI\0"
1671 "SEGUISYM.TTF,Segoe UI Symbol\0";
1673 static const char system_link_microsoft_jheng_hei_bold
[] =
1674 "SEGOEUIB.TTF,Segoe UI Bold\0"
1675 "MINGLIU.TTC,MingLiU\0"
1676 "MSYHBD.TTC,Microsoft YaHei Bold\0"
1677 "MEIRYOB.TTC,Meiryo Bold\0"
1678 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1679 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1680 "SEGUISYM.TTF,Segoe UI Symbol\0";
1682 static const char system_link_microsoft_jheng_hei_ui
[] =
1683 "SEGOEUI.TTF,Segoe UI\0"
1684 "MINGLIU.TTC,MingLiU\0"
1685 "MSYH.TTC,Microsoft YaHei UI\0"
1686 "MEIRYO.TTC,Meiryo UI\0"
1687 "MALGUN.TTF,Malgun Gothic\0"
1688 "YUGOTHM.TTC,Yu Gothic UI\0"
1689 "SEGUISYM.TTF,Segoe UI Symbol\0";
1691 static const char system_link_microsoft_jheng_hei_ui_bold
[] =
1692 "SEGOEUIB.TTF,Segoe UI Bold\0"
1693 "MINGLIU.TTC,MingLiU\0"
1694 "MSYHBD.TTC,Microsoft YaHei UI Bold\0"
1695 "MEIRYOB.TTC,Meiryo UI Bold\0"
1696 "MALGUNBD.TTF,Malgun Gothic Bold\0"
1697 "YUGOTHB.TTC,Yu Gothic UI Bold\0"
1698 "SEGUISYM.TTF,Segoe UI Symbol\0";
1700 static const char system_link_microsoft_jheng_hei_ui_light
[] =
1701 "SEGOEUIL.TTF,Segoe UI Light\0"
1702 "MINGLIU.TTC,MingLiU\0"
1703 "MSYHL.TTC,Microsoft YaHei UI Light\0"
1704 "MEIRYO.TTC,Meiryo UI\0"
1705 "MALGUNSL.TTF,Malgun Gothic Semilight\0"
1706 "YUGOTHL.TTC,Yu Gothic UI Light\0"
1707 "SEGUISYM.TTF,Segoe UI Symbol\0";
1709 static const char system_link_ming_li_u
[] =
1710 "MICROSS.TTF,Microsoft Sans Serif\0"
1711 "SIMSUN.TTC,SimSun\0"
1712 "MSMINCHO.TTC,MS Mincho\0"
1713 "BATANG.TTC,BatangChe\0"
1714 "MSJH.TTC,Microsoft JhengHei UI\0"
1715 "MSYH.TTC,Microsoft YaHei UI\0"
1716 "YUGOTHM.TTC,Yu Gothic UI\0"
1717 "MALGUN.TTF,Malgun Gothic\0"
1718 "SEGUISYM.TTF,Segoe UI Symbol\0";
1720 static const char system_link_p_ming_li_u
[] =
1721 "MICROSS.TTF,Microsoft Sans Serif\0"
1722 "SIMSUN.TTC,SimSun\0"
1723 "MSMINCHO.TTC,MS PMincho\0"
1724 "BATANG.TTC,Batang\0"
1725 "MSJH.TTC,Microsoft JhengHei UI\0"
1726 "MSYH.TTC,Microsoft YaHei UI\0"
1727 "YUGOTHM.TTC,Yu Gothic UI\0"
1728 "MALGUN.TTF,Malgun Gothic\0"
1729 "SEGUISYM.TTF,Segoe UI Symbol\0";
1731 static const char system_link_ming_li_u_hkscs
[] =
1732 "MICROSS.TTF,Microsoft Sans Serif\0"
1733 "MINGLIU.TTC,MingLiU\0"
1734 "SIMSUN.TTC,SimSun\0"
1735 "MSMINCHO.TTC,MS Mincho\0"
1736 "BATANG.TTC,BatangChe\0"
1737 "MSJH.TTC,Microsoft JhengHei UI\0"
1738 "MSYH.TTC,Microsoft YaHei UI\0"
1739 "YUGOTHM.TTC,Yu Gothic UI\0"
1740 "MALGUN.TTF,Malgun Gothic\0"
1741 "SEGUISYM.TTF,Segoe UI Symbol\0";
1743 static const char system_link_ming_li_u_ext_b
[] =
1744 "MICROSS.TTF,Microsoft Sans Serif\0"
1745 "MINGLIU.TTC,MingLiU\0"
1746 "SIMSUN.TTC,SimSun\0"
1747 "MSMINCHO.TTC,MS Mincho\0"
1748 "BATANG.TTC,BatangChe\0"
1749 "MSJH.TTC,Microsoft JhengHei UI\0"
1750 "MSYH.TTC,Microsoft YaHei UI\0"
1751 "YUGOTHM.TTC,Yu Gothic UI\0"
1752 "MALGUN.TTF,Malgun Gothic\0"
1753 "SEGUISYM.TTF,Segoe UI Symbol\0";
1755 static const char system_link_p_ming_li_u_ext_b
[] =
1756 "MICROSS.TTF,Microsoft Sans Serif\0"
1757 "MINGLIU.TTC,PMingLiU\0"
1758 "SIMSUN.TTC,SimSun\0"
1759 "MSMINCHO.TTC,MS PMincho\0"
1760 "BATANG.TTC,Batang\0"
1761 "MSJH.TTC,Microsoft JhengHei UI\0"
1762 "MSYH.TTC,Microsoft YaHei UI\0"
1763 "YUGOTHM.TTC,Yu Gothic UI\0"
1764 "MALGUN.TTF,Malgun Gothic\0"
1765 "SEGUISYM.TTF,Segoe UI Symbol\0";
1767 static const char system_link_ming_li_u_hkscs_ext_b
[] =
1768 "MICROSS.TTF,Microsoft Sans Serif\0"
1769 "MINGLIU.TTC,MingLiU_HKSCS\0"
1770 "MINGLIU.TTC,MingLiU\0"
1771 "SIMSUN.TTC,SimSun\0"
1772 "MSMINCHO.TTC,MS Mincho\0"
1773 "BATANG.TTC,BatangChe\0"
1774 "MSJH.TTC,Microsoft JhengHei UI\0"
1775 "MSYH.TTC,Microsoft YaHei UI\0"
1776 "YUGOTHM.TTC,Yu Gothic UI\0"
1777 "MALGUN.TTF,Malgun Gothic\0"
1778 "SEGUISYM.TTF,Segoe UI Symbol\0";
1780 static const struct system_link_reg
1782 const WCHAR
*font_name
;
1783 BOOL locale_dependent
;
1784 const char *link_non_cjk
;
1785 DWORD link_non_cjk_len
;
1786 const char *link_sc
;
1788 const char *link_tc
;
1790 const char *link_jp
;
1792 const char *link_kr
;
1795 default_system_link
[] =
1799 system_link_tahoma_non_cjk
, sizeof(system_link_tahoma_non_cjk
),
1800 system_link_tahoma_sc
, sizeof(system_link_tahoma_sc
),
1801 system_link_tahoma_tc
, sizeof(system_link_tahoma_tc
),
1802 system_link_tahoma_jp
, sizeof(system_link_tahoma_jp
),
1803 system_link_tahoma_kr
, sizeof(system_link_tahoma_kr
),
1806 microsoft_sans_serifW
, TRUE
,
1807 system_link_tahoma_non_cjk
, sizeof(system_link_tahoma_non_cjk
),
1808 system_link_tahoma_sc
, sizeof(system_link_tahoma_sc
),
1809 system_link_tahoma_tc
, sizeof(system_link_tahoma_tc
),
1810 system_link_tahoma_jp
, sizeof(system_link_tahoma_jp
),
1811 system_link_tahoma_kr
, sizeof(system_link_tahoma_kr
),
1814 lucida_sans_unicodeW
, TRUE
,
1815 system_link_tahoma_non_cjk
, sizeof(system_link_tahoma_non_cjk
),
1816 system_link_tahoma_sc
, sizeof(system_link_tahoma_sc
),
1817 system_link_tahoma_tc
, sizeof(system_link_tahoma_tc
),
1818 system_link_tahoma_jp
, sizeof(system_link_tahoma_jp
),
1819 system_link_tahoma_kr
, sizeof(system_link_tahoma_kr
),
1821 { ms_gothicW
, FALSE
, system_link_ms_gothic
, sizeof(system_link_ms_gothic
) },
1822 { ms_p_gothicW
, FALSE
, system_link_ms_p_gothic
, sizeof(system_link_ms_p_gothic
) },
1823 { ms_ui_gothicW
, FALSE
, system_link_ms_ui_gothic
, sizeof(system_link_ms_ui_gothic
) },
1824 { microsoft_jheng_heiW
, FALSE
, system_link_microsoft_jheng_hei
, sizeof(system_link_microsoft_jheng_hei
) },
1825 { microsoft_jheng_hei_boldW
, FALSE
, system_link_microsoft_jheng_hei_bold
, sizeof(system_link_microsoft_jheng_hei_bold
) },
1826 { microsoft_jheng_hei_uiW
, FALSE
, system_link_microsoft_jheng_hei_ui
, sizeof(system_link_microsoft_jheng_hei_ui
) },
1827 { microsoft_jheng_hei_ui_boldW
, FALSE
, system_link_microsoft_jheng_hei_ui_bold
, sizeof(system_link_microsoft_jheng_hei_ui_bold
) },
1828 { microsoft_jheng_hei_ui_lightW
, FALSE
, system_link_microsoft_jheng_hei_ui_light
, sizeof(system_link_microsoft_jheng_hei_ui_light
) },
1829 { ming_li_uW
, FALSE
, system_link_ming_li_u
, sizeof(system_link_ming_li_u
) },
1830 { p_ming_li_uW
, FALSE
, system_link_p_ming_li_u
, sizeof(system_link_p_ming_li_u
) },
1831 { ming_li_u_hkscsW
, FALSE
, system_link_ming_li_u_hkscs
, sizeof(system_link_ming_li_u_hkscs
) },
1832 { ming_li_u_ext_bW
, FALSE
, system_link_ming_li_u_ext_b
, sizeof(system_link_ming_li_u_ext_b
) },
1833 { p_ming_li_u_ext_bW
, FALSE
, system_link_p_ming_li_u_ext_b
, sizeof(system_link_p_ming_li_u_ext_b
) },
1834 { ming_li_u_hkscs_ext_bW
, FALSE
, system_link_ming_li_u_hkscs_ext_b
, sizeof(system_link_ming_li_u_hkscs_ext_b
) },
1837 static void populate_system_links( const WCHAR
*name
, const WCHAR
* const *values
)
1839 struct gdi_font_family
*family
;
1840 struct gdi_font_face
*face
;
1841 struct gdi_font_link
*font_link
;
1842 const WCHAR
*file
, *value
;
1844 /* Don't store fonts that are only substitutes for other fonts */
1845 if (get_gdi_font_subst( name
, -1, NULL
))
1847 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
) );
1850 font_link
= add_gdi_font_link( name
);
1851 for ( ; *values
; values
++)
1853 if (!facename_compare( name
, *values
, -1 )) continue;
1854 if (!(value
= get_gdi_font_subst( *values
, -1, NULL
))) value
= *values
;
1855 if (!(family
= find_family_from_name( value
))) continue;
1856 /* use first extant filename for this Family */
1857 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1859 if (!face
->file
) continue;
1860 file
= wcsrchr(face
->file
, '\\');
1861 if (!file
) file
= face
->file
;
1863 if ((face
= find_face_from_filename( file
, value
)))
1865 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1866 TRACE( "added internal SystemLink for %s to %s in %s\n",
1867 debugstr_w(name
), debugstr_w(value
), debugstr_w(file
) );
1869 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
) );
1875 static void load_system_links(void)
1879 const WCHAR
*shelldlg_name
;
1880 struct gdi_font_link
*font_link
, *system_font_link
;
1881 struct gdi_font_face
*face
;
1883 static const WCHAR ms_shell_dlgW
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
1884 static const WCHAR systemW
[] = {'S','y','s','t','e','m',0};
1885 static const WCHAR tahoma_ttfW
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1887 if ((hkey
= reg_open_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
) )))
1890 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1891 WCHAR value
[MAX_PATH
];
1892 WCHAR
*entry
, *next
;
1895 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
), value
, sizeof(value
) ))
1897 /* Don't store fonts that are only substitutes for other fonts */
1898 if (!get_gdi_font_subst( value
, -1, NULL
))
1900 char *data
= (char *)info
+ info
->DataOffset
;
1901 font_link
= add_gdi_font_link( value
);
1902 for (entry
= (WCHAR
*)data
; (char *)entry
< data
+ info
->DataLength
&& *entry
; entry
= next
)
1904 const WCHAR
*family_name
= NULL
;
1907 TRACE( "%s: %s\n", debugstr_w(value
), debugstr_w(entry
) );
1909 next
= entry
+ lstrlenW(entry
) + 1;
1910 if ((p
= wcschr( entry
, ',' )))
1913 while (*p
== ' ' || *p
== '\t') p
++;
1914 if (!(family_name
= get_gdi_font_subst( p
, -1, NULL
))) family_name
= p
;
1916 if ((face
= find_face_from_filename( entry
, family_name
)))
1918 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1919 TRACE("Adding file %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1921 else TRACE( "Unable to find file %s family %s\n",
1922 debugstr_w(entry
), debugstr_w(family_name
) );
1925 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1930 if ((shelldlg_name
= get_gdi_font_subst( ms_shell_dlgW
, -1, NULL
)))
1932 for (i
= 0; i
< ARRAY_SIZE(font_links_defaults_list
); i
++)
1934 const WCHAR
*subst
= get_gdi_font_subst( font_links_defaults_list
[i
].shelldlg
, -1, NULL
);
1936 if ((!facename_compare( font_links_defaults_list
[i
].shelldlg
, shelldlg_name
, -1 ) ||
1937 (subst
&& !facename_compare( subst
, shelldlg_name
, -1 ))))
1939 for (j
= 0; j
< ARRAY_SIZE(font_links_list
); j
++)
1940 populate_system_links( font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
1941 if (!facename_compare(shelldlg_name
, font_links_defaults_list
[i
].substitutes
[0], -1))
1942 populate_system_links( shelldlg_name
, font_links_defaults_list
[i
].substitutes
);
1946 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1948 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1951 system_font_link
= add_gdi_font_link( systemW
);
1952 if ((face
= find_face_from_filename( tahoma_ttfW
, tahomaW
)))
1954 add_gdi_font_link_entry( system_font_link
, face
->family
->family_name
, face
->fs
);
1955 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1957 if ((font_link
= find_gdi_font_link( tahomaW
)))
1959 struct gdi_font_link_entry
*entry
;
1960 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1961 add_gdi_font_link_entry( system_font_link
, entry
->family_name
, entry
->fs
);
1965 /* see TranslateCharsetInfo */
1966 BOOL
translate_charset_info( DWORD
*src
, CHARSETINFO
*cs
, DWORD flags
)
1972 case TCI_SRCFONTSIG
:
1973 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
1974 if (charset_info
[i
].fs
.fsCsb
[0] & src
[0]) goto found
;
1976 case TCI_SRCCODEPAGE
:
1977 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
1978 if (PtrToUlong(src
) == charset_info
[i
].ciACP
) goto found
;
1980 case TCI_SRCCHARSET
:
1981 for (i
= 0; i
< ARRAY_SIZE(charset_info
); i
++)
1982 if (PtrToUlong(src
) == charset_info
[i
].ciCharset
) goto found
;
1988 *cs
= charset_info
[i
];
1994 static BOOL
can_select_face( const struct gdi_font_face
*face
, FONTSIGNATURE fs
, BOOL can_use_bitmap
)
1996 struct gdi_font_link
*font_link
;
1998 if (!face
->scalable
&& !can_use_bitmap
) return FALSE
;
1999 if (!fs
.fsCsb
[0]) return TRUE
;
2000 if (fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return TRUE
;
2001 if (!(font_link
= find_gdi_font_link( face
->family
->family_name
))) return FALSE
;
2002 if (fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) return TRUE
;
2006 static struct gdi_font_face
*find_best_matching_face( const struct gdi_font_family
*family
,
2007 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
2008 BOOL can_use_bitmap
)
2010 struct gdi_font_face
*face
= NULL
, *best
= NULL
, *best_bitmap
= NULL
;
2011 unsigned int best_score
= 4;
2013 int it
= !!lf
->lfItalic
;
2014 int bd
= lf
->lfWeight
> 550;
2015 int height
= lf
->lfHeight
;
2017 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2019 int italic
= !!(face
->ntmFlags
& NTM_ITALIC
);
2020 int bold
= !!(face
->ntmFlags
& NTM_BOLD
);
2021 int score
= (italic
^ it
) + (bold
^ bd
);
2023 if (!can_select_face( face
, fs
, can_use_bitmap
)) continue;
2024 if (score
> best_score
) continue;
2025 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic
, bold
, it
, bd
);
2028 if (best
->scalable
&& best_score
== 0) break;
2029 if (!best
->scalable
)
2033 diff
= height
- (signed int)best
->size
.height
;
2035 diff
= -height
- ((signed int)best
->size
.height
- best
->size
.internal_leading
);
2037 (best_diff
> 0 && diff
>= 0 && diff
< best_diff
) ||
2038 (best_diff
< 0 && diff
> best_diff
))
2040 TRACE( "%d is better for %d diff was %d\n", best
->size
.height
, height
, best_diff
);
2043 if (best_score
== 0 && best_diff
== 0) break;
2047 if (!best
) return NULL
;
2048 return best
->scalable
? best
: best_bitmap
;
2051 static struct gdi_font_face
*find_matching_face_by_name( const WCHAR
*name
, const WCHAR
*subst
,
2052 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
2053 BOOL can_use_bitmap
, const WCHAR
**orig_name
)
2055 struct gdi_font_family
*family
;
2056 struct gdi_font_face
*face
;
2058 family
= find_family_from_any_name( name
);
2059 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
2062 family
= find_family_from_any_name( subst
);
2063 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) goto found
;
2066 /* search by full face name */
2067 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2068 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2069 if (!facename_compare( face
->full_name
, name
, LF_FACESIZE
- 1 ) &&
2070 can_select_face( face
, fs
, can_use_bitmap
))
2073 if ((family
= find_family_from_font_links( name
, subst
, fs
)))
2075 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
2080 if (orig_name
&& family
!= face
->family
)
2081 *orig_name
= family
->family_name
;
2085 static struct gdi_font_face
*find_any_face( const LOGFONTW
*lf
, FONTSIGNATURE fs
,
2086 BOOL can_use_bitmap
, BOOL want_vertical
)
2088 struct gdi_font_family
*family
;
2089 struct gdi_font_face
*face
;
2090 WCHAR name
[LF_FACESIZE
+ 1];
2093 /* first try the family fallbacks */
2094 while (enum_fallbacks( lf
->lfPitchAndFamily
, i
++, name
))
2098 memmove(name
+ 1, name
, min(lstrlenW(name
), LF_FACESIZE
));
2102 if (!(family
= find_family_from_any_name(name
))) continue;
2103 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
2105 /* otherwise try only scalable */
2106 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2108 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
2109 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
2111 if (!can_use_bitmap
) return NULL
;
2112 /* then also bitmap fonts */
2113 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2115 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
2116 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
2121 static struct gdi_font_face
*find_matching_face( const LOGFONTW
*lf
, CHARSETINFO
*csi
, BOOL can_use_bitmap
,
2122 BOOL
*substituted
, const WCHAR
**orig_name
)
2124 BOOL want_vertical
= (lf
->lfFaceName
[0] == '@');
2125 struct gdi_font_face
*face
;
2127 if (!translate_charset_info( (DWORD
*)(INT_PTR
)lf
->lfCharSet
, csi
, TCI_SRCCHARSET
))
2129 if (lf
->lfCharSet
!= DEFAULT_CHARSET
) FIXME( "Untranslated charset %d\n", lf
->lfCharSet
);
2130 csi
->fs
.fsCsb
[0] = 0;
2133 if (lf
->lfFaceName
[0])
2136 const WCHAR
*subst
= get_gdi_font_subst( lf
->lfFaceName
, lf
->lfCharSet
, &subst_charset
);
2140 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf
->lfFaceName
), lf
->lfCharSet
,
2141 debugstr_w(subst
), (subst_charset
!= -1) ? subst_charset
: lf
->lfCharSet
);
2142 if (subst_charset
!= -1)
2143 translate_charset_info( (DWORD
*)(INT_PTR
)subst_charset
, csi
, TCI_SRCCHARSET
);
2144 *substituted
= TRUE
;
2147 if ((face
= find_matching_face_by_name( lf
->lfFaceName
, subst
, lf
, csi
->fs
, can_use_bitmap
, orig_name
)))
2150 *substituted
= FALSE
; /* substitution is no longer relevant */
2152 /* If requested charset was DEFAULT_CHARSET then try using charset
2153 corresponding to the current ansi codepage */
2154 if (!csi
->fs
.fsCsb
[0])
2156 if (!translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, csi
, TCI_SRCCODEPAGE
))
2158 FIXME( "TCI failed on codepage %d\n", ansi_cp
.CodePage
);
2159 csi
->fs
.fsCsb
[0] = 0;
2163 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
2164 if (csi
->fs
.fsCsb
[0])
2166 csi
->fs
.fsCsb
[0] = 0;
2167 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
2169 if (want_vertical
&& (face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, FALSE
))) return face
;
2173 /* realized font objects */
2175 #define FIRST_FONT_HANDLE 1
2176 #define MAX_FONT_HANDLES 256
2178 struct font_handle_entry
2180 struct gdi_font
*font
;
2181 WORD generation
; /* generation count for reusing handle values */
2184 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
2185 static struct font_handle_entry
*next_free
;
2186 static struct font_handle_entry
*next_unused
= font_handles
;
2188 static struct font_handle_entry
*handle_entry( DWORD handle
)
2190 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
2192 if (idx
< MAX_FONT_HANDLES
)
2194 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
2195 return &font_handles
[idx
];
2197 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
2201 static struct gdi_font
*get_font_from_handle( DWORD handle
)
2203 struct font_handle_entry
*entry
= handle_entry( handle
);
2205 if (entry
) return entry
->font
;
2206 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2210 static DWORD
alloc_font_handle( struct gdi_font
*font
)
2212 struct font_handle_entry
*entry
;
2216 next_free
= (struct font_handle_entry
*)entry
->font
;
2217 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
2218 entry
= next_unused
++;
2221 ERR( "out of realized font handles\n" );
2225 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
2226 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
2229 static void free_font_handle( DWORD handle
)
2231 struct font_handle_entry
*entry
;
2233 if ((entry
= handle_entry( handle
)))
2235 entry
->font
= (struct gdi_font
*)next_free
;
2240 static struct gdi_font
*alloc_gdi_font( const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
)
2242 UINT len
= file
? lstrlenW(file
) : 0;
2243 struct gdi_font
*font
= calloc( 1, offsetof( struct gdi_font
, file
[len
+ 1] ));
2246 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
2248 font
->kern_count
= -1;
2249 list_init( &font
->child_fonts
);
2253 FILE_NETWORK_OPEN_INFORMATION info
;
2254 UNICODE_STRING nt_name
;
2255 OBJECT_ATTRIBUTES attr
;
2257 nt_name
.Buffer
= (WCHAR
*)file
;
2258 nt_name
.Length
= nt_name
.MaximumLength
= len
* sizeof(WCHAR
);
2260 attr
.Length
= sizeof(attr
);
2261 attr
.RootDirectory
= 0;
2262 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2263 attr
.ObjectName
= &nt_name
;
2264 attr
.SecurityDescriptor
= NULL
;
2265 attr
.SecurityQualityOfService
= NULL
;
2267 if (!NtQueryFullAttributesFile( &attr
, &info
))
2269 font
->writetime
.dwLowDateTime
= info
.LastWriteTime
.LowPart
;
2270 font
->writetime
.dwHighDateTime
= info
.LastWriteTime
.HighPart
;
2271 font
->data_size
= info
.EndOfFile
.QuadPart
;
2272 memcpy( font
->file
, file
, len
* sizeof(WCHAR
) );
2277 font
->data_ptr
= data_ptr
;
2278 font
->data_size
= data_size
;
2281 font
->handle
= alloc_font_handle( font
);
2285 static void free_gdi_font( struct gdi_font
*font
)
2288 struct gdi_font
*child
, *child_next
;
2290 if (font
->private) font_funcs
->destroy_font( font
);
2291 free_font_handle( font
->handle
);
2292 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, struct gdi_font
, entry
)
2294 list_remove( &child
->entry
);
2295 free_gdi_font( child
);
2297 for (i
= 0; i
< font
->gm_size
; i
++) free( font
->gm
[i
] );
2298 free( font
->otm
.otmpFamilyName
);
2299 free( font
->otm
.otmpStyleName
);
2300 free( font
->otm
.otmpFaceName
);
2301 free( font
->otm
.otmpFullName
);
2303 free( font
->kern_pairs
);
2304 free( font
->gsub_table
);
2308 static inline const WCHAR
*get_gdi_font_name( struct gdi_font
*font
)
2310 return font
->use_logfont_name
? font
->lf
.lfFaceName
: (WCHAR
*)font
->otm
.otmpFamilyName
;
2313 static struct gdi_font
*create_gdi_font( const struct gdi_font_face
*face
, const WCHAR
*family_name
,
2314 const LOGFONTW
*lf
)
2316 struct gdi_font
*font
;
2318 if (!(font
= alloc_gdi_font( face
->file
, face
->data_ptr
, face
->data_size
))) return NULL
;
2319 font
->fs
= face
->fs
;
2321 font
->fake_italic
= (lf
->lfItalic
&& !(face
->ntmFlags
& NTM_ITALIC
));
2322 font
->fake_bold
= (lf
->lfWeight
> 550 && !(face
->ntmFlags
& NTM_BOLD
));
2323 font
->scalable
= face
->scalable
;
2324 font
->face_index
= face
->face_index
;
2325 font
->ntmFlags
= face
->ntmFlags
;
2326 font
->aa_flags
= HIWORD( face
->flags
);
2327 if (!family_name
) family_name
= face
->family
->family_name
;
2328 font
->otm
.otmpFamilyName
= (char *)wcsdup( family_name
);
2329 font
->otm
.otmpStyleName
= (char *)wcsdup( face
->style_name
);
2330 font
->otm
.otmpFaceName
= (char *)wcsdup( face
->full_name
);
2334 struct glyph_metrics
2337 ABC abc
; /* metrics of the unrotated char */
2341 #define GM_BLOCK_SIZE 128
2343 /* TODO: GGO format support */
2344 static BOOL
get_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
, GLYPHMETRICS
*gm
, ABC
*abc
)
2346 UINT block
= index
/ GM_BLOCK_SIZE
;
2347 UINT entry
= index
% GM_BLOCK_SIZE
;
2349 if (block
< font
->gm_size
&& font
->gm
[block
] && font
->gm
[block
][entry
].init
)
2351 *gm
= font
->gm
[block
][entry
].gm
;
2352 *abc
= font
->gm
[block
][entry
].abc
;
2354 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
2355 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point( &gm
->gmptGlyphOrigin
),
2356 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2363 static void set_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
,
2364 const GLYPHMETRICS
*gm
, const ABC
*abc
)
2366 UINT block
= index
/ GM_BLOCK_SIZE
;
2367 UINT entry
= index
% GM_BLOCK_SIZE
;
2369 if (block
>= font
->gm_size
)
2371 struct glyph_metrics
**ptr
;
2373 if (!(ptr
= realloc( font
->gm
, (block
+ 1) * sizeof(*ptr
) ))) return;
2374 memset( ptr
+ font
->gm_size
, 0, (block
+ 1 - font
->gm_size
) * sizeof(*ptr
) );
2375 font
->gm_size
= block
+ 1;
2378 if (!font
->gm
[block
])
2380 font
->gm
[block
] = calloc( sizeof(**font
->gm
), GM_BLOCK_SIZE
);
2381 if (!font
->gm
[block
]) return;
2383 font
->gm
[block
][entry
].gm
= *gm
;
2384 font
->gm
[block
][entry
].abc
= *abc
;
2385 font
->gm
[block
][entry
].init
= TRUE
;
2389 /* GSUB table support */
2403 } GSUB_ScriptRecord
;
2408 GSUB_ScriptRecord ScriptRecord
[1];
2415 } GSUB_LangSysRecord
;
2419 WORD DefaultLangSys
;
2421 GSUB_LangSysRecord LangSysRecord
[1];
2426 WORD LookupOrder
; /* Reserved */
2427 WORD ReqFeatureIndex
;
2429 WORD FeatureIndex
[1];
2436 } GSUB_FeatureRecord
;
2441 GSUB_FeatureRecord FeatureRecord
[1];
2446 WORD FeatureParams
; /* Reserved */
2448 WORD LookupListIndex
[1];
2467 WORD CoverageFormat
;
2470 } GSUB_CoverageFormat1
;
2476 WORD StartCoverageIndex
;
2481 WORD CoverageFormat
;
2483 GSUB_RangeRecord RangeRecord
[1];
2484 } GSUB_CoverageFormat2
;
2488 WORD SubstFormat
; /* = 1 */
2491 } GSUB_SingleSubstFormat1
;
2495 WORD SubstFormat
; /* = 2 */
2499 } GSUB_SingleSubstFormat2
;
2501 static GSUB_Script
*GSUB_get_script_table( GSUB_Header
*header
, const char *tag
)
2503 GSUB_ScriptList
*script
;
2504 GSUB_Script
*deflt
= NULL
;
2507 script
= (GSUB_ScriptList
*)((BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
2508 TRACE("%i scripts in this font\n", GET_BE_WORD(script
->ScriptCount
) );
2509 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
2511 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
2512 GSUB_Script
*scr
= (GSUB_Script
*)((BYTE
*)script
+ offset
);
2513 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, tag
, 4 )) return scr
;
2514 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, "dflt", 4 )) deflt
= scr
;
2519 static GSUB_LangSys
*GSUB_get_lang_table( GSUB_Script
*script
, const char *tag
)
2524 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
2526 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
2528 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
2529 lang
= (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2530 if (!memcmp( script
->LangSysRecord
[i
].LangSysTag
, tag
, 4 )) return lang
;
2532 offset
= GET_BE_WORD(script
->DefaultLangSys
);
2533 if (offset
) return (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
2537 static GSUB_Feature
*GSUB_get_feature( GSUB_Header
*header
, GSUB_LangSys
*lang
, const char *tag
)
2540 const GSUB_FeatureList
*feature
;
2542 feature
= (GSUB_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
2543 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
2544 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
2546 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
2547 if (!memcmp( feature
->FeatureRecord
[index
].FeatureTag
, tag
, 4 ))
2548 return (GSUB_Feature
*)((BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
2553 static const char *get_opentype_script( const struct gdi_font
*font
)
2556 * I am not sure if this is the correct way to generate our script tag
2558 switch (font
->charset
)
2560 case ANSI_CHARSET
: return "latn";
2561 case BALTIC_CHARSET
: return "latn"; /* ?? */
2562 case CHINESEBIG5_CHARSET
: return "hani";
2563 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
2564 case GB2312_CHARSET
: return "hani";
2565 case GREEK_CHARSET
: return "grek";
2566 case HANGUL_CHARSET
: return "hang";
2567 case RUSSIAN_CHARSET
: return "cyrl";
2568 case SHIFTJIS_CHARSET
: return "kana";
2569 case TURKISH_CHARSET
: return "latn"; /* ?? */
2570 case VIETNAMESE_CHARSET
: return "latn";
2571 case JOHAB_CHARSET
: return "latn"; /* ?? */
2572 case ARABIC_CHARSET
: return "arab";
2573 case HEBREW_CHARSET
: return "hebr";
2574 case THAI_CHARSET
: return "thai";
2575 default: return "latn";
2579 static void *get_GSUB_vert_feature( struct gdi_font
*font
)
2581 GSUB_Header
*header
;
2582 GSUB_Script
*script
;
2583 GSUB_LangSys
*language
;
2584 GSUB_Feature
*feature
;
2585 DWORD length
= font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, NULL
, 0 );
2587 if (length
== GDI_ERROR
) return NULL
;
2589 header
= malloc( length
);
2590 font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, header
, length
);
2591 TRACE( "Loaded GSUB table of %i bytes\n", length
);
2593 if ((script
= GSUB_get_script_table( header
, get_opentype_script(font
) )))
2595 if ((language
= GSUB_get_lang_table( script
, "xxxx" ))) /* Need to get Lang tag */
2597 feature
= GSUB_get_feature( header
, language
, "vrt2" );
2598 if (!feature
) feature
= GSUB_get_feature( header
, language
, "vert" );
2601 font
->gsub_table
= header
;
2604 TRACE("vrt2/vert feature not found\n");
2606 else TRACE("Language not found\n");
2608 else TRACE("Script not found\n");
2614 static int GSUB_is_glyph_covered( void *table
, UINT glyph
)
2616 GSUB_CoverageFormat1
*cf1
= table
;
2618 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
2620 int i
, count
= GET_BE_WORD(cf1
->GlyphCount
);
2622 TRACE("Coverage Format 1, %i glyphs\n",count
);
2623 for (i
= 0; i
< count
; i
++) if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
])) return i
;
2626 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
2629 GSUB_CoverageFormat2
*cf2
= table
;
2631 count
= GET_BE_WORD(cf2
->RangeCount
);
2632 TRACE("Coverage Format 2, %i ranges\n",count
);
2633 for (i
= 0; i
< count
; i
++)
2635 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) return -1;
2636 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
2637 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
2639 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
2640 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
2645 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
2650 static UINT
GSUB_apply_feature( GSUB_Header
*header
, GSUB_Feature
*feature
, UINT glyph
)
2652 GSUB_LookupList
*lookup
= (GSUB_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2655 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
2656 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
2658 GSUB_LookupTable
*look
;
2659 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
2660 look
= (GSUB_LookupTable
*)((BYTE
*)lookup
+ offset
);
2661 TRACE("type %i, flag %x, subtables %i\n",
2662 GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
2663 if (GET_BE_WORD(look
->LookupType
) == 1)
2665 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
2667 GSUB_SingleSubstFormat1
*ssf1
;
2668 offset
= GET_BE_WORD(look
->SubTable
[j
]);
2669 ssf1
= (GSUB_SingleSubstFormat1
*)((BYTE
*)look
+ offset
);
2670 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
2672 int offset
= GET_BE_WORD(ssf1
->Coverage
);
2673 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
2674 if (GSUB_is_glyph_covered( (BYTE
*) ssf1
+ offset
, glyph
) != -1)
2676 TRACE(" Glyph 0x%x ->",glyph
);
2677 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
2678 TRACE(" 0x%x\n",glyph
);
2683 GSUB_SingleSubstFormat2
*ssf2
;
2686 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
2687 offset
= GET_BE_WORD(ssf1
->Coverage
);
2688 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
2689 index
= GSUB_is_glyph_covered( (BYTE
*)ssf2
+ offset
, glyph
);
2690 TRACE(" Coverage index %i\n",index
);
2693 TRACE(" Glyph is 0x%x ->",glyph
);
2694 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
2695 TRACE("0x%x\n",glyph
);
2700 else FIXME("We only handle SubType 1\n");
2705 static UINT
get_GSUB_vert_glyph( struct gdi_font
*font
, UINT glyph
)
2707 if (!glyph
) return glyph
;
2708 if (!font
->gsub_table
) return glyph
;
2709 return GSUB_apply_feature( font
->gsub_table
, font
->vert_feature
, glyph
);
2712 static void add_child_font( struct gdi_font
*font
, const WCHAR
*family_name
)
2714 FONTSIGNATURE fs
= {{0}};
2715 struct gdi_font
*child
;
2716 struct gdi_font_face
*face
;
2718 if (!(face
= find_matching_face_by_name( family_name
, NULL
, &font
->lf
, fs
, FALSE
, NULL
))) return;
2720 if (!(child
= create_gdi_font( face
, family_name
, &font
->lf
))) return;
2721 child
->matrix
= font
->matrix
;
2722 child
->can_use_bitmap
= font
->can_use_bitmap
;
2723 child
->scale_y
= font
->scale_y
;
2724 child
->aveWidth
= font
->aveWidth
;
2725 child
->charset
= font
->charset
;
2726 child
->codepage
= font
->codepage
;
2727 child
->base_font
= font
;
2728 list_add_tail( &font
->child_fonts
, &child
->entry
);
2729 TRACE( "created child font %p for base %p\n", child
, font
);
2732 static void create_child_font_list( struct gdi_font
*font
)
2734 struct gdi_font_link
*font_link
;
2735 struct gdi_font_link_entry
*entry
;
2736 const WCHAR
* font_name
= (WCHAR
*)font
->otm
.otmpFaceName
;
2738 if ((font_link
= find_gdi_font_link( font_name
)))
2740 TRACE("found entry in system list\n");
2741 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2742 add_child_font( font
, entry
->family_name
);
2745 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2746 * Sans Serif. This is how asian windows get default fallbacks for fonts
2748 if (ansi_cp
.MaximumCharacterSize
== 2 && font
->charset
!= SYMBOL_CHARSET
&& font
->charset
!= OEM_CHARSET
&&
2749 facename_compare( font_name
, microsoft_sans_serifW
, -1 ) != 0)
2751 if ((font_link
= find_gdi_font_link( microsoft_sans_serifW
)))
2753 TRACE("found entry in default fallback list\n");
2754 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2755 add_child_font( font
, entry
->family_name
);
2762 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
2763 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
2764 static unsigned int unused_font_count
;
2765 #define UNUSED_CACHE_SIZE 10
2767 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
2768 const FMAT2
*matrix
, BOOL can_use_bitmap
)
2770 if (font
->hash
!= hash
) return TRUE
;
2771 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
2772 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2773 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
2774 return facename_compare( font
->lf
.lfFaceName
, lf
->lfFaceName
, -1 );
2777 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2779 DWORD hash
= 0, *ptr
, two_chars
;
2783 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
2785 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
2787 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
2790 pwc
= (WCHAR
*)&two_chars
;
2792 *pwc
= towupper(*pwc
);
2794 *pwc
= towupper(*pwc
);
2798 hash
^= !can_use_bitmap
;
2802 static void cache_gdi_font( struct gdi_font
*font
)
2804 static DWORD cache_num
= 1;
2806 font
->cache_num
= cache_num
++;
2807 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
2808 list_add_head( &gdi_font_list
, &font
->entry
);
2809 TRACE( "font %p\n", font
);
2812 static struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2814 struct gdi_font
*font
;
2815 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
2817 /* try the in-use list */
2818 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
2820 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
2821 list_remove( &font
->entry
);
2822 list_add_head( &gdi_font_list
, &font
->entry
);
2823 if (!font
->refcount
++)
2825 list_remove( &font
->unused_entry
);
2826 unused_font_count
--;
2833 static void release_gdi_font( struct gdi_font
*font
)
2837 TRACE( "font %p\n", font
);
2839 /* add it to the unused list */
2840 pthread_mutex_lock( &font_lock
);
2841 if (!--font
->refcount
)
2843 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
2844 if (unused_font_count
> UNUSED_CACHE_SIZE
)
2846 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
2847 TRACE( "freeing %p\n", font
);
2848 list_remove( &font
->entry
);
2849 list_remove( &font
->unused_entry
);
2850 free_gdi_font( font
);
2852 else unused_font_count
++;
2854 pthread_mutex_unlock( &font_lock
);
2857 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
2859 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
2861 set_reg_ascii_value( hkey
, "Courier", fl
->courier
);
2862 set_reg_ascii_value( hkey
, "MS Serif", fl
->serif
);
2863 set_reg_ascii_value( hkey
, "MS Sans Serif", sserif
);
2864 set_reg_ascii_value( hkey
, "Small Fonts", fl
->small
);
2867 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2870 set_reg_ascii_value( hkey
, name
, value
);
2874 asciiz_to_unicode( nameW
, name
);
2875 reg_delete_value( hkey
, nameW
);
2879 static void update_font_association_info(void)
2881 static const WCHAR associated_charsetW
[] =
2882 { 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t' };
2884 if (ansi_cp
.MaximumCharacterSize
== 2)
2887 if ((hkey
= reg_create_key( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
), 0, NULL
)))
2890 if ((hsubkey
= reg_create_key( hkey
, associated_charsetW
, sizeof(associated_charsetW
),
2893 switch (ansi_cp
.CodePage
)
2896 set_value_key(hsubkey
, "ANSI(00)", "NO");
2897 set_value_key(hsubkey
, "OEM(FF)", "NO");
2898 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2903 set_value_key(hsubkey
, "ANSI(00)", "YES");
2904 set_value_key(hsubkey
, "OEM(FF)", "YES");
2905 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2911 /* TODO: Associated DefaultFonts */
2917 reg_delete_tree( NULL
, font_assoc_keyW
, sizeof(font_assoc_keyW
) );
2920 static void set_multi_value_key( HKEY hkey
, const WCHAR
*name
, const char *value
, DWORD len
)
2923 ascii_to_unicode( valueW
, value
, len
);
2925 set_reg_value( hkey
, name
, REG_MULTI_SZ
, valueW
, len
* sizeof(WCHAR
) );
2927 reg_delete_value( hkey
, name
);
2930 static void update_font_system_link_info(void)
2934 if ((hkey
= reg_create_key( NULL
, system_link_keyW
, sizeof(system_link_keyW
), 0, NULL
)))
2939 for (i
= 0; i
< ARRAY_SIZE(default_system_link
); ++i
)
2941 const struct system_link_reg
*link_reg
= &default_system_link
[i
];
2943 link
= link_reg
->link_non_cjk
;
2944 len
= link_reg
->link_non_cjk_len
;
2946 if (link_reg
->locale_dependent
)
2948 switch (ansi_cp
.CodePage
)
2951 link
= link_reg
->link_jp
;
2952 len
= link_reg
->link_jp_len
;
2955 link
= link_reg
->link_sc
;
2956 len
= link_reg
->link_sc_len
;
2959 link
= link_reg
->link_kr
;
2960 len
= link_reg
->link_kr_len
;
2963 link
= link_reg
->link_tc
;
2964 len
= link_reg
->link_tc_len
;
2968 set_multi_value_key(hkey
, link_reg
->font_name
, link
, len
);
2974 static void update_codepage( UINT screen_dpi
)
2976 USHORT utf8_hdr
[2] = { 0, CP_UTF8
};
2977 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[40 * sizeof(WCHAR
)])];
2978 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
2985 BOOL done
= FALSE
, cp_match
= FALSE
;
2987 static const WCHAR log_pixelsW
[] = {'L','o','g','P','i','x','e','l','s',0};
2989 size
= query_reg_value( wine_fonts_key
, log_pixelsW
, info
, sizeof(value_buffer
) );
2990 if (size
== sizeof(DWORD
) && info
->Type
== REG_DWORD
)
2991 font_dpi
= *(DWORD
*)info
->Data
;
2993 RtlInitCodePageTable( utf8_hdr
, &utf8_cp
);
2994 if (NtCurrentTeb()->Peb
->AnsiCodePageData
)
2995 RtlInitCodePageTable( NtCurrentTeb()->Peb
->AnsiCodePageData
, &ansi_cp
);
2998 if (NtCurrentTeb()->Peb
->OemCodePageData
)
2999 RtlInitCodePageTable( NtCurrentTeb()->Peb
->OemCodePageData
, &oem_cp
);
3002 sprintf( cpbuf
, "%u,%u", ansi_cp
.CodePage
, oem_cp
.CodePage
);
3003 asciiz_to_unicode( cpbufW
, cpbuf
);
3005 if (query_reg_ascii_value( wine_fonts_key
, "Codepages", info
, sizeof(value_buffer
) ))
3007 cp_match
= !wcscmp( (const WCHAR
*)info
->Data
, cpbufW
);
3008 if (cp_match
&& screen_dpi
== font_dpi
) return; /* already set correctly */
3009 TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3010 debugstr_w((const WCHAR
*)info
->Data
), font_dpi
, ansi_cp
.CodePage
, oem_cp
.CodePage
, screen_dpi
);
3012 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3013 ansi_cp
.CodePage
, oem_cp
.CodePage
, screen_dpi
);
3015 set_reg_ascii_value( wine_fonts_key
, "Codepages", cpbuf
);
3016 set_reg_value( wine_fonts_key
, log_pixelsW
, REG_DWORD
, &screen_dpi
, sizeof(screen_dpi
) );
3018 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
3020 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
.CodePage
&&
3021 nls_update_font_list
[i
].oem_cp
== oem_cp
.CodePage
)
3024 if ((software_hkey
= reg_create_key( NULL
, software_config_keyW
,
3025 sizeof(software_config_keyW
), 0, NULL
)))
3027 static const WCHAR fontsW
[] = {'F','o','n','t','s'};
3028 hkey
= reg_create_key( software_hkey
, fontsW
, sizeof(fontsW
), 0, NULL
);
3029 NtClose( software_hkey
);
3032 set_reg_ascii_value( hkey
, "OEMFONT.FON", nls_update_font_list
[i
].oem
);
3033 set_reg_ascii_value( hkey
, "FIXEDFON.FON", nls_update_font_list
[i
].fixed
);
3034 set_reg_ascii_value( hkey
, "FONTS.FON", nls_update_font_list
[i
].system
);
3038 if ((hkey
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
),
3041 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3044 if ((hkey
= reg_create_key( NULL
, fonts_win9x_config_keyW
,
3045 sizeof(fonts_win9x_config_keyW
), 0, NULL
)))
3047 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3050 /* Only update these if the Codepage changed. */
3052 (hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
3055 set_reg_ascii_value( hkey
, "MS Shell Dlg", nls_update_font_list
[i
].shelldlg
);
3056 set_reg_ascii_value( hkey
, "Tms Rmn", nls_update_font_list
[i
].tmsrmn
);
3058 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3059 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3060 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3061 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3062 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3063 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3064 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3065 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3067 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3068 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3069 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3077 /* Delete the FontSubstitutes from other locales */
3078 if ((hkey
= reg_create_key( NULL
, font_substitutes_keyW
, sizeof(font_substitutes_keyW
),
3081 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3082 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3083 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3089 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
.CodePage
, oem_cp
.CodePage
);
3091 /* update locale dependent font association info and font system link info in registry.
3092 update only when codepages changed, not logpixels. */
3095 update_font_association_info();
3096 update_font_system_link_info();
3101 /*************************************************************
3104 static BOOL CDECL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR device
, LPCWSTR output
,
3105 const DEVMODEW
*devmode
)
3107 struct font_physdev
*physdev
;
3109 if (!font_funcs
) return TRUE
;
3110 if (!(physdev
= calloc( 1, sizeof(*physdev
) ))) return FALSE
;
3111 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
3116 /*************************************************************
3119 static BOOL CDECL
font_DeleteDC( PHYSDEV dev
)
3121 struct font_physdev
*physdev
= get_font_dev( dev
);
3123 release_gdi_font( physdev
->font
);
3129 struct gdi_font_enum_data
3132 NEWTEXTMETRICEXW ntm
;
3142 static BOOL
is_complex_script_ansi_cp(void)
3144 return (ansi_cp
.CodePage
== 874 /* Thai */
3145 || ansi_cp
.CodePage
== 1255 /* Hebrew */
3146 || ansi_cp
.CodePage
== 1256 /* Arabic */
3150 /***************************************************
3151 * create_enum_charset_list
3153 * This function creates charset enumeration list because in DEFAULT_CHARSET
3154 * case, the ANSI codepage's charset takes precedence over other charsets.
3155 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
3156 * This function works as a filter other than DEFAULT_CHARSET case.
3158 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset
*list
)
3160 struct enum_charset
*start
= list
;
3164 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) && csi
.fs
.fsCsb
[0] != 0)
3166 list
->mask
= csi
.fs
.fsCsb
[0];
3167 list
->charset
= csi
.ciCharset
;
3168 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
3171 else /* charset is DEFAULT_CHARSET or invalid. */
3175 /* Set the current codepage's charset as the first element. */
3176 if (!is_complex_script_ansi_cp() &&
3177 translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, &csi
, TCI_SRCCODEPAGE
) &&
3178 csi
.fs
.fsCsb
[0] != 0)
3180 list
->mask
= csi
.fs
.fsCsb
[0];
3181 list
->charset
= csi
.ciCharset
;
3182 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
3183 mask
|= csi
.fs
.fsCsb
[0];
3187 /* Fill out left elements. */
3188 for (i
= 0; i
< 32; i
++)
3191 fs
.fsCsb
[0] = 1u << i
;
3193 if (fs
.fsCsb
[0] & mask
) continue; /* skip, already added. */
3194 if (!translate_charset_info( fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
3195 continue; /* skip, this is an invalid fsCsb bit. */
3196 list
->mask
= fs
.fsCsb
[0];
3197 list
->charset
= csi
.ciCharset
;
3199 mask
|= fs
.fsCsb
[0];
3202 /* add catch all mask for remaining bits */
3206 list
->charset
= DEFAULT_CHARSET
;
3207 list
->script
= 33; /* other */
3211 return list
- start
;
3214 static UINT
get_font_type( const NEWTEXTMETRICEXW
*ntm
)
3218 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ret
|= TRUETYPE_FONTTYPE
;
3219 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
) ret
|= DEVICE_FONTTYPE
;
3220 if (!(ntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
)) ret
|= RASTER_FONTTYPE
;
3224 static BOOL
get_face_enum_data( struct gdi_font_face
*face
, ENUMLOGFONTEXW
*elf
, NEWTEXTMETRICEXW
*ntm
)
3226 struct gdi_font
*font
;
3227 LOGFONTW lf
= { .lfHeight
= -4096 /* preferable EM Square size */ };
3229 if (!face
->scalable
) lf
.lfHeight
= 0;
3231 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
3233 if (!font_funcs
->load_font( font
))
3235 free_gdi_font( font
);
3239 if (font
->scalable
&& -lf
.lfHeight
% font
->otm
.otmEMSquare
!= 0)
3241 /* reload with the original EM Square size */
3242 lf
.lfHeight
= -font
->otm
.otmEMSquare
;
3243 free_gdi_font( font
);
3245 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
3246 if (!font_funcs
->load_font( font
))
3248 free_gdi_font( font
);
3253 if (font_funcs
->set_outline_text_metrics( font
))
3255 static const DWORD ntm_ppem
= 32;
3258 #define TM font->otm.otmTextMetrics
3259 #define SCALE_NTM(value) (muldiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
3260 cell_height
= TM
.tmHeight
/ ( -lf
.lfHeight
/ font
->otm
.otmEMSquare
);
3261 ntm
->ntmTm
.tmHeight
= muldiv( ntm_ppem
, cell_height
, font
->otm
.otmEMSquare
);
3262 ntm
->ntmTm
.tmAscent
= SCALE_NTM( TM
.tmAscent
);
3263 ntm
->ntmTm
.tmDescent
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmAscent
;
3264 ntm
->ntmTm
.tmInternalLeading
= SCALE_NTM( TM
.tmInternalLeading
);
3265 ntm
->ntmTm
.tmExternalLeading
= SCALE_NTM( TM
.tmExternalLeading
);
3266 ntm
->ntmTm
.tmAveCharWidth
= SCALE_NTM( TM
.tmAveCharWidth
);
3267 ntm
->ntmTm
.tmMaxCharWidth
= SCALE_NTM( TM
.tmMaxCharWidth
);
3269 memcpy((char *)&ntm
->ntmTm
+ offsetof( TEXTMETRICW
, tmWeight
),
3270 (const char *)&TM
+ offsetof( TEXTMETRICW
, tmWeight
),
3271 sizeof(TEXTMETRICW
) - offsetof( TEXTMETRICW
, tmWeight
));
3272 ntm
->ntmTm
.ntmSizeEM
= font
->otm
.otmEMSquare
;
3273 ntm
->ntmTm
.ntmCellHeight
= cell_height
;
3274 ntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
3278 else if (font_funcs
->set_bitmap_text_metrics( font
))
3280 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
3281 ntm
->ntmTm
.ntmSizeEM
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmInternalLeading
;
3282 ntm
->ntmTm
.ntmCellHeight
= ntm
->ntmTm
.tmHeight
;
3283 ntm
->ntmTm
.ntmAvgWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3285 ntm
->ntmTm
.ntmFlags
= font
->ntmFlags
;
3286 ntm
->ntmFontSig
= font
->fs
;
3288 elf
->elfLogFont
.lfEscapement
= 0;
3289 elf
->elfLogFont
.lfOrientation
= 0;
3290 elf
->elfLogFont
.lfHeight
= ntm
->ntmTm
.tmHeight
;
3291 elf
->elfLogFont
.lfWidth
= ntm
->ntmTm
.tmAveCharWidth
;
3292 elf
->elfLogFont
.lfWeight
= ntm
->ntmTm
.tmWeight
;
3293 elf
->elfLogFont
.lfItalic
= ntm
->ntmTm
.tmItalic
;
3294 elf
->elfLogFont
.lfUnderline
= ntm
->ntmTm
.tmUnderlined
;
3295 elf
->elfLogFont
.lfStrikeOut
= ntm
->ntmTm
.tmStruckOut
;
3296 elf
->elfLogFont
.lfCharSet
= ntm
->ntmTm
.tmCharSet
;
3297 elf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3298 elf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3299 elf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3300 elf
->elfLogFont
.lfPitchAndFamily
= (ntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3301 lstrcpynW( elf
->elfLogFont
.lfFaceName
, (WCHAR
*)font
->otm
.otmpFamilyName
, LF_FACESIZE
);
3302 lstrcpynW( elf
->elfFullName
, (WCHAR
*)font
->otm
.otmpFaceName
, LF_FULLFACESIZE
);
3303 lstrcpynW( elf
->elfStyle
, (WCHAR
*)font
->otm
.otmpStyleName
, LF_FACESIZE
);
3305 free_gdi_font( font
);
3309 static BOOL
family_matches( struct gdi_font_family
*family
, const WCHAR
*face_name
)
3311 struct gdi_font_face
*face
;
3313 if (!facename_compare( face_name
, family
->family_name
, LF_FACESIZE
- 1 )) return TRUE
;
3314 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3315 if (!facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 )) return TRUE
;
3319 static BOOL
face_matches( const WCHAR
*family_name
, struct gdi_font_face
*face
, const WCHAR
*face_name
)
3321 if (!facename_compare( face_name
, family_name
, LF_FACESIZE
- 1)) return TRUE
;
3322 return !facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 );
3325 static BOOL
enum_face_charsets( const struct gdi_font_family
*family
, struct gdi_font_face
*face
,
3326 struct enum_charset
*list
, DWORD count
, FONTENUMPROCW proc
, LPARAM lparam
,
3327 const WCHAR
*subst
)
3330 NEWTEXTMETRICEXW ntm
;
3333 if (!face
->cached_enum_data
)
3335 struct gdi_font_enum_data
*data
;
3337 if (!(data
= calloc( 1, sizeof(*data
) )) ||
3338 !get_face_enum_data( face
, &data
->elf
, &data
->ntm
))
3343 face
->cached_enum_data
= data
;
3346 elf
= face
->cached_enum_data
->elf
;
3347 ntm
= face
->cached_enum_data
->ntm
;
3348 type
= get_font_type( &ntm
);
3350 /* font replacement */
3351 if (family
!= face
->family
)
3353 lstrcpynW( elf
.elfLogFont
.lfFaceName
, family
->family_name
, LF_FACESIZE
);
3354 lstrcpynW( elf
.elfFullName
, face
->full_name
, LF_FULLFACESIZE
);
3356 if (subst
) lstrcpynW( elf
.elfLogFont
.lfFaceName
, subst
, LF_FACESIZE
);
3358 for (i
= 0; i
< count
; i
++)
3360 if (face
->fs
.fsCsb
[0] == 0) /* OEM */
3362 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3363 elf
.elfScript
[0] = 32;
3364 i
= count
; /* break out of loop after enumeration */
3368 if (!(face
->fs
.fsCsb
[0] & list
[i
].mask
)) continue;
3369 /* use the DEFAULT_CHARSET case only if no other charset is present */
3370 if (list
[i
].charset
== DEFAULT_CHARSET
&& (face
->fs
.fsCsb
[0] & ~list
[i
].mask
)) continue;
3371 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
[i
].charset
;
3372 /* caller may fill elfScript with the actual string, see load_script_name */
3373 elf
.elfScript
[0] = list
[i
].script
;
3375 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3376 debugstr_w(elf
.elfLogFont
.lfFaceName
), debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3377 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
3378 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
, ntm
.ntmTm
.ntmFlags
);
3379 /* release section before callback (FIXME) */
3380 pthread_mutex_unlock( &font_lock
);
3381 if (!proc( &elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
3382 pthread_mutex_lock( &font_lock
);
3387 /*************************************************************
3390 static BOOL CDECL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, FONTENUMPROCW proc
, LPARAM lparam
)
3392 struct gdi_font_family
*family
;
3393 struct gdi_font_face
*face
;
3394 struct enum_charset enum_charsets
[32];
3395 DWORD count
, charset
;
3397 charset
= lf
? lf
->lfCharSet
: DEFAULT_CHARSET
;
3399 count
= create_enum_charset_list( charset
, enum_charsets
);
3401 pthread_mutex_lock( &font_lock
);
3403 if (lf
&& lf
->lfFaceName
[0])
3405 const WCHAR
*face_name
= get_gdi_font_subst( lf
->lfFaceName
, charset
, NULL
);
3406 const WCHAR
*orig_name
= NULL
;
3408 TRACE( "facename = %s charset %d\n", debugstr_w(lf
->lfFaceName
), charset
);
3411 orig_name
= lf
->lfFaceName
;
3412 TRACE( "substituting %s -> %s\n", debugstr_w(lf
->lfFaceName
), debugstr_w(face_name
) );
3414 else face_name
= lf
->lfFaceName
;
3416 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3418 if (!family_matches(family
, face_name
)) continue;
3419 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
3421 if (!face_matches( family
->family_name
, face
, face_name
)) continue;
3422 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, orig_name
))
3429 TRACE( "charset %d\n", charset
);
3430 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
3432 face
= LIST_ENTRY( list_head(get_family_face_list(family
)), struct gdi_font_face
, entry
);
3433 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, NULL
))
3437 pthread_mutex_unlock( &font_lock
);
3442 static BOOL
check_unicode_tategaki( WCHAR ch
)
3444 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
3445 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[ch
>> 8]+((ch
>> 4) & 0x0f)]+ (ch
& 0xf)];
3447 /* We only reach this code if typographical substitution did not occur */
3448 /* Type: U or Type: Tu */
3449 return (orientation
== 1 || orientation
== 3);
3452 static UINT
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
3456 if (glyph
< 0x100) glyph
+= 0xf000;
3457 /* there are a number of old pre-Unicode "broken" TTFs, which
3458 do have symbols at U+00XX instead of U+f0XX */
3460 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3463 index
= glyph
- 0xf000;
3464 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3469 CPTABLEINFO
*get_cptable( WORD cp
)
3471 static CPTABLEINFO tables
[100];
3476 if (cp
== CP_ACP
) return &ansi_cp
;
3477 if (cp
== CP_UTF8
) return &utf8_cp
;
3479 for (i
= 0; i
< ARRAY_SIZE(tables
) && tables
[i
].CodePage
; i
++)
3480 if (tables
[i
].CodePage
== cp
) return &tables
[i
];
3481 if (NtGetNlsSectionPtr( 11, cp
, NULL
, (void **)&ptr
, &size
)) return NULL
;
3482 if (i
== ARRAY_SIZE(tables
))
3484 ERR( "too many code pages\n" );
3487 RtlInitCodePageTable( ptr
, &tables
[i
] );
3491 DWORD
win32u_wctomb( CPTABLEINFO
*info
, char *dst
, DWORD dstlen
, const WCHAR
*src
, DWORD srclen
)
3495 if (info
->CodePage
== CP_UTF8
)
3496 RtlUnicodeToUTF8N( dst
, dstlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
3498 RtlUnicodeToCustomCPN( info
, dst
, dstlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
3503 DWORD
win32u_wctomb_size( CPTABLEINFO
*info
, const WCHAR
*src
, DWORD srclen
)
3507 if (info
->CodePage
== CP_UTF8
)
3509 RtlUnicodeToUTF8N( NULL
, 0, &ret
, src
, srclen
* sizeof(WCHAR
) );
3511 else if(info
->DBCSCodePage
)
3513 WCHAR
*uni2cp
= info
->WideCharTable
;
3514 for (ret
= srclen
; srclen
; srclen
--, src
++)
3515 if (uni2cp
[*src
] & 0xff00) ret
++;
3525 DWORD
win32u_mbtowc( CPTABLEINFO
*info
, WCHAR
*dst
, DWORD dstlen
, const char *src
, DWORD srclen
)
3529 if (info
->CodePage
== CP_UTF8
)
3530 RtlUTF8ToUnicodeN( dst
, dstlen
* sizeof(WCHAR
), &ret
, src
, srclen
);
3532 RtlCustomCPToUnicodeN( info
, dst
, dstlen
* sizeof(WCHAR
), &ret
, src
, srclen
);
3534 return ret
/ sizeof(WCHAR
);
3537 static BOOL
wc_to_index( UINT cp
, WCHAR wc
, unsigned char *dst
, BOOL allow_default
)
3539 const CPTABLEINFO
*info
;
3541 if (!(info
= get_cptable( cp
))) return FALSE
;
3543 if (info
->CodePage
== CP_UTF8
)
3550 if (!allow_default
) return FALSE
;
3551 *dst
= info
->DefaultChar
;
3554 else if (info
->DBCSCodePage
)
3556 WCHAR
*uni2cp
= info
->WideCharTable
;
3557 if (uni2cp
[wc
] & 0xff00) return FALSE
;
3562 char *uni2cp
= info
->WideCharTable
;
3566 if (info
->MultiByteTable
[*dst
] != wc
)
3568 if (!allow_default
) return FALSE
;
3569 *dst
= info
->DefaultChar
;
3575 static UINT
get_glyph_index( struct gdi_font
*font
, UINT glyph
)
3580 if (font_funcs
->get_glyph_index( font
, &glyph
, TRUE
)) return glyph
;
3582 if (font
->codepage
== CP_SYMBOL
)
3584 glyph
= get_glyph_index_symbol( font
, wc
);
3587 if (wc_to_index( CP_ACP
, wc
, &ch
, TRUE
))
3588 glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
3591 else if (wc_to_index( font
->codepage
, wc
, &ch
, FALSE
))
3593 glyph
= (unsigned char)ch
;
3594 font_funcs
->get_glyph_index( font
, &glyph
, FALSE
);
3601 static UINT
get_glyph_index_linked( struct gdi_font
**font
, UINT glyph
)
3603 struct gdi_font
*child
;
3606 if ((res
= get_glyph_index( *font
, glyph
))) return res
;
3607 if (glyph
< 32) return 0; /* don't check linked fonts for control characters */
3609 LIST_FOR_EACH_ENTRY( child
, &(*font
)->child_fonts
, struct gdi_font
, entry
)
3611 if (!child
->private && !font_funcs
->load_font( child
)) continue;
3612 if ((res
= get_glyph_index( child
, glyph
)))
3621 static DWORD
get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3622 GLYPHMETRICS
*gm_ret
, ABC
*abc_ret
, DWORD buflen
, void *buf
,
3629 BOOL tategaki
= (*get_gdi_font_name( font
) == '@');
3631 if (format
& GGO_GLYPH_INDEX
)
3633 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
3634 as glyph index. "Treasure Adventure Game" depends on this. */
3635 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
3636 format
&= ~GGO_GLYPH_INDEX
;
3637 /* TODO: Window also turns off tategaki for glyphs passed in by index
3638 if their unicode code points fall outside of the range that is
3643 index
= get_glyph_index_linked( &font
, glyph
);
3647 index
= get_GSUB_vert_glyph( font
, index
);
3648 if (index
== orig
) tategaki
= check_unicode_tategaki( glyph
);
3652 if (mat
&& !memcmp( mat
, &identity
, sizeof(*mat
) )) mat
= NULL
;
3654 if (format
== GGO_METRICS
&& !mat
&& get_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
))
3657 ret
= font_funcs
->get_glyph_outline( font
, index
, format
, &gm
, &abc
, buflen
, buf
, mat
, tategaki
);
3658 if (ret
== GDI_ERROR
) return ret
;
3660 if (format
== GGO_METRICS
&& !mat
)
3661 set_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
);
3664 if (gm_ret
) *gm_ret
= gm
;
3665 if (abc_ret
) *abc_ret
= abc
;
3670 /*************************************************************
3673 static BOOL CDECL
font_FontIsLinked( PHYSDEV dev
)
3675 struct font_physdev
*physdev
= get_font_dev( dev
);
3679 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
3680 return dev
->funcs
->pFontIsLinked( dev
);
3682 return !list_empty( &physdev
->font
->child_fonts
);
3686 /*************************************************************
3687 * font_GetCharABCWidths
3689 static BOOL CDECL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT count
,
3690 WCHAR
*chars
, ABC
*buffer
)
3692 struct font_physdev
*physdev
= get_font_dev( dev
);
3697 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
3698 return dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
3701 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3703 pthread_mutex_lock( &font_lock
);
3704 for (i
= 0; i
< count
; i
++)
3706 c
= chars
? chars
[i
] : first
+ i
;
3707 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &buffer
[i
], 0, NULL
, NULL
);
3709 pthread_mutex_unlock( &font_lock
);
3714 /*************************************************************
3715 * font_GetCharABCWidthsI
3717 static BOOL CDECL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
3719 struct font_physdev
*physdev
= get_font_dev( dev
);
3724 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
3725 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
3728 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3730 pthread_mutex_lock( &font_lock
);
3731 for (c
= 0; c
< count
; c
++, buffer
++)
3732 get_glyph_outline( physdev
->font
, gi
? gi
[c
] : first
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3733 NULL
, buffer
, 0, NULL
, NULL
);
3734 pthread_mutex_unlock( &font_lock
);
3739 /*************************************************************
3742 static BOOL CDECL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT count
,
3743 const WCHAR
*chars
, INT
*buffer
)
3745 struct font_physdev
*physdev
= get_font_dev( dev
);
3751 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
3752 return dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buffer
);
3755 TRACE( "%p, %d, %d, %p\n", physdev
->font
, first
, count
, buffer
);
3757 pthread_mutex_lock( &font_lock
);
3758 for (i
= 0; i
< count
; i
++)
3760 c
= chars
? chars
[i
] : i
+ first
;
3761 if (get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
) == GDI_ERROR
)
3764 buffer
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3766 pthread_mutex_unlock( &font_lock
);
3771 /*************************************************************
3772 * font_GetCharWidthInfo
3774 static BOOL CDECL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
3776 struct font_physdev
*physdev
= get_font_dev( dev
);
3777 struct char_width_info
*info
= ptr
;
3781 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
3782 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
3786 if (!physdev
->font
->scalable
|| !font_funcs
->get_char_width_info( physdev
->font
, info
))
3787 info
->lsb
= info
->rsb
= 0;
3793 /*************************************************************
3796 static DWORD CDECL
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
3798 struct font_physdev
*physdev
= get_font_dev( dev
);
3802 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
3803 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
3805 return font_funcs
->get_font_data( physdev
->font
, table
, offset
, buf
, size
);
3809 /*************************************************************
3810 * font_GetFontRealizationInfo
3812 static BOOL CDECL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
3814 struct font_physdev
*physdev
= get_font_dev( dev
);
3815 struct font_realization_info
*info
= ptr
;
3819 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
3820 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
3823 TRACE( "(%p, %p)\n", physdev
->font
, info
);
3826 if (physdev
->font
->scalable
) info
->flags
|= 2;
3828 info
->cache_num
= physdev
->font
->cache_num
;
3829 info
->instance_id
= physdev
->font
->handle
;
3830 if (info
->size
== sizeof(*info
))
3832 info
->file_count
= 1;
3833 info
->face_index
= physdev
->font
->face_index
;
3834 info
->simulations
= 0;
3835 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
3836 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
3842 /*************************************************************
3843 * font_GetFontUnicodeRanges
3845 static DWORD CDECL
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
3847 struct font_physdev
*physdev
= get_font_dev( dev
);
3848 DWORD size
, num_ranges
;
3852 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
3853 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
3856 num_ranges
= font_funcs
->get_unicode_ranges( physdev
->font
, glyphset
);
3857 size
= offsetof( GLYPHSET
, ranges
[num_ranges
] );
3860 glyphset
->cbThis
= size
;
3861 glyphset
->cRanges
= num_ranges
;
3862 glyphset
->flAccel
= 0;
3868 /*************************************************************
3869 * font_GetGlyphIndices
3871 static DWORD CDECL
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
3873 struct font_physdev
*physdev
= get_font_dev( dev
);
3876 BOOL got_default
= FALSE
;
3881 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
3882 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
3885 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
3887 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
3891 pthread_mutex_lock( &font_lock
);
3893 for (i
= 0; i
< count
; i
++)
3895 UINT glyph
= str
[i
];
3897 if (!font_funcs
->get_glyph_index( physdev
->font
, &glyph
, TRUE
))
3900 if (physdev
->font
->codepage
== CP_SYMBOL
)
3902 if (str
[i
] >= 0xf020 && str
[i
] <= 0xf100) glyph
= str
[i
] - 0xf000;
3903 else if (str
[i
] < 0x100) glyph
= str
[i
];
3905 else if (wc_to_index( physdev
->font
->codepage
, str
[i
], &ch
, FALSE
))
3906 glyph
= (unsigned char)ch
;
3912 default_char
= font_funcs
->get_default_glyph( physdev
->font
);
3915 gi
[i
] = default_char
;
3917 else gi
[i
] = get_GSUB_vert_glyph( physdev
->font
, glyph
);
3920 pthread_mutex_unlock( &font_lock
);
3925 /*************************************************************
3926 * font_GetGlyphOutline
3928 static DWORD CDECL
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
3929 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
3931 struct font_physdev
*physdev
= get_font_dev( dev
);
3936 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
3937 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
3939 pthread_mutex_lock( &font_lock
);
3940 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, gm
, NULL
, buflen
, buf
, mat
);
3941 pthread_mutex_unlock( &font_lock
);
3946 /*************************************************************
3947 * font_GetKerningPairs
3949 static DWORD CDECL
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
3951 struct font_physdev
*physdev
= get_font_dev( dev
);
3955 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
3956 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
3959 pthread_mutex_lock( &font_lock
);
3960 if (physdev
->font
->kern_count
== -1)
3961 physdev
->font
->kern_count
= font_funcs
->get_kerning_pairs( physdev
->font
,
3962 &physdev
->font
->kern_pairs
);
3963 pthread_mutex_unlock( &font_lock
);
3967 count
= min( count
, physdev
->font
->kern_count
);
3968 memcpy( pairs
, physdev
->font
->kern_pairs
, count
* sizeof(*pairs
) );
3970 else count
= physdev
->font
->kern_count
;
3976 static void scale_outline_font_metrics( const struct gdi_font
*font
, OUTLINETEXTMETRICW
*otm
)
3978 double scale_x
, scale_y
;
3982 scale_x
= (double)font
->aveWidth
;
3983 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3986 scale_x
= font
->scale_y
;
3988 scale_x
*= fabs(font
->matrix
.eM11
);
3989 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3991 /* Windows scales these values as signed integers even if they are unsigned */
3992 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3993 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3995 SCALE_Y(otm
->otmTextMetrics
.tmHeight
);
3996 SCALE_Y(otm
->otmTextMetrics
.tmAscent
);
3997 SCALE_Y(otm
->otmTextMetrics
.tmDescent
);
3998 SCALE_Y(otm
->otmTextMetrics
.tmInternalLeading
);
3999 SCALE_Y(otm
->otmTextMetrics
.tmExternalLeading
);
4001 SCALE_X(otm
->otmTextMetrics
.tmOverhang
);
4002 if (font
->fake_bold
)
4004 if (!font
->scalable
) otm
->otmTextMetrics
.tmOverhang
++;
4005 otm
->otmTextMetrics
.tmAveCharWidth
++;
4006 otm
->otmTextMetrics
.tmMaxCharWidth
++;
4008 SCALE_X(otm
->otmTextMetrics
.tmAveCharWidth
);
4009 SCALE_X(otm
->otmTextMetrics
.tmMaxCharWidth
);
4011 SCALE_Y(otm
->otmAscent
);
4012 SCALE_Y(otm
->otmDescent
);
4013 SCALE_Y(otm
->otmLineGap
);
4014 SCALE_Y(otm
->otmsCapEmHeight
);
4015 SCALE_Y(otm
->otmsXHeight
);
4016 SCALE_Y(otm
->otmrcFontBox
.top
);
4017 SCALE_Y(otm
->otmrcFontBox
.bottom
);
4018 SCALE_X(otm
->otmrcFontBox
.left
);
4019 SCALE_X(otm
->otmrcFontBox
.right
);
4020 SCALE_Y(otm
->otmMacAscent
);
4021 SCALE_Y(otm
->otmMacDescent
);
4022 SCALE_Y(otm
->otmMacLineGap
);
4023 SCALE_X(otm
->otmptSubscriptSize
.x
);
4024 SCALE_Y(otm
->otmptSubscriptSize
.y
);
4025 SCALE_X(otm
->otmptSubscriptOffset
.x
);
4026 SCALE_Y(otm
->otmptSubscriptOffset
.y
);
4027 SCALE_X(otm
->otmptSuperscriptSize
.x
);
4028 SCALE_Y(otm
->otmptSuperscriptSize
.y
);
4029 SCALE_X(otm
->otmptSuperscriptOffset
.x
);
4030 SCALE_Y(otm
->otmptSuperscriptOffset
.y
);
4031 SCALE_Y(otm
->otmsStrikeoutSize
);
4032 SCALE_Y(otm
->otmsStrikeoutPosition
);
4033 SCALE_Y(otm
->otmsUnderscoreSize
);
4034 SCALE_Y(otm
->otmsUnderscorePosition
);
4040 /*************************************************************
4041 * font_GetOutlineTextMetrics
4043 static UINT CDECL
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
4045 struct font_physdev
*physdev
= get_font_dev( dev
);
4050 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
4051 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
4054 if (!physdev
->font
->scalable
) return 0;
4056 pthread_mutex_lock( &font_lock
);
4057 if (font_funcs
->set_outline_text_metrics( physdev
->font
))
4059 ret
= physdev
->font
->otm
.otmSize
;
4060 if (metrics
&& size
>= physdev
->font
->otm
.otmSize
)
4062 WCHAR
*ptr
= (WCHAR
*)(metrics
+ 1);
4063 *metrics
= physdev
->font
->otm
;
4064 metrics
->otmpFamilyName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4065 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFamilyName
);
4066 ptr
+= lstrlenW(ptr
) + 1;
4067 metrics
->otmpStyleName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4068 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpStyleName
);
4069 ptr
+= lstrlenW(ptr
) + 1;
4070 metrics
->otmpFaceName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4071 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFaceName
);
4072 ptr
+= lstrlenW(ptr
) + 1;
4073 metrics
->otmpFullName
= (char *)ptr
- (ULONG_PTR
)metrics
;
4074 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFullName
);
4075 scale_outline_font_metrics( physdev
->font
, metrics
);
4078 pthread_mutex_unlock( &font_lock
);
4083 /*************************************************************
4084 * font_GetTextCharsetInfo
4086 static UINT CDECL
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
4088 struct font_physdev
*physdev
= get_font_dev( dev
);
4092 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
4093 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4095 if (fs
) *fs
= physdev
->font
->fs
;
4096 return physdev
->font
->charset
;
4100 /*************************************************************
4101 * font_GetTextExtentExPoint
4103 static BOOL CDECL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
4105 struct font_physdev
*physdev
= get_font_dev( dev
);
4111 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
4112 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
4115 TRACE( "%p, %s, %d\n", physdev
->font
, debugstr_wn(str
, count
), count
);
4117 pthread_mutex_lock( &font_lock
);
4118 for (i
= pos
= 0; i
< count
; i
++)
4120 get_glyph_outline( physdev
->font
, str
[i
], GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
);
4121 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
4124 pthread_mutex_unlock( &font_lock
);
4129 /*************************************************************
4130 * font_GetTextExtentExPointI
4132 static BOOL CDECL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
4134 struct font_physdev
*physdev
= get_font_dev( dev
);
4140 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
4141 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
4144 TRACE( "%p, %p, %d\n", physdev
->font
, indices
, count
);
4146 pthread_mutex_lock( &font_lock
);
4147 for (i
= pos
= 0; i
< count
; i
++)
4149 get_glyph_outline( physdev
->font
, indices
[i
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4150 NULL
, &abc
, 0, NULL
, NULL
);
4151 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
4154 pthread_mutex_unlock( &font_lock
);
4159 /*************************************************************
4162 static INT CDECL
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
4164 struct font_physdev
*physdev
= get_font_dev( dev
);
4165 const WCHAR
*font_name
;
4170 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
4171 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
4173 font_name
= get_gdi_font_name( physdev
->font
);
4174 len
= lstrlenW( font_name
) + 1;
4177 lstrcpynW( str
, font_name
, count
);
4178 len
= min( count
, len
);
4184 static void scale_font_metrics( struct gdi_font
*font
, TEXTMETRICW
*tm
)
4186 double scale_x
, scale_y
;
4188 /* Make sure that the font has sane width/height ratio */
4189 if (font
->aveWidth
&& (font
->aveWidth
+ tm
->tmHeight
- 1) / tm
->tmHeight
> 100)
4191 WARN( "Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
4197 scale_x
= (double)font
->aveWidth
;
4198 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
4201 scale_x
= font
->scale_y
;
4203 scale_x
*= fabs(font
->matrix
.eM11
);
4204 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
4206 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
4207 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
4209 SCALE_Y(tm
->tmHeight
);
4210 SCALE_Y(tm
->tmAscent
);
4211 SCALE_Y(tm
->tmDescent
);
4212 SCALE_Y(tm
->tmInternalLeading
);
4213 SCALE_Y(tm
->tmExternalLeading
);
4215 SCALE_X(tm
->tmOverhang
);
4216 if (font
->fake_bold
)
4218 if (!font
->scalable
) tm
->tmOverhang
++;
4219 tm
->tmAveCharWidth
++;
4220 tm
->tmMaxCharWidth
++;
4222 SCALE_X(tm
->tmAveCharWidth
);
4223 SCALE_X(tm
->tmMaxCharWidth
);
4229 /*************************************************************
4230 * font_GetTextMetrics
4232 static BOOL CDECL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
4234 struct font_physdev
*physdev
= get_font_dev( dev
);
4239 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
4240 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
4243 pthread_mutex_lock( &font_lock
);
4244 if (font_funcs
->set_outline_text_metrics( physdev
->font
) ||
4245 font_funcs
->set_bitmap_text_metrics( physdev
->font
))
4247 *metrics
= physdev
->font
->otm
.otmTextMetrics
;
4248 scale_font_metrics( physdev
->font
, metrics
);
4251 pthread_mutex_unlock( &font_lock
);
4256 static void get_nearest_charset( const WCHAR
*family_name
, struct gdi_font_face
*face
, CHARSETINFO
*csi
)
4258 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4259 a single face with the requested charset. The idea is to check if
4260 the selected font supports the current ANSI codepage, if it does
4261 return the corresponding charset, else return the first charset */
4265 if (translate_charset_info( (DWORD
*)(INT_PTR
)ansi_cp
.CodePage
, csi
, TCI_SRCCODEPAGE
))
4267 const struct gdi_font_link
*font_link
;
4269 if (csi
->fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return;
4270 font_link
= find_gdi_font_link(family_name
);
4271 if (font_link
&& (csi
->fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])) return;
4273 for (i
= 0; i
< 32; i
++)
4275 DWORD fs0
= 1u << i
;
4276 if (face
->fs
.fsCsb
[0] & fs0
)
4278 if (translate_charset_info(&fs0
, csi
, TCI_SRCFONTSIG
)) return;
4279 FIXME("TCI failing on %x\n", fs0
);
4283 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4284 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4285 csi
->ciACP
= ansi_cp
.CodePage
;
4286 csi
->ciCharset
= DEFAULT_CHARSET
;
4289 static struct gdi_font
*select_font( LOGFONTW
*lf
, FMAT2 dcmat
, BOOL can_use_bitmap
)
4291 struct gdi_font
*font
;
4292 struct gdi_font_face
*face
;
4295 const WCHAR
*orig_name
= NULL
;
4296 BOOL substituted
= FALSE
;
4298 static const WCHAR symbolW
[] = {'S','y','m','b','o','l',0};
4300 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4301 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4302 original value lfCharSet. Note this is a special case for
4303 Symbol and doesn't happen at least for "Wingdings*" */
4304 if (!facename_compare( lf
->lfFaceName
, symbolW
, -1 )) lf
->lfCharSet
= SYMBOL_CHARSET
;
4306 /* check the cache first */
4307 if ((font
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4309 TRACE( "returning cached gdiFont(%p)\n", font
);
4312 if (!(face
= find_matching_face( lf
, &csi
, can_use_bitmap
, &substituted
, &orig_name
)))
4314 FIXME( "can't find a single appropriate font - bailing\n" );
4317 height
= lf
->lfHeight
;
4319 font
= create_gdi_font( face
, orig_name
, lf
);
4320 font
->use_logfont_name
= substituted
;
4321 font
->matrix
= dcmat
;
4322 font
->can_use_bitmap
= can_use_bitmap
;
4323 if (!csi
.fs
.fsCsb
[0]) get_nearest_charset( face
->family
->family_name
, face
, &csi
);
4324 font
->charset
= csi
.ciCharset
;
4325 font
->codepage
= csi
.ciACP
;
4327 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face
->full_name
), debugstr_w(face
->file
),
4328 face
->data_ptr
, face
->face_index
);
4330 font
->aveWidth
= height
? lf
->lfWidth
: 0;
4331 if (!face
->scalable
)
4333 /* Windows uses integer scaling factors for bitmap fonts */
4334 INT scale
, scaled_height
, diff
;
4335 struct gdi_font
*cachedfont
;
4338 diff
= height
- (signed int)face
->size
.height
;
4340 diff
= -height
- ((signed int)face
->size
.height
- face
->size
.internal_leading
);
4342 /* FIXME: rotation of bitmap fonts is ignored */
4343 height
= abs(GDI_ROUND( (double)height
* font
->matrix
.eM22
));
4345 font
->aveWidth
= (double)font
->aveWidth
* font
->matrix
.eM11
;
4346 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
4347 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4348 /* As we changed the matrix, we need to search the cache for the font again,
4349 * otherwise we might explode the cache. */
4350 if ((cachedfont
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
4352 TRACE("Found cached font after non-scalable matrix rescale!\n");
4353 free_gdi_font( font
);
4357 if (height
!= 0) height
= diff
;
4358 height
+= face
->size
.height
;
4360 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4361 scaled_height
= scale
* face
->size
.height
;
4362 /* Only jump to the next height if the difference <= 25% original height */
4363 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4364 /* The jump between unscaled and doubled is delayed by 1 */
4365 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4366 font
->scale_y
= scale
;
4367 TRACE("font scale y: %d\n", font
->scale_y
);
4370 if (!font_funcs
->load_font( font
))
4372 free_gdi_font( font
);
4376 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
4377 font
->vert_feature
= get_GSUB_vert_feature( font
);
4379 create_child_font_list( font
);
4381 TRACE( "caching: gdiFont=%p\n", font
);
4382 cache_gdi_font( font
);
4386 /*************************************************************
4389 static HFONT CDECL
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4391 struct font_physdev
*physdev
= get_font_dev( dev
);
4392 struct gdi_font
*font
= NULL
, *prev
= physdev
->font
;
4393 DC
*dc
= get_physdev_dc( dev
);
4399 BOOL can_use_bitmap
= !!(NtGdiGetDeviceCaps( dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
);
4401 NtGdiExtGetObjectW( hfont
, sizeof(lf
), &lf
);
4402 switch (lf
.lfQuality
)
4404 case NONANTIALIASED_QUALITY
:
4405 if (!*aa_flags
) *aa_flags
= GGO_BITMAP
;
4407 case ANTIALIASED_QUALITY
:
4408 if (!*aa_flags
) *aa_flags
= GGO_GRAY4_BITMAP
;
4412 lf
.lfWidth
= abs(lf
.lfWidth
);
4414 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4415 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4416 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4419 if (dc
->attr
->graphics_mode
== GM_ADVANCED
)
4421 memcpy( &dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
) );
4422 /* try to avoid not necessary glyph transformations */
4423 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4425 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4426 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4427 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4432 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
4433 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4434 dcmat
.eM21
= dcmat
.eM12
= 0;
4435 lf
.lfOrientation
= lf
.lfEscapement
;
4436 if (dc
->vport2WorldValid
)
4438 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4439 lf
.lfOrientation
= -lf
.lfOrientation
;
4440 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4441 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4444 TRACE( "DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
, dcmat
.eM21
, dcmat
.eM22
);
4446 pthread_mutex_lock( &font_lock
);
4448 font
= select_font( &lf
, dcmat
, can_use_bitmap
);
4452 if (!*aa_flags
) *aa_flags
= font
->aa_flags
;
4455 if (lf
.lfQuality
== CLEARTYPE_QUALITY
|| lf
.lfQuality
== CLEARTYPE_NATURAL_QUALITY
)
4456 *aa_flags
= subpixel_orientation
;
4458 *aa_flags
= font_smoothing
;
4460 *aa_flags
= font_funcs
->get_aa_flags( font
, *aa_flags
, antialias_fakes
);
4462 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
4463 pthread_mutex_unlock( &font_lock
);
4465 physdev
->font
= font
;
4466 if (prev
) release_gdi_font( prev
);
4467 return font
? hfont
: 0;
4471 const struct gdi_dc_funcs font_driver
=
4473 NULL
, /* pAbortDoc */
4474 NULL
, /* pAbortPath */
4475 NULL
, /* pAlphaBlend */
4476 NULL
, /* pAngleArc */
4479 NULL
, /* pBeginPath */
4480 NULL
, /* pBlendImage */
4482 NULL
, /* pCloseFigure */
4483 NULL
, /* pCreateCompatibleDC */
4484 font_CreateDC
, /* pCreateDC */
4485 font_DeleteDC
, /* pDeleteDC */
4486 NULL
, /* pDeleteObject */
4487 NULL
, /* pEllipse */
4489 NULL
, /* pEndPage */
4490 NULL
, /* pEndPath */
4491 font_EnumFonts
, /* pEnumFonts */
4492 NULL
, /* pExtEscape */
4493 NULL
, /* pExtFloodFill */
4494 NULL
, /* pExtTextOut */
4495 NULL
, /* pFillPath */
4496 NULL
, /* pFillRgn */
4497 font_FontIsLinked
, /* pFontIsLinked */
4498 NULL
, /* pFrameRgn */
4499 NULL
, /* pGetBoundsRect */
4500 font_GetCharABCWidths
, /* pGetCharABCWidths */
4501 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
4502 font_GetCharWidth
, /* pGetCharWidth */
4503 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
4504 NULL
, /* pGetDeviceCaps */
4505 NULL
, /* pGetDeviceGammaRamp */
4506 font_GetFontData
, /* pGetFontData */
4507 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
4508 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
4509 font_GetGlyphIndices
, /* pGetGlyphIndices */
4510 font_GetGlyphOutline
, /* pGetGlyphOutline */
4511 NULL
, /* pGetICMProfile */
4512 NULL
, /* pGetImage */
4513 font_GetKerningPairs
, /* pGetKerningPairs */
4514 NULL
, /* pGetNearestColor */
4515 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
4516 NULL
, /* pGetPixel */
4517 NULL
, /* pGetSystemPaletteEntries */
4518 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
4519 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
4520 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
4521 font_GetTextFace
, /* pGetTextFace */
4522 font_GetTextMetrics
, /* pGetTextMetrics */
4523 NULL
, /* pGradientFill */
4524 NULL
, /* pInvertRgn */
4527 NULL
, /* pPaintRgn */
4530 NULL
, /* pPolyBezier */
4531 NULL
, /* pPolyBezierTo */
4532 NULL
, /* pPolyDraw */
4533 NULL
, /* pPolyPolygon */
4534 NULL
, /* pPolyPolyline */
4535 NULL
, /* pPolylineTo */
4536 NULL
, /* pPutImage */
4537 NULL
, /* pRealizeDefaultPalette */
4538 NULL
, /* pRealizePalette */
4539 NULL
, /* pRectangle */
4540 NULL
, /* pResetDC */
4541 NULL
, /* pRoundRect */
4542 NULL
, /* pSelectBitmap */
4543 NULL
, /* pSelectBrush */
4544 font_SelectFont
, /* pSelectFont */
4545 NULL
, /* pSelectPen */
4546 NULL
, /* pSetBkColor */
4547 NULL
, /* pSetBoundsRect */
4548 NULL
, /* pSetDCBrushColor */
4549 NULL
, /* pSetDCPenColor */
4550 NULL
, /* pSetDIBitsToDevice */
4551 NULL
, /* pSetDeviceClipping */
4552 NULL
, /* pSetDeviceGammaRamp */
4553 NULL
, /* pSetPixel */
4554 NULL
, /* pSetTextColor */
4555 NULL
, /* pStartDoc */
4556 NULL
, /* pStartPage */
4557 NULL
, /* pStretchBlt */
4558 NULL
, /* pStretchDIBits */
4559 NULL
, /* pStrokeAndFillPath */
4560 NULL
, /* pStrokePath */
4561 NULL
, /* pUnrealizePalette */
4562 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
4563 NULL
, /* pD3DKMTCloseAdapter */
4564 NULL
, /* pD3DKMTOpenAdapterFromLuid */
4565 NULL
, /* pD3DKMTQueryVideoMemoryInfo */
4566 NULL
, /* pD3DKMTSetVidPnSourceOwner */
4567 GDI_PRIORITY_FONT_DRV
/* priority */
4570 static BOOL
get_key_value( HKEY key
, const char *name
, DWORD
*value
)
4572 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[12 * sizeof(WCHAR
)])];
4573 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4576 count
= query_reg_ascii_value( key
, name
, info
, sizeof(value_buffer
) );
4579 if (info
->Type
== REG_DWORD
) memcpy( value
, info
->Data
, sizeof(*value
) );
4580 else *value
= wcstol( (const WCHAR
*)info
->Data
, NULL
, 10 );
4585 static UINT
init_font_options(void)
4587 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[20 * sizeof(WCHAR
)])];
4588 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4590 DWORD i
, val
, gamma
= 1400;
4593 if (query_reg_ascii_value( wine_fonts_key
, "AntialiasFakeBoldOrItalic",
4594 info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
4596 static const WCHAR valsW
[] = {'y','Y','t','T','1',0};
4597 antialias_fakes
= (wcschr( valsW
, *(const WCHAR
*)info
->Data
) != NULL
);
4600 if ((key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
4602 /* FIXME: handle vertical orientations even though Windows doesn't */
4603 if (get_key_value( key
, "FontSmoothingOrientation", &val
))
4607 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
4608 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
4610 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
4611 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
4615 if (get_key_value( key
, "FontSmoothing", &val
) && val
/* enabled */)
4617 if (get_key_value( key
, "FontSmoothingType", &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
4618 font_smoothing
= subpixel_orientation
;
4620 font_smoothing
= GGO_GRAY4_BITMAP
;
4622 if (get_key_value( key
, "FontSmoothingGamma", &val
) && val
)
4624 gamma
= min( max( val
, 1000 ), 2200 );
4626 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4630 /* Calibrating the difference between the registry value and the Wine gamma value.
4631 This looks roughly similar to Windows Native with the same registry value.
4632 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4633 gamma
= 1000 * gamma
/ 1400;
4636 for (i
= 0; i
< 256; i
++)
4638 font_gamma_ramp
.encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
4639 font_gamma_ramp
.decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
4643 if (!dpi
&& (key
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) )))
4645 if (get_key_value( key
, "LogPixels", &val
)) dpi
= val
;
4650 font_gamma_ramp
.gamma
= gamma
;
4651 TRACE( "gamma %d screen dpi %u\n", font_gamma_ramp
.gamma
, dpi
);
4656 /* compute positions for text rendering, in device coords */
4657 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
4662 size
->cx
= size
->cy
= 0;
4663 if (!count
) return TRUE
;
4665 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4666 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4668 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
4669 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
4671 if (dc
->breakExtra
|| dc
->breakRem
)
4673 int i
, space
= 0, rem
= dc
->breakRem
;
4675 for (i
= 0; i
< count
; i
++)
4677 if (str
[i
] == tm
.tmBreakChar
)
4679 space
+= dc
->breakExtra
;
4689 size
->cx
= dx
[count
- 1];
4690 size
->cy
= tm
.tmHeight
;
4694 /* compute positions for text rendering, in device coords */
4695 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
4700 size
->cx
= size
->cy
= 0;
4701 if (!count
) return TRUE
;
4703 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4704 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4706 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
4707 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
4709 if (dc
->breakExtra
|| dc
->breakRem
)
4712 int i
, space
= 0, rem
= dc
->breakRem
;
4714 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4715 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
4717 for (i
= 0; i
< count
; i
++)
4719 if (indices
[i
] == space_index
)
4721 space
+= dc
->breakExtra
;
4731 size
->cx
= dx
[count
- 1];
4732 size
->cy
= tm
.tmHeight
;
4736 /***********************************************************************
4737 * get_text_charset_info
4739 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4741 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
4743 UINT ret
= DEFAULT_CHARSET
;
4746 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
4747 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4749 if (ret
== DEFAULT_CHARSET
&& fs
)
4750 memset(fs
, 0, sizeof(FONTSIGNATURE
));
4754 /***********************************************************************
4755 * NtGdiGetTextCharsetInfo (win32u.@)
4757 UINT WINAPI
NtGdiGetTextCharsetInfo( HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
4759 UINT ret
= DEFAULT_CHARSET
;
4760 DC
*dc
= get_dc_ptr(hdc
);
4764 ret
= get_text_charset_info( dc
, fs
, flags
);
4765 release_dc_ptr( dc
);
4770 /***********************************************************************
4771 * NtGdiHfontCreate (win32u.@)
4773 HFONT WINAPI
NtGdiHfontCreate( const void *logfont
, ULONG size
, ULONG type
,
4774 ULONG flags
, void *data
)
4778 const LOGFONTW
*plf
;
4780 if (!logfont
) return 0;
4782 if (size
== sizeof(ENUMLOGFONTEXDVW
) || size
== sizeof(ENUMLOGFONTEXW
))
4784 const ENUMLOGFONTEXW
*lfex
= logfont
;
4786 if (lfex
->elfFullName
[0] || lfex
->elfStyle
[0] || lfex
->elfScript
[0])
4788 FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
4789 debugstr_w( lfex
->elfFullName
), debugstr_w( lfex
->elfStyle
),
4790 debugstr_w( lfex
->elfScript
));
4793 plf
= &lfex
->elfLogFont
;
4795 else if (size
!= sizeof(LOGFONTW
))
4797 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4802 if (!(fontPtr
= malloc( sizeof(*fontPtr
) ))) return 0;
4804 fontPtr
->logfont
= *plf
;
4806 if (!(hFont
= alloc_gdi_handle( &fontPtr
->obj
, NTGDI_OBJ_FONT
, &fontobj_funcs
)))
4812 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4813 plf
->lfHeight
, plf
->lfWidth
,
4814 plf
->lfEscapement
, plf
->lfOrientation
,
4815 plf
->lfPitchAndFamily
,
4816 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
4817 plf
->lfQuality
, plf
->lfCharSet
,
4818 debugstr_w(plf
->lfFaceName
),
4819 plf
->lfWeight
> 400 ? "Bold" : "",
4820 plf
->lfItalic
? "Italic" : "",
4821 plf
->lfUnderline
? "Underline" : "", hFont
);
4826 #define ASSOC_CHARSET_OEM 1
4827 #define ASSOC_CHARSET_ANSI 2
4828 #define ASSOC_CHARSET_SYMBOL 4
4830 static DWORD
get_associated_charset_info(void)
4832 static DWORD associated_charset
= -1;
4834 if (associated_charset
== -1)
4836 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[32 * sizeof(WCHAR
)])];
4837 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
4840 static const WCHAR yesW
[] = {'y','e','s',0};
4842 associated_charset
= 0;
4844 if (!(hkey
= reg_open_key( NULL
, associated_charset_keyW
, sizeof(associated_charset_keyW
) )))
4847 if (query_reg_ascii_value( hkey
, "ANSI(00)", info
, sizeof(value_buffer
) ) &&
4848 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4849 associated_charset
|= ASSOC_CHARSET_ANSI
;
4851 if (query_reg_ascii_value( hkey
, "OEM(FF)", info
, sizeof(value_buffer
) ) &&
4852 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4853 associated_charset
|= ASSOC_CHARSET_OEM
;
4855 if (query_reg_ascii_value( hkey
, "SYMBOL(02)", info
, sizeof(value_buffer
) ) &&
4856 info
->Type
== REG_SZ
&& !wcsicmp( (const WCHAR
*)info
->Data
, yesW
))
4857 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
4861 TRACE("associated_charset = %d\n", associated_charset
);
4864 return associated_charset
;
4867 static void update_font_code_page( DC
*dc
, HANDLE font
)
4870 int charset
= get_text_charset_info( dc
, NULL
, 0 );
4872 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
4876 NtGdiExtGetObjectW( font
, sizeof(lf
), &lf
);
4877 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
4878 charset
= DEFAULT_CHARSET
;
4881 /* Hmm, nicely designed api this one! */
4882 if (translate_charset_info( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
4883 dc
->attr
->font_code_page
= csi
.ciACP
;
4887 dc
->attr
->font_code_page
= oem_cp
.CodePage
;
4889 case DEFAULT_CHARSET
:
4890 dc
->attr
->font_code_page
= ansi_cp
.CodePage
;
4893 case VISCII_CHARSET
:
4899 case CELTIC_CHARSET
:
4900 /* FIXME: These have no place here, but because x11drv
4901 enumerates fonts with these (made up) charsets some apps
4902 might use them and then the FIXME below would become
4903 annoying. Now we could pick the intended codepage for
4904 each of these, but since it's broken anyway we'll just
4905 use CP_ACP and hope it'll go away...
4907 dc
->attr
->font_code_page
= CP_ACP
;
4911 FIXME("Can't find codepage for charset %d\n", charset
);
4912 dc
->attr
->font_code_page
= CP_ACP
;
4917 TRACE( "charset %d => cp %d\n", charset
, dc
->attr
->font_code_page
);
4920 /***********************************************************************
4921 * NtGdiSelectFont (win32u.@)
4923 HGDIOBJ WINAPI
NtGdiSelectFont( HDC hdc
, HGDIOBJ handle
)
4926 DC
*dc
= get_dc_ptr( hdc
);
4932 if (!GDI_inc_ref_count( handle
))
4934 release_dc_ptr( dc
);
4938 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
4939 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
4943 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
4944 update_font_code_page( dc
, handle
);
4945 if (dc
->font_gamma_ramp
== NULL
)
4946 dc
->font_gamma_ramp
= &font_gamma_ramp
;
4947 GDI_dec_ref_count( ret
);
4949 else GDI_dec_ref_count( handle
);
4951 release_dc_ptr( dc
);
4956 /***********************************************************************
4959 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
4961 FONTOBJ
*font
= GDI_GetObjPtr( handle
, NTGDI_OBJ_FONT
);
4963 if (!font
) return 0;
4966 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
4967 memcpy( buffer
, &font
->logfont
, count
);
4969 else count
= sizeof(LOGFONTW
);
4970 GDI_ReleaseObj( handle
);
4975 /***********************************************************************
4978 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
4982 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
4991 struct font_enum_entry
*buf
;
4997 static INT WINAPI
font_enum_proc( const LOGFONTW
*lf
, const TEXTMETRICW
*tm
,
4998 DWORD type
, LPARAM lp
)
5000 struct font_enum
*fe
= (struct font_enum
*)lp
;
5002 if (fe
->charset
!= DEFAULT_CHARSET
&& lf
->lfCharSet
!= fe
->charset
) return 1;
5003 if ((type
& RASTER_FONTTYPE
) && !(NtGdiGetDeviceCaps( fe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
))
5006 if (fe
->buf
&& fe
->count
< fe
->size
)
5008 fe
->buf
[fe
->count
].type
= type
;
5009 fe
->buf
[fe
->count
].lf
= *(const ENUMLOGFONTEXW
*)lf
;
5010 fe
->buf
[fe
->count
].tm
= *(const NEWTEXTMETRICEXW
*)tm
;
5016 /***********************************************************************
5017 * NtGdiEnumFonts (win32u.@)
5019 BOOL WINAPI
NtGdiEnumFonts( HDC hdc
, ULONG type
, ULONG win32_compat
, ULONG face_name_len
,
5020 const WCHAR
*face_name
, ULONG charset
, ULONG
*count
, void *buf
)
5022 struct font_enum fe
;
5028 if (!(dc
= get_dc_ptr( hdc
))) return 0;
5030 memset( &lf
, 0, sizeof(lf
) );
5031 lf
.lfCharSet
= charset
;
5032 if (face_name_len
) memcpy( lf
.lfFaceName
, face_name
, face_name_len
* sizeof(WCHAR
) );
5036 fe
.size
= *count
/ sizeof(*fe
.buf
);
5038 fe
.charset
= charset
;
5040 physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
5041 ret
= physdev
->funcs
->pEnumFonts( physdev
, &lf
, font_enum_proc
, (LPARAM
)&fe
);
5042 if (ret
&& buf
) ret
= fe
.count
<= fe
.size
;
5043 *count
= fe
.count
* sizeof(*fe
.buf
);
5045 release_dc_ptr( dc
);
5050 /***********************************************************************
5051 * NtGdiSetTextJustification (win32u.@)
5053 BOOL WINAPI
NtGdiSetTextJustification( HDC hdc
, INT extra
, INT breaks
)
5057 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
5059 extra
= abs( (extra
* dc
->attr
->vport_ext
.cx
+ dc
->attr
->wnd_ext
.cx
/ 2) /
5060 dc
->attr
->wnd_ext
.cx
);
5061 if (!extra
) breaks
= 0;
5064 dc
->breakExtra
= extra
/ breaks
;
5065 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
5073 release_dc_ptr( dc
);
5078 /***********************************************************************
5079 * NtGdiGetTextFaceW (win32u.@)
5081 INT WINAPI
NtGdiGetTextFaceW( HDC hdc
, INT count
, WCHAR
*name
, BOOL alias_name
)
5086 DC
* dc
= get_dc_ptr( hdc
);
5089 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
5090 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
5091 release_dc_ptr( dc
);
5096 /***********************************************************************
5097 * NtGdiGetTextExtentExW (win32u.@)
5099 * Return the size of the string as it would be if it was output properly by
5102 BOOL WINAPI
NtGdiGetTextExtentExW( HDC hdc
, const WCHAR
*str
, INT count
, INT max_ext
,
5103 INT
*nfit
, INT
*dxs
, SIZE
*size
, UINT flags
)
5108 INT buffer
[256], *pos
= dxs
;
5110 if (count
< 0) return FALSE
;
5112 dc
= get_dc_ptr(hdc
);
5113 if (!dc
) return FALSE
;
5118 if (count
> 256 && !(pos
= malloc( count
* sizeof(*pos
) )))
5120 release_dc_ptr( dc
);
5127 ret
= get_char_positions_indices( dc
, str
, count
, pos
, size
);
5129 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
5134 for (i
= 0; i
< count
; i
++)
5136 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) +
5137 (i
+ 1) * dc
->attr
->char_extra
;
5138 if (nfit
&& dx
> (unsigned int)max_ext
) break;
5139 if (dxs
) dxs
[i
] = dx
;
5141 if (nfit
) *nfit
= i
;
5144 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->attr
->char_extra
;
5145 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
5148 if (pos
!= buffer
&& pos
!= dxs
) free( pos
);
5149 release_dc_ptr( dc
);
5151 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
5155 /***********************************************************************
5156 * NtGdiGetTextMetricsW (win32u.@)
5158 BOOL WINAPI
NtGdiGetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
, ULONG flags
)
5162 DC
* dc
= get_dc_ptr( hdc
);
5163 if (!dc
) return FALSE
;
5165 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5166 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
5170 /* device layer returns values in device units
5171 * therefore we have to convert them to logical */
5173 metrics
->tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
5174 metrics
->tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
5175 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
5176 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
5177 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
5178 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
5179 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
5180 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
5181 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
5182 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
5185 TRACE("text metrics:\n"
5186 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5187 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5188 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5189 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5190 " PitchAndFamily = %02x\n"
5191 " --------------------\n"
5192 " InternalLeading = %i\n"
5196 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
5197 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
5198 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
5199 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
5200 metrics
->tmPitchAndFamily
,
5201 metrics
->tmInternalLeading
,
5204 metrics
->tmHeight
);
5206 release_dc_ptr( dc
);
5211 /***********************************************************************
5212 * NtGdiGetOutlineTextMetricsInternalW (win32u.@)
5214 UINT WINAPI
NtGdiGetOutlineTextMetricsInternalW( HDC hdc
, UINT cbData
,
5215 OUTLINETEXTMETRICW
*lpOTM
, ULONG opts
)
5217 DC
*dc
= get_dc_ptr( hdc
);
5218 OUTLINETEXTMETRICW
*output
= lpOTM
;
5222 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
5225 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
5226 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
5228 if (lpOTM
&& ret
> cbData
)
5230 output
= malloc( ret
);
5231 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
5236 output
->otmTextMetrics
.tmDigitizedAspectX
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSX
);
5237 output
->otmTextMetrics
.tmDigitizedAspectY
= NtGdiGetDeviceCaps(hdc
, LOGPIXELSY
);
5238 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
5239 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
5240 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
5241 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
5242 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
5243 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
5244 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
5245 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
5246 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
5247 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
5248 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
5249 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
5250 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
5251 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
5252 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
5253 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
5254 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
5255 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
5256 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
5257 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
5258 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
5259 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
5260 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
5261 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
5262 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
5263 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
5264 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
5265 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
5266 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
5267 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
5268 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
5269 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
5273 memcpy(lpOTM
, output
, cbData
);
5282 /***********************************************************************
5283 * NtGdiGetCharWidthW (win32u.@)
5285 BOOL WINAPI
NtGdiGetCharWidthW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
5286 ULONG flags
, void *buf
)
5288 UINT i
, count
= last
;
5293 if (flags
& NTGDI_GETCHARWIDTH_INDICES
)
5298 if (!(abc
= malloc( count
* sizeof(ABC
) )))
5301 if (!NtGdiGetCharABCWidthsW( hdc
, first
, last
, chars
,
5302 NTGDI_GETCHARABCWIDTHS_INT
| NTGDI_GETCHARABCWIDTHS_INDICES
,
5309 for (i
= 0; i
< count
; i
++)
5310 ((INT
*)buf
)[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
5316 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
5318 if (!chars
) count
= last
- first
+ 1;
5319 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
5320 ret
= dev
->funcs
->pGetCharWidth( dev
, first
, count
, chars
, buf
);
5324 if (flags
& NTGDI_GETCHARWIDTH_INT
)
5327 /* convert device units to logical */
5328 for (i
= 0; i
< count
; i
++)
5329 buffer
[i
] = width_to_LP( dc
, buffer
[i
] );
5333 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
5334 for (i
= 0; i
< count
; i
++)
5335 ((float *)buf
)[i
] = ((int *)buf
)[i
] * scale
;
5338 release_dc_ptr( dc
);
5343 /* helper for nulldrv_ExtTextOut */
5344 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
5345 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
5347 UINT indices
[3] = {0, 0, 0x20};
5353 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
5355 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
5358 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
, FALSE
);
5359 if (ret
!= GDI_ERROR
) break;
5362 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
5363 if (!image
) return ERROR_SUCCESS
;
5367 if (!ret
) /* empty glyph */
5369 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
5370 return ERROR_SUCCESS
;
5373 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5374 size
= metrics
->gmBlackBoxY
* stride
;
5376 if (!(image
->ptr
= malloc( size
))) return ERROR_OUTOFMEMORY
;
5377 image
->is_copy
= TRUE
;
5378 image
->free
= free_heap_bits
;
5380 ret
= NtGdiGetGlyphOutline( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
,
5382 if (ret
== GDI_ERROR
)
5385 return ERROR_NOT_FOUND
;
5387 return ERROR_SUCCESS
;
5390 /* helper for nulldrv_ExtTextOut */
5391 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
5392 LPCWSTR str
, UINT count
, const INT
*dx
)
5397 reset_bounds( &bounds
);
5398 for (i
= 0; i
< count
; i
++)
5400 GLYPHMETRICS metrics
;
5402 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
5404 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
5405 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
5406 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
5407 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
5408 add_bounds_rect( &bounds
, &rect
);
5412 if (flags
& ETO_PDY
)
5415 y
+= dx
[ i
* 2 + 1];
5421 x
+= metrics
.gmCellIncX
;
5422 y
+= metrics
.gmCellIncY
;
5428 /* helper for nulldrv_ExtTextOut */
5429 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
5430 const struct gdi_image_bits
*image
, const RECT
*clip
)
5432 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5433 UINT i
, count
, max_count
;
5435 BYTE
*ptr
= image
->ptr
;
5436 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5438 RECT rect
, clipped_rect
;
5440 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
5441 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
5442 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
5443 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
5444 if (!clip
) clipped_rect
= rect
;
5445 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
5447 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
5448 pts
= malloc( max_count
* sizeof(*pts
) );
5452 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
5453 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
5455 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
5457 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5458 pts
[count
].x
= rect
.left
+ x
;
5459 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5460 pts
[count
+ 1].x
= rect
.left
+ x
;
5461 if (pts
[count
+ 1].x
> pts
[count
].x
)
5463 pts
[count
].y
= pts
[count
+ 1].y
= y
;
5468 assert( count
<= max_count
);
5469 dp_to_lp( dc
, pts
, count
);
5470 for (i
= 0; i
< count
; i
+= 2)
5472 const ULONG pts_count
= 2;
5473 NtGdiPolyPolyDraw( dc
->hSelf
, pts
+ i
, &pts_count
, 1, NtGdiPolyPolyline
);
5478 /***********************************************************************
5479 * nulldrv_ExtTextOut
5481 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5482 LPCWSTR str
, UINT count
, const INT
*dx
)
5484 DC
*dc
= get_nulldrv_dc( dev
);
5490 if (flags
& ETO_OPAQUE
)
5493 COLORREF brush_color
= NtGdiGetNearestColor( dev
->hdc
, dc
->attr
->background_color
);
5494 HBRUSH brush
= NtGdiCreateSolidBrush( brush_color
, NULL
);
5498 orig
= NtGdiSelectBrush( dev
->hdc
, brush
);
5499 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5500 NtGdiPatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5501 NtGdiSelectBrush( dev
->hdc
, orig
);
5502 NtGdiDeleteObjectApp( brush
);
5506 if (!count
) return TRUE
;
5508 if (dc
->aa_flags
!= GGO_BITMAP
)
5510 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5511 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5512 struct gdi_image_bits bits
;
5513 struct bitblt_coords src
, dst
;
5515 /* FIXME Subpixel modes */
5516 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5518 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5519 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5520 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5521 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5523 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5524 src
.x
= src
.visrect
.left
;
5525 src
.y
= src
.visrect
.top
;
5526 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5527 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5529 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5530 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5532 /* we can avoid the GetImage, just query the needed format */
5533 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5534 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5535 info
->bmiHeader
.biWidth
= src
.width
;
5536 info
->bmiHeader
.biHeight
= -src
.height
;
5537 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5538 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5539 if (!err
|| err
== ERROR_BAD_FORMAT
)
5541 /* make the source rectangle relative to the source bits */
5543 src
.visrect
.left
= src
.visrect
.top
= 0;
5544 src
.visrect
.right
= src
.width
;
5545 src
.visrect
.bottom
= src
.height
;
5547 bits
.ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5548 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5549 bits
.is_copy
= TRUE
;
5550 bits
.free
= free_heap_bits
;
5551 err
= ERROR_SUCCESS
;
5556 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5557 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5558 if (!err
&& !bits
.is_copy
)
5560 void *ptr
= malloc( info
->bmiHeader
.biSizeImage
);
5563 if (bits
.free
) bits
.free( &bits
);
5564 return ERROR_OUTOFMEMORY
;
5566 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5567 if (bits
.free
) bits
.free( &bits
);
5569 bits
.is_copy
= TRUE
;
5570 bits
.free
= free_heap_bits
;
5575 /* make x,y relative to the image bits */
5576 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5577 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5578 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5579 aa_flags
, str
, count
, dx
);
5580 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5581 if (bits
.free
) bits
.free( &bits
);
5586 pen
= NtGdiCreatePen( PS_SOLID
, 1, dc
->attr
->text_color
, NULL
);
5587 orig
= NtGdiSelectPen( dev
->hdc
, pen
);
5589 for (i
= 0; i
< count
; i
++)
5591 GLYPHMETRICS metrics
;
5592 struct gdi_image_bits image
;
5594 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5597 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5598 if (image
.free
) image
.free( &image
);
5602 if (flags
& ETO_PDY
)
5605 y
+= dx
[ i
* 2 + 1];
5611 x
+= metrics
.gmCellIncX
;
5612 y
+= metrics
.gmCellIncY
;
5616 NtGdiSelectPen( dev
->hdc
, orig
);
5617 NtGdiDeleteObjectApp( pen
);
5621 /***********************************************************************
5624 * Scale the underline / strikeout line width.
5626 static inline int get_line_width( DC
*dc
, int metric_size
)
5628 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5629 if (width
== 0) width
= 1;
5630 if (metric_size
< 0) width
= -width
;
5634 /***********************************************************************
5635 * NtGdiExtTextOutW (win32u.@)
5637 * Draws text using the currently selected font, background color, and text color.
5641 * x,y [I] coordinates of string
5643 * ETO_GRAYED - undocumented on MSDN
5644 * ETO_OPAQUE - use background color for fill the rectangle
5645 * ETO_CLIPPED - clipping text to the rectangle
5646 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5647 * than encoded characters. Implies ETO_IGNORELANGUAGE
5648 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5649 * Affects BiDi ordering
5650 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5651 * ETO_PDY - unimplemented
5652 * ETO_NUMERICSLATIN - unimplemented always assumed -
5653 * do not translate numbers into locale representations
5654 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5655 * lprect [I] dimensions for clipping or/and opaquing
5656 * str [I] text string
5657 * count [I] number of symbols in string
5658 * lpDx [I] optional parameter with distance between drawing characters
5664 BOOL WINAPI
NtGdiExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
, const RECT
*lprect
,
5665 const WCHAR
*str
, UINT count
, const INT
*lpDx
, DWORD cp
)
5673 double cosEsc
, sinEsc
;
5677 POINT
*deltas
= NULL
, width
= {0, 0};
5678 DC
* dc
= get_dc_ptr( hdc
);
5681 static int quietfixme
= 0;
5683 if (!dc
) return FALSE
;
5684 if (count
> INT_MAX
) return FALSE
;
5686 align
= dc
->attr
->text_align
;
5687 breakRem
= dc
->breakRem
;
5688 layout
= dc
->attr
->layout
;
5690 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5692 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5697 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5699 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5700 if (layout
& LAYOUT_RTL
)
5702 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5703 align
^= TA_RTLREADING
;
5706 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
5707 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
5708 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->attr
->background_mode
,
5709 dc
->attr
->map_mode
);
5711 if(align
& TA_UPDATECP
)
5713 pt
= dc
->attr
->cur_pos
;
5718 NtGdiGetTextMetricsW( hdc
, &tm
, 0 );
5719 NtGdiExtGetObjectW( dc
->hFont
, sizeof(lf
), &lf
);
5721 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
5722 lf
.lfEscapement
= 0;
5724 if ((dc
->attr
->graphics_mode
== GM_COMPATIBLE
) &&
5725 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
5727 lf
.lfEscapement
= -lf
.lfEscapement
;
5730 if(lf
.lfEscapement
!= 0)
5732 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
5733 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
5741 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
5744 lp_to_dp(dc
, (POINT
*)&rc
, 2);
5746 if (flags
& ETO_OPAQUE
)
5747 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
5749 else flags
&= ~ETO_CLIPPED
;
5759 lp_to_dp(dc
, &pt
, 1);
5763 char_extra
= dc
->attr
->char_extra
;
5764 if (char_extra
&& lpDx
&& NtGdiGetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
5765 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5767 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
5770 POINT total
= {0, 0}, desired
[2];
5772 deltas
= malloc( count
* sizeof(*deltas
) );
5775 if (flags
& ETO_PDY
)
5777 for (i
= 0; i
< count
; i
++)
5779 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
5780 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
5785 for (i
= 0; i
< count
; i
++)
5787 deltas
[i
].x
= lpDx
[i
] + char_extra
;
5794 INT
*dx
= malloc( count
* sizeof(*dx
) );
5796 NtGdiGetTextExtentExW( hdc
, str
, count
, -1, NULL
, dx
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5798 deltas
[0].x
= dx
[0];
5800 for (i
= 1; i
< count
; i
++)
5802 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
5808 for(i
= 0; i
< count
; i
++)
5810 total
.x
+= deltas
[i
].x
;
5811 total
.y
+= deltas
[i
].y
;
5813 desired
[0].x
= desired
[0].y
= 0;
5815 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
5816 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
5818 lp_to_dp(dc
, desired
, 2);
5819 desired
[1].x
-= desired
[0].x
;
5820 desired
[1].y
-= desired
[0].y
;
5822 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5824 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5825 desired
[1].x
= -desired
[1].x
;
5826 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5827 desired
[1].y
= -desired
[1].y
;
5830 deltas
[i
].x
= desired
[1].x
- width
.x
;
5831 deltas
[i
].y
= desired
[1].y
- width
.y
;
5841 NtGdiGetTextExtentExW( hdc
, str
, count
, 0, NULL
, NULL
, &sz
, !!(flags
& ETO_GLYPH_INDEX
) );
5842 desired
[0].x
= desired
[0].y
= 0;
5843 desired
[1].x
= sz
.cx
;
5845 lp_to_dp(dc
, desired
, 2);
5846 desired
[1].x
-= desired
[0].x
;
5847 desired
[1].y
-= desired
[0].y
;
5849 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
5851 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5852 desired
[1].x
= -desired
[1].x
;
5853 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5854 desired
[1].y
= -desired
[1].y
;
5859 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
5860 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
5861 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
5864 if (align
& TA_UPDATECP
)
5868 dp_to_lp(dc
, &pt
, 1);
5869 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5881 if (align
& TA_UPDATECP
)
5885 dp_to_lp(dc
, &pt
, 1);
5886 NtGdiMoveTo( hdc
, pt
.x
, pt
.y
, NULL
);
5891 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
5894 y
+= tm
.tmAscent
* cosEsc
;
5895 x
+= tm
.tmAscent
* sinEsc
;
5899 y
-= tm
.tmDescent
* cosEsc
;
5900 x
-= tm
.tmDescent
* sinEsc
;
5907 if (dc
->attr
->background_mode
!= TRANSPARENT
)
5909 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
5911 if(!(flags
& ETO_OPAQUE
) || !lprect
||
5912 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
5913 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
5917 text_box
.right
= x
+ width
.x
;
5918 text_box
.top
= y
- tm
.tmAscent
;
5919 text_box
.bottom
= y
+ tm
.tmDescent
;
5921 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
5922 if (!IsRectEmpty( &text_box
))
5923 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
5928 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
5929 str
, count
, (INT
*)deltas
);
5934 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
5936 int underlinePos
, strikeoutPos
;
5937 int underlineWidth
, strikeoutWidth
;
5938 UINT size
= NtGdiGetOutlineTextMetricsInternalW( hdc
, 0, NULL
, 0 );
5939 OUTLINETEXTMETRICW
* otm
= NULL
;
5941 HPEN hpen
= NtGdiSelectPen( hdc
, GetStockObject(NULL_PEN
) );
5942 HBRUSH hbrush
= NtGdiCreateSolidBrush( dc
->attr
->text_color
, NULL
);
5944 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
5949 underlineWidth
= tm
.tmAscent
/ 20 + 1;
5950 strikeoutPos
= tm
.tmAscent
/ 2;
5951 strikeoutWidth
= underlineWidth
;
5955 otm
= malloc( size
);
5956 NtGdiGetOutlineTextMetricsInternalW( hdc
, size
, otm
, 0 );
5957 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
5958 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
5959 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
5960 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
5961 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
5962 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
5969 const ULONG cnt
= 5;
5970 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5971 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5972 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5973 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5974 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
5975 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
5976 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
5977 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
5978 pts
[4].x
= pts
[0].x
;
5979 pts
[4].y
= pts
[0].y
;
5980 dp_to_lp(dc
, pts
, 5);
5981 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
5986 const ULONG cnt
= 5;
5987 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5988 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5989 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5990 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5991 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
5992 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
5993 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
5994 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
5995 pts
[4].x
= pts
[0].x
;
5996 pts
[4].y
= pts
[0].y
;
5997 dp_to_lp(dc
, pts
, 5);
5998 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
6001 NtGdiSelectPen(hdc
, hpen
);
6002 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
6003 NtGdiDeleteObjectApp( hbrush
);
6006 release_dc_ptr( dc
);
6012 /******************************************************************************
6013 * NtGdiGetCharABCWidthsW (win32u.@)
6015 * Retrieves widths of characters in range.
6018 * hdc [I] Handle of device context
6019 * firstChar [I] First character in range to query
6020 * lastChar [I] Last character in range to query
6021 * abc [O] Address of character-width structure
6024 * Only works with TrueType fonts
6026 BOOL WINAPI
NtGdiGetCharABCWidthsW( HDC hdc
, UINT first
, UINT last
, WCHAR
*chars
,
6027 ULONG flags
, void *buffer
)
6029 DC
*dc
= get_dc_ptr(hdc
);
6031 unsigned int i
, count
= last
;
6035 if (!dc
) return FALSE
;
6039 release_dc_ptr( dc
);
6043 if (flags
& NTGDI_GETCHARABCWIDTHS_INDICES
)
6045 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
6046 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, chars
, buffer
);
6050 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
6052 /* unlike float variant, this one is supposed to fail on non-scalable fonts */
6053 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
6054 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
6056 release_dc_ptr( dc
);
6061 if (!chars
) count
= last
- first
+ 1;
6062 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
6063 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, count
, chars
, buffer
);
6069 if (flags
& NTGDI_GETCHARABCWIDTHS_INT
)
6071 /* convert device units to logical */
6072 for (i
= 0; i
< count
; i
++)
6074 abc
[i
].abcA
= width_to_LP( dc
, abc
[i
].abcA
);
6075 abc
[i
].abcB
= width_to_LP( dc
, abc
[i
].abcB
);
6076 abc
[i
].abcC
= width_to_LP( dc
, abc
[i
].abcC
);
6081 /* convert device units to logical */
6082 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
6083 ABCFLOAT
*abcf
= buffer
;
6085 for (i
= 0; i
< count
; i
++)
6087 abcf
[i
].abcfA
= abc
[i
].abcA
* scale
;
6088 abcf
[i
].abcfB
= abc
[i
].abcB
* scale
;
6089 abcf
[i
].abcfC
= abc
[i
].abcC
* scale
;
6094 release_dc_ptr( dc
);
6099 /***********************************************************************
6100 * NtGdiGetGlyphOutline (win32u.@)
6102 DWORD WINAPI
NtGdiGetGlyphOutline( HDC hdc
, UINT ch
, UINT format
, GLYPHMETRICS
*metrics
,
6103 DWORD size
, void *buffer
, const MAT2
*mat2
,
6104 BOOL ignore_rotation
)
6110 TRACE( "(%p, %04x, %04x, %p, %d, %p, %p)\n", hdc
, ch
, format
, metrics
, size
, buffer
, mat2
);
6112 if (!mat2
) return GDI_ERROR
;
6114 dc
= get_dc_ptr(hdc
);
6115 if(!dc
) return GDI_ERROR
;
6117 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
6118 ret
= dev
->funcs
->pGetGlyphOutline( dev
, ch
& 0xffff, format
, metrics
, size
, buffer
, mat2
);
6119 release_dc_ptr( dc
);
6124 /**********************************************************************
6125 * __wine_get_file_outline_text_metric (win32u.@)
6127 BOOL CDECL
__wine_get_file_outline_text_metric( const WCHAR
*path
, OUTLINETEXTMETRICW
*otm
)
6129 struct gdi_font
*font
= NULL
;
6131 if (!path
|| !font_funcs
) return FALSE
;
6133 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
6134 font
->lf
.lfHeight
= 100;
6135 if (!font_funcs
->load_font( font
)) goto done
;
6136 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
6138 free_gdi_font( font
);
6142 if (font
) free_gdi_font( font
);
6143 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
6147 /*************************************************************************
6148 * NtGdiGetKerningPairs (win32u.@)
6150 DWORD WINAPI
NtGdiGetKerningPairs( HDC hdc
, DWORD count
, KERNINGPAIR
*kern_pair
)
6156 TRACE( "(%p,%d,%p)\n", hdc
, count
, kern_pair
);
6158 if (!count
&& kern_pair
)
6160 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
6164 dc
= get_dc_ptr( hdc
);
6167 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
6168 ret
= dev
->funcs
->pGetKerningPairs( dev
, count
, kern_pair
);
6169 release_dc_ptr( dc
);
6173 /*************************************************************************
6174 * NtGdiGetFontData (win32u.@)
6176 * Retrieve data for TrueType font.
6180 * success: Number of bytes returned
6181 * failure: GDI_ERROR
6185 * Calls RtlSetLastWin32Error()
6188 DWORD WINAPI
NtGdiGetFontData( HDC hdc
, DWORD table
, DWORD offset
, void *buffer
, DWORD length
)
6190 DC
*dc
= get_dc_ptr(hdc
);
6194 if(!dc
) return GDI_ERROR
;
6196 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
6197 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
6198 release_dc_ptr( dc
);
6202 /*************************************************************************
6203 * NtGdiGetGlyphIndicesW (win32u.@)
6205 DWORD WINAPI
NtGdiGetGlyphIndicesW( HDC hdc
, const WCHAR
*str
, INT count
,
6206 WORD
*indices
, DWORD flags
)
6208 DC
*dc
= get_dc_ptr(hdc
);
6212 TRACE( "(%p, %s, %d, %p, 0x%x)\n", hdc
, debugstr_wn(str
, count
), count
, indices
, flags
);
6214 if(!dc
) return GDI_ERROR
;
6216 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
6217 ret
= dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, indices
, flags
);
6218 release_dc_ptr( dc
);
6222 /***********************************************************************
6224 * Font Resource API *
6226 ***********************************************************************/
6229 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
6231 WCHAR path
[MAX_PATH
];
6234 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
6235 get_fonts_win_dir_path( file
, path
);
6236 pthread_mutex_lock( &font_lock
);
6237 ret
= font_funcs
->add_font( path
, flags
);
6238 pthread_mutex_unlock( &font_lock
);
6239 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
6242 get_fonts_data_dir_path( file
, path
);
6243 pthread_mutex_lock( &font_lock
);
6244 ret
= font_funcs
->add_font( path
, flags
);
6245 pthread_mutex_unlock( &font_lock
);
6250 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
6252 WCHAR path
[MAX_PATH
];
6255 get_fonts_win_dir_path( file
, path
);
6256 if (!(ret
= remove_font( path
, flags
)))
6258 get_fonts_data_dir_path( file
, path
);
6259 ret
= remove_font( path
, flags
);
6264 static int add_font_resource( LPCWSTR file
, DWORD flags
)
6270 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6272 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6273 pthread_mutex_lock( &font_lock
);
6274 ret
= font_funcs
->add_font( file
, addfont_flags
);
6275 pthread_mutex_unlock( &font_lock
);
6277 else if (!wcschr( file
, '\\' ))
6278 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6283 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
6289 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
6291 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
6292 ret
= remove_font( file
, addfont_flags
);
6294 else if (!wcschr( file
, '\\' ))
6295 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6300 static void load_system_bitmap_fonts(void)
6302 static const char * const fonts
[] = { "FONTS.FON", "OEMFONT.FON", "FIXEDFON.FON" };
6303 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6304 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6308 if (!(hkey
= reg_open_key( NULL
, fonts_config_keyW
, sizeof(fonts_config_keyW
) ))) return;
6309 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
6311 if (query_reg_ascii_value( hkey
, fonts
[i
], info
, sizeof(value_buffer
) ) && info
->Type
== REG_SZ
)
6312 add_system_font_resource( (const WCHAR
*)info
->Data
, ADDFONT_ALLOW_BITMAP
);
6317 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
6319 OBJECT_ATTRIBUTES attr
;
6320 UNICODE_STRING nt_name
;
6326 len
= lstrlenW( path
);
6327 while (len
&& path
[len
- 1] == '\\') len
--;
6329 nt_name
.Buffer
= path
;
6330 nt_name
.MaximumLength
= nt_name
.Length
= len
* sizeof(WCHAR
);
6332 attr
.Length
= sizeof(attr
);
6333 attr
.RootDirectory
= 0;
6334 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
6335 attr
.ObjectName
= &nt_name
;
6336 attr
.SecurityDescriptor
= NULL
;
6337 attr
.SecurityQualityOfService
= NULL
;
6339 if (NtOpenFile( &handle
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
,
6340 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
6341 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
))
6346 while (!NtQueryDirectoryFile( handle
, 0, NULL
, NULL
, &io
, buf
, sizeof(buf
),
6347 FileBothDirectoryInformation
, FALSE
, NULL
, FALSE
) &&
6350 FILE_BOTH_DIR_INFORMATION
*info
= (FILE_BOTH_DIR_INFORMATION
*)buf
;
6353 if (!(info
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
6355 memcpy( path
+ len
, info
->FileName
, info
->FileNameLength
);
6356 path
[len
+ info
->FileNameLength
/ sizeof(WCHAR
)] = 0;
6357 font_funcs
->add_font( path
, flags
);
6359 if (!info
->NextEntryOffset
) break;
6360 info
= (FILE_BOTH_DIR_INFORMATION
*)((char *)info
+ info
->NextEntryOffset
);
6367 static void load_file_system_fonts(void)
6369 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024 * sizeof(WCHAR
)])];
6370 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6371 WCHAR
*ptr
, *next
, path
[MAX_PATH
];
6373 /* Windows directory */
6374 get_fonts_win_dir_path( NULL
, path
);
6375 load_directory_fonts( path
, 0 );
6377 /* Wine data directory */
6378 get_fonts_data_dir_path( NULL
, path
);
6379 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6382 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
6383 if (query_reg_ascii_value( wine_fonts_key
, "Path", info
, sizeof(value_buffer
) ) &&
6384 info
->Type
== REG_SZ
)
6386 for (ptr
= (WCHAR
*)info
->Data
; ptr
; ptr
= next
)
6388 if ((next
= wcschr( ptr
, ';' ))) *next
++ = 0;
6389 if (next
&& next
- ptr
< 2) continue;
6390 lstrcpynW( path
, ptr
, MAX_PATH
);
6393 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, (lstrlenW( path
) + 1) * sizeof(WCHAR
) );
6394 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6396 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
6404 WCHAR value
[LF_FULLFACESIZE
+ 12];
6407 static void update_external_font_keys(void)
6409 struct list external_keys
= LIST_INIT(external_keys
);
6410 HKEY winnt_key
= 0, win9x_key
= 0;
6411 struct gdi_font_family
*family
;
6412 struct external_key
*key
, *next
;
6413 struct gdi_font_face
*face
;
6415 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6417 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
6421 static const WCHAR external_fontsW
[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s'};
6423 winnt_key
= reg_create_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
), 0, NULL
);
6424 win9x_key
= reg_create_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
), 0, NULL
);
6426 /* enumerate the fonts and add external ones to the two keys */
6428 if (!(hkey
= reg_create_key( wine_fonts_key
, external_fontsW
, sizeof(external_fontsW
), 0, NULL
)))
6431 while (reg_enum_value( hkey
, i
++, info
, sizeof(buffer
) - sizeof(nt_prefixW
),
6432 value
, LF_FULLFACESIZE
* sizeof(WCHAR
) ))
6434 if (info
->Type
!= REG_SZ
) continue;
6436 path
= (WCHAR
*)(buffer
+ info
->DataOffset
);
6437 if (path
[0] && path
[1] == ':')
6439 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, info
->DataLength
);
6440 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6443 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6444 if ((face
= find_face_from_full_name( value
)) && !wcsicmp( face
->file
, path
))
6446 face
->flags
|= ADDFONT_EXTERNAL_FOUND
;
6449 if (tmp
&& !*tmp
) *tmp
= ' ';
6450 if (!(key
= malloc( sizeof(*key
) ))) break;
6451 lstrcpyW( key
->value
, value
);
6452 list_add_tail( &external_keys
, &key
->entry
);
6455 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
6457 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
6459 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
6460 if ((face
->flags
& ADDFONT_EXTERNAL_FOUND
)) continue;
6462 lstrcpyW( value
, face
->full_name
);
6463 if (face
->scalable
) lstrcatW( value
, true_type_suffixW
);
6465 if (face
->file
[0] == '\\')
6468 if (file
[5] == ':') file
+= ARRAYSIZE(nt_prefixW
);
6470 else if ((file
= wcsrchr( face
->file
, '\\' )))
6475 len
= (lstrlenW(file
) + 1) * sizeof(WCHAR
);
6476 set_reg_value( winnt_key
, value
, REG_SZ
, file
, len
);
6477 set_reg_value( win9x_key
, value
, REG_SZ
, file
, len
);
6478 set_reg_value( hkey
, value
, REG_SZ
, file
, len
);
6481 LIST_FOR_EACH_ENTRY_SAFE( key
, next
, &external_keys
, struct external_key
, entry
)
6483 reg_delete_value( win9x_key
, key
->value
);
6484 reg_delete_value( winnt_key
, key
->value
);
6485 reg_delete_value( hkey
, key
->value
);
6486 list_remove( &key
->entry
);
6489 NtClose( win9x_key
);
6490 NtClose( winnt_key
);
6494 static void load_registry_fonts(void)
6496 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[MAX_PATH
* sizeof(WCHAR
)])];
6497 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)value_buffer
;
6498 KEY_VALUE_FULL_INFORMATION
*enum_info
= (KEY_VALUE_FULL_INFORMATION
*)value_buffer
;
6499 WCHAR value
[LF_FULLFACESIZE
+ 12], *tmp
, *path
;
6503 static const WCHAR dot_fonW
[] = {'.','f','o','n',0};
6505 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
6506 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
6507 full path as the entry. Also look for any .fon fonts, since ReadFontDir
6510 hkey
= reg_open_key( NULL
, fonts_win9x_config_keyW
, sizeof(fonts_win9x_config_keyW
) );
6512 hkey
= reg_open_key( NULL
, fonts_winnt_config_keyW
, sizeof(fonts_winnt_config_keyW
) );
6515 while (reg_enum_value( hkey
, i
++, enum_info
, sizeof(value_buffer
), value
, sizeof(value
) ))
6517 if (enum_info
->Type
!= REG_SZ
) continue;
6518 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, true_type_suffixW
, -1 )) *tmp
= 0;
6519 if (find_face_from_full_name( value
)) continue;
6520 if (tmp
&& !*tmp
) *tmp
= ' ';
6522 if (!(dlen
= query_reg_value( hkey
, value
, info
, sizeof(value_buffer
) - sizeof(nt_prefixW
) )) ||
6523 info
->Type
!= REG_SZ
)
6525 WARN( "Unable to get face path %s\n", debugstr_w(value
) );
6529 path
= (WCHAR
*)info
->Data
;
6530 if (path
[0] && path
[1] == ':')
6532 memmove( path
+ ARRAYSIZE(nt_prefixW
), path
, dlen
);
6533 memcpy( path
, nt_prefixW
, sizeof(nt_prefixW
) );
6534 dlen
+= sizeof(nt_prefixW
);
6537 dlen
/= sizeof(WCHAR
);
6539 add_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6540 else if (dlen
>= 6 && !wcsicmp( path
+ dlen
- 5, dot_fonW
))
6541 add_system_font_resource( path
, ADDFONT_ALLOW_BITMAP
);
6546 static HKEY
open_hkcu(void)
6550 DWORD_PTR sid_data
[(sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
) / sizeof(DWORD_PTR
)];
6551 DWORD i
, len
= sizeof(sid_data
);
6554 if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser
, sid_data
, len
, &len
))
6557 sid
= ((TOKEN_USER
*)sid_data
)->User
.Sid
;
6558 len
= sprintf( buffer
, "\\Registry\\User\\S-%u-%u", sid
->Revision
,
6559 MAKELONG( MAKEWORD( sid
->IdentifierAuthority
.Value
[5], sid
->IdentifierAuthority
.Value
[4] ),
6560 MAKEWORD( sid
->IdentifierAuthority
.Value
[3], sid
->IdentifierAuthority
.Value
[2] )));
6561 for (i
= 0; i
< sid
->SubAuthorityCount
; i
++)
6562 len
+= sprintf( buffer
+ len
, "-%u", sid
->SubAuthority
[i
] );
6563 ascii_to_unicode( bufferW
, buffer
, len
+ 1 );
6565 return reg_open_key( NULL
, bufferW
, len
* sizeof(WCHAR
) );
6568 /***********************************************************************
6571 UINT
font_init(void)
6573 OBJECT_ATTRIBUTES attr
= { sizeof(attr
) };
6574 UNICODE_STRING name
;
6579 static WCHAR wine_font_mutexW
[] =
6580 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
6581 '\\','_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_'};
6582 static const WCHAR wine_fonts_keyW
[] =
6583 {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','o','n','t','s'};
6584 static const WCHAR cacheW
[] = {'C','a','c','h','e'};
6586 if (!(hkcu_key
= open_hkcu())) return 0;
6587 wine_fonts_key
= reg_create_key( hkcu_key
, wine_fonts_keyW
, sizeof(wine_fonts_keyW
), 0, NULL
);
6588 if (wine_fonts_key
) dpi
= init_font_options();
6589 if (!dpi
) return 96;
6590 update_codepage( dpi
);
6592 if (!(font_funcs
= init_freetype_lib()))
6595 load_system_bitmap_fonts();
6596 load_file_system_fonts();
6597 font_funcs
->load_fonts();
6599 attr
.Attributes
= OBJ_OPENIF
;
6600 attr
.ObjectName
= &name
;
6601 name
.Buffer
= wine_font_mutexW
;
6602 name
.Length
= name
.MaximumLength
= sizeof(wine_font_mutexW
);
6604 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return dpi
;
6605 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
6607 wine_fonts_cache_key
= reg_create_key( wine_fonts_key
, cacheW
, sizeof(cacheW
),
6608 REG_OPTION_VOLATILE
, &disposition
);
6610 if (disposition
== REG_CREATED_NEW_KEY
)
6612 load_registry_fonts();
6613 update_external_font_keys();
6616 NtReleaseMutant( mutex
, NULL
);
6618 if (disposition
!= REG_CREATED_NEW_KEY
)
6620 load_registry_fonts();
6621 load_font_list_from_cache();
6624 reorder_font_list();
6625 load_gdi_font_subst();
6626 load_gdi_font_replacements();
6627 load_system_links();
6628 dump_gdi_font_list();
6629 dump_gdi_font_subst();
6633 /***********************************************************************
6634 * NtGdiAddFontResourceW (win32u.@)
6636 INT WINAPI
NtGdiAddFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6637 DWORD tid
, void *dv
)
6639 if (!font_funcs
) return 1;
6640 return add_font_resource( str
, flags
);
6643 /***********************************************************************
6644 * NtGdiAddFontMemResourceEx (win32u.@)
6646 HANDLE WINAPI
NtGdiAddFontMemResourceEx( void *ptr
, DWORD size
, void *dv
, ULONG dv_size
,
6653 if (!ptr
|| !size
|| !count
)
6655 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER
);
6658 if (!font_funcs
) return NULL
;
6659 if (!(copy
= malloc( size
))) return NULL
;
6660 memcpy( copy
, ptr
, size
);
6662 pthread_mutex_lock( &font_lock
);
6663 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
6664 pthread_mutex_unlock( &font_lock
);
6672 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
6673 * For now return something unique but quite random
6675 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
6683 WARN( "page fault while writing to *count (%p)\n", count
);
6684 NtGdiRemoveFontMemResourceEx( ret
);
6688 TRACE( "Returning handle %p\n", ret
);
6692 /***********************************************************************
6693 * NtGdiRemoveFontMemResourceEx (win32u.@)
6695 BOOL WINAPI
NtGdiRemoveFontMemResourceEx( HANDLE handle
)
6697 FIXME( "(%p) stub\n", handle
);
6701 /***********************************************************************
6702 * NtGdiRemoveFontResourceW (win32u.@)
6704 BOOL WINAPI
NtGdiRemoveFontResourceW( const WCHAR
*str
, ULONG size
, ULONG files
, DWORD flags
,
6705 DWORD tid
, void *dv
)
6707 if (!font_funcs
) return TRUE
;
6708 return remove_font_resource( str
, flags
);
6711 /***********************************************************************
6712 * NtGdiGetFontUnicodeRanges (win32u.@)
6714 * Retrieve a list of supported Unicode characters in a font.
6717 * hdc [I] Handle to a device context.
6718 * lpgs [O] GLYPHSET structure specifying supported character ranges.
6721 * Success: Number of bytes written to the buffer pointed to by lpgs.
6725 DWORD WINAPI
NtGdiGetFontUnicodeRanges( HDC hdc
, GLYPHSET
*lpgs
)
6729 DC
*dc
= get_dc_ptr(hdc
);
6731 TRACE("(%p, %p)\n", hdc
, lpgs
);
6735 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
6736 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
6742 /*************************************************************
6743 * NtGdiFontIsLinked (win32u.@)
6745 BOOL WINAPI
NtGdiFontIsLinked( HDC hdc
)
6747 DC
*dc
= get_dc_ptr(hdc
);
6751 if (!dc
) return FALSE
;
6752 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
6753 ret
= dev
->funcs
->pFontIsLinked( dev
);
6755 TRACE("returning %d\n", ret
);
6759 /*************************************************************
6760 * NtGdiGetRealizationInfo (win32u.@)
6762 BOOL WINAPI
NtGdiGetRealizationInfo( HDC hdc
, struct font_realization_info
*info
)
6764 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, file_count
);
6769 if (info
->size
!= sizeof(*info
) && !is_v0
)
6772 dc
= get_dc_ptr(hdc
);
6773 if (!dc
) return FALSE
;
6774 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
6775 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
6780 /*************************************************************************
6781 * NtGdiGetRasterizerCaps (win32u.@)
6783 BOOL WINAPI
NtGdiGetRasterizerCaps( RASTERIZER_STATUS
*status
, UINT size
)
6785 status
->nSize
= sizeof(RASTERIZER_STATUS
);
6786 status
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
6787 status
->nLanguageID
= 0;
6791 /*************************************************************************
6792 * NtGdiGetFontFileData (win32u.@)
6794 BOOL WINAPI
NtGdiGetFontFileData( DWORD instance_id
, DWORD file_index
, UINT64
*offset
,
6795 void *buff
, DWORD buff_size
)
6797 struct gdi_font
*font
;
6798 DWORD tag
= 0, size
;
6801 if (!font_funcs
) return FALSE
;
6802 pthread_mutex_lock( &font_lock
);
6803 if ((font
= get_font_from_handle( instance_id
)))
6805 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
6806 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
6807 if (size
!= GDI_ERROR
&& size
>= buff_size
&& *offset
<= size
- buff_size
)
6808 ret
= font_funcs
->get_font_data( font
, tag
, *offset
, buff
, buff_size
) != GDI_ERROR
;
6810 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
6812 pthread_mutex_unlock( &font_lock
);
6816 /*************************************************************************
6817 * NtGdiGetFontFileInfo (win32u.@)
6819 BOOL WINAPI
NtGdiGetFontFileInfo( DWORD instance_id
, DWORD file_index
, struct font_fileinfo
*info
,
6820 SIZE_T size
, SIZE_T
*needed
)
6822 SIZE_T required_size
= 0;
6823 struct gdi_font
*font
;
6826 pthread_mutex_lock( &font_lock
);
6828 if ((font
= get_font_from_handle( instance_id
)))
6830 required_size
= sizeof(*info
) + lstrlenW( font
->file
) * sizeof(WCHAR
);
6831 if (required_size
<= size
)
6833 info
->writetime
= font
->writetime
;
6834 info
->size
.QuadPart
= font
->data_size
;
6835 lstrcpyW( info
->path
, font
->file
);
6838 else RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
6841 pthread_mutex_unlock( &font_lock
);
6842 if (needed
) *needed
= required_size
;
6846 /*************************************************************
6847 * NtGdiGetCharWidthInfo (win32u.@)
6849 BOOL WINAPI
NtGdiGetCharWidthInfo( HDC hdc
, struct char_width_info
*info
)
6855 dc
= get_dc_ptr(hdc
);
6856 if (!dc
) return FALSE
;
6857 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
6858 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
6862 info
->lsb
= width_to_LP( dc
, info
->lsb
);
6863 info
->rsb
= width_to_LP( dc
, info
->rsb
);
6869 /***********************************************************************
6870 * DrawTextW (win32u.so)
6872 INT WINAPI
DrawTextW( HDC hdc
, const WCHAR
*str
, INT count
, RECT
*rect
, UINT flags
)
6874 struct draw_text_params
*params
;
6875 ULONG ret_len
, size
;
6879 if (count
== -1) count
= wcslen( str
);
6880 size
= FIELD_OFFSET( struct draw_text_params
, str
[count
] );
6881 if (!(params
= malloc( size
))) return 0;
6883 params
->rect
= *rect
;
6884 params
->ret_rect
= rect
;
6885 params
->flags
= flags
;
6886 if (count
) memcpy( params
->str
, str
, count
* sizeof(WCHAR
) );
6887 ret
= KeUserModeCallback( NtUserDrawText
, params
, size
, &ret_ptr
, &ret_len
);
6888 if (ret_len
== sizeof(*rect
)) *rect
= *(const RECT
*)ret_ptr
;