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