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