4 * Copyright 1993 Alexandre Julliard
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "gdi_private.h"
36 #include "wine/exception.h"
37 #include "wine/heap.h"
38 #include "wine/rbtree.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(font
);
43 static HKEY wine_fonts_key
;
44 static HKEY wine_fonts_cache_key
;
48 struct gdi_physdev dev
;
49 struct gdi_font
*font
;
52 static inline struct font_physdev
*get_font_dev( PHYSDEV dev
)
54 return (struct font_physdev
*)dev
;
57 struct gdi_font_family
59 struct wine_rb_entry name_entry
;
60 struct wine_rb_entry second_name_entry
;
61 unsigned int refcount
;
62 WCHAR family_name
[LF_FACESIZE
];
63 WCHAR second_name
[LF_FACESIZE
];
65 struct gdi_font_family
*replacement
;
71 unsigned int refcount
;
81 DWORD flags
; /* ADDFONT flags */
83 struct bitmap_font_size size
; /* set if face is a bitmap */
84 struct gdi_font_family
*family
;
85 struct gdi_font_enum_data
*cached_enum_data
;
86 struct wine_rb_entry full_name_entry
;
89 static const struct font_backend_funcs
*font_funcs
;
91 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
93 static UINT font_smoothing
= GGO_BITMAP
;
94 static UINT subpixel_orientation
= GGO_GRAY4_BITMAP
;
95 static BOOL antialias_fakes
= TRUE
;
96 static struct font_gamma_ramp font_gamma_ramp
;
98 static void add_face_to_cache( struct gdi_font_face
*face
);
99 static void remove_face_from_cache( struct gdi_font_face
*face
);
101 static inline WCHAR
facename_tolower( WCHAR c
)
103 if (c
>= 'A' && c
<= 'Z') return c
- 'A' + 'a';
104 else if (c
> 127) return RtlDowncaseUnicodeChar( c
);
108 static inline int facename_compare( const WCHAR
*str1
, const WCHAR
*str2
, SIZE_T len
)
112 WCHAR c1
= facename_tolower( *str1
++ ), c2
= facename_tolower( *str2
++ );
113 if (c1
!= c2
) return c1
- c2
;
114 else if (!c1
) return 0;
119 /* Device -> World size conversion */
121 /* Performs a device to world transformation on the specified width (which
122 * is in integer format).
124 static inline INT
INTERNAL_XDSTOWS(DC
*dc
, INT width
)
128 /* Perform operation with floating point */
129 floatWidth
= (double)width
* dc
->xformVport2World
.eM11
;
130 /* Round to integers */
131 return GDI_ROUND(floatWidth
);
134 /* Performs a device to world transformation on the specified size (which
135 * is in integer format).
137 static inline INT
INTERNAL_YDSTOWS(DC
*dc
, INT height
)
141 /* Perform operation with floating point */
142 floatHeight
= (double)height
* dc
->xformVport2World
.eM22
;
143 /* Round to integers */
144 return GDI_ROUND(floatHeight
);
147 /* scale width and height but don't mirror them */
149 static inline INT
width_to_LP( DC
*dc
, INT width
)
151 return GDI_ROUND( (double)width
* fabs( dc
->xformVport2World
.eM11
));
154 static inline INT
height_to_LP( DC
*dc
, INT height
)
156 return GDI_ROUND( (double)height
* fabs( dc
->xformVport2World
.eM22
));
159 static inline INT
INTERNAL_YWSTODS(DC
*dc
, INT height
)
162 pt
[0].x
= pt
[0].y
= 0;
166 return pt
[1].y
- pt
[0].y
;
169 static inline BOOL
is_win9x(void)
171 return GetVersion() & 0x80000000;
174 static inline WCHAR
*strdupW( const WCHAR
*p
)
177 DWORD len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
178 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
183 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
);
184 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
);
185 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
);
186 static BOOL
FONT_DeleteObject( HGDIOBJ handle
);
188 static const struct gdi_obj_funcs fontobj_funcs
=
190 FONT_SelectObject
, /* pSelectObject */
191 FONT_GetObjectA
, /* pGetObjectA */
192 FONT_GetObjectW
, /* pGetObjectW */
193 NULL
, /* pUnrealizeObject */
194 FONT_DeleteObject
/* pDeleteObject */
204 LPLOGFONTW lpLogFontParam
;
205 FONTENUMPROCW lpEnumFunc
;
213 * For TranslateCharsetInfo
215 #define MAXTCIINDEX 32
216 static const CHARSETINFO FONT_tci
[MAXTCIINDEX
] = {
218 { ANSI_CHARSET
, 1252, {{0,0,0,0},{FS_LATIN1
,0}} },
219 { EASTEUROPE_CHARSET
, 1250, {{0,0,0,0},{FS_LATIN2
,0}} },
220 { RUSSIAN_CHARSET
, 1251, {{0,0,0,0},{FS_CYRILLIC
,0}} },
221 { GREEK_CHARSET
, 1253, {{0,0,0,0},{FS_GREEK
,0}} },
222 { TURKISH_CHARSET
, 1254, {{0,0,0,0},{FS_TURKISH
,0}} },
223 { HEBREW_CHARSET
, 1255, {{0,0,0,0},{FS_HEBREW
,0}} },
224 { ARABIC_CHARSET
, 1256, {{0,0,0,0},{FS_ARABIC
,0}} },
225 { BALTIC_CHARSET
, 1257, {{0,0,0,0},{FS_BALTIC
,0}} },
226 { VIETNAMESE_CHARSET
, 1258, {{0,0,0,0},{FS_VIETNAMESE
,0}} },
227 /* reserved by ANSI */
228 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
229 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
230 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
231 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
232 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
233 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
234 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
236 { THAI_CHARSET
, 874, {{0,0,0,0},{FS_THAI
,0}} },
237 { SHIFTJIS_CHARSET
, 932, {{0,0,0,0},{FS_JISJAPAN
,0}} },
238 { GB2312_CHARSET
, 936, {{0,0,0,0},{FS_CHINESESIMP
,0}} },
239 { HANGEUL_CHARSET
, 949, {{0,0,0,0},{FS_WANSUNG
,0}} },
240 { CHINESEBIG5_CHARSET
, 950, {{0,0,0,0},{FS_CHINESETRAD
,0}} },
241 { JOHAB_CHARSET
, 1361, {{0,0,0,0},{FS_JOHAB
,0}} },
242 /* reserved for alternate ANSI and OEM */
243 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
244 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
245 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
246 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
247 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
248 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
249 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
250 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
251 /* reserved for system */
252 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
253 { SYMBOL_CHARSET
, CP_SYMBOL
, {{0,0,0,0},{FS_SYMBOL
,0}} }
256 static const WCHAR
* const default_serif_list
[3] =
260 L
"Bitstream Vera Serif"
262 static const WCHAR
* const default_fixed_list
[3] =
266 L
"Bitstream Vera Sans Mono"
268 static const WCHAR
* const default_sans_list
[3] =
272 L
"Bitstream Vera Sans"
274 static WCHAR ff_roman_default
[LF_FACESIZE
];
275 static WCHAR ff_modern_default
[LF_FACESIZE
];
276 static WCHAR ff_swiss_default
[LF_FACESIZE
];
278 static const struct nls_update_font_list
280 UINT ansi_cp
, oem_cp
;
281 const char *oem
, *fixed
, *system
;
282 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
283 /* these are for font substitutes */
284 const char *shelldlg
, *tmsrmn
;
285 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
, *helv_0
, *tmsrmn_0
;
286 struct subst
{ const char *from
, *to
; } arial_0
, courier_new_0
, times_new_roman_0
;
287 } nls_update_font_list
[] =
289 /* Latin 1 (United States) */
290 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
291 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
292 "Tahoma","Times New Roman"
294 /* Latin 1 (Multilingual) */
295 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
296 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
297 "Tahoma","Times New Roman" /* FIXME unverified */
300 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
301 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
302 "Tahoma","Times New Roman", /* FIXME unverified */
303 "Fixedsys,238", "System,238",
304 "Courier New,238", "MS Serif,238", "Small Fonts,238",
305 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
306 { "Arial CE,0", "Arial,238" },
307 { "Courier New CE,0", "Courier New,238" },
308 { "Times New Roman CE,0", "Times New Roman,238" }
311 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
312 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
313 "Tahoma","Times New Roman", /* FIXME unverified */
314 "Fixedsys,204", "System,204",
315 "Courier New,204", "MS Serif,204", "Small Fonts,204",
316 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
317 { "Arial Cyr,0", "Arial,204" },
318 { "Courier New Cyr,0", "Courier New,204" },
319 { "Times New Roman Cyr,0", "Times New Roman,204" }
322 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
323 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
324 "Tahoma","Times New Roman", /* FIXME unverified */
325 "Fixedsys,161", "System,161",
326 "Courier New,161", "MS Serif,161", "Small Fonts,161",
327 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
328 { "Arial Greek,0", "Arial,161" },
329 { "Courier New Greek,0", "Courier New,161" },
330 { "Times New Roman Greek,0", "Times New Roman,161" }
333 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
334 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
335 "Tahoma","Times New Roman", /* FIXME unverified */
336 "Fixedsys,162", "System,162",
337 "Courier New,162", "MS Serif,162", "Small Fonts,162",
338 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
339 { "Arial Tur,0", "Arial,162" },
340 { "Courier New Tur,0", "Courier New,162" },
341 { "Times New Roman Tur,0", "Times New Roman,162" }
344 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
345 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
346 "Tahoma","Times New Roman", /* FIXME unverified */
347 "Fixedsys,177", "System,177",
348 "Courier New,177", "MS Serif,177", "Small Fonts,177",
349 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
352 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
353 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
354 "Microsoft Sans Serif","Times New Roman",
355 "Fixedsys,178", "System,178",
356 "Courier New,178", "MS Serif,178", "Small Fonts,178",
357 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
360 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
361 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
362 "Tahoma","Times New Roman", /* FIXME unverified */
363 "Fixedsys,186", "System,186",
364 "Courier New,186", "MS Serif,186", "Small Fonts,186",
365 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
366 { "Arial Baltic,0", "Arial,186" },
367 { "Courier New Baltic,0", "Courier New,186" },
368 { "Times New Roman Baltic,0", "Times New Roman,186" }
371 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
372 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
373 "Tahoma","Times New Roman" /* FIXME unverified */
376 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
377 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
378 "Tahoma","Times New Roman" /* FIXME unverified */
381 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
382 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
383 "MS UI Gothic","MS Serif"
385 /* Chinese Simplified */
386 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
387 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
391 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
392 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
395 /* Chinese Traditional */
396 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
397 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
398 "PMingLiU", "MingLiU"
402 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
404 return ( ansi_cp
== 932 /* CP932 for Japanese */
405 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
406 || ansi_cp
== 949 /* CP949 for Korean */
407 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
410 static CRITICAL_SECTION font_cs
;
411 static CRITICAL_SECTION_DEBUG critsect_debug
=
414 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
415 0, 0, { (DWORD_PTR
)(__FILE__
": font_cs") }
417 static CRITICAL_SECTION font_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
419 #ifndef WINE_FONT_DIR
420 #define WINE_FONT_DIR "fonts"
423 #ifdef WORDS_BIGENDIAN
424 #define GET_BE_WORD(x) (x)
425 #define GET_BE_DWORD(x) (x)
427 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
428 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
431 static void get_fonts_data_dir_path( const WCHAR
*file
, WCHAR
*path
)
433 if (GetEnvironmentVariableW( L
"WINEDATADIR", path
, MAX_PATH
))
434 lstrcatW( path
, L
"\\" WINE_FONT_DIR
"\\" );
435 else if (GetEnvironmentVariableW( L
"WINEBUILDDIR", path
, MAX_PATH
))
436 lstrcatW( path
, L
"\\fonts\\" );
438 lstrcatW( path
, file
);
439 if (path
[5] == ':') memmove( path
, path
+ 4, (lstrlenW(path
) - 3) * sizeof(WCHAR
) );
440 else path
[1] = '\\'; /* change \??\ to \\?\ */
443 static void get_fonts_win_dir_path( const WCHAR
*file
, WCHAR
*path
)
445 GetWindowsDirectoryW( path
, MAX_PATH
);
446 lstrcatW( path
, L
"\\fonts\\" );
447 lstrcatW( path
, file
);
450 /* font substitutions */
452 struct gdi_font_subst
460 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
462 static inline WCHAR
*get_subst_to_name( struct gdi_font_subst
*subst
)
464 return subst
->names
+ lstrlenW( subst
->names
) + 1;
467 static void dump_gdi_font_subst(void)
469 struct gdi_font_subst
*subst
;
471 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
473 if (subst
->from_charset
!= -1 || subst
->to_charset
!= -1)
474 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst
->names
),
475 subst
->from_charset
, debugstr_w(get_subst_to_name(subst
)), subst
->to_charset
);
477 TRACE("%s -> %s\n", debugstr_w(subst
->names
), debugstr_w(get_subst_to_name(subst
)));
481 static const WCHAR
*get_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, int *to_charset
)
483 struct gdi_font_subst
*subst
;
485 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
487 if (!facename_compare( subst
->names
, from_name
, -1 ) &&
488 (subst
->from_charset
== from_charset
|| subst
->from_charset
== -1))
490 if (to_charset
) *to_charset
= subst
->to_charset
;
491 return get_subst_to_name( subst
);
497 static BOOL
add_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, const WCHAR
*to_name
, int to_charset
)
499 struct gdi_font_subst
*subst
;
500 int len
= lstrlenW( from_name
) + lstrlenW( to_name
) + 2;
502 if (get_gdi_font_subst( from_name
, from_charset
, NULL
)) return FALSE
; /* already exists */
504 if (!(subst
= HeapAlloc( GetProcessHeap(), 0,
505 offsetof( struct gdi_font_subst
, names
[len
] ))))
507 lstrcpyW( subst
->names
, from_name
);
508 lstrcpyW( get_subst_to_name(subst
), to_name
);
509 subst
->from_charset
= from_charset
;
510 subst
->to_charset
= to_charset
;
511 list_add_tail( &font_subst_list
, &subst
->entry
);
515 static void load_gdi_font_subst(void)
518 DWORD i
= 0, type
, dlen
, vlen
;
519 WCHAR value
[64], data
[64], *p
;
521 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
525 vlen
= ARRAY_SIZE(value
);
526 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)data
, &dlen
))
528 int from_charset
= -1, to_charset
= -1;
530 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
531 if ((p
= wcsrchr( value
, ',' )) && p
[1])
534 from_charset
= wcstol( p
, NULL
, 10 );
536 if ((p
= wcsrchr( data
, ',' )) && p
[1])
539 to_charset
= wcstol( p
, NULL
, 10 );
542 /* Win 2000 doesn't allow mapping between different charsets
543 or mapping of DEFAULT_CHARSET */
544 if ((!from_charset
|| to_charset
== from_charset
) && to_charset
!= DEFAULT_CHARSET
)
545 add_gdi_font_subst( value
, from_charset
, data
, to_charset
);
547 /* reset dlen and vlen */
549 vlen
= ARRAY_SIZE(value
);
556 static int family_namecmp( const WCHAR
*str1
, const WCHAR
*str2
)
558 int prio1
, prio2
, vert1
= (str1
[0] == '@' ? 1 : 0), vert2
= (str2
[0] == '@' ? 1 : 0);
560 if (!facename_compare( str1
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio1
= 0;
561 else if (!facename_compare( str1
, ff_modern_default
, LF_FACESIZE
- 1 )) prio1
= 1;
562 else if (!facename_compare( str1
, ff_roman_default
, LF_FACESIZE
- 1 )) prio1
= 2;
565 if (!facename_compare( str2
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio2
= 0;
566 else if (!facename_compare( str2
, ff_modern_default
, LF_FACESIZE
- 1 )) prio2
= 1;
567 else if (!facename_compare( str2
, ff_roman_default
, LF_FACESIZE
- 1 )) prio2
= 2;
570 if (prio1
!= prio2
) return prio1
- prio2
;
571 if (vert1
!= vert2
) return vert1
- vert2
;
572 return facename_compare( str1
+ vert1
, str2
+ vert2
, LF_FACESIZE
- 1 );
575 static int family_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
577 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, name_entry
);
578 return family_namecmp( (const WCHAR
*)key
, family
->family_name
);
581 static int family_second_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
583 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, second_name_entry
);
584 return family_namecmp( (const WCHAR
*)key
, family
->second_name
);
587 static int face_full_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
589 const struct gdi_font_face
*face
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_face
, full_name_entry
);
590 return facename_compare( (const WCHAR
*)key
, face
->full_name
, LF_FULLFACESIZE
- 1 );
593 static struct wine_rb_tree family_name_tree
= { family_name_compare
};
594 static struct wine_rb_tree family_second_name_tree
= { family_second_name_compare
};
595 static struct wine_rb_tree face_full_name_tree
= { face_full_name_compare
};
597 static int face_is_in_full_name_tree( const struct gdi_font_face
*face
)
599 return face
->full_name_entry
.parent
|| face_full_name_tree
.root
== &face
->full_name_entry
;
602 static struct gdi_font_family
*create_family( const WCHAR
*name
, const WCHAR
*second_name
)
604 struct gdi_font_family
*family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
606 family
->refcount
= 1;
607 lstrcpynW( family
->family_name
, name
, LF_FACESIZE
);
608 if (second_name
&& second_name
[0] && wcsicmp( name
, second_name
))
610 lstrcpynW( family
->second_name
, second_name
, LF_FACESIZE
);
611 add_gdi_font_subst( second_name
, -1, name
, -1 );
613 else family
->second_name
[0] = 0;
614 list_init( &family
->faces
);
615 family
->replacement
= NULL
;
616 wine_rb_put( &family_name_tree
, family
->family_name
, &family
->name_entry
);
617 if (family
->second_name
[0]) wine_rb_put( &family_second_name_tree
, family
->second_name
, &family
->second_name_entry
);
621 static void release_family( struct gdi_font_family
*family
)
623 if (--family
->refcount
) return;
624 assert( list_empty( &family
->faces
));
625 wine_rb_remove( &family_name_tree
, &family
->name_entry
);
626 if (family
->second_name
[0]) wine_rb_remove( &family_second_name_tree
, &family
->second_name_entry
);
627 if (family
->replacement
) release_family( family
->replacement
);
628 HeapFree( GetProcessHeap(), 0, family
);
631 static struct gdi_font_family
*find_family_from_name( const WCHAR
*name
)
633 struct wine_rb_entry
*entry
;
634 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) return NULL
;
635 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, name_entry
);
638 static struct gdi_font_family
*find_family_from_any_name( const WCHAR
*name
)
640 struct wine_rb_entry
*entry
;
641 struct gdi_font_family
*family
;
642 if ((family
= find_family_from_name( name
))) return family
;
643 if (!(entry
= wine_rb_get( &family_second_name_tree
, name
))) return NULL
;
644 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, second_name_entry
);
647 static struct gdi_font_face
*find_face_from_full_name( const WCHAR
*full_name
)
649 struct wine_rb_entry
*entry
;
650 if (!(entry
= wine_rb_get( &face_full_name_tree
, full_name
))) return NULL
;
651 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_face
, full_name_entry
);
654 static const struct list
*get_family_face_list( const struct gdi_font_family
*family
)
656 return family
->replacement
? &family
->replacement
->faces
: &family
->faces
;
659 static struct gdi_font_face
*family_find_face_from_filename( struct gdi_font_family
*family
, const WCHAR
*file_name
)
661 struct gdi_font_face
*face
;
663 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
665 if (!face
->file
) continue;
666 file
= wcsrchr(face
->file
, '\\');
667 if (!file
) file
= face
->file
;
669 if (wcsicmp( file
, file_name
)) continue;
676 static struct gdi_font_face
*find_face_from_filename( const WCHAR
*file_name
, const WCHAR
*family_name
)
678 struct gdi_font_family
*family
;
679 struct gdi_font_face
*face
;
681 TRACE( "looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(family_name
) );
685 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
686 if ((face
= family_find_face_from_filename( family
, file_name
))) return face
;
690 if (!(family
= find_family_from_name( family_name
))) return NULL
;
691 return family_find_face_from_filename( family
, file_name
);
694 static BOOL
add_family_replacement( const WCHAR
*new_name
, const WCHAR
*replace
)
696 struct gdi_font_family
*new_family
, *family
;
697 struct gdi_font_face
*face
;
698 WCHAR new_name_vert
[LF_FACESIZE
], replace_vert
[LF_FACESIZE
];
700 if (!(family
= find_family_from_any_name( replace
)))
702 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace
) );
706 if (!(new_family
= create_family( new_name
, NULL
))) return FALSE
;
707 new_family
->replacement
= family
;
709 TRACE( "mapping %s to %s\n", debugstr_w(replace
), debugstr_w(new_name
) );
711 /* also add replacement for vertical font if necessary */
712 if (replace
[0] == '@') return TRUE
;
713 if (list_empty( &family
->faces
)) return TRUE
;
714 face
= LIST_ENTRY( list_head(&family
->faces
), struct gdi_font_face
, entry
);
715 if (!(face
->fs
.fsCsb
[0] & FS_DBCS_MASK
)) return TRUE
;
717 new_name_vert
[0] = '@';
718 lstrcpynW( new_name_vert
+ 1, new_name
, LF_FACESIZE
- 1 );
719 if (find_family_from_any_name( new_name_vert
)) return TRUE
; /* already exists */
721 replace_vert
[0] = '@';
722 lstrcpynW( replace_vert
+ 1, replace
, LF_FACESIZE
- 1 );
723 add_family_replacement( new_name_vert
, replace_vert
);
728 * The replacement list is a way to map an entire font
729 * family onto another family. For example adding
731 * [HKCU\Software\Wine\Fonts\Replacements]
732 * "Wingdings"="Winedings"
734 * would enumerate the Winedings font both as Winedings and
735 * Wingdings. However if a real Wingdings font is present the
736 * replacement does not take place.
738 static void load_gdi_font_replacements(void)
741 DWORD i
= 0, type
, dlen
, vlen
;
742 WCHAR value
[LF_FACESIZE
], data
[1024];
744 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
745 if (RegOpenKeyW( wine_fonts_key
, L
"Replacements", &hkey
)) return;
748 vlen
= ARRAY_SIZE(value
);
749 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)data
, &dlen
))
751 /* "NewName"="Oldname" */
752 if (!find_family_from_any_name( value
))
754 if (type
== REG_MULTI_SZ
)
756 WCHAR
*replace
= data
;
759 if (add_family_replacement( value
, replace
)) break;
760 replace
+= lstrlenW(replace
) + 1;
763 else if (type
== REG_SZ
) add_family_replacement( value
, data
);
765 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
767 /* reset dlen and vlen */
769 vlen
= ARRAY_SIZE(value
);
774 static void dump_gdi_font_list(void)
776 struct gdi_font_family
*family
;
777 struct gdi_font_face
*face
;
779 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
781 TRACE( "Family: %s\n", debugstr_w(family
->family_name
) );
782 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
784 TRACE( "\t%s\t%s\t%08x", debugstr_w(face
->style_name
), debugstr_w(face
->full_name
),
786 if (!face
->scalable
) TRACE(" %d", face
->size
.height
);
792 static BOOL
enum_fallbacks( DWORD pitch_and_family
, int index
, WCHAR buffer
[LF_FACESIZE
] )
796 const WCHAR
* const *defaults
;
798 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
)
799 defaults
= default_fixed_list
;
800 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
)
801 defaults
= default_serif_list
;
803 defaults
= default_sans_list
;
804 lstrcpynW( buffer
, defaults
[index
], LF_FACESIZE
);
807 return font_funcs
->enum_family_fallbacks( pitch_and_family
, index
- 3, buffer
);
810 static void set_default_family( DWORD pitch_and_family
, WCHAR
*default_name
)
812 struct wine_rb_entry
*entry
;
813 WCHAR name
[LF_FACESIZE
];
816 while (enum_fallbacks( pitch_and_family
, i
++, name
))
818 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) continue;
819 wine_rb_remove( &family_name_tree
, entry
);
820 lstrcpynW( default_name
, name
, LF_FACESIZE
- 1 );
821 wine_rb_put( &family_name_tree
, name
, entry
);
826 static void reorder_font_list(void)
828 set_default_family( FF_ROMAN
, ff_roman_default
);
829 set_default_family( FF_MODERN
, ff_modern_default
);
830 set_default_family( FF_SWISS
, ff_swiss_default
);
833 static void release_face( struct gdi_font_face
*face
)
835 if (--face
->refcount
) return;
838 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
839 list_remove( &face
->entry
);
840 release_family( face
->family
);
842 if (face_is_in_full_name_tree( face
)) wine_rb_remove( &face_full_name_tree
, &face
->full_name_entry
);
843 HeapFree( GetProcessHeap(), 0, face
->file
);
844 HeapFree( GetProcessHeap(), 0, face
->style_name
);
845 HeapFree( GetProcessHeap(), 0, face
->full_name
);
846 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
847 HeapFree( GetProcessHeap(), 0, face
);
850 static int remove_font( const WCHAR
*file
, DWORD flags
)
852 struct gdi_font_family
*family
, *family_next
;
853 struct gdi_font_face
*face
, *face_next
;
856 EnterCriticalSection( &font_cs
);
857 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family
, family_next
, &family_name_tree
, struct gdi_font_family
, name_entry
)
860 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, struct gdi_font_face
, entry
)
862 if (!face
->file
) continue;
863 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
864 if (!wcsicmp( face
->file
, file
))
866 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
867 release_face( face
);
871 release_family( family
);
873 LeaveCriticalSection( &font_cs
);
877 static inline BOOL
faces_equal( const struct gdi_font_face
*f1
, const struct gdi_font_face
*f2
)
879 if (facename_compare( f1
->full_name
, f2
->full_name
, -1 )) return FALSE
;
880 if (f1
->scalable
) return TRUE
;
881 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
882 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
885 static inline int style_order( const struct gdi_font_face
*face
)
887 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
895 case NTM_BOLD
| NTM_ITALIC
:
898 WARN( "Don't know how to order face %s with flags 0x%08x\n",
899 debugstr_w(face
->full_name
), face
->ntmFlags
);
904 static BOOL
insert_face_in_family_list( struct gdi_font_face
*face
, struct gdi_font_family
*family
)
906 struct gdi_font_face
*cursor
;
908 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, struct gdi_font_face
, entry
)
910 if (faces_equal( face
, cursor
))
912 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
913 debugstr_w(face
->full_name
), debugstr_w(family
->family_name
),
914 cursor
->version
, face
->version
);
916 if (face
->file
&& cursor
->file
&& !wcsicmp( face
->file
, cursor
->file
))
919 TRACE("Font %s already in list, refcount now %d\n",
920 debugstr_w(face
->file
), cursor
->refcount
);
923 if (face
->version
<= cursor
->version
)
925 TRACE("Original font %s is newer so skipping %s\n",
926 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
931 TRACE("Replacing original %s with %s\n",
932 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
933 list_add_before( &cursor
->entry
, &face
->entry
);
934 face
->family
= family
;
937 if (face_is_in_full_name_tree( cursor
))
939 wine_rb_replace( &face_full_name_tree
, &cursor
->full_name_entry
, &face
->full_name_entry
);
940 memset( &cursor
->full_name_entry
, 0, sizeof(cursor
->full_name_entry
) );
942 release_face( cursor
);
946 if (style_order( face
) < style_order( cursor
)) break;
949 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face
->full_name
),
950 debugstr_w(family
->family_name
), debugstr_w(face
->file
) );
951 list_add_before( &cursor
->entry
, &face
->entry
);
952 if (face
->scalable
) wine_rb_put( &face_full_name_tree
, face
->full_name
, &face
->full_name_entry
);
953 face
->family
= family
;
959 static struct gdi_font_face
*create_face( struct gdi_font_family
*family
, const WCHAR
*style
,
960 const WCHAR
*fullname
, const WCHAR
*file
,
961 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
962 DWORD ntmflags
, DWORD version
, DWORD flags
,
963 const struct bitmap_font_size
*size
)
965 struct gdi_font_face
*face
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*face
) );
968 face
->style_name
= strdupW( style
);
969 face
->full_name
= strdupW( fullname
);
970 face
->face_index
= index
;
972 face
->ntmFlags
= ntmflags
;
973 face
->version
= version
;
975 face
->data_ptr
= data_ptr
;
976 face
->data_size
= data_size
;
977 if (file
) face
->file
= strdupW( file
);
978 if (size
) face
->size
= *size
;
979 else face
->scalable
= TRUE
;
980 if (insert_face_in_family_list( face
, family
)) return face
;
981 release_face( face
);
985 static int CDECL
add_gdi_face( const WCHAR
*family_name
, const WCHAR
*second_name
,
986 const WCHAR
*style
, const WCHAR
*fullname
, const WCHAR
*file
,
987 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
988 DWORD ntmflags
, DWORD version
, DWORD flags
,
989 const struct bitmap_font_size
*size
)
991 struct gdi_font_face
*face
;
992 struct gdi_font_family
*family
;
995 if ((family
= find_family_from_name( family_name
))) family
->refcount
++;
996 else if (!(family
= create_family( family_name
, second_name
))) return ret
;
998 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
999 index
, fs
, ntmflags
, version
, flags
, size
)))
1001 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1002 release_face( face
);
1004 release_family( family
);
1007 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
1009 WCHAR vert_family
[LF_FACESIZE
], vert_second
[LF_FACESIZE
], vert_full
[LF_FULLFACESIZE
];
1011 vert_family
[0] = '@';
1012 lstrcpynW( vert_family
+ 1, family_name
, LF_FACESIZE
- 1 );
1014 if (second_name
&& second_name
[0])
1016 vert_second
[0] = '@';
1017 lstrcpynW( vert_second
+ 1, second_name
, LF_FACESIZE
- 1 );
1019 else vert_second
[0] = 0;
1024 lstrcpynW( vert_full
+ 1, fullname
, LF_FULLFACESIZE
- 1 );
1025 fullname
= vert_full
;
1028 if ((family
= find_family_from_name( vert_family
))) family
->refcount
++;
1029 else if (!(family
= create_family( vert_family
, vert_second
))) return ret
;
1031 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1032 index
, fs
, ntmflags
, version
, flags
| ADDFONT_VERTICAL_FONT
, size
)))
1034 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1035 release_face( face
);
1037 release_family( family
);
1051 struct bitmap_font_size size
;
1054 /* WCHAR file_name[]; */
1057 static void load_face_from_cache( HKEY hkey_family
, struct gdi_font_family
*family
,
1058 void *buffer
, DWORD buffer_size
, BOOL scalable
)
1060 DWORD type
, size
, needed
, index
= 0;
1061 struct gdi_font_face
*face
;
1064 struct cached_face
*cached
= (struct cached_face
*)buffer
;
1066 size
= sizeof(name
);
1067 needed
= buffer_size
- sizeof(DWORD
);
1068 while (!RegEnumValueW( hkey_family
, index
++, name
, &size
, NULL
, &type
, buffer
, &needed
))
1070 if (type
== REG_BINARY
&& needed
> sizeof(*cached
))
1072 ((DWORD
*)buffer
)[needed
/ sizeof(DWORD
)] = 0;
1073 if ((face
= create_face( family
, name
, cached
->full_name
,
1074 cached
->full_name
+ lstrlenW(cached
->full_name
) + 1,
1075 NULL
, 0, cached
->index
, cached
->fs
, cached
->ntmflags
, cached
->version
,
1076 cached
->flags
, scalable
? NULL
: &cached
->size
)))
1079 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1080 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1081 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1083 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1084 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1085 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1086 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1088 release_face( face
);
1091 size
= sizeof(name
);
1092 needed
= buffer_size
- sizeof(DWORD
);
1095 /* load bitmap strikes */
1098 needed
= buffer_size
;
1099 while (!RegEnumKeyExW( hkey_family
, index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1101 if (!RegOpenKeyExW( hkey_family
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1103 load_face_from_cache( hkey_strike
, family
, buffer
, buffer_size
, FALSE
);
1104 RegCloseKey( hkey_strike
);
1106 needed
= buffer_size
;
1110 static void load_font_list_from_cache(void)
1112 DWORD size
, family_index
= 0;
1113 struct gdi_font_family
*family
;
1115 WCHAR buffer
[4096], second_name
[LF_FACESIZE
];
1117 size
= sizeof(buffer
);
1118 while (!RegEnumKeyExW( wine_fonts_cache_key
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1120 RegOpenKeyExW( wine_fonts_cache_key
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1121 TRACE("opened family key %s\n", debugstr_w(buffer
));
1122 size
= sizeof(second_name
);
1123 if (RegQueryValueExW( hkey_family
, NULL
, NULL
, NULL
, (BYTE
*)second_name
, &size
))
1126 family
= create_family( buffer
, second_name
);
1128 load_face_from_cache( hkey_family
, family
, buffer
, sizeof(buffer
), TRUE
);
1130 RegCloseKey( hkey_family
);
1131 release_family( family
);
1132 size
= sizeof(buffer
);
1136 static void add_face_to_cache( struct gdi_font_face
*face
)
1138 HKEY hkey_family
, hkey_face
;
1139 DWORD len
, buffer
[1024];
1140 struct cached_face
*cached
= (struct cached_face
*)buffer
;
1142 if (RegCreateKeyExW( wine_fonts_cache_key
, face
->family
->family_name
, 0, NULL
, REG_OPTION_VOLATILE
,
1143 KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
))
1146 if (face
->family
->second_name
[0])
1147 RegSetValueExW( hkey_family
, NULL
, 0, REG_SZ
, (BYTE
*)face
->family
->second_name
,
1148 (lstrlenW( face
->family
->second_name
) + 1) * sizeof(WCHAR
) );
1150 if (!face
->scalable
)
1154 swprintf( name
, ARRAY_SIZE(name
), L
"%d", face
->size
.y_ppem
);
1155 RegCreateKeyExW( hkey_family
, name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
,
1156 NULL
, &hkey_face
, NULL
);
1158 else hkey_face
= hkey_family
;
1160 memset( cached
, 0, sizeof(*cached
) );
1161 cached
->index
= face
->face_index
;
1162 cached
->flags
= face
->flags
;
1163 cached
->ntmflags
= face
->ntmFlags
;
1164 cached
->version
= face
->version
;
1165 cached
->fs
= face
->fs
;
1166 if (!face
->scalable
) cached
->size
= face
->size
;
1167 lstrcpyW( cached
->full_name
, face
->full_name
);
1168 len
= lstrlenW( face
->full_name
) + 1;
1169 lstrcpyW( cached
->full_name
+ len
, face
->file
);
1170 len
+= lstrlenW( face
->file
) + 1;
1172 RegSetValueExW( hkey_face
, face
->style_name
, 0, REG_BINARY
, (BYTE
*)cached
,
1173 offsetof( struct cached_face
, full_name
[len
] ));
1175 if (hkey_face
!= hkey_family
) RegCloseKey( hkey_face
);
1176 RegCloseKey( hkey_family
);
1179 static void remove_face_from_cache( struct gdi_font_face
*face
)
1183 if (RegOpenKeyExW( wine_fonts_cache_key
, face
->family
->family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
))
1186 if (!face
->scalable
)
1189 swprintf( name
, ARRAY_SIZE(name
), L
"%d", face
->size
.y_ppem
);
1190 RegDeleteKeyW( hkey_family
, name
);
1192 else RegDeleteValueW( hkey_family
, face
->style_name
);
1194 RegCloseKey( hkey_family
);
1199 struct gdi_font_link
1203 WCHAR name
[LF_FACESIZE
];
1207 struct gdi_font_link_entry
1211 WCHAR family_name
[LF_FACESIZE
];
1214 static struct list font_links
= LIST_INIT(font_links
);
1216 static struct gdi_font_link
*find_gdi_font_link( const WCHAR
*name
)
1218 struct gdi_font_link
*link
;
1220 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1221 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 )) return link
;
1225 static struct gdi_font_family
*find_family_from_font_links( const WCHAR
*name
, const WCHAR
*subst
,
1228 struct gdi_font_link
*link
;
1229 struct gdi_font_link_entry
*entry
;
1230 struct gdi_font_family
*family
;
1232 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1234 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 ) ||
1235 (subst
&& !facename_compare( link
->name
, subst
, LF_FACESIZE
- 1 )))
1237 TRACE("found entry in system list\n");
1238 LIST_FOR_EACH_ENTRY( entry
, &link
->links
, struct gdi_font_link_entry
, entry
)
1240 const struct gdi_font_link
*links
;
1242 family
= find_family_from_name( entry
->family_name
);
1243 if (!fs
.fsCsb
[0]) return family
;
1244 if (fs
.fsCsb
[0] & entry
->fs
.fsCsb
[0]) return family
;
1245 if ((links
= find_gdi_font_link( family
->family_name
)) && fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
1253 static struct gdi_font_link
*add_gdi_font_link( const WCHAR
*name
)
1255 struct gdi_font_link
*link
= find_gdi_font_link( name
);
1257 if (link
) return link
;
1258 if ((link
= HeapAlloc( GetProcessHeap(), 0, sizeof(*link
) )))
1260 lstrcpynW( link
->name
, name
, LF_FACESIZE
);
1261 memset( &link
->fs
, 0, sizeof(link
->fs
) );
1262 list_init( &link
->links
);
1263 list_add_tail( &font_links
, &link
->entry
);
1268 static void add_gdi_font_link_entry( struct gdi_font_link
*link
, const WCHAR
*family_name
, FONTSIGNATURE fs
)
1270 struct gdi_font_link_entry
*entry
;
1272 entry
= HeapAlloc( GetProcessHeap(), 0, sizeof(*entry
) );
1273 lstrcpynW( entry
->family_name
, family_name
, LF_FACESIZE
);
1275 link
->fs
.fsCsb
[0] |= fs
.fsCsb
[0];
1276 link
->fs
.fsCsb
[1] |= fs
.fsCsb
[1];
1277 list_add_tail( &link
->links
, &entry
->entry
);
1280 static const WCHAR
* const font_links_list
[] =
1282 L
"Lucida Sans Unicode",
1283 L
"Microsoft Sans Serif",
1287 static const struct font_links_defaults_list
1289 /* Keyed off substitution for "MS Shell Dlg" */
1290 const WCHAR
*shelldlg
;
1291 /* Maximum of four substitutes, plus terminating NULL pointer */
1292 const WCHAR
*substitutes
[5];
1293 } font_links_defaults_list
[] =
1295 /* Non East-Asian */
1296 { L
"Tahoma", /* FIXME unverified ordering */
1297 { L
"MS UI Gothic", L
"SimSun", L
"Gulim", L
"PMingLiU", NULL
}
1299 /* Below lists are courtesy of
1300 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1304 { L
"MS UI Gothic", L
"PMingLiU", L
"SimSun", L
"Gulim", NULL
}
1306 /* Chinese Simplified */
1308 { L
"SimSun", L
"PMingLiU", L
"MS UI Gothic", L
"Batang", NULL
}
1312 { L
"Gulim", L
"PMingLiU", L
"MS UI Gothic", L
"SimSun", NULL
}
1314 /* Chinese Traditional */
1316 { L
"PMingLiU", L
"SimSun", L
"MS UI Gothic", L
"Batang", NULL
}
1320 static void populate_system_links( const WCHAR
*name
, const WCHAR
* const *values
)
1322 struct gdi_font_family
*family
;
1323 struct gdi_font_face
*face
;
1324 struct gdi_font_link
*font_link
;
1325 const WCHAR
*file
, *value
;
1327 /* Don't store fonts that are only substitutes for other fonts */
1328 if (get_gdi_font_subst( name
, -1, NULL
))
1330 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
) );
1333 font_link
= add_gdi_font_link( name
);
1334 for ( ; *values
; values
++)
1336 if (!facename_compare( name
, *values
, -1 )) continue;
1337 if (!(value
= get_gdi_font_subst( *values
, -1, NULL
))) value
= *values
;
1338 if (!(family
= find_family_from_name( value
))) continue;
1339 /* use first extant filename for this Family */
1340 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1342 if (!face
->file
) continue;
1343 file
= wcsrchr(face
->file
, '\\');
1344 if (!file
) file
= face
->file
;
1346 if ((face
= find_face_from_filename( file
, value
)))
1348 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1349 TRACE( "added internal SystemLink for %s to %s in %s\n",
1350 debugstr_w(name
), debugstr_w(value
), debugstr_w(file
) );
1352 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
) );
1358 static void load_system_links(void)
1362 const WCHAR
*shelldlg_name
;
1363 struct gdi_font_link
*font_link
, *system_font_link
;
1364 struct gdi_font_face
*face
;
1366 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE
,
1367 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey
))
1369 WCHAR value
[MAX_PATH
], data
[1024];
1370 DWORD type
, val_len
, data_len
;
1371 WCHAR
*entry
, *next
;
1373 val_len
= ARRAY_SIZE(value
);
1374 data_len
= sizeof(data
);
1376 while (!RegEnumValueW( hkey
, i
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
))
1378 /* Don't store fonts that are only substitutes for other fonts */
1379 if (!get_gdi_font_subst( value
, -1, NULL
))
1381 font_link
= add_gdi_font_link( value
);
1382 for (entry
= data
; (char *)entry
< (char *)data
+ data_len
&& *entry
; entry
= next
)
1384 const WCHAR
*family_name
= NULL
;
1387 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1389 next
= entry
+ lstrlenW(entry
) + 1;
1390 if ((p
= wcschr( entry
, ',' )))
1393 while (iswspace(*p
)) p
++;
1394 if (!(family_name
= get_gdi_font_subst( p
, -1, NULL
))) family_name
= p
;
1396 if ((face
= find_face_from_filename( entry
, family_name
)))
1398 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1399 TRACE("Adding file %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1401 else TRACE( "Unable to find file %s family %s\n",
1402 debugstr_w(entry
), debugstr_w(family_name
) );
1405 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1407 val_len
= ARRAY_SIZE(value
);
1408 data_len
= sizeof(data
);
1410 RegCloseKey( hkey
);
1413 if ((shelldlg_name
= get_gdi_font_subst( L
"MS Shell Dlg", -1, NULL
)))
1415 for (i
= 0; i
< ARRAY_SIZE(font_links_defaults_list
); i
++)
1417 const WCHAR
*subst
= get_gdi_font_subst( font_links_defaults_list
[i
].shelldlg
, -1, NULL
);
1419 if ((!facename_compare( font_links_defaults_list
[i
].shelldlg
, shelldlg_name
, -1 ) ||
1420 (subst
&& !facename_compare( subst
, shelldlg_name
, -1 ))))
1422 for (j
= 0; j
< ARRAY_SIZE(font_links_list
); j
++)
1423 populate_system_links( font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
1424 if (!facename_compare(shelldlg_name
, font_links_defaults_list
[i
].substitutes
[0], -1))
1425 populate_system_links( shelldlg_name
, font_links_defaults_list
[i
].substitutes
);
1429 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1431 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1434 system_font_link
= add_gdi_font_link( L
"System" );
1435 if ((face
= find_face_from_filename( L
"tahoma.ttf", L
"Tahoma" )))
1437 add_gdi_font_link_entry( system_font_link
, face
->family
->family_name
, face
->fs
);
1438 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1440 if ((font_link
= find_gdi_font_link( L
"Tahoma" )))
1442 struct gdi_font_link_entry
*entry
;
1443 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1444 add_gdi_font_link_entry( system_font_link
, entry
->family_name
, entry
->fs
);
1450 static BOOL
can_select_face( const struct gdi_font_face
*face
, FONTSIGNATURE fs
, BOOL can_use_bitmap
)
1452 struct gdi_font_link
*font_link
;
1454 if (!face
->scalable
&& !can_use_bitmap
) return FALSE
;
1455 if (!fs
.fsCsb
[0]) return TRUE
;
1456 if (fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return TRUE
;
1457 if (!(font_link
= find_gdi_font_link( face
->family
->family_name
))) return FALSE
;
1458 if (fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) return TRUE
;
1462 static struct gdi_font_face
*find_best_matching_face( const struct gdi_font_family
*family
,
1463 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1464 BOOL can_use_bitmap
)
1466 struct gdi_font_face
*face
= NULL
, *best
= NULL
, *best_bitmap
= NULL
;
1467 unsigned int best_score
= 4;
1469 int it
= !!lf
->lfItalic
;
1470 int bd
= lf
->lfWeight
> 550;
1471 int height
= lf
->lfHeight
;
1473 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1475 int italic
= !!(face
->ntmFlags
& NTM_ITALIC
);
1476 int bold
= !!(face
->ntmFlags
& NTM_BOLD
);
1477 int score
= (italic
^ it
) + (bold
^ bd
);
1479 if (!can_select_face( face
, fs
, can_use_bitmap
)) continue;
1480 if (score
> best_score
) continue;
1481 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic
, bold
, it
, bd
);
1484 if (best
->scalable
&& best_score
== 0) break;
1485 if (!best
->scalable
)
1489 diff
= height
- (signed int)best
->size
.height
;
1491 diff
= -height
- ((signed int)best
->size
.height
- best
->size
.internal_leading
);
1493 (best_diff
> 0 && diff
>= 0 && diff
< best_diff
) ||
1494 (best_diff
< 0 && diff
> best_diff
))
1496 TRACE( "%d is better for %d diff was %d\n", best
->size
.height
, height
, best_diff
);
1499 if (best_score
== 0 && best_diff
== 0) break;
1503 if (!best
) return NULL
;
1504 return best
->scalable
? best
: best_bitmap
;
1507 static struct gdi_font_face
*find_matching_face_by_name( const WCHAR
*name
, const WCHAR
*subst
,
1508 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1509 BOOL can_use_bitmap
)
1511 struct gdi_font_family
*family
;
1512 struct gdi_font_face
*face
;
1514 family
= find_family_from_any_name( name
);
1515 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1518 family
= find_family_from_any_name( subst
);
1519 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1522 /* search by full face name */
1523 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1524 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1525 if (!facename_compare( face
->full_name
, name
, LF_FACESIZE
- 1 ) &&
1526 can_select_face( face
, fs
, can_use_bitmap
))
1529 if ((family
= find_family_from_font_links( name
, subst
, fs
)))
1531 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1536 static struct gdi_font_face
*find_any_face( const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1537 BOOL can_use_bitmap
, BOOL want_vertical
)
1539 struct gdi_font_family
*family
;
1540 struct gdi_font_face
*face
;
1541 WCHAR name
[LF_FACESIZE
+ 1];
1544 /* first try the family fallbacks */
1545 while (enum_fallbacks( lf
->lfPitchAndFamily
, i
++, name
))
1549 memmove(name
+ 1, name
, min(lstrlenW(name
), LF_FACESIZE
));
1553 if (!(family
= find_family_from_any_name(name
))) continue;
1554 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1556 /* otherwise try only scalable */
1557 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1559 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1560 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1562 if (!can_use_bitmap
) return NULL
;
1563 /* then also bitmap fonts */
1564 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1566 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1567 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1572 static struct gdi_font_face
*find_matching_face( const LOGFONTW
*lf
, CHARSETINFO
*csi
, BOOL can_use_bitmap
,
1573 const WCHAR
**orig_name
)
1575 BOOL want_vertical
= (lf
->lfFaceName
[0] == '@');
1576 struct gdi_font_face
*face
;
1578 if (!TranslateCharsetInfo( (DWORD
*)(INT_PTR
)lf
->lfCharSet
, csi
, TCI_SRCCHARSET
))
1580 if (lf
->lfCharSet
!= DEFAULT_CHARSET
) FIXME( "Untranslated charset %d\n", lf
->lfCharSet
);
1581 csi
->fs
.fsCsb
[0] = 0;
1584 if (lf
->lfFaceName
[0])
1587 const WCHAR
*subst
= get_gdi_font_subst( lf
->lfFaceName
, lf
->lfCharSet
, &subst_charset
);
1591 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf
->lfFaceName
), lf
->lfCharSet
,
1592 debugstr_w(subst
), (subst_charset
!= -1) ? subst_charset
: lf
->lfCharSet
);
1593 if (subst_charset
!= -1)
1594 TranslateCharsetInfo( (DWORD
*)(INT_PTR
)subst_charset
, csi
, TCI_SRCCHARSET
);
1595 *orig_name
= lf
->lfFaceName
;
1598 if ((face
= find_matching_face_by_name( lf
->lfFaceName
, subst
, lf
, csi
->fs
, can_use_bitmap
)))
1601 *orig_name
= NULL
; /* substitution is no longer relevant */
1603 /* If requested charset was DEFAULT_CHARSET then try using charset
1604 corresponding to the current ansi codepage */
1605 if (!csi
->fs
.fsCsb
[0])
1608 if (!TranslateCharsetInfo( (DWORD
*)(INT_PTR
)acp
, csi
, TCI_SRCCODEPAGE
))
1610 FIXME( "TCI failed on codepage %d\n", acp
);
1611 csi
->fs
.fsCsb
[0] = 0;
1615 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1616 if (csi
->fs
.fsCsb
[0])
1618 csi
->fs
.fsCsb
[0] = 0;
1619 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1621 if (want_vertical
&& (face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, FALSE
))) return face
;
1625 /* realized font objects */
1627 #define FIRST_FONT_HANDLE 1
1628 #define MAX_FONT_HANDLES 256
1630 struct font_handle_entry
1632 struct gdi_font
*font
;
1633 WORD generation
; /* generation count for reusing handle values */
1636 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
1637 static struct font_handle_entry
*next_free
;
1638 static struct font_handle_entry
*next_unused
= font_handles
;
1640 static struct font_handle_entry
*handle_entry( DWORD handle
)
1642 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
1644 if (idx
< MAX_FONT_HANDLES
)
1646 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
1647 return &font_handles
[idx
];
1649 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
1653 static struct gdi_font
*get_font_from_handle( DWORD handle
)
1655 struct font_handle_entry
*entry
= handle_entry( handle
);
1657 if (entry
) return entry
->font
;
1658 SetLastError( ERROR_INVALID_PARAMETER
);
1662 static DWORD
alloc_font_handle( struct gdi_font
*font
)
1664 struct font_handle_entry
*entry
;
1668 next_free
= (struct font_handle_entry
*)entry
->font
;
1669 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
1670 entry
= next_unused
++;
1673 ERR( "out of realized font handles\n" );
1677 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
1678 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
1681 static void free_font_handle( DWORD handle
)
1683 struct font_handle_entry
*entry
;
1685 if ((entry
= handle_entry( handle
)))
1687 entry
->font
= (struct gdi_font
*)next_free
;
1692 static struct gdi_font
*alloc_gdi_font( const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
)
1694 UINT len
= file
? lstrlenW(file
) : 0;
1695 struct gdi_font
*font
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1696 offsetof( struct gdi_font
, file
[len
+ 1] ));
1699 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
1701 font
->kern_count
= -1;
1702 list_init( &font
->child_fonts
);
1706 WIN32_FILE_ATTRIBUTE_DATA info
;
1707 if (GetFileAttributesExW( file
, GetFileExInfoStandard
, &info
))
1709 font
->writetime
= info
.ftLastWriteTime
;
1710 font
->data_size
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
1711 memcpy( font
->file
, file
, len
* sizeof(WCHAR
) );
1716 font
->data_ptr
= data_ptr
;
1717 font
->data_size
= data_size
;
1720 font
->handle
= alloc_font_handle( font
);
1724 static void free_gdi_font( struct gdi_font
*font
)
1727 struct gdi_font
*child
, *child_next
;
1729 if (font
->private) font_funcs
->destroy_font( font
);
1730 free_font_handle( font
->handle
);
1731 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, struct gdi_font
, entry
)
1733 list_remove( &child
->entry
);
1734 free_gdi_font( child
);
1736 for (i
= 0; i
< font
->gm_size
; i
++) HeapFree( GetProcessHeap(), 0, font
->gm
[i
] );
1737 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFamilyName
);
1738 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpStyleName
);
1739 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFaceName
);
1740 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFullName
);
1741 HeapFree( GetProcessHeap(), 0, font
->gm
);
1742 HeapFree( GetProcessHeap(), 0, font
->kern_pairs
);
1743 HeapFree( GetProcessHeap(), 0, font
->gsub_table
);
1744 HeapFree( GetProcessHeap(), 0, font
);
1747 static inline const WCHAR
*get_gdi_font_name( struct gdi_font
*font
)
1749 return (WCHAR
*)font
->otm
.otmpFamilyName
;
1752 static struct gdi_font
*create_gdi_font( const struct gdi_font_face
*face
, const WCHAR
*family_name
,
1753 const LOGFONTW
*lf
)
1755 struct gdi_font
*font
;
1757 if (!(font
= alloc_gdi_font( face
->file
, face
->data_ptr
, face
->data_size
))) return NULL
;
1758 font
->fs
= face
->fs
;
1760 font
->fake_italic
= (lf
->lfItalic
&& !(face
->ntmFlags
& NTM_ITALIC
));
1761 font
->fake_bold
= (lf
->lfWeight
> 550 && !(face
->ntmFlags
& NTM_BOLD
));
1762 font
->scalable
= face
->scalable
;
1763 font
->face_index
= face
->face_index
;
1764 font
->ntmFlags
= face
->ntmFlags
;
1765 font
->aa_flags
= HIWORD( face
->flags
);
1766 if (!family_name
) family_name
= face
->family
->family_name
;
1767 font
->otm
.otmpFamilyName
= (char *)strdupW( family_name
);
1768 font
->otm
.otmpStyleName
= (char *)strdupW( face
->style_name
);
1769 font
->otm
.otmpFaceName
= (char *)strdupW( face
->full_name
);
1773 struct glyph_metrics
1776 ABC abc
; /* metrics of the unrotated char */
1780 #define GM_BLOCK_SIZE 128
1782 /* TODO: GGO format support */
1783 static BOOL
get_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
, GLYPHMETRICS
*gm
, ABC
*abc
)
1785 UINT block
= index
/ GM_BLOCK_SIZE
;
1786 UINT entry
= index
% GM_BLOCK_SIZE
;
1788 if (block
< font
->gm_size
&& font
->gm
[block
] && font
->gm
[block
][entry
].init
)
1790 *gm
= font
->gm
[block
][entry
].gm
;
1791 *abc
= font
->gm
[block
][entry
].abc
;
1793 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
1794 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point( &gm
->gmptGlyphOrigin
),
1795 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
1802 static void set_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
,
1803 const GLYPHMETRICS
*gm
, const ABC
*abc
)
1805 UINT block
= index
/ GM_BLOCK_SIZE
;
1806 UINT entry
= index
% GM_BLOCK_SIZE
;
1808 if (block
>= font
->gm_size
)
1810 struct glyph_metrics
**ptr
;
1813 ptr
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
, (block
+ 1) * sizeof(*ptr
) );
1815 ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, (block
+ 1) * sizeof(*ptr
) );
1817 font
->gm_size
= block
+ 1;
1820 if (!font
->gm
[block
])
1822 font
->gm
[block
] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**font
->gm
) * GM_BLOCK_SIZE
);
1823 if (!font
->gm
[block
]) return;
1825 font
->gm
[block
][entry
].gm
= *gm
;
1826 font
->gm
[block
][entry
].abc
= *abc
;
1827 font
->gm
[block
][entry
].init
= TRUE
;
1831 /* GSUB table support */
1845 } GSUB_ScriptRecord
;
1850 GSUB_ScriptRecord ScriptRecord
[1];
1857 } GSUB_LangSysRecord
;
1861 WORD DefaultLangSys
;
1863 GSUB_LangSysRecord LangSysRecord
[1];
1868 WORD LookupOrder
; /* Reserved */
1869 WORD ReqFeatureIndex
;
1871 WORD FeatureIndex
[1];
1878 } GSUB_FeatureRecord
;
1883 GSUB_FeatureRecord FeatureRecord
[1];
1888 WORD FeatureParams
; /* Reserved */
1890 WORD LookupListIndex
[1];
1909 WORD CoverageFormat
;
1912 } GSUB_CoverageFormat1
;
1918 WORD StartCoverageIndex
;
1923 WORD CoverageFormat
;
1925 GSUB_RangeRecord RangeRecord
[1];
1926 } GSUB_CoverageFormat2
;
1930 WORD SubstFormat
; /* = 1 */
1933 } GSUB_SingleSubstFormat1
;
1937 WORD SubstFormat
; /* = 2 */
1941 } GSUB_SingleSubstFormat2
;
1943 static GSUB_Script
*GSUB_get_script_table( GSUB_Header
*header
, const char *tag
)
1945 GSUB_ScriptList
*script
;
1946 GSUB_Script
*deflt
= NULL
;
1949 script
= (GSUB_ScriptList
*)((BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1950 TRACE("%i scripts in this font\n", GET_BE_WORD(script
->ScriptCount
) );
1951 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
1953 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
1954 GSUB_Script
*scr
= (GSUB_Script
*)((BYTE
*)script
+ offset
);
1955 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, tag
, 4 )) return scr
;
1956 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, "dflt", 4 )) deflt
= scr
;
1961 static GSUB_LangSys
*GSUB_get_lang_table( GSUB_Script
*script
, const char *tag
)
1966 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
1968 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
1970 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
1971 lang
= (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
1972 if (!memcmp( script
->LangSysRecord
[i
].LangSysTag
, tag
, 4 )) return lang
;
1974 offset
= GET_BE_WORD(script
->DefaultLangSys
);
1975 if (offset
) return (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
1979 static GSUB_Feature
*GSUB_get_feature( GSUB_Header
*header
, GSUB_LangSys
*lang
, const char *tag
)
1982 const GSUB_FeatureList
*feature
;
1984 feature
= (GSUB_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1985 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
1986 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
1988 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
1989 if (!memcmp( feature
->FeatureRecord
[index
].FeatureTag
, tag
, 4 ))
1990 return (GSUB_Feature
*)((BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
1995 static const char *get_opentype_script( const struct gdi_font
*font
)
1998 * I am not sure if this is the correct way to generate our script tag
2000 switch (font
->charset
)
2002 case ANSI_CHARSET
: return "latn";
2003 case BALTIC_CHARSET
: return "latn"; /* ?? */
2004 case CHINESEBIG5_CHARSET
: return "hani";
2005 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
2006 case GB2312_CHARSET
: return "hani";
2007 case GREEK_CHARSET
: return "grek";
2008 case HANGUL_CHARSET
: return "hang";
2009 case RUSSIAN_CHARSET
: return "cyrl";
2010 case SHIFTJIS_CHARSET
: return "kana";
2011 case TURKISH_CHARSET
: return "latn"; /* ?? */
2012 case VIETNAMESE_CHARSET
: return "latn";
2013 case JOHAB_CHARSET
: return "latn"; /* ?? */
2014 case ARABIC_CHARSET
: return "arab";
2015 case HEBREW_CHARSET
: return "hebr";
2016 case THAI_CHARSET
: return "thai";
2017 default: return "latn";
2021 static void *get_GSUB_vert_feature( struct gdi_font
*font
)
2023 GSUB_Header
*header
;
2024 GSUB_Script
*script
;
2025 GSUB_LangSys
*language
;
2026 GSUB_Feature
*feature
;
2027 DWORD length
= font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, NULL
, 0 );
2029 if (length
== GDI_ERROR
) return NULL
;
2031 header
= HeapAlloc( GetProcessHeap(), 0, length
);
2032 font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, header
, length
);
2033 TRACE( "Loaded GSUB table of %i bytes\n", length
);
2035 if ((script
= GSUB_get_script_table( header
, get_opentype_script(font
) )))
2037 if ((language
= GSUB_get_lang_table( script
, "xxxx" ))) /* Need to get Lang tag */
2039 feature
= GSUB_get_feature( header
, language
, "vrt2" );
2040 if (!feature
) feature
= GSUB_get_feature( header
, language
, "vert" );
2043 font
->gsub_table
= header
;
2046 TRACE("vrt2/vert feature not found\n");
2048 else TRACE("Language not found\n");
2050 else TRACE("Script not found\n");
2052 HeapFree( GetProcessHeap(), 0, header
);
2056 static int GSUB_is_glyph_covered( void *table
, UINT glyph
)
2058 GSUB_CoverageFormat1
*cf1
= table
;
2060 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
2062 int i
, count
= GET_BE_WORD(cf1
->GlyphCount
);
2064 TRACE("Coverage Format 1, %i glyphs\n",count
);
2065 for (i
= 0; i
< count
; i
++) if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
])) return i
;
2068 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
2071 GSUB_CoverageFormat2
*cf2
= table
;
2073 count
= GET_BE_WORD(cf2
->RangeCount
);
2074 TRACE("Coverage Format 2, %i ranges\n",count
);
2075 for (i
= 0; i
< count
; i
++)
2077 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) return -1;
2078 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
2079 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
2081 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
2082 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
2087 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
2092 static UINT
GSUB_apply_feature( GSUB_Header
*header
, GSUB_Feature
*feature
, UINT glyph
)
2094 GSUB_LookupList
*lookup
= (GSUB_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2097 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
2098 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
2100 GSUB_LookupTable
*look
;
2101 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
2102 look
= (GSUB_LookupTable
*)((BYTE
*)lookup
+ offset
);
2103 TRACE("type %i, flag %x, subtables %i\n",
2104 GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
2105 if (GET_BE_WORD(look
->LookupType
) == 1)
2107 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
2109 GSUB_SingleSubstFormat1
*ssf1
;
2110 offset
= GET_BE_WORD(look
->SubTable
[j
]);
2111 ssf1
= (GSUB_SingleSubstFormat1
*)((BYTE
*)look
+ offset
);
2112 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
2114 int offset
= GET_BE_WORD(ssf1
->Coverage
);
2115 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
2116 if (GSUB_is_glyph_covered( (BYTE
*) ssf1
+ offset
, glyph
) != -1)
2118 TRACE(" Glyph 0x%x ->",glyph
);
2119 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
2120 TRACE(" 0x%x\n",glyph
);
2125 GSUB_SingleSubstFormat2
*ssf2
;
2128 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
2129 offset
= GET_BE_WORD(ssf1
->Coverage
);
2130 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
2131 index
= GSUB_is_glyph_covered( (BYTE
*)ssf2
+ offset
, glyph
);
2132 TRACE(" Coverage index %i\n",index
);
2135 TRACE(" Glyph is 0x%x ->",glyph
);
2136 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
2137 TRACE("0x%x\n",glyph
);
2142 else FIXME("We only handle SubType 1\n");
2147 static UINT
get_GSUB_vert_glyph( struct gdi_font
*font
, UINT glyph
)
2149 if (!glyph
) return glyph
;
2150 if (!font
->gsub_table
) return glyph
;
2151 return GSUB_apply_feature( font
->gsub_table
, font
->vert_feature
, glyph
);
2154 static void add_child_font( struct gdi_font
*font
, const WCHAR
*family_name
)
2156 FONTSIGNATURE fs
= {{0}};
2157 struct gdi_font
*child
;
2158 struct gdi_font_face
*face
;
2160 if (!(face
= find_matching_face_by_name( family_name
, NULL
, &font
->lf
, fs
, FALSE
))) return;
2162 if (!(child
= create_gdi_font( face
, family_name
, &font
->lf
))) return;
2163 child
->matrix
= font
->matrix
;
2164 child
->can_use_bitmap
= font
->can_use_bitmap
;
2165 child
->scale_y
= font
->scale_y
;
2166 child
->aveWidth
= font
->aveWidth
;
2167 child
->charset
= font
->charset
;
2168 child
->codepage
= font
->codepage
;
2169 child
->base_font
= font
;
2170 list_add_tail( &font
->child_fonts
, &child
->entry
);
2171 TRACE( "created child font %p for base %p\n", child
, font
);
2174 static void create_child_font_list( struct gdi_font
*font
)
2176 struct gdi_font_link
*font_link
;
2177 struct gdi_font_link_entry
*entry
;
2178 const WCHAR
* font_name
;
2180 if (!(font_name
= get_gdi_font_subst( get_gdi_font_name(font
), -1, NULL
)))
2181 font_name
= get_gdi_font_name( font
);
2183 if ((font_link
= find_gdi_font_link( font_name
)))
2185 TRACE("found entry in system list\n");
2186 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2187 add_child_font( font
, entry
->family_name
);
2190 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2191 * Sans Serif. This is how asian windows get default fallbacks for fonts
2193 if (is_dbcs_ansi_cp(GetACP()) && font
->charset
!= SYMBOL_CHARSET
&& font
->charset
!= OEM_CHARSET
&&
2194 facename_compare( font_name
, L
"Microsoft Sans Serif", -1 ) != 0)
2196 if ((font_link
= find_gdi_font_link( L
"Microsoft Sans Serif" )))
2198 TRACE("found entry in default fallback list\n");
2199 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2200 add_child_font( font
, entry
->family_name
);
2207 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
2208 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
2209 static unsigned int unused_font_count
;
2210 #define UNUSED_CACHE_SIZE 10
2212 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
2213 const FMAT2
*matrix
, BOOL can_use_bitmap
)
2215 if (font
->hash
!= hash
) return TRUE
;
2216 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
2217 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2218 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
2219 return facename_compare( font
->lf
.lfFaceName
, lf
->lfFaceName
, -1 );
2222 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2224 DWORD hash
= 0, *ptr
, two_chars
;
2228 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
2230 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
2232 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
2235 pwc
= (WCHAR
*)&two_chars
;
2237 *pwc
= towupper(*pwc
);
2239 *pwc
= towupper(*pwc
);
2243 hash
^= !can_use_bitmap
;
2247 static void cache_gdi_font( struct gdi_font
*font
)
2249 static DWORD cache_num
= 1;
2251 font
->cache_num
= cache_num
++;
2252 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
2253 list_add_head( &gdi_font_list
, &font
->entry
);
2254 TRACE( "font %p\n", font
);
2257 static struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2259 struct gdi_font
*font
;
2260 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
2262 /* try the in-use list */
2263 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
2265 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
2266 list_remove( &font
->entry
);
2267 list_add_head( &gdi_font_list
, &font
->entry
);
2268 if (!font
->refcount
++)
2270 list_remove( &font
->unused_entry
);
2271 unused_font_count
--;
2278 static void release_gdi_font( struct gdi_font
*font
)
2281 if (--font
->refcount
) return;
2283 TRACE( "font %p\n", font
);
2285 /* add it to the unused list */
2286 EnterCriticalSection( &font_cs
);
2287 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
2288 if (unused_font_count
> UNUSED_CACHE_SIZE
)
2290 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
2291 TRACE( "freeing %p\n", font
);
2292 list_remove( &font
->entry
);
2293 list_remove( &font
->unused_entry
);
2294 free_gdi_font( font
);
2296 else unused_font_count
++;
2297 LeaveCriticalSection( &font_cs
);
2300 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
2302 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
2304 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2305 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2306 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
2307 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2310 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2313 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2315 RegDeleteValueA(hkey
, name
);
2318 static void update_font_association_info(UINT current_ansi_codepage
)
2320 if (is_dbcs_ansi_cp(current_ansi_codepage
))
2323 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\FontAssoc", &hkey
) == ERROR_SUCCESS
)
2326 if (RegCreateKeyW(hkey
, L
"Associated Charset", &hsubkey
) == ERROR_SUCCESS
)
2328 switch (current_ansi_codepage
)
2331 set_value_key(hsubkey
, "ANSI(00)", "NO");
2332 set_value_key(hsubkey
, "OEM(FF)", "NO");
2333 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2338 set_value_key(hsubkey
, "ANSI(00)", "YES");
2339 set_value_key(hsubkey
, "OEM(FF)", "YES");
2340 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2343 RegCloseKey(hsubkey
);
2346 /* TODO: Associated DefaultFonts */
2352 RegDeleteTreeW(HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\FontAssoc");
2355 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
2358 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
2360 RegDeleteValueW(hkey
, name
);
2363 static void update_font_system_link_info(UINT current_ansi_codepage
)
2365 static const WCHAR system_link_simplified_chinese
[] =
2366 L
"SIMSUN.TTC,SimSun\0"
2367 L
"MINGLIU.TTC,PMingLiu\0"
2368 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2369 L
"BATANG.TTC,Batang\0";
2370 static const WCHAR system_link_traditional_chinese
[] =
2371 L
"MINGLIU.TTC,PMingLiu\0"
2372 L
"SIMSUN.TTC,SimSun\0"
2373 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2374 L
"BATANG.TTC,Batang\0";
2375 static const WCHAR system_link_japanese
[] =
2376 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2377 L
"MINGLIU.TTC,PMingLiU\0"
2378 L
"SIMSUN.TTC,SimSun\0"
2379 L
"GULIM.TTC,Gulim\0";
2380 static const WCHAR system_link_korean
[] =
2381 L
"GULIM.TTC,Gulim\0"
2382 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2383 L
"MINGLIU.TTC,PMingLiU\0"
2384 L
"SIMSUN.TTC,SimSun\0";
2385 static const WCHAR system_link_non_cjk
[] =
2386 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2387 L
"MINGLIU.TTC,PMingLiU\0"
2388 L
"SIMSUN.TTC,SimSun\0"
2389 L
"GULIM.TTC,Gulim\0";
2392 if (!RegCreateKeyW(HKEY_LOCAL_MACHINE
,
2393 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey
))
2398 switch (current_ansi_codepage
)
2401 link
= system_link_japanese
;
2402 len
= sizeof(system_link_japanese
);
2405 link
= system_link_simplified_chinese
;
2406 len
= sizeof(system_link_simplified_chinese
);
2409 link
= system_link_korean
;
2410 len
= sizeof(system_link_korean
);
2413 link
= system_link_traditional_chinese
;
2414 len
= sizeof(system_link_traditional_chinese
);
2417 link
= system_link_non_cjk
;
2418 len
= sizeof(system_link_non_cjk
);
2420 set_multi_value_key(hkey
, L
"Lucida Sans Unicode", link
, len
);
2421 set_multi_value_key(hkey
, L
"Microsoft Sans Serif", link
, len
);
2422 set_multi_value_key(hkey
, L
"Tahoma", link
, len
);
2427 static void update_codepage(void)
2429 char buf
[40], cpbuf
[40];
2431 DWORD len
, type
, size
;
2432 UINT i
, ansi_cp
, oem_cp
;
2433 DWORD screen_dpi
, font_dpi
= 0;
2436 screen_dpi
= get_dpi();
2437 if (!screen_dpi
) screen_dpi
= 96;
2439 size
= sizeof(DWORD
);
2440 if (RegQueryValueExW(wine_fonts_key
, L
"LogPixels", NULL
, &type
, (BYTE
*)&font_dpi
, &size
) ||
2441 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
2445 oem_cp
= GetOEMCP();
2446 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2450 if (!RegQueryValueExA(wine_fonts_key
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) && type
== REG_SZ
)
2452 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) return; /* already set correctly */
2453 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2454 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
2456 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2457 ansi_cp
, oem_cp
, screen_dpi
);
2459 RegSetValueExA(wine_fonts_key
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2460 RegSetValueExW(wine_fonts_key
, L
"LogPixels", 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
2462 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
2464 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&& nls_update_font_list
[i
].oem_cp
== oem_cp
)
2466 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG
, L
"Software\\Fonts", &hkey
))
2468 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
,
2469 strlen(nls_update_font_list
[i
].oem
)+1);
2470 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
,
2471 strlen(nls_update_font_list
[i
].fixed
)+1);
2472 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
,
2473 strlen(nls_update_font_list
[i
].system
)+1);
2476 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
,
2477 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey
))
2479 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2482 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
,
2483 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey
))
2485 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2488 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
,
2489 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2491 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2492 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2493 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2494 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2496 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2497 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2498 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2499 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2500 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2501 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2502 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2503 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2505 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2506 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2507 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2515 /* Delete the FontSubstitutes from other locales */
2516 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2518 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2519 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2520 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2526 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2528 /* update locale dependent font association info and font system link info in registry.
2529 update only when codepages changed, not logpixels. */
2530 if (strcmp(buf
, cpbuf
) != 0)
2532 update_font_association_info(ansi_cp
);
2533 update_font_system_link_info(ansi_cp
);
2538 /*************************************************************
2541 static BOOL CDECL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
2542 LPCWSTR output
, const DEVMODEW
*devmode
)
2544 struct font_physdev
*physdev
;
2546 if (!font_funcs
) return TRUE
;
2547 if (!(physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) ))) return FALSE
;
2548 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
2553 /*************************************************************
2556 static BOOL CDECL
font_DeleteDC( PHYSDEV dev
)
2558 struct font_physdev
*physdev
= get_font_dev( dev
);
2560 release_gdi_font( physdev
->font
);
2561 HeapFree( GetProcessHeap(), 0, physdev
);
2566 struct gdi_font_enum_data
2569 NEWTEXTMETRICEXW ntm
;
2579 static int load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
2586 id
+= IDS_FIRST_SCRIPT
;
2587 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
2588 if (!rsrc
) return 0;
2589 hMem
= LoadResource( gdi32_module
, rsrc
);
2590 if (!hMem
) return 0;
2592 p
= LockResource( hMem
);
2594 while (id
--) p
+= *p
+ 1;
2596 i
= min(LF_FACESIZE
- 1, *p
);
2597 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
2602 static BOOL
is_complex_script_ansi_cp( UINT ansi_cp
)
2604 return (ansi_cp
== 874 /* Thai */
2605 || ansi_cp
== 1255 /* Hebrew */
2606 || ansi_cp
== 1256 /* Arabic */
2610 /***************************************************
2611 * create_enum_charset_list
2613 * This function creates charset enumeration list because in DEFAULT_CHARSET
2614 * case, the ANSI codepage's charset takes precedence over other charsets.
2615 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2616 * This function works as a filter other than DEFAULT_CHARSET case.
2618 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset
*list
)
2620 struct enum_charset
*start
= list
;
2624 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) && csi
.fs
.fsCsb
[0] != 0)
2626 list
->mask
= csi
.fs
.fsCsb
[0];
2627 list
->charset
= csi
.ciCharset
;
2628 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2631 else /* charset is DEFAULT_CHARSET or invalid. */
2636 /* Set the current codepage's charset as the first element. */
2637 if (!is_complex_script_ansi_cp(acp
) &&
2638 TranslateCharsetInfo( (DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
2639 csi
.fs
.fsCsb
[0] != 0)
2641 list
->mask
= csi
.fs
.fsCsb
[0];
2642 list
->charset
= csi
.ciCharset
;
2643 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2644 mask
|= csi
.fs
.fsCsb
[0];
2648 /* Fill out left elements. */
2649 for (i
= 0; i
< 32; i
++)
2652 fs
.fsCsb
[0] = 1u << i
;
2654 if (fs
.fsCsb
[0] & mask
) continue; /* skip, already added. */
2655 if (!TranslateCharsetInfo( fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
2656 continue; /* skip, this is an invalid fsCsb bit. */
2657 list
->mask
= fs
.fsCsb
[0];
2658 list
->charset
= csi
.ciCharset
;
2660 mask
|= fs
.fsCsb
[0];
2663 /* add catch all mask for remaining bits */
2667 list
->charset
= DEFAULT_CHARSET
;
2668 list
->script
= IDS_OTHER
- IDS_FIRST_SCRIPT
;
2672 return list
- start
;
2675 static UINT
get_font_type( const NEWTEXTMETRICEXW
*ntm
)
2679 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ret
|= TRUETYPE_FONTTYPE
;
2680 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
) ret
|= DEVICE_FONTTYPE
;
2681 if (!(ntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
)) ret
|= RASTER_FONTTYPE
;
2685 static BOOL
get_face_enum_data( struct gdi_font_face
*face
, ENUMLOGFONTEXW
*elf
, NEWTEXTMETRICEXW
*ntm
)
2687 struct gdi_font
*font
;
2688 LOGFONTW lf
= { .lfHeight
= -4096 /* preferable EM Square size */ };
2690 if (!face
->scalable
) lf
.lfHeight
= 0;
2692 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2694 if (!font_funcs
->load_font( font
))
2696 free_gdi_font( font
);
2700 if (font
->scalable
&& -lf
.lfHeight
% font
->otm
.otmEMSquare
!= 0)
2702 /* reload with the original EM Square size */
2703 lf
.lfHeight
= -font
->otm
.otmEMSquare
;
2704 free_gdi_font( font
);
2706 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2707 if (!font_funcs
->load_font( font
))
2709 free_gdi_font( font
);
2714 if (font_funcs
->set_outline_text_metrics( font
))
2716 static const DWORD ntm_ppem
= 32;
2719 #define TM font->otm.otmTextMetrics
2720 #define SCALE_NTM(value) (MulDiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
2721 cell_height
= TM
.tmHeight
/ ( -lf
.lfHeight
/ font
->otm
.otmEMSquare
);
2722 ntm
->ntmTm
.tmHeight
= MulDiv( ntm_ppem
, cell_height
, font
->otm
.otmEMSquare
);
2723 ntm
->ntmTm
.tmAscent
= SCALE_NTM( TM
.tmAscent
);
2724 ntm
->ntmTm
.tmDescent
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmAscent
;
2725 ntm
->ntmTm
.tmInternalLeading
= SCALE_NTM( TM
.tmInternalLeading
);
2726 ntm
->ntmTm
.tmExternalLeading
= SCALE_NTM( TM
.tmExternalLeading
);
2727 ntm
->ntmTm
.tmAveCharWidth
= SCALE_NTM( TM
.tmAveCharWidth
);
2728 ntm
->ntmTm
.tmMaxCharWidth
= SCALE_NTM( TM
.tmMaxCharWidth
);
2730 memcpy((char *)&ntm
->ntmTm
+ offsetof( TEXTMETRICW
, tmWeight
),
2731 (const char *)&TM
+ offsetof( TEXTMETRICW
, tmWeight
),
2732 sizeof(TEXTMETRICW
) - offsetof( TEXTMETRICW
, tmWeight
));
2733 ntm
->ntmTm
.ntmSizeEM
= font
->otm
.otmEMSquare
;
2734 ntm
->ntmTm
.ntmCellHeight
= cell_height
;
2735 ntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
2739 else if (font_funcs
->set_bitmap_text_metrics( font
))
2741 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
2742 ntm
->ntmTm
.ntmSizeEM
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmInternalLeading
;
2743 ntm
->ntmTm
.ntmCellHeight
= ntm
->ntmTm
.tmHeight
;
2744 ntm
->ntmTm
.ntmAvgWidth
= ntm
->ntmTm
.tmAveCharWidth
;
2746 ntm
->ntmTm
.ntmFlags
= font
->ntmFlags
;
2747 ntm
->ntmFontSig
= font
->fs
;
2749 elf
->elfLogFont
.lfEscapement
= 0;
2750 elf
->elfLogFont
.lfOrientation
= 0;
2751 elf
->elfLogFont
.lfHeight
= ntm
->ntmTm
.tmHeight
;
2752 elf
->elfLogFont
.lfWidth
= ntm
->ntmTm
.tmAveCharWidth
;
2753 elf
->elfLogFont
.lfWeight
= ntm
->ntmTm
.tmWeight
;
2754 elf
->elfLogFont
.lfItalic
= ntm
->ntmTm
.tmItalic
;
2755 elf
->elfLogFont
.lfUnderline
= ntm
->ntmTm
.tmUnderlined
;
2756 elf
->elfLogFont
.lfStrikeOut
= ntm
->ntmTm
.tmStruckOut
;
2757 elf
->elfLogFont
.lfCharSet
= ntm
->ntmTm
.tmCharSet
;
2758 elf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2759 elf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2760 elf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2761 elf
->elfLogFont
.lfPitchAndFamily
= (ntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
2762 lstrcpynW( elf
->elfLogFont
.lfFaceName
, (WCHAR
*)font
->otm
.otmpFamilyName
, LF_FACESIZE
);
2763 lstrcpynW( elf
->elfFullName
, (WCHAR
*)font
->otm
.otmpFaceName
, LF_FULLFACESIZE
);
2764 lstrcpynW( elf
->elfStyle
, (WCHAR
*)font
->otm
.otmpStyleName
, LF_FACESIZE
);
2766 free_gdi_font( font
);
2770 static BOOL
family_matches( struct gdi_font_family
*family
, const WCHAR
*face_name
)
2772 struct gdi_font_face
*face
;
2774 if (!facename_compare( face_name
, family
->family_name
, LF_FACESIZE
- 1 )) return TRUE
;
2775 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2776 if (!facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 )) return TRUE
;
2780 static BOOL
face_matches( const WCHAR
*family_name
, struct gdi_font_face
*face
, const WCHAR
*face_name
)
2782 if (!facename_compare( face_name
, family_name
, LF_FACESIZE
- 1)) return TRUE
;
2783 return !facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 );
2786 static BOOL
enum_face_charsets( const struct gdi_font_family
*family
, struct gdi_font_face
*face
,
2787 struct enum_charset
*list
, DWORD count
, FONTENUMPROCW proc
, LPARAM lparam
,
2788 const WCHAR
*subst
)
2791 NEWTEXTMETRICEXW ntm
;
2794 if (!face
->cached_enum_data
)
2796 struct gdi_font_enum_data
*data
;
2798 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) )) ||
2799 !get_face_enum_data( face
, &data
->elf
, &data
->ntm
))
2801 HeapFree( GetProcessHeap(), 0, data
);
2804 face
->cached_enum_data
= data
;
2807 elf
= face
->cached_enum_data
->elf
;
2808 ntm
= face
->cached_enum_data
->ntm
;
2809 type
= get_font_type( &ntm
);
2811 /* font replacement */
2812 if (family
!= face
->family
)
2814 lstrcpynW( elf
.elfLogFont
.lfFaceName
, family
->family_name
, LF_FACESIZE
);
2815 lstrcpynW( elf
.elfFullName
, face
->full_name
, LF_FULLFACESIZE
);
2817 if (subst
) lstrcpynW( elf
.elfLogFont
.lfFaceName
, subst
, LF_FACESIZE
);
2819 for (i
= 0; i
< count
; i
++)
2821 if (!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) /* OEM bitmap */
2823 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2824 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
2825 i
= count
; /* break out of loop after enumeration */
2829 if (!(face
->fs
.fsCsb
[0] & list
[i
].mask
)) continue;
2830 /* use the DEFAULT_CHARSET case only if no other charset is present */
2831 if (list
[i
].charset
== DEFAULT_CHARSET
&& (face
->fs
.fsCsb
[0] & ~list
[i
].mask
)) continue;
2832 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
[i
].charset
;
2833 load_script_name( list
[i
].script
, elf
.elfScript
);
2834 if (!elf
.elfScript
[0]) FIXME("Unknown elfscript for id %u\n", list
[i
].script
);
2836 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2837 debugstr_w(elf
.elfLogFont
.lfFaceName
), debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2838 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
2839 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
, ntm
.ntmTm
.ntmFlags
);
2840 /* release section before callback (FIXME) */
2841 LeaveCriticalSection( &font_cs
);
2842 if (!proc( &elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
2843 EnterCriticalSection( &font_cs
);
2848 /*************************************************************
2851 static BOOL CDECL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, FONTENUMPROCW proc
, LPARAM lparam
)
2853 struct gdi_font_family
*family
;
2854 struct gdi_font_face
*face
;
2855 struct enum_charset enum_charsets
[32];
2856 DWORD count
, charset
;
2858 charset
= lf
? lf
->lfCharSet
: DEFAULT_CHARSET
;
2860 count
= create_enum_charset_list( charset
, enum_charsets
);
2862 EnterCriticalSection( &font_cs
);
2864 if (lf
&& lf
->lfFaceName
[0])
2866 const WCHAR
*face_name
= get_gdi_font_subst( lf
->lfFaceName
, charset
, NULL
);
2867 const WCHAR
*orig_name
= NULL
;
2869 TRACE( "facename = %s charset %d\n", debugstr_w(lf
->lfFaceName
), charset
);
2872 orig_name
= lf
->lfFaceName
;
2873 TRACE( "substituting %s -> %s\n", debugstr_w(lf
->lfFaceName
), debugstr_w(face_name
) );
2875 else face_name
= lf
->lfFaceName
;
2877 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2879 if (!family_matches(family
, face_name
)) continue;
2880 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2882 if (!face_matches( family
->family_name
, face
, face_name
)) continue;
2883 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, orig_name
))
2890 TRACE( "charset %d\n", charset
);
2891 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2893 face
= LIST_ENTRY( list_head(get_family_face_list(family
)), struct gdi_font_face
, entry
);
2894 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, NULL
))
2898 LeaveCriticalSection( &font_cs
);
2903 static BOOL
check_unicode_tategaki( WCHAR ch
)
2905 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
2906 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[ch
>> 8]+((ch
>> 4) & 0x0f)]+ (ch
& 0xf)];
2908 /* We only reach this code if typographical substitution did not occur */
2909 /* Type: U or Type: Tu */
2910 return (orientation
== 1 || orientation
== 3);
2913 static UINT
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2917 if (glyph
< 0x100) glyph
+= 0xf000;
2918 /* there are a number of old pre-Unicode "broken" TTFs, which
2919 do have symbols at U+00XX instead of U+f0XX */
2921 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2924 index
= glyph
- 0xf000;
2925 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2930 static UINT
get_glyph_index( struct gdi_font
*font
, UINT glyph
)
2936 if (font_funcs
->get_glyph_index( font
, &glyph
, TRUE
)) return glyph
;
2938 if (font
->codepage
== CP_SYMBOL
)
2940 glyph
= get_glyph_index_symbol( font
, wc
);
2943 if (WideCharToMultiByte( CP_ACP
, WC_NO_BEST_FIT_CHARS
, &wc
, 1, &ch
, 1, NULL
, NULL
))
2944 glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2947 else if (WideCharToMultiByte( font
->codepage
, WC_NO_BEST_FIT_CHARS
, &wc
, 1, &ch
, 1, NULL
, &used
) && !used
)
2949 glyph
= (unsigned char)ch
;
2950 font_funcs
->get_glyph_index( font
, &glyph
, FALSE
);
2957 static UINT
get_glyph_index_linked( struct gdi_font
**font
, UINT glyph
)
2959 struct gdi_font
*child
;
2962 if ((res
= get_glyph_index( *font
, glyph
))) return res
;
2963 if (glyph
< 32) return 0; /* don't check linked fonts for control characters */
2965 LIST_FOR_EACH_ENTRY( child
, &(*font
)->child_fonts
, struct gdi_font
, entry
)
2967 if (!child
->private && !font_funcs
->load_font( child
)) continue;
2968 if ((res
= get_glyph_index( child
, glyph
)))
2977 static DWORD
get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
2978 GLYPHMETRICS
*gm_ret
, ABC
*abc_ret
, DWORD buflen
, void *buf
,
2985 BOOL tategaki
= (*get_gdi_font_name( font
) == '@');
2987 if (format
& GGO_GLYPH_INDEX
)
2989 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
2990 as glyph index. "Treasure Adventure Game" depends on this. */
2991 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2992 format
&= ~GGO_GLYPH_INDEX
;
2993 /* TODO: Window also turns off tategaki for glyphs passed in by index
2994 if their unicode code points fall outside of the range that is
2999 index
= get_glyph_index_linked( &font
, glyph
);
3003 index
= get_GSUB_vert_glyph( font
, index
);
3004 if (index
== orig
) tategaki
= check_unicode_tategaki( glyph
);
3008 if (mat
&& !memcmp( mat
, &identity
, sizeof(*mat
) )) mat
= NULL
;
3010 if (format
== GGO_METRICS
&& !mat
&& get_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
))
3013 ret
= font_funcs
->get_glyph_outline( font
, index
, format
, &gm
, &abc
, buflen
, buf
, mat
, tategaki
);
3014 if (ret
== GDI_ERROR
) return ret
;
3016 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) && !mat
)
3017 set_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
);
3020 if (gm_ret
) *gm_ret
= gm
;
3021 if (abc_ret
) *abc_ret
= abc
;
3026 /*************************************************************
3029 static BOOL CDECL
font_FontIsLinked( PHYSDEV dev
)
3031 struct font_physdev
*physdev
= get_font_dev( dev
);
3035 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
3036 return dev
->funcs
->pFontIsLinked( dev
);
3038 return !list_empty( &physdev
->font
->child_fonts
);
3042 /*************************************************************
3043 * font_GetCharABCWidths
3045 static BOOL CDECL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT last
, ABC
*buffer
)
3047 struct font_physdev
*physdev
= get_font_dev( dev
);
3052 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
3053 return dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, buffer
);
3056 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, last
, buffer
);
3058 EnterCriticalSection( &font_cs
);
3059 for (c
= first
; c
<= last
; c
++, buffer
++)
3060 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, buffer
, 0, NULL
, NULL
);
3061 LeaveCriticalSection( &font_cs
);
3066 /*************************************************************
3067 * font_GetCharABCWidthsI
3069 static BOOL CDECL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
3071 struct font_physdev
*physdev
= get_font_dev( dev
);
3076 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
3077 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
3080 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3082 EnterCriticalSection( &font_cs
);
3083 for (c
= 0; c
< count
; c
++, buffer
++)
3084 get_glyph_outline( physdev
->font
, gi
? gi
[c
] : first
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3085 NULL
, buffer
, 0, NULL
, NULL
);
3086 LeaveCriticalSection( &font_cs
);
3091 /*************************************************************
3094 static BOOL CDECL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT last
, INT
*buffer
)
3096 struct font_physdev
*physdev
= get_font_dev( dev
);
3102 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
3103 return dev
->funcs
->pGetCharWidth( dev
, first
, last
, buffer
);
3106 TRACE( "%p, %d, %d, %p\n", physdev
->font
, first
, last
, buffer
);
3108 EnterCriticalSection( &font_cs
);
3109 for (c
= first
; c
<= last
; c
++)
3111 if (get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
) == GDI_ERROR
)
3112 buffer
[c
- first
] = 0;
3114 buffer
[c
- first
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3116 LeaveCriticalSection( &font_cs
);
3121 /*************************************************************
3122 * font_GetCharWidthInfo
3124 static BOOL CDECL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
3126 struct font_physdev
*physdev
= get_font_dev( dev
);
3127 struct char_width_info
*info
= ptr
;
3131 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
3132 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
3136 if (!physdev
->font
->scalable
|| !font_funcs
->get_char_width_info( physdev
->font
, info
))
3137 info
->lsb
= info
->rsb
= 0;
3143 /*************************************************************
3146 static DWORD CDECL
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
3148 struct font_physdev
*physdev
= get_font_dev( dev
);
3152 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
3153 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
3155 return font_funcs
->get_font_data( physdev
->font
, table
, offset
, buf
, size
);
3159 /*************************************************************
3160 * font_GetFontRealizationInfo
3162 static BOOL CDECL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
3164 struct font_physdev
*physdev
= get_font_dev( dev
);
3165 struct font_realization_info
*info
= ptr
;
3169 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
3170 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
3173 TRACE( "(%p, %p)\n", physdev
->font
, info
);
3176 if (physdev
->font
->scalable
) info
->flags
|= 2;
3178 info
->cache_num
= physdev
->font
->cache_num
;
3179 info
->instance_id
= physdev
->font
->handle
;
3180 if (info
->size
== sizeof(*info
))
3183 info
->face_index
= physdev
->font
->face_index
;
3184 info
->simulations
= 0;
3185 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
3186 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
3192 /*************************************************************
3193 * font_GetFontUnicodeRanges
3195 static DWORD CDECL
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
3197 struct font_physdev
*physdev
= get_font_dev( dev
);
3198 DWORD size
, num_ranges
;
3202 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
3203 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
3206 num_ranges
= font_funcs
->get_unicode_ranges( physdev
->font
, glyphset
);
3207 size
= offsetof( GLYPHSET
, ranges
[num_ranges
] );
3210 glyphset
->cbThis
= size
;
3211 glyphset
->cRanges
= num_ranges
;
3212 glyphset
->flAccel
= 0;
3218 /*************************************************************
3219 * font_GetGlyphIndices
3221 static DWORD CDECL
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
3223 struct font_physdev
*physdev
= get_font_dev( dev
);
3226 BOOL used
, got_default
= FALSE
;
3231 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
3232 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
3235 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
3237 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
3241 EnterCriticalSection( &font_cs
);
3243 for (i
= 0; i
< count
; i
++)
3245 UINT glyph
= str
[i
];
3247 if (!font_funcs
->get_glyph_index( physdev
->font
, &glyph
, TRUE
))
3250 if (physdev
->font
->codepage
== CP_SYMBOL
)
3252 if (str
[i
] >= 0xf020 && str
[i
] <= 0xf100) glyph
= str
[i
] - 0xf000;
3253 else if (str
[i
] < 0x100) glyph
= str
[i
];
3255 else if (WideCharToMultiByte( physdev
->font
->codepage
, WC_NO_BEST_FIT_CHARS
, &str
[i
], 1,
3256 &ch
, 1, NULL
, &used
) && !used
)
3257 glyph
= (unsigned char)ch
;
3263 default_char
= font_funcs
->get_default_glyph( physdev
->font
);
3266 gi
[i
] = default_char
;
3268 else gi
[i
] = get_GSUB_vert_glyph( physdev
->font
, glyph
);
3271 LeaveCriticalSection( &font_cs
);
3276 /*************************************************************
3277 * font_GetGlyphOutline
3279 static DWORD CDECL
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
3280 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
3282 struct font_physdev
*physdev
= get_font_dev( dev
);
3287 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
3288 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
3290 EnterCriticalSection( &font_cs
);
3291 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, gm
, NULL
, buflen
, buf
, mat
);
3292 LeaveCriticalSection( &font_cs
);
3297 /*************************************************************
3298 * font_GetKerningPairs
3300 static DWORD CDECL
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
3302 struct font_physdev
*physdev
= get_font_dev( dev
);
3306 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
3307 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
3310 EnterCriticalSection( &font_cs
);
3311 if (physdev
->font
->kern_count
== -1)
3312 physdev
->font
->kern_count
= font_funcs
->get_kerning_pairs( physdev
->font
,
3313 &physdev
->font
->kern_pairs
);
3314 LeaveCriticalSection( &font_cs
);
3318 count
= min( count
, physdev
->font
->kern_count
);
3319 memcpy( pairs
, physdev
->font
->kern_pairs
, count
* sizeof(*pairs
) );
3321 else count
= physdev
->font
->kern_count
;
3327 static void scale_outline_font_metrics( const struct gdi_font
*font
, OUTLINETEXTMETRICW
*otm
)
3329 double scale_x
, scale_y
;
3333 scale_x
= (double)font
->aveWidth
;
3334 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3337 scale_x
= font
->scale_y
;
3339 scale_x
*= fabs(font
->matrix
.eM11
);
3340 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3342 /* Windows scales these values as signed integers even if they are unsigned */
3343 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3344 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3346 SCALE_Y(otm
->otmTextMetrics
.tmHeight
);
3347 SCALE_Y(otm
->otmTextMetrics
.tmAscent
);
3348 SCALE_Y(otm
->otmTextMetrics
.tmDescent
);
3349 SCALE_Y(otm
->otmTextMetrics
.tmInternalLeading
);
3350 SCALE_Y(otm
->otmTextMetrics
.tmExternalLeading
);
3352 SCALE_X(otm
->otmTextMetrics
.tmOverhang
);
3353 if (font
->fake_bold
)
3355 if (!font
->scalable
) otm
->otmTextMetrics
.tmOverhang
++;
3356 otm
->otmTextMetrics
.tmAveCharWidth
++;
3357 otm
->otmTextMetrics
.tmMaxCharWidth
++;
3359 SCALE_X(otm
->otmTextMetrics
.tmAveCharWidth
);
3360 SCALE_X(otm
->otmTextMetrics
.tmMaxCharWidth
);
3362 SCALE_Y(otm
->otmAscent
);
3363 SCALE_Y(otm
->otmDescent
);
3364 SCALE_Y(otm
->otmLineGap
);
3365 SCALE_Y(otm
->otmsCapEmHeight
);
3366 SCALE_Y(otm
->otmsXHeight
);
3367 SCALE_Y(otm
->otmrcFontBox
.top
);
3368 SCALE_Y(otm
->otmrcFontBox
.bottom
);
3369 SCALE_X(otm
->otmrcFontBox
.left
);
3370 SCALE_X(otm
->otmrcFontBox
.right
);
3371 SCALE_Y(otm
->otmMacAscent
);
3372 SCALE_Y(otm
->otmMacDescent
);
3373 SCALE_Y(otm
->otmMacLineGap
);
3374 SCALE_X(otm
->otmptSubscriptSize
.x
);
3375 SCALE_Y(otm
->otmptSubscriptSize
.y
);
3376 SCALE_X(otm
->otmptSubscriptOffset
.x
);
3377 SCALE_Y(otm
->otmptSubscriptOffset
.y
);
3378 SCALE_X(otm
->otmptSuperscriptSize
.x
);
3379 SCALE_Y(otm
->otmptSuperscriptSize
.y
);
3380 SCALE_X(otm
->otmptSuperscriptOffset
.x
);
3381 SCALE_Y(otm
->otmptSuperscriptOffset
.y
);
3382 SCALE_Y(otm
->otmsStrikeoutSize
);
3383 SCALE_Y(otm
->otmsStrikeoutPosition
);
3384 SCALE_Y(otm
->otmsUnderscoreSize
);
3385 SCALE_Y(otm
->otmsUnderscorePosition
);
3391 /*************************************************************
3392 * font_GetOutlineTextMetrics
3394 static UINT CDECL
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
3396 struct font_physdev
*physdev
= get_font_dev( dev
);
3401 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
3402 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
3405 if (!physdev
->font
->scalable
) return 0;
3407 EnterCriticalSection( &font_cs
);
3408 if (font_funcs
->set_outline_text_metrics( physdev
->font
))
3410 ret
= physdev
->font
->otm
.otmSize
;
3411 if (metrics
&& size
>= physdev
->font
->otm
.otmSize
)
3413 WCHAR
*ptr
= (WCHAR
*)(metrics
+ 1);
3414 *metrics
= physdev
->font
->otm
;
3415 metrics
->otmpFamilyName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3416 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFamilyName
);
3417 ptr
+= lstrlenW(ptr
) + 1;
3418 metrics
->otmpStyleName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3419 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpStyleName
);
3420 ptr
+= lstrlenW(ptr
) + 1;
3421 metrics
->otmpFaceName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3422 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFaceName
);
3423 ptr
+= lstrlenW(ptr
) + 1;
3424 metrics
->otmpFullName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3425 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFullName
);
3426 scale_outline_font_metrics( physdev
->font
, metrics
);
3429 LeaveCriticalSection( &font_cs
);
3434 /*************************************************************
3435 * font_GetTextCharsetInfo
3437 static UINT CDECL
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
3439 struct font_physdev
*physdev
= get_font_dev( dev
);
3443 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
3444 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
3446 if (fs
) *fs
= physdev
->font
->fs
;
3447 return physdev
->font
->charset
;
3451 /*************************************************************
3452 * font_GetTextExtentExPoint
3454 static BOOL CDECL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
3456 struct font_physdev
*physdev
= get_font_dev( dev
);
3462 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
3463 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
3466 TRACE( "%p, %s, %d\n", physdev
->font
, debugstr_wn(str
, count
), count
);
3468 EnterCriticalSection( &font_cs
);
3469 for (i
= pos
= 0; i
< count
; i
++)
3471 get_glyph_outline( physdev
->font
, str
[i
], GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
);
3472 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3475 LeaveCriticalSection( &font_cs
);
3480 /*************************************************************
3481 * font_GetTextExtentExPointI
3483 static BOOL CDECL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
3485 struct font_physdev
*physdev
= get_font_dev( dev
);
3491 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
3492 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
3495 TRACE( "%p, %p, %d\n", physdev
->font
, indices
, count
);
3497 EnterCriticalSection( &font_cs
);
3498 for (i
= pos
= 0; i
< count
; i
++)
3500 get_glyph_outline( physdev
->font
, indices
[i
], GGO_METRICS
| GGO_GLYPH_INDEX
,
3501 NULL
, &abc
, 0, NULL
, NULL
);
3502 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3505 LeaveCriticalSection( &font_cs
);
3510 /*************************************************************
3513 static INT CDECL
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
3515 struct font_physdev
*physdev
= get_font_dev( dev
);
3520 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
3521 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
3523 len
= lstrlenW( get_gdi_font_name(physdev
->font
) ) + 1;
3526 lstrcpynW( str
, get_gdi_font_name(physdev
->font
), count
);
3527 len
= min( count
, len
);
3533 static void scale_font_metrics( struct gdi_font
*font
, TEXTMETRICW
*tm
)
3535 double scale_x
, scale_y
;
3537 /* Make sure that the font has sane width/height ratio */
3538 if (font
->aveWidth
&& (font
->aveWidth
+ tm
->tmHeight
- 1) / tm
->tmHeight
> 100)
3540 WARN( "Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
3546 scale_x
= (double)font
->aveWidth
;
3547 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3550 scale_x
= font
->scale_y
;
3552 scale_x
*= fabs(font
->matrix
.eM11
);
3553 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3555 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3556 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3558 SCALE_Y(tm
->tmHeight
);
3559 SCALE_Y(tm
->tmAscent
);
3560 SCALE_Y(tm
->tmDescent
);
3561 SCALE_Y(tm
->tmInternalLeading
);
3562 SCALE_Y(tm
->tmExternalLeading
);
3564 SCALE_X(tm
->tmOverhang
);
3565 if (font
->fake_bold
)
3567 if (!font
->scalable
) tm
->tmOverhang
++;
3568 tm
->tmAveCharWidth
++;
3569 tm
->tmMaxCharWidth
++;
3571 SCALE_X(tm
->tmAveCharWidth
);
3572 SCALE_X(tm
->tmMaxCharWidth
);
3578 /*************************************************************
3579 * font_GetTextMetrics
3581 static BOOL CDECL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
3583 struct font_physdev
*physdev
= get_font_dev( dev
);
3588 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
3589 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
3592 EnterCriticalSection( &font_cs
);
3593 if (font_funcs
->set_outline_text_metrics( physdev
->font
) ||
3594 font_funcs
->set_bitmap_text_metrics( physdev
->font
))
3596 *metrics
= physdev
->font
->otm
.otmTextMetrics
;
3597 scale_font_metrics( physdev
->font
, metrics
);
3600 LeaveCriticalSection( &font_cs
);
3605 static void get_nearest_charset( const WCHAR
*family_name
, struct gdi_font_face
*face
, CHARSETINFO
*csi
)
3607 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3608 a single face with the requested charset. The idea is to check if
3609 the selected font supports the current ANSI codepage, if it does
3610 return the corresponding charset, else return the first charset */
3614 if (TranslateCharsetInfo( (DWORD
*)(INT_PTR
)GetACP(), csi
, TCI_SRCCODEPAGE
))
3616 const struct gdi_font_link
*font_link
;
3618 if (csi
->fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return;
3619 font_link
= find_gdi_font_link(family_name
);
3620 if (font_link
&& (csi
->fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])) return;
3622 for (i
= 0; i
< 32; i
++)
3624 DWORD fs0
= 1u << i
;
3625 if (face
->fs
.fsCsb
[0] & fs0
)
3627 if (TranslateCharsetInfo(&fs0
, csi
, TCI_SRCFONTSIG
)) return;
3628 FIXME("TCI failing on %x\n", fs0
);
3632 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3633 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
3634 csi
->ciACP
= GetACP();
3635 csi
->ciCharset
= DEFAULT_CHARSET
;
3638 static struct gdi_font
*select_font( LOGFONTW
*lf
, FMAT2 dcmat
, BOOL can_use_bitmap
)
3640 struct gdi_font
*font
;
3641 struct gdi_font_face
*face
;
3644 const WCHAR
*orig_name
= NULL
;
3646 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3647 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3648 original value lfCharSet. Note this is a special case for
3649 Symbol and doesn't happen at least for "Wingdings*" */
3650 if (!facename_compare( lf
->lfFaceName
, L
"Symbol", -1 )) lf
->lfCharSet
= SYMBOL_CHARSET
;
3652 /* check the cache first */
3653 if ((font
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
3655 TRACE( "returning cached gdiFont(%p)\n", font
);
3658 if (!(face
= find_matching_face( lf
, &csi
, can_use_bitmap
, &orig_name
)))
3660 FIXME( "can't find a single appropriate font - bailing\n" );
3663 height
= lf
->lfHeight
;
3665 font
= create_gdi_font( face
, orig_name
, lf
);
3666 font
->matrix
= dcmat
;
3667 font
->can_use_bitmap
= can_use_bitmap
;
3668 if (!csi
.fs
.fsCsb
[0]) get_nearest_charset( face
->family
->family_name
, face
, &csi
);
3669 font
->charset
= csi
.ciCharset
;
3670 font
->codepage
= csi
.ciACP
;
3672 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face
->full_name
), debugstr_w(face
->file
),
3673 face
->data_ptr
, face
->face_index
);
3675 font
->aveWidth
= height
? lf
->lfWidth
: 0;
3676 if (!face
->scalable
)
3678 /* Windows uses integer scaling factors for bitmap fonts */
3679 INT scale
, scaled_height
, diff
;
3680 struct gdi_font
*cachedfont
;
3683 diff
= height
- (signed int)face
->size
.height
;
3685 diff
= -height
- ((signed int)face
->size
.height
- face
->size
.internal_leading
);
3687 /* FIXME: rotation of bitmap fonts is ignored */
3688 height
= abs(GDI_ROUND( (double)height
* font
->matrix
.eM22
));
3690 font
->aveWidth
= (double)font
->aveWidth
* font
->matrix
.eM11
;
3691 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
3692 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3693 /* As we changed the matrix, we need to search the cache for the font again,
3694 * otherwise we might explode the cache. */
3695 if ((cachedfont
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
3697 TRACE("Found cached font after non-scalable matrix rescale!\n");
3698 free_gdi_font( font
);
3702 if (height
!= 0) height
= diff
;
3703 height
+= face
->size
.height
;
3705 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3706 scaled_height
= scale
* face
->size
.height
;
3707 /* Only jump to the next height if the difference <= 25% original height */
3708 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3709 /* The jump between unscaled and doubled is delayed by 1 */
3710 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3711 font
->scale_y
= scale
;
3712 TRACE("font scale y: %d\n", font
->scale_y
);
3715 if (!font_funcs
->load_font( font
))
3717 free_gdi_font( font
);
3721 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
3722 font
->vert_feature
= get_GSUB_vert_feature( font
);
3724 create_child_font_list( font
);
3726 TRACE( "caching: gdiFont=%p\n", font
);
3727 cache_gdi_font( font
);
3731 /*************************************************************
3734 static HFONT CDECL
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
3736 struct font_physdev
*physdev
= get_font_dev( dev
);
3737 struct gdi_font
*font
= NULL
, *prev
= physdev
->font
;
3738 DC
*dc
= get_physdev_dc( dev
);
3744 BOOL can_use_bitmap
= !!(GetDeviceCaps( dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
);
3746 GetObjectW( hfont
, sizeof(lf
), &lf
);
3747 switch (lf
.lfQuality
)
3749 case NONANTIALIASED_QUALITY
:
3750 if (!*aa_flags
) *aa_flags
= GGO_BITMAP
;
3752 case ANTIALIASED_QUALITY
:
3753 if (!*aa_flags
) *aa_flags
= GGO_GRAY4_BITMAP
;
3757 lf
.lfWidth
= abs(lf
.lfWidth
);
3759 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3760 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3761 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3764 if (dc
->GraphicsMode
== GM_ADVANCED
)
3766 memcpy( &dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
) );
3767 /* try to avoid not necessary glyph transformations */
3768 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3770 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3771 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3772 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
3777 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
3778 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3779 dcmat
.eM21
= dcmat
.eM12
= 0;
3780 lf
.lfOrientation
= lf
.lfEscapement
;
3781 if (dc
->vport2WorldValid
)
3783 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
3784 lf
.lfOrientation
= -lf
.lfOrientation
;
3785 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
3786 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
3789 TRACE( "DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
, dcmat
.eM21
, dcmat
.eM22
);
3791 EnterCriticalSection( &font_cs
);
3793 font
= select_font( &lf
, dcmat
, can_use_bitmap
);
3797 if (!*aa_flags
) *aa_flags
= font
->aa_flags
;
3800 if (lf
.lfQuality
== CLEARTYPE_QUALITY
|| lf
.lfQuality
== CLEARTYPE_NATURAL_QUALITY
)
3801 *aa_flags
= subpixel_orientation
;
3803 *aa_flags
= font_smoothing
;
3805 *aa_flags
= font_funcs
->get_aa_flags( font
, *aa_flags
, antialias_fakes
);
3807 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
3808 LeaveCriticalSection( &font_cs
);
3810 physdev
->font
= font
;
3811 if (prev
) release_gdi_font( prev
);
3812 return font
? hfont
: 0;
3816 const struct gdi_dc_funcs font_driver
=
3818 NULL
, /* pAbortDoc */
3819 NULL
, /* pAbortPath */
3820 NULL
, /* pAlphaBlend */
3821 NULL
, /* pAngleArc */
3824 NULL
, /* pBeginPath */
3825 NULL
, /* pBlendImage */
3827 NULL
, /* pCloseFigure */
3828 NULL
, /* pCreateCompatibleDC */
3829 font_CreateDC
, /* pCreateDC */
3830 font_DeleteDC
, /* pDeleteDC */
3831 NULL
, /* pDeleteObject */
3832 NULL
, /* pDeviceCapabilities */
3833 NULL
, /* pEllipse */
3835 NULL
, /* pEndPage */
3836 NULL
, /* pEndPath */
3837 font_EnumFonts
, /* pEnumFonts */
3838 NULL
, /* pEnumICMProfiles */
3839 NULL
, /* pExcludeClipRect */
3840 NULL
, /* pExtDeviceMode */
3841 NULL
, /* pExtEscape */
3842 NULL
, /* pExtFloodFill */
3843 NULL
, /* pExtSelectClipRgn */
3844 NULL
, /* pExtTextOut */
3845 NULL
, /* pFillPath */
3846 NULL
, /* pFillRgn */
3847 NULL
, /* pFlattenPath */
3848 font_FontIsLinked
, /* pFontIsLinked */
3849 NULL
, /* pFrameRgn */
3850 NULL
, /* pGdiComment */
3851 NULL
, /* pGetBoundsRect */
3852 font_GetCharABCWidths
, /* pGetCharABCWidths */
3853 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
3854 font_GetCharWidth
, /* pGetCharWidth */
3855 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
3856 NULL
, /* pGetDeviceCaps */
3857 NULL
, /* pGetDeviceGammaRamp */
3858 font_GetFontData
, /* pGetFontData */
3859 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
3860 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
3861 font_GetGlyphIndices
, /* pGetGlyphIndices */
3862 font_GetGlyphOutline
, /* pGetGlyphOutline */
3863 NULL
, /* pGetICMProfile */
3864 NULL
, /* pGetImage */
3865 font_GetKerningPairs
, /* pGetKerningPairs */
3866 NULL
, /* pGetNearestColor */
3867 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
3868 NULL
, /* pGetPixel */
3869 NULL
, /* pGetSystemPaletteEntries */
3870 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
3871 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
3872 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
3873 font_GetTextFace
, /* pGetTextFace */
3874 font_GetTextMetrics
, /* pGetTextMetrics */
3875 NULL
, /* pGradientFill */
3876 NULL
, /* pIntersectClipRect */
3877 NULL
, /* pInvertRgn */
3879 NULL
, /* pModifyWorldTransform */
3881 NULL
, /* pOffsetClipRgn */
3882 NULL
, /* pOffsetViewportOrg */
3883 NULL
, /* pOffsetWindowOrg */
3884 NULL
, /* pPaintRgn */
3887 NULL
, /* pPolyBezier */
3888 NULL
, /* pPolyBezierTo */
3889 NULL
, /* pPolyDraw */
3890 NULL
, /* pPolyPolygon */
3891 NULL
, /* pPolyPolyline */
3892 NULL
, /* pPolygon */
3893 NULL
, /* pPolyline */
3894 NULL
, /* pPolylineTo */
3895 NULL
, /* pPutImage */
3896 NULL
, /* pRealizeDefaultPalette */
3897 NULL
, /* pRealizePalette */
3898 NULL
, /* pRectangle */
3899 NULL
, /* pResetDC */
3900 NULL
, /* pRestoreDC */
3901 NULL
, /* pRoundRect */
3903 NULL
, /* pScaleViewportExt */
3904 NULL
, /* pScaleWindowExt */
3905 NULL
, /* pSelectBitmap */
3906 NULL
, /* pSelectBrush */
3907 NULL
, /* pSelectClipPath */
3908 font_SelectFont
, /* pSelectFont */
3909 NULL
, /* pSelectPalette */
3910 NULL
, /* pSelectPen */
3911 NULL
, /* pSetArcDirection */
3912 NULL
, /* pSetBkColor */
3913 NULL
, /* pSetBkMode */
3914 NULL
, /* pSetBoundsRect */
3915 NULL
, /* pSetDCBrushColor */
3916 NULL
, /* pSetDCPenColor */
3917 NULL
, /* pSetDIBitsToDevice */
3918 NULL
, /* pSetDeviceClipping */
3919 NULL
, /* pSetDeviceGammaRamp */
3920 NULL
, /* pSetLayout */
3921 NULL
, /* pSetMapMode */
3922 NULL
, /* pSetMapperFlags */
3923 NULL
, /* pSetPixel */
3924 NULL
, /* pSetPolyFillMode */
3925 NULL
, /* pSetROP2 */
3926 NULL
, /* pSetRelAbs */
3927 NULL
, /* pSetStretchBltMode */
3928 NULL
, /* pSetTextAlign */
3929 NULL
, /* pSetTextCharacterExtra */
3930 NULL
, /* pSetTextColor */
3931 NULL
, /* pSetTextJustification */
3932 NULL
, /* pSetViewportExt */
3933 NULL
, /* pSetViewportOrg */
3934 NULL
, /* pSetWindowExt */
3935 NULL
, /* pSetWindowOrg */
3936 NULL
, /* pSetWorldTransform */
3937 NULL
, /* pStartDoc */
3938 NULL
, /* pStartPage */
3939 NULL
, /* pStretchBlt */
3940 NULL
, /* pStretchDIBits */
3941 NULL
, /* pStrokeAndFillPath */
3942 NULL
, /* pStrokePath */
3943 NULL
, /* pUnrealizePalette */
3944 NULL
, /* pWidenPath */
3945 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
3946 NULL
, /* pD3DKMTSetVidPnSourceOwner */
3947 NULL
, /* wine_get_wgl_driver */
3948 NULL
, /* wine_get_vulkan_driver */
3949 GDI_PRIORITY_FONT_DRV
/* priority */
3952 static DWORD
get_key_value( HKEY key
, const WCHAR
*name
, DWORD
*value
)
3955 DWORD count
= sizeof(buf
), type
, err
;
3957 err
= RegQueryValueExW( key
, name
, NULL
, &type
, (BYTE
*)buf
, &count
);
3960 if (type
== REG_DWORD
) memcpy( value
, buf
, sizeof(*value
) );
3961 else *value
= wcstol( buf
, NULL
, 10 );
3966 static void init_font_options(void)
3969 DWORD i
, type
, size
, val
, gamma
= 1400;
3972 size
= sizeof(buffer
);
3973 if (!RegQueryValueExW( wine_fonts_key
, L
"AntialiasFakeBoldOrItalic", NULL
,
3974 &type
, (BYTE
*)buffer
, &size
) && type
== REG_SZ
&& size
>= 1)
3976 antialias_fakes
= (wcschr(L
"yYtT1", buffer
[0]) != NULL
);
3979 if (!RegOpenKeyW( HKEY_CURRENT_USER
, L
"Control Panel\\Desktop", &key
))
3981 /* FIXME: handle vertical orientations even though Windows doesn't */
3982 if (!get_key_value( key
, L
"FontSmoothingOrientation", &val
))
3986 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
3987 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
3989 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
3990 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
3994 if (!get_key_value( key
, L
"FontSmoothing", &val
) && val
/* enabled */)
3996 if (!get_key_value( key
, L
"FontSmoothingType", &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
3997 font_smoothing
= subpixel_orientation
;
3999 font_smoothing
= GGO_GRAY4_BITMAP
;
4001 if (!get_key_value( key
, L
"FontSmoothingGamma", &val
) && val
)
4003 gamma
= min( max( val
, 1000 ), 2200 );
4008 /* Calibrating the difference between the registry value and the Wine gamma value.
4009 This looks roughly similar to Windows Native with the same registry value.
4010 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4011 gamma
= 1000 * gamma
/ 1400;
4012 for (i
= 0; i
< 256; i
++)
4014 font_gamma_ramp
.encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
4015 font_gamma_ramp
.decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
4017 font_gamma_ramp
.gamma
= gamma
;
4018 TRACE("gamma %d\n", font_gamma_ramp
.gamma
);
4022 static void FONT_LogFontAToW( const LOGFONTA
*fontA
, LPLOGFONTW fontW
)
4024 memcpy(fontW
, fontA
, sizeof(LOGFONTA
) - LF_FACESIZE
);
4025 MultiByteToWideChar(CP_ACP
, 0, fontA
->lfFaceName
, -1, fontW
->lfFaceName
,
4027 fontW
->lfFaceName
[LF_FACESIZE
-1] = 0;
4030 static void FONT_LogFontWToA( const LOGFONTW
*fontW
, LPLOGFONTA fontA
)
4032 memcpy(fontA
, fontW
, sizeof(LOGFONTA
) - LF_FACESIZE
);
4033 WideCharToMultiByte(CP_ACP
, 0, fontW
->lfFaceName
, -1, fontA
->lfFaceName
,
4034 LF_FACESIZE
, NULL
, NULL
);
4035 fontA
->lfFaceName
[LF_FACESIZE
-1] = 0;
4038 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW
*fontW
, LPENUMLOGFONTEXA fontA
)
4040 FONT_LogFontWToA( &fontW
->elfLogFont
, &fontA
->elfLogFont
);
4042 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfFullName
, -1,
4043 (LPSTR
) fontA
->elfFullName
, LF_FULLFACESIZE
, NULL
, NULL
);
4044 fontA
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
4045 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfStyle
, -1,
4046 (LPSTR
) fontA
->elfStyle
, LF_FACESIZE
, NULL
, NULL
);
4047 fontA
->elfStyle
[LF_FACESIZE
-1] = '\0';
4048 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfScript
, -1,
4049 (LPSTR
) fontA
->elfScript
, LF_FACESIZE
, NULL
, NULL
);
4050 fontA
->elfScript
[LF_FACESIZE
-1] = '\0';
4053 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA
*fontA
, LPENUMLOGFONTEXW fontW
)
4055 FONT_LogFontAToW( &fontA
->elfLogFont
, &fontW
->elfLogFont
);
4057 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfFullName
, -1,
4058 fontW
->elfFullName
, LF_FULLFACESIZE
);
4059 fontW
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
4060 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfStyle
, -1,
4061 fontW
->elfStyle
, LF_FACESIZE
);
4062 fontW
->elfStyle
[LF_FACESIZE
-1] = '\0';
4063 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfScript
, -1,
4064 fontW
->elfScript
, LF_FACESIZE
);
4065 fontW
->elfScript
[LF_FACESIZE
-1] = '\0';
4068 /***********************************************************************
4069 * TEXTMETRIC conversion functions.
4071 static void FONT_TextMetricWToA(const TEXTMETRICW
*ptmW
, LPTEXTMETRICA ptmA
)
4073 ptmA
->tmHeight
= ptmW
->tmHeight
;
4074 ptmA
->tmAscent
= ptmW
->tmAscent
;
4075 ptmA
->tmDescent
= ptmW
->tmDescent
;
4076 ptmA
->tmInternalLeading
= ptmW
->tmInternalLeading
;
4077 ptmA
->tmExternalLeading
= ptmW
->tmExternalLeading
;
4078 ptmA
->tmAveCharWidth
= ptmW
->tmAveCharWidth
;
4079 ptmA
->tmMaxCharWidth
= ptmW
->tmMaxCharWidth
;
4080 ptmA
->tmWeight
= ptmW
->tmWeight
;
4081 ptmA
->tmOverhang
= ptmW
->tmOverhang
;
4082 ptmA
->tmDigitizedAspectX
= ptmW
->tmDigitizedAspectX
;
4083 ptmA
->tmDigitizedAspectY
= ptmW
->tmDigitizedAspectY
;
4084 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 255);
4085 if (ptmW
->tmCharSet
== SYMBOL_CHARSET
)
4087 ptmA
->tmFirstChar
= 0x1e;
4088 ptmA
->tmLastChar
= 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
4090 else if (ptmW
->tmPitchAndFamily
& TMPF_TRUETYPE
)
4092 ptmA
->tmFirstChar
= ptmW
->tmDefaultChar
- 1;
4093 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
4097 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 0xff);
4098 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
4100 ptmA
->tmDefaultChar
= ptmW
->tmDefaultChar
;
4101 ptmA
->tmBreakChar
= ptmW
->tmBreakChar
;
4102 ptmA
->tmItalic
= ptmW
->tmItalic
;
4103 ptmA
->tmUnderlined
= ptmW
->tmUnderlined
;
4104 ptmA
->tmStruckOut
= ptmW
->tmStruckOut
;
4105 ptmA
->tmPitchAndFamily
= ptmW
->tmPitchAndFamily
;
4106 ptmA
->tmCharSet
= ptmW
->tmCharSet
;
4110 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW
*ptmW
, NEWTEXTMETRICEXA
*ptmA
)
4112 FONT_TextMetricWToA((const TEXTMETRICW
*)ptmW
, (LPTEXTMETRICA
)ptmA
);
4113 ptmA
->ntmTm
.ntmFlags
= ptmW
->ntmTm
.ntmFlags
;
4114 ptmA
->ntmTm
.ntmSizeEM
= ptmW
->ntmTm
.ntmSizeEM
;
4115 ptmA
->ntmTm
.ntmCellHeight
= ptmW
->ntmTm
.ntmCellHeight
;
4116 ptmA
->ntmTm
.ntmAvgWidth
= ptmW
->ntmTm
.ntmAvgWidth
;
4117 memcpy(&ptmA
->ntmFontSig
, &ptmW
->ntmFontSig
, sizeof(FONTSIGNATURE
));
4120 /* compute positions for text rendering, in device coords */
4121 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
4126 size
->cx
= size
->cy
= 0;
4127 if (!count
) return TRUE
;
4129 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4130 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4132 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
4133 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
4135 if (dc
->breakExtra
|| dc
->breakRem
)
4137 int i
, space
= 0, rem
= dc
->breakRem
;
4139 for (i
= 0; i
< count
; i
++)
4141 if (str
[i
] == tm
.tmBreakChar
)
4143 space
+= dc
->breakExtra
;
4153 size
->cx
= dx
[count
- 1];
4154 size
->cy
= tm
.tmHeight
;
4158 /* compute positions for text rendering, in device coords */
4159 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
4164 size
->cx
= size
->cy
= 0;
4165 if (!count
) return TRUE
;
4167 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4168 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4170 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
4171 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
4173 if (dc
->breakExtra
|| dc
->breakRem
)
4176 int i
, space
= 0, rem
= dc
->breakRem
;
4178 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4179 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
4181 for (i
= 0; i
< count
; i
++)
4183 if (indices
[i
] == space_index
)
4185 space
+= dc
->breakExtra
;
4195 size
->cx
= dx
[count
- 1];
4196 size
->cy
= tm
.tmHeight
;
4200 /***********************************************************************
4201 * GdiGetCodePage (GDI32.@)
4203 DWORD WINAPI
GdiGetCodePage( HDC hdc
)
4206 DC
*dc
= get_dc_ptr( hdc
);
4210 cp
= dc
->font_code_page
;
4211 release_dc_ptr( dc
);
4216 /***********************************************************************
4217 * get_text_charset_info
4219 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4221 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
4223 UINT ret
= DEFAULT_CHARSET
;
4226 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
4227 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4229 if (ret
== DEFAULT_CHARSET
&& fs
)
4230 memset(fs
, 0, sizeof(FONTSIGNATURE
));
4234 /***********************************************************************
4235 * GetTextCharsetInfo (GDI32.@)
4237 UINT WINAPI
GetTextCharsetInfo(HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
4239 UINT ret
= DEFAULT_CHARSET
;
4240 DC
*dc
= get_dc_ptr(hdc
);
4244 ret
= get_text_charset_info( dc
, fs
, flags
);
4245 release_dc_ptr( dc
);
4250 /***********************************************************************
4253 * Returns a Unicode translation of str using the charset of the
4254 * currently selected font in hdc. If count is -1 then str is assumed
4255 * to be '\0' terminated, otherwise it contains the number of bytes to
4256 * convert. If plenW is non-NULL, on return it will point to the
4257 * number of WCHARs that have been written. If pCP is non-NULL, on
4258 * return it will point to the codepage used in the conversion. The
4259 * caller should free the returned LPWSTR from the process heap
4262 static LPWSTR
FONT_mbtowc(HDC hdc
, LPCSTR str
, INT count
, INT
*plenW
, UINT
*pCP
)
4268 cp
= GdiGetCodePage( hdc
);
4270 if(count
== -1) count
= strlen(str
);
4271 lenW
= MultiByteToWideChar(cp
, 0, str
, count
, NULL
, 0);
4272 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
*sizeof(WCHAR
));
4273 MultiByteToWideChar(cp
, 0, str
, count
, strW
, lenW
);
4274 TRACE("mapped %s -> %s\n", debugstr_an(str
, count
), debugstr_wn(strW
, lenW
));
4275 if(plenW
) *plenW
= lenW
;
4280 /***********************************************************************
4281 * CreateFontIndirectExA (GDI32.@)
4283 HFONT WINAPI
CreateFontIndirectExA( const ENUMLOGFONTEXDVA
*penumexA
)
4285 ENUMLOGFONTEXDVW enumexW
;
4287 if (!penumexA
) return 0;
4289 FONT_EnumLogFontExAToW( &penumexA
->elfEnumLogfontEx
, &enumexW
.elfEnumLogfontEx
);
4290 enumexW
.elfDesignVector
= penumexA
->elfDesignVector
;
4291 return CreateFontIndirectExW( &enumexW
);
4294 /***********************************************************************
4295 * CreateFontIndirectExW (GDI32.@)
4297 HFONT WINAPI
CreateFontIndirectExW( const ENUMLOGFONTEXDVW
*penumex
)
4301 const LOGFONTW
*plf
;
4303 if (!penumex
) return 0;
4305 if (penumex
->elfEnumLogfontEx
.elfFullName
[0] ||
4306 penumex
->elfEnumLogfontEx
.elfStyle
[0] ||
4307 penumex
->elfEnumLogfontEx
.elfScript
[0])
4309 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4310 debugstr_w(penumex
->elfEnumLogfontEx
.elfFullName
),
4311 debugstr_w(penumex
->elfEnumLogfontEx
.elfStyle
),
4312 debugstr_w(penumex
->elfEnumLogfontEx
.elfScript
));
4315 plf
= &penumex
->elfEnumLogfontEx
.elfLogFont
;
4316 if (!(fontPtr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr
) ))) return 0;
4318 fontPtr
->logfont
= *plf
;
4320 if (!(hFont
= alloc_gdi_handle( fontPtr
, OBJ_FONT
, &fontobj_funcs
)))
4322 HeapFree( GetProcessHeap(), 0, fontPtr
);
4326 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4327 plf
->lfHeight
, plf
->lfWidth
,
4328 plf
->lfEscapement
, plf
->lfOrientation
,
4329 plf
->lfPitchAndFamily
,
4330 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
4331 plf
->lfQuality
, plf
->lfCharSet
,
4332 debugstr_w(plf
->lfFaceName
),
4333 plf
->lfWeight
> 400 ? "Bold" : "",
4334 plf
->lfItalic
? "Italic" : "",
4335 plf
->lfUnderline
? "Underline" : "", hFont
);
4340 /***********************************************************************
4341 * CreateFontIndirectA (GDI32.@)
4343 HFONT WINAPI
CreateFontIndirectA( const LOGFONTA
*plfA
)
4347 if (!plfA
) return 0;
4349 FONT_LogFontAToW( plfA
, &lfW
);
4350 return CreateFontIndirectW( &lfW
);
4353 /***********************************************************************
4354 * CreateFontIndirectW (GDI32.@)
4356 HFONT WINAPI
CreateFontIndirectW( const LOGFONTW
*plf
)
4358 ENUMLOGFONTEXDVW exdv
;
4362 exdv
.elfEnumLogfontEx
.elfLogFont
= *plf
;
4363 exdv
.elfEnumLogfontEx
.elfFullName
[0] = 0;
4364 exdv
.elfEnumLogfontEx
.elfStyle
[0] = 0;
4365 exdv
.elfEnumLogfontEx
.elfScript
[0] = 0;
4366 return CreateFontIndirectExW( &exdv
);
4369 /*************************************************************************
4370 * CreateFontA (GDI32.@)
4372 HFONT WINAPI
CreateFontA( INT height
, INT width
, INT esc
,
4373 INT orient
, INT weight
, DWORD italic
,
4374 DWORD underline
, DWORD strikeout
, DWORD charset
,
4375 DWORD outpres
, DWORD clippres
, DWORD quality
,
4376 DWORD pitch
, LPCSTR name
)
4380 logfont
.lfHeight
= height
;
4381 logfont
.lfWidth
= width
;
4382 logfont
.lfEscapement
= esc
;
4383 logfont
.lfOrientation
= orient
;
4384 logfont
.lfWeight
= weight
;
4385 logfont
.lfItalic
= italic
;
4386 logfont
.lfUnderline
= underline
;
4387 logfont
.lfStrikeOut
= strikeout
;
4388 logfont
.lfCharSet
= charset
;
4389 logfont
.lfOutPrecision
= outpres
;
4390 logfont
.lfClipPrecision
= clippres
;
4391 logfont
.lfQuality
= quality
;
4392 logfont
.lfPitchAndFamily
= pitch
;
4395 lstrcpynA(logfont
.lfFaceName
,name
,sizeof(logfont
.lfFaceName
));
4397 logfont
.lfFaceName
[0] = '\0';
4399 return CreateFontIndirectA( &logfont
);
4402 /*************************************************************************
4403 * CreateFontW (GDI32.@)
4405 HFONT WINAPI
CreateFontW( INT height
, INT width
, INT esc
,
4406 INT orient
, INT weight
, DWORD italic
,
4407 DWORD underline
, DWORD strikeout
, DWORD charset
,
4408 DWORD outpres
, DWORD clippres
, DWORD quality
,
4409 DWORD pitch
, LPCWSTR name
)
4413 logfont
.lfHeight
= height
;
4414 logfont
.lfWidth
= width
;
4415 logfont
.lfEscapement
= esc
;
4416 logfont
.lfOrientation
= orient
;
4417 logfont
.lfWeight
= weight
;
4418 logfont
.lfItalic
= italic
;
4419 logfont
.lfUnderline
= underline
;
4420 logfont
.lfStrikeOut
= strikeout
;
4421 logfont
.lfCharSet
= charset
;
4422 logfont
.lfOutPrecision
= outpres
;
4423 logfont
.lfClipPrecision
= clippres
;
4424 logfont
.lfQuality
= quality
;
4425 logfont
.lfPitchAndFamily
= pitch
;
4428 lstrcpynW(logfont
.lfFaceName
, name
, ARRAY_SIZE(logfont
.lfFaceName
));
4430 logfont
.lfFaceName
[0] = '\0';
4432 return CreateFontIndirectW( &logfont
);
4435 #define ASSOC_CHARSET_OEM 1
4436 #define ASSOC_CHARSET_ANSI 2
4437 #define ASSOC_CHARSET_SYMBOL 4
4439 static DWORD
get_associated_charset_info(void)
4441 static DWORD associated_charset
= -1;
4443 if (associated_charset
== -1)
4447 DWORD type
, data_len
;
4449 associated_charset
= 0;
4451 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
,
4452 L
"System\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset", &hkey
))
4455 data_len
= sizeof(dataW
);
4456 if (!RegQueryValueExW(hkey
, L
"ANSI(00)", NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
4457 type
== REG_SZ
&& !wcsicmp(dataW
, L
"yes"))
4458 associated_charset
|= ASSOC_CHARSET_ANSI
;
4460 data_len
= sizeof(dataW
);
4461 if (!RegQueryValueExW(hkey
, L
"OEM(FF)", NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
4462 type
== REG_SZ
&& !wcsicmp(dataW
, L
"yes"))
4463 associated_charset
|= ASSOC_CHARSET_OEM
;
4465 data_len
= sizeof(dataW
);
4466 if (!RegQueryValueExW(hkey
, L
"SYMBOL(02)", NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
4467 type
== REG_SZ
&& !wcsicmp(dataW
, L
"yes"))
4468 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
4472 TRACE("associated_charset = %d\n", associated_charset
);
4475 return associated_charset
;
4478 static void update_font_code_page( DC
*dc
, HANDLE font
)
4481 int charset
= get_text_charset_info( dc
, NULL
, 0 );
4483 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
4487 GetObjectW( font
, sizeof(lf
), &lf
);
4488 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
4489 charset
= DEFAULT_CHARSET
;
4492 /* Hmm, nicely designed api this one! */
4493 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
4494 dc
->font_code_page
= csi
.ciACP
;
4498 dc
->font_code_page
= GetOEMCP();
4500 case DEFAULT_CHARSET
:
4501 dc
->font_code_page
= GetACP();
4504 case VISCII_CHARSET
:
4510 case CELTIC_CHARSET
:
4511 /* FIXME: These have no place here, but because x11drv
4512 enumerates fonts with these (made up) charsets some apps
4513 might use them and then the FIXME below would become
4514 annoying. Now we could pick the intended codepage for
4515 each of these, but since it's broken anyway we'll just
4516 use CP_ACP and hope it'll go away...
4518 dc
->font_code_page
= CP_ACP
;
4522 FIXME("Can't find codepage for charset %d\n", charset
);
4523 dc
->font_code_page
= CP_ACP
;
4528 TRACE("charset %d => cp %d\n", charset
, dc
->font_code_page
);
4531 /***********************************************************************
4534 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
)
4537 DC
*dc
= get_dc_ptr( hdc
);
4543 if (!GDI_inc_ref_count( handle
))
4545 release_dc_ptr( dc
);
4549 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
4550 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
4554 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
4555 update_font_code_page( dc
, handle
);
4556 if (dc
->font_gamma_ramp
== NULL
)
4557 dc
->font_gamma_ramp
= &font_gamma_ramp
;
4558 GDI_dec_ref_count( ret
);
4560 else GDI_dec_ref_count( handle
);
4562 release_dc_ptr( dc
);
4567 /***********************************************************************
4570 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
)
4572 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
4575 if (!font
) return 0;
4578 FONT_LogFontWToA( &font
->logfont
, &lfA
);
4579 if (count
> sizeof(lfA
)) count
= sizeof(lfA
);
4580 memcpy( buffer
, &lfA
, count
);
4582 else count
= sizeof(lfA
);
4583 GDI_ReleaseObj( handle
);
4587 /***********************************************************************
4590 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
4592 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
4594 if (!font
) return 0;
4597 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
4598 memcpy( buffer
, &font
->logfont
, count
);
4600 else count
= sizeof(LOGFONTW
);
4601 GDI_ReleaseObj( handle
);
4606 /***********************************************************************
4609 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
4613 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
4614 HeapFree( GetProcessHeap(), 0, obj
);
4619 /***********************************************************************
4622 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
4623 * We have to use other types because of the FONTENUMPROCW definition.
4625 static INT CALLBACK
FONT_EnumInstance( const LOGFONTW
*plf
, const TEXTMETRICW
*ptm
,
4626 DWORD fType
, LPARAM lp
)
4628 struct font_enum
*pfe
= (struct font_enum
*)lp
;
4631 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
4632 if ((!pfe
->lpLogFontParam
||
4633 pfe
->lpLogFontParam
->lfCharSet
== DEFAULT_CHARSET
||
4634 pfe
->lpLogFontParam
->lfCharSet
== plf
->lfCharSet
) &&
4635 (!(fType
& RASTER_FONTTYPE
) || GetDeviceCaps(pfe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
) )
4637 /* convert font metrics */
4638 ENUMLOGFONTEXA logfont
;
4639 NEWTEXTMETRICEXA tmA
;
4643 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW
*)plf
, &logfont
);
4644 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW
*)ptm
, &tmA
);
4645 plf
= (LOGFONTW
*)&logfont
.elfLogFont
;
4646 ptm
= (TEXTMETRICW
*)&tmA
;
4648 ret
= pfe
->lpEnumFunc( plf
, ptm
, fType
, pfe
->lpData
);
4654 /***********************************************************************
4655 * FONT_EnumFontFamiliesEx
4657 static INT
FONT_EnumFontFamiliesEx( HDC hDC
, LPLOGFONTW plf
, FONTENUMPROCW efproc
,
4658 LPARAM lParam
, BOOL unicode
)
4661 DC
*dc
= get_dc_ptr( hDC
);
4662 struct font_enum fe
;
4666 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
4668 if (plf
) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4669 fe
.lpLogFontParam
= plf
;
4670 fe
.lpEnumFunc
= efproc
;
4672 fe
.unicode
= unicode
;
4675 ret
= physdev
->funcs
->pEnumFonts( physdev
, plf
, FONT_EnumInstance
, (LPARAM
)&fe
);
4676 release_dc_ptr( dc
);
4678 return ret
? fe
.retval
: 0;
4681 /***********************************************************************
4682 * EnumFontFamiliesExW (GDI32.@)
4684 INT WINAPI
EnumFontFamiliesExW( HDC hDC
, LPLOGFONTW plf
,
4685 FONTENUMPROCW efproc
,
4686 LPARAM lParam
, DWORD dwFlags
)
4688 return FONT_EnumFontFamiliesEx( hDC
, plf
, efproc
, lParam
, TRUE
);
4691 /***********************************************************************
4692 * EnumFontFamiliesExA (GDI32.@)
4694 INT WINAPI
EnumFontFamiliesExA( HDC hDC
, LPLOGFONTA plf
,
4695 FONTENUMPROCA efproc
,
4696 LPARAM lParam
, DWORD dwFlags
)
4698 LOGFONTW lfW
, *plfW
;
4702 FONT_LogFontAToW( plf
, &lfW
);
4707 return FONT_EnumFontFamiliesEx( hDC
, plfW
, (FONTENUMPROCW
)efproc
, lParam
, FALSE
);
4710 /***********************************************************************
4711 * EnumFontFamiliesA (GDI32.@)
4713 INT WINAPI
EnumFontFamiliesA( HDC hDC
, LPCSTR lpFamily
,
4714 FONTENUMPROCA efproc
, LPARAM lpData
)
4720 if (!*lpFamily
) return 1;
4721 lstrcpynA( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
4722 lf
.lfCharSet
= DEFAULT_CHARSET
;
4723 lf
.lfPitchAndFamily
= 0;
4728 return EnumFontFamiliesExA( hDC
, plf
, efproc
, lpData
, 0 );
4731 /***********************************************************************
4732 * EnumFontFamiliesW (GDI32.@)
4734 INT WINAPI
EnumFontFamiliesW( HDC hDC
, LPCWSTR lpFamily
,
4735 FONTENUMPROCW efproc
, LPARAM lpData
)
4741 if (!*lpFamily
) return 1;
4742 lstrcpynW( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
4743 lf
.lfCharSet
= DEFAULT_CHARSET
;
4744 lf
.lfPitchAndFamily
= 0;
4749 return EnumFontFamiliesExW( hDC
, plf
, efproc
, lpData
, 0 );
4752 /***********************************************************************
4753 * EnumFontsA (GDI32.@)
4755 INT WINAPI
EnumFontsA( HDC hDC
, LPCSTR lpName
, FONTENUMPROCA efproc
,
4758 return EnumFontFamiliesA( hDC
, lpName
, efproc
, lpData
);
4761 /***********************************************************************
4762 * EnumFontsW (GDI32.@)
4764 INT WINAPI
EnumFontsW( HDC hDC
, LPCWSTR lpName
, FONTENUMPROCW efproc
,
4767 return EnumFontFamiliesW( hDC
, lpName
, efproc
, lpData
);
4771 /***********************************************************************
4772 * GetTextCharacterExtra (GDI32.@)
4774 INT WINAPI
GetTextCharacterExtra( HDC hdc
)
4777 DC
*dc
= get_dc_ptr( hdc
);
4778 if (!dc
) return 0x80000000;
4779 ret
= dc
->charExtra
;
4780 release_dc_ptr( dc
);
4785 /***********************************************************************
4786 * SetTextCharacterExtra (GDI32.@)
4788 INT WINAPI
SetTextCharacterExtra( HDC hdc
, INT extra
)
4790 INT ret
= 0x80000000;
4791 DC
* dc
= get_dc_ptr( hdc
);
4795 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetTextCharacterExtra
);
4796 extra
= physdev
->funcs
->pSetTextCharacterExtra( physdev
, extra
);
4797 if (extra
!= 0x80000000)
4799 ret
= dc
->charExtra
;
4800 dc
->charExtra
= extra
;
4802 release_dc_ptr( dc
);
4808 /***********************************************************************
4809 * SetTextJustification (GDI32.@)
4811 BOOL WINAPI
SetTextJustification( HDC hdc
, INT extra
, INT breaks
)
4815 DC
* dc
= get_dc_ptr( hdc
);
4817 if (!dc
) return FALSE
;
4819 physdev
= GET_DC_PHYSDEV( dc
, pSetTextJustification
);
4820 ret
= physdev
->funcs
->pSetTextJustification( physdev
, extra
, breaks
);
4823 extra
= abs((extra
* dc
->vport_ext
.cx
+ dc
->wnd_ext
.cx
/ 2) / dc
->wnd_ext
.cx
);
4824 if (!extra
) breaks
= 0;
4827 dc
->breakExtra
= extra
/ breaks
;
4828 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
4836 release_dc_ptr( dc
);
4841 /***********************************************************************
4842 * GetTextFaceA (GDI32.@)
4844 INT WINAPI
GetTextFaceA( HDC hdc
, INT count
, LPSTR name
)
4846 INT res
= GetTextFaceW(hdc
, 0, NULL
);
4847 LPWSTR nameW
= HeapAlloc( GetProcessHeap(), 0, res
* 2 );
4848 GetTextFaceW( hdc
, res
, nameW
);
4854 res
= WideCharToMultiByte(CP_ACP
, 0, nameW
, -1, name
, count
, NULL
, NULL
);
4858 /* GetTextFaceA does NOT include the nul byte in the return count. */
4865 res
= WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, NULL
, 0, NULL
, NULL
);
4866 HeapFree( GetProcessHeap(), 0, nameW
);
4870 /***********************************************************************
4871 * GetTextFaceW (GDI32.@)
4873 INT WINAPI
GetTextFaceW( HDC hdc
, INT count
, LPWSTR name
)
4878 DC
* dc
= get_dc_ptr( hdc
);
4881 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
4882 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
4883 release_dc_ptr( dc
);
4888 /***********************************************************************
4889 * GetTextExtentPoint32A (GDI32.@)
4891 * See GetTextExtentPoint32W.
4893 BOOL WINAPI
GetTextExtentPoint32A( HDC hdc
, LPCSTR str
, INT count
,
4900 if (count
< 0) return FALSE
;
4902 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
4906 ret
= GetTextExtentPoint32W( hdc
, p
, wlen
, size
);
4907 HeapFree( GetProcessHeap(), 0, p
);
4910 TRACE("(%p %s %d %p): returning %d x %d\n",
4911 hdc
, debugstr_an (str
, count
), count
, size
, size
->cx
, size
->cy
);
4916 /***********************************************************************
4917 * GetTextExtentPoint32W [GDI32.@]
4919 * Computes width/height for a string.
4921 * Computes width and height of the specified string.
4927 BOOL WINAPI
GetTextExtentPoint32W(
4928 HDC hdc
, /* [in] Handle of device context */
4929 LPCWSTR str
, /* [in] Address of text string */
4930 INT count
, /* [in] Number of characters in string */
4931 LPSIZE size
) /* [out] Address of structure for string size */
4933 return GetTextExtentExPointW(hdc
, str
, count
, 0, NULL
, NULL
, size
);
4936 /***********************************************************************
4937 * GetTextExtentExPointI [GDI32.@]
4939 * Computes width and height of the array of glyph indices.
4942 * hdc [I] Handle of device context.
4943 * indices [I] Glyph index array.
4944 * count [I] Number of glyphs in array.
4945 * max_ext [I] Maximum width in glyphs.
4946 * nfit [O] Maximum number of characters.
4947 * dxs [O] Partial string widths.
4948 * size [O] Returned string size.
4954 BOOL WINAPI
GetTextExtentExPointI( HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
4955 LPINT nfit
, LPINT dxs
, LPSIZE size
)
4960 INT buffer
[256], *pos
= dxs
;
4962 if (count
< 0) return FALSE
;
4964 dc
= get_dc_ptr( hdc
);
4965 if (!dc
) return FALSE
;
4970 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
4972 release_dc_ptr( dc
);
4977 ret
= get_char_positions_indices( dc
, indices
, count
, pos
, size
);
4982 for (i
= 0; i
< count
; i
++)
4984 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
4985 if (nfit
&& dx
> (unsigned int)max_ext
) break;
4986 if (dxs
) dxs
[i
] = dx
;
4988 if (nfit
) *nfit
= i
;
4991 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
4992 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
4995 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
4996 release_dc_ptr( dc
);
4998 TRACE("(%p %p %d %p): returning %d x %d\n",
4999 hdc
, indices
, count
, size
, size
->cx
, size
->cy
);
5003 /***********************************************************************
5004 * GetTextExtentPointI [GDI32.@]
5006 * Computes width and height of the array of glyph indices.
5009 * hdc [I] Handle of device context.
5010 * indices [I] Glyph index array.
5011 * count [I] Number of glyphs in array.
5012 * size [O] Returned string size.
5018 BOOL WINAPI
GetTextExtentPointI( HDC hdc
, const WORD
*indices
, INT count
, LPSIZE size
)
5020 return GetTextExtentExPointI( hdc
, indices
, count
, 0, NULL
, NULL
, size
);
5024 /***********************************************************************
5025 * GetTextExtentPointA (GDI32.@)
5027 BOOL WINAPI
GetTextExtentPointA( HDC hdc
, LPCSTR str
, INT count
,
5030 TRACE("not bug compatible.\n");
5031 return GetTextExtentPoint32A( hdc
, str
, count
, size
);
5034 /***********************************************************************
5035 * GetTextExtentPointW (GDI32.@)
5037 BOOL WINAPI
GetTextExtentPointW( HDC hdc
, LPCWSTR str
, INT count
,
5040 TRACE("not bug compatible.\n");
5041 return GetTextExtentPoint32W( hdc
, str
, count
, size
);
5045 /***********************************************************************
5046 * GetTextExtentExPointA (GDI32.@)
5048 BOOL WINAPI
GetTextExtentExPointA( HDC hdc
, LPCSTR str
, INT count
,
5049 INT maxExt
, LPINT lpnFit
,
5050 LPINT alpDx
, LPSIZE size
)
5057 if (count
< 0) return FALSE
;
5058 if (maxExt
< -1) return FALSE
;
5062 walpDx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(INT
) );
5063 if (!walpDx
) return FALSE
;
5066 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
5067 ret
= GetTextExtentExPointW( hdc
, p
, wlen
, maxExt
, lpnFit
, walpDx
, size
);
5070 INT n
= lpnFit
? *lpnFit
: wlen
;
5072 for(i
= 0, j
= 0; i
< n
; i
++, j
++)
5074 alpDx
[j
] = walpDx
[i
];
5075 if (IsDBCSLeadByte(str
[j
])) alpDx
[++j
] = walpDx
[i
];
5078 if (lpnFit
) *lpnFit
= WideCharToMultiByte(CP_ACP
,0,p
,*lpnFit
,NULL
,0,NULL
,NULL
);
5079 HeapFree( GetProcessHeap(), 0, p
);
5080 HeapFree( GetProcessHeap(), 0, walpDx
);
5085 /***********************************************************************
5086 * GetTextExtentExPointW (GDI32.@)
5088 * Return the size of the string as it would be if it was output properly by
5091 BOOL WINAPI
GetTextExtentExPointW( HDC hdc
, LPCWSTR str
, INT count
, INT max_ext
,
5092 LPINT nfit
, LPINT dxs
, LPSIZE size
)
5097 INT buffer
[256], *pos
= dxs
;
5099 if (count
< 0) return FALSE
;
5101 dc
= get_dc_ptr(hdc
);
5102 if (!dc
) return FALSE
;
5107 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
5109 release_dc_ptr( dc
);
5114 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
5119 for (i
= 0; i
< count
; i
++)
5121 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
5122 if (nfit
&& dx
> (unsigned int)max_ext
) break;
5123 if (dxs
) dxs
[i
] = dx
;
5125 if (nfit
) *nfit
= i
;
5128 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
5129 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
5132 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
5133 release_dc_ptr( dc
);
5135 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
5139 /***********************************************************************
5140 * GetTextMetricsA (GDI32.@)
5142 BOOL WINAPI
GetTextMetricsA( HDC hdc
, TEXTMETRICA
*metrics
)
5146 if (!GetTextMetricsW( hdc
, &tm32
)) return FALSE
;
5147 FONT_TextMetricWToA( &tm32
, metrics
);
5151 /***********************************************************************
5152 * GetTextMetricsW (GDI32.@)
5154 BOOL WINAPI
GetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
)
5158 DC
* dc
= get_dc_ptr( hdc
);
5159 if (!dc
) return FALSE
;
5161 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5162 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
5166 /* device layer returns values in device units
5167 * therefore we have to convert them to logical */
5169 metrics
->tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
5170 metrics
->tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
5171 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
5172 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
5173 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
5174 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
5175 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
5176 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
5177 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
5178 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
5181 TRACE("text metrics:\n"
5182 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5183 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5184 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5185 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5186 " PitchAndFamily = %02x\n"
5187 " --------------------\n"
5188 " InternalLeading = %i\n"
5192 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
5193 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
5194 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
5195 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
5196 metrics
->tmPitchAndFamily
,
5197 metrics
->tmInternalLeading
,
5200 metrics
->tmHeight
);
5202 release_dc_ptr( dc
);
5207 /***********************************************************************
5208 * GetOutlineTextMetricsA (GDI32.@)
5209 * Gets metrics for TrueType fonts.
5212 * If the supplied buffer isn't big enough Windows partially fills it up to
5213 * its given length and returns that length.
5216 * Success: Non-zero or size of required buffer
5219 UINT WINAPI
GetOutlineTextMetricsA(
5220 HDC hdc
, /* [in] Handle of device context */
5221 UINT cbData
, /* [in] Size of metric data array */
5222 LPOUTLINETEXTMETRICA lpOTM
) /* [out] Address of metric data array */
5224 char buf
[512], *ptr
;
5226 OUTLINETEXTMETRICW
*lpOTMW
= (OUTLINETEXTMETRICW
*)buf
;
5227 OUTLINETEXTMETRICA
*output
= lpOTM
;
5230 if((ret
= GetOutlineTextMetricsW(hdc
, 0, NULL
)) == 0)
5232 if(ret
> sizeof(buf
))
5233 lpOTMW
= HeapAlloc(GetProcessHeap(), 0, ret
);
5234 GetOutlineTextMetricsW(hdc
, ret
, lpOTMW
);
5236 needed
= sizeof(OUTLINETEXTMETRICA
);
5237 if(lpOTMW
->otmpFamilyName
)
5238 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5239 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
5240 NULL
, 0, NULL
, NULL
);
5241 if(lpOTMW
->otmpFaceName
)
5242 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5243 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
5244 NULL
, 0, NULL
, NULL
);
5245 if(lpOTMW
->otmpStyleName
)
5246 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5247 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
5248 NULL
, 0, NULL
, NULL
);
5249 if(lpOTMW
->otmpFullName
)
5250 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5251 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
5252 NULL
, 0, NULL
, NULL
);
5259 TRACE("needed = %d\n", needed
);
5261 /* Since the supplied buffer isn't big enough, we'll alloc one
5262 that is and memcpy the first cbData bytes into the lpOTM at
5264 output
= HeapAlloc(GetProcessHeap(), 0, needed
);
5266 ret
= output
->otmSize
= min(needed
, cbData
);
5267 FONT_TextMetricWToA( &lpOTMW
->otmTextMetrics
, &output
->otmTextMetrics
);
5268 output
->otmFiller
= 0;
5269 output
->otmPanoseNumber
= lpOTMW
->otmPanoseNumber
;
5270 output
->otmfsSelection
= lpOTMW
->otmfsSelection
;
5271 output
->otmfsType
= lpOTMW
->otmfsType
;
5272 output
->otmsCharSlopeRise
= lpOTMW
->otmsCharSlopeRise
;
5273 output
->otmsCharSlopeRun
= lpOTMW
->otmsCharSlopeRun
;
5274 output
->otmItalicAngle
= lpOTMW
->otmItalicAngle
;
5275 output
->otmEMSquare
= lpOTMW
->otmEMSquare
;
5276 output
->otmAscent
= lpOTMW
->otmAscent
;
5277 output
->otmDescent
= lpOTMW
->otmDescent
;
5278 output
->otmLineGap
= lpOTMW
->otmLineGap
;
5279 output
->otmsCapEmHeight
= lpOTMW
->otmsCapEmHeight
;
5280 output
->otmsXHeight
= lpOTMW
->otmsXHeight
;
5281 output
->otmrcFontBox
= lpOTMW
->otmrcFontBox
;
5282 output
->otmMacAscent
= lpOTMW
->otmMacAscent
;
5283 output
->otmMacDescent
= lpOTMW
->otmMacDescent
;
5284 output
->otmMacLineGap
= lpOTMW
->otmMacLineGap
;
5285 output
->otmusMinimumPPEM
= lpOTMW
->otmusMinimumPPEM
;
5286 output
->otmptSubscriptSize
= lpOTMW
->otmptSubscriptSize
;
5287 output
->otmptSubscriptOffset
= lpOTMW
->otmptSubscriptOffset
;
5288 output
->otmptSuperscriptSize
= lpOTMW
->otmptSuperscriptSize
;
5289 output
->otmptSuperscriptOffset
= lpOTMW
->otmptSuperscriptOffset
;
5290 output
->otmsStrikeoutSize
= lpOTMW
->otmsStrikeoutSize
;
5291 output
->otmsStrikeoutPosition
= lpOTMW
->otmsStrikeoutPosition
;
5292 output
->otmsUnderscoreSize
= lpOTMW
->otmsUnderscoreSize
;
5293 output
->otmsUnderscorePosition
= lpOTMW
->otmsUnderscorePosition
;
5296 ptr
= (char*)(output
+ 1);
5297 left
= needed
- sizeof(*output
);
5299 if(lpOTMW
->otmpFamilyName
) {
5300 output
->otmpFamilyName
= (LPSTR
)(ptr
- (char*)output
);
5301 len
= WideCharToMultiByte(CP_ACP
, 0,
5302 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
5303 ptr
, left
, NULL
, NULL
);
5307 output
->otmpFamilyName
= 0;
5309 if(lpOTMW
->otmpFaceName
) {
5310 output
->otmpFaceName
= (LPSTR
)(ptr
- (char*)output
);
5311 len
= WideCharToMultiByte(CP_ACP
, 0,
5312 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
5313 ptr
, left
, NULL
, NULL
);
5317 output
->otmpFaceName
= 0;
5319 if(lpOTMW
->otmpStyleName
) {
5320 output
->otmpStyleName
= (LPSTR
)(ptr
- (char*)output
);
5321 len
= WideCharToMultiByte(CP_ACP
, 0,
5322 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
5323 ptr
, left
, NULL
, NULL
);
5327 output
->otmpStyleName
= 0;
5329 if(lpOTMW
->otmpFullName
) {
5330 output
->otmpFullName
= (LPSTR
)(ptr
- (char*)output
);
5331 len
= WideCharToMultiByte(CP_ACP
, 0,
5332 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
5333 ptr
, left
, NULL
, NULL
);
5336 output
->otmpFullName
= 0;
5340 if(output
!= lpOTM
) {
5341 memcpy(lpOTM
, output
, cbData
);
5342 HeapFree(GetProcessHeap(), 0, output
);
5344 /* check if the string offsets really fit into the provided size */
5345 /* FIXME: should we check string length as well? */
5346 /* make sure that we don't read/write beyond the provided buffer */
5347 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFamilyName
) + sizeof(LPSTR
))
5349 if ((UINT_PTR
)lpOTM
->otmpFamilyName
>= lpOTM
->otmSize
)
5350 lpOTM
->otmpFamilyName
= 0; /* doesn't fit */
5353 /* make sure that we don't read/write beyond the provided buffer */
5354 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFaceName
) + sizeof(LPSTR
))
5356 if ((UINT_PTR
)lpOTM
->otmpFaceName
>= lpOTM
->otmSize
)
5357 lpOTM
->otmpFaceName
= 0; /* doesn't fit */
5360 /* make sure that we don't read/write beyond the provided buffer */
5361 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpStyleName
) + sizeof(LPSTR
))
5363 if ((UINT_PTR
)lpOTM
->otmpStyleName
>= lpOTM
->otmSize
)
5364 lpOTM
->otmpStyleName
= 0; /* doesn't fit */
5367 /* make sure that we don't read/write beyond the provided buffer */
5368 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFullName
) + sizeof(LPSTR
))
5370 if ((UINT_PTR
)lpOTM
->otmpFullName
>= lpOTM
->otmSize
)
5371 lpOTM
->otmpFullName
= 0; /* doesn't fit */
5376 if(lpOTMW
!= (OUTLINETEXTMETRICW
*)buf
)
5377 HeapFree(GetProcessHeap(), 0, lpOTMW
);
5383 /***********************************************************************
5384 * GetOutlineTextMetricsW [GDI32.@]
5386 UINT WINAPI
GetOutlineTextMetricsW(
5387 HDC hdc
, /* [in] Handle of device context */
5388 UINT cbData
, /* [in] Size of metric data array */
5389 LPOUTLINETEXTMETRICW lpOTM
) /* [out] Address of metric data array */
5391 DC
*dc
= get_dc_ptr( hdc
);
5392 OUTLINETEXTMETRICW
*output
= lpOTM
;
5396 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
5399 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
5400 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
5402 if (lpOTM
&& ret
> cbData
)
5404 output
= HeapAlloc(GetProcessHeap(), 0, ret
);
5405 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
5410 output
->otmTextMetrics
.tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
5411 output
->otmTextMetrics
.tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
5412 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
5413 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
5414 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
5415 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
5416 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
5417 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
5418 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
5419 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
5420 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
5421 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
5422 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
5423 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
5424 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
5425 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
5426 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
5427 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
5428 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
5429 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
5430 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
5431 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
5432 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
5433 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
5434 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
5435 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
5436 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
5437 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
5438 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
5439 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
5440 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
5441 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
5442 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
5443 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
5447 memcpy(lpOTM
, output
, cbData
);
5448 HeapFree(GetProcessHeap(), 0, output
);
5456 static LPSTR
FONT_GetCharsByRangeA(HDC hdc
, UINT firstChar
, UINT lastChar
, PINT pByteLen
)
5458 INT i
, count
= lastChar
- firstChar
+ 1;
5466 mbcp
= GdiGetCodePage(hdc
);
5474 if (lastChar
> 0xffff)
5476 if ((firstChar
^ lastChar
) > 0xff)
5480 if (lastChar
> 0xff)
5486 str
= HeapAlloc(GetProcessHeap(), 0, count
* 2 + 1);
5490 for(i
= 0, c
= firstChar
; c
<= lastChar
; i
++, c
++)
5494 str
[i
++] = (BYTE
)(c
>> 8);
5495 if (c
<= 0xff && IsDBCSLeadByteEx(mbcp
, c
))
5496 str
[i
] = 0x1f; /* FIXME: use default character */
5510 /***********************************************************************
5511 * GetCharWidthW (GDI32.@)
5512 * GetCharWidth32W (GDI32.@)
5514 BOOL WINAPI
GetCharWidth32W( HDC hdc
, UINT firstChar
, UINT lastChar
,
5520 DC
* dc
= get_dc_ptr( hdc
);
5522 if (!dc
) return FALSE
;
5524 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
5525 ret
= dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
5529 /* convert device units to logical */
5530 for( i
= firstChar
; i
<= lastChar
; i
++, buffer
++ )
5531 *buffer
= width_to_LP( dc
, *buffer
);
5533 release_dc_ptr( dc
);
5538 /***********************************************************************
5539 * GetCharWidthA (GDI32.@)
5540 * GetCharWidth32A (GDI32.@)
5542 BOOL WINAPI
GetCharWidth32A( HDC hdc
, UINT firstChar
, UINT lastChar
,
5550 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
5554 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
5556 for(i
= 0; i
< wlen
; i
++)
5558 if(!GetCharWidth32W(hdc
, wstr
[i
], wstr
[i
], buffer
))
5566 HeapFree(GetProcessHeap(), 0, str
);
5567 HeapFree(GetProcessHeap(), 0, wstr
);
5573 /* helper for nulldrv_ExtTextOut */
5574 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
5575 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
5577 UINT indices
[3] = {0, 0, 0x20};
5583 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
5585 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
5588 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
);
5589 if (ret
!= GDI_ERROR
) break;
5592 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
5593 if (!image
) return ERROR_SUCCESS
;
5597 if (!ret
) /* empty glyph */
5599 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
5600 return ERROR_SUCCESS
;
5603 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5604 size
= metrics
->gmBlackBoxY
* stride
;
5606 if (!(image
->ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
5607 image
->is_copy
= TRUE
;
5608 image
->free
= free_heap_bits
;
5610 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
, &identity
);
5611 if (ret
== GDI_ERROR
)
5613 HeapFree( GetProcessHeap(), 0, image
->ptr
);
5614 return ERROR_NOT_FOUND
;
5616 return ERROR_SUCCESS
;
5619 /* helper for nulldrv_ExtTextOut */
5620 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
5621 LPCWSTR str
, UINT count
, const INT
*dx
)
5626 reset_bounds( &bounds
);
5627 for (i
= 0; i
< count
; i
++)
5629 GLYPHMETRICS metrics
;
5631 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
5633 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
5634 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
5635 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
5636 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
5637 add_bounds_rect( &bounds
, &rect
);
5641 if (flags
& ETO_PDY
)
5644 y
+= dx
[ i
* 2 + 1];
5650 x
+= metrics
.gmCellIncX
;
5651 y
+= metrics
.gmCellIncY
;
5657 /* helper for nulldrv_ExtTextOut */
5658 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
5659 const struct gdi_image_bits
*image
, const RECT
*clip
)
5661 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5662 UINT i
, count
, max_count
;
5664 BYTE
*ptr
= image
->ptr
;
5665 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5667 RECT rect
, clipped_rect
;
5669 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
5670 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
5671 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
5672 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
5673 if (!clip
) clipped_rect
= rect
;
5674 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
5676 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
5677 pts
= HeapAlloc( GetProcessHeap(), 0, max_count
* sizeof(*pts
) );
5681 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
5682 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
5684 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
5686 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5687 pts
[count
].x
= rect
.left
+ x
;
5688 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5689 pts
[count
+ 1].x
= rect
.left
+ x
;
5690 if (pts
[count
+ 1].x
> pts
[count
].x
)
5692 pts
[count
].y
= pts
[count
+ 1].y
= y
;
5697 assert( count
<= max_count
);
5698 dp_to_lp( dc
, pts
, count
);
5699 for (i
= 0; i
< count
; i
+= 2) Polyline( dc
->hSelf
, pts
+ i
, 2 );
5700 HeapFree( GetProcessHeap(), 0, pts
);
5703 /***********************************************************************
5704 * nulldrv_ExtTextOut
5706 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5707 LPCWSTR str
, UINT count
, const INT
*dx
)
5709 DC
*dc
= get_nulldrv_dc( dev
);
5715 if (flags
& ETO_OPAQUE
)
5718 HBRUSH brush
= CreateSolidBrush( GetNearestColor( dev
->hdc
, dc
->backgroundColor
) );
5722 orig
= SelectObject( dev
->hdc
, brush
);
5723 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5724 PatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5725 SelectObject( dev
->hdc
, orig
);
5726 DeleteObject( brush
);
5730 if (!count
) return TRUE
;
5732 if (dc
->aa_flags
!= GGO_BITMAP
)
5734 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5735 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5736 struct gdi_image_bits bits
;
5737 struct bitblt_coords src
, dst
;
5739 /* FIXME Subpixel modes */
5740 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5742 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5743 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5744 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5745 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5747 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5748 src
.x
= src
.visrect
.left
;
5749 src
.y
= src
.visrect
.top
;
5750 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5751 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5753 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5754 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5756 /* we can avoid the GetImage, just query the needed format */
5757 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5758 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5759 info
->bmiHeader
.biWidth
= src
.width
;
5760 info
->bmiHeader
.biHeight
= -src
.height
;
5761 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5762 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5763 if (!err
|| err
== ERROR_BAD_FORMAT
)
5765 /* make the source rectangle relative to the source bits */
5767 src
.visrect
.left
= src
.visrect
.top
= 0;
5768 src
.visrect
.right
= src
.width
;
5769 src
.visrect
.bottom
= src
.height
;
5771 bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
5772 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5773 bits
.is_copy
= TRUE
;
5774 bits
.free
= free_heap_bits
;
5775 err
= ERROR_SUCCESS
;
5780 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5781 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5782 if (!err
&& !bits
.is_copy
)
5784 void *ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
5787 if (bits
.free
) bits
.free( &bits
);
5788 return ERROR_OUTOFMEMORY
;
5790 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5791 if (bits
.free
) bits
.free( &bits
);
5793 bits
.is_copy
= TRUE
;
5794 bits
.free
= free_heap_bits
;
5799 /* make x,y relative to the image bits */
5800 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5801 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5802 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5803 aa_flags
, str
, count
, dx
);
5804 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5805 if (bits
.free
) bits
.free( &bits
);
5810 pen
= CreatePen( PS_SOLID
, 1, dc
->textColor
);
5811 orig
= SelectObject( dev
->hdc
, pen
);
5813 for (i
= 0; i
< count
; i
++)
5815 GLYPHMETRICS metrics
;
5816 struct gdi_image_bits image
;
5818 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5821 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5822 if (image
.free
) image
.free( &image
);
5826 if (flags
& ETO_PDY
)
5829 y
+= dx
[ i
* 2 + 1];
5835 x
+= metrics
.gmCellIncX
;
5836 y
+= metrics
.gmCellIncY
;
5840 SelectObject( dev
->hdc
, orig
);
5841 DeleteObject( pen
);
5846 /***********************************************************************
5847 * ExtTextOutA (GDI32.@)
5851 BOOL WINAPI
ExtTextOutA( HDC hdc
, INT x
, INT y
, UINT flags
,
5852 const RECT
*lprect
, LPCSTR str
, UINT count
, const INT
*lpDx
)
5860 if (count
> INT_MAX
) return FALSE
;
5862 if (flags
& ETO_GLYPH_INDEX
)
5863 return ExtTextOutW( hdc
, x
, y
, flags
, lprect
, (LPCWSTR
)str
, count
, lpDx
);
5865 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, &codepage
);
5868 unsigned int i
= 0, j
= 0;
5870 /* allocate enough for a ETO_PDY */
5871 lpDxW
= HeapAlloc( GetProcessHeap(), 0, 2*wlen
*sizeof(INT
));
5873 if(IsDBCSLeadByteEx(codepage
, str
[i
]))
5877 lpDxW
[j
++] = lpDx
[i
* 2] + lpDx
[(i
+ 1) * 2];
5878 lpDxW
[j
++] = lpDx
[i
* 2 + 1] + lpDx
[(i
+ 1) * 2 + 1];
5881 lpDxW
[j
++] = lpDx
[i
] + lpDx
[i
+ 1];
5888 lpDxW
[j
++] = lpDx
[i
* 2];
5889 lpDxW
[j
++] = lpDx
[i
* 2 + 1];
5892 lpDxW
[j
++] = lpDx
[i
];
5898 ret
= ExtTextOutW( hdc
, x
, y
, flags
, lprect
, p
, wlen
, lpDxW
);
5900 HeapFree( GetProcessHeap(), 0, p
);
5901 HeapFree( GetProcessHeap(), 0, lpDxW
);
5905 /***********************************************************************
5908 * Scale the underline / strikeout line width.
5910 static inline int get_line_width( DC
*dc
, int metric_size
)
5912 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5913 if (width
== 0) width
= 1;
5914 if (metric_size
< 0) width
= -width
;
5918 /***********************************************************************
5919 * ExtTextOutW (GDI32.@)
5921 * Draws text using the currently selected font, background color, and text color.
5925 * x,y [I] coordinates of string
5927 * ETO_GRAYED - undocumented on MSDN
5928 * ETO_OPAQUE - use background color for fill the rectangle
5929 * ETO_CLIPPED - clipping text to the rectangle
5930 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5931 * than encoded characters. Implies ETO_IGNORELANGUAGE
5932 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5933 * Affects BiDi ordering
5934 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5935 * ETO_PDY - unimplemented
5936 * ETO_NUMERICSLATIN - unimplemented always assumed -
5937 * do not translate numbers into locale representations
5938 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5939 * lprect [I] dimensions for clipping or/and opaquing
5940 * str [I] text string
5941 * count [I] number of symbols in string
5942 * lpDx [I] optional parameter with distance between drawing characters
5948 BOOL WINAPI
ExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
,
5949 const RECT
*lprect
, LPCWSTR str
, UINT count
, const INT
*lpDx
)
5952 LPWSTR reordered_str
= (LPWSTR
)str
;
5953 WORD
*glyphs
= NULL
;
5959 double cosEsc
, sinEsc
;
5963 POINT
*deltas
= NULL
, width
= {0, 0};
5965 DC
* dc
= get_dc_ptr( hdc
);
5968 static int quietfixme
= 0;
5970 if (!dc
) return FALSE
;
5971 if (count
> INT_MAX
) return FALSE
;
5973 align
= dc
->textAlign
;
5974 breakRem
= dc
->breakRem
;
5975 layout
= dc
->layout
;
5977 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5979 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5984 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5985 type
= GetObjectType(hdc
);
5986 if(type
== OBJ_METADC
|| type
== OBJ_ENHMETADC
)
5988 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, flags
, lprect
, str
, count
, lpDx
);
5989 release_dc_ptr( dc
);
5993 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5994 if (layout
& LAYOUT_RTL
)
5996 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5997 align
^= TA_RTLREADING
;
6000 if( !(flags
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)) && count
> 0 )
6003 reordered_str
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
6005 BIDI_Reorder( hdc
, str
, count
, GCP_REORDER
,
6006 (align
& TA_RTLREADING
) ? WINE_GCPW_FORCE_RTL
: WINE_GCPW_FORCE_LTR
,
6007 reordered_str
, count
, NULL
, &glyphs
, &cGlyphs
);
6009 flags
|= ETO_IGNORELANGUAGE
;
6012 flags
|= ETO_GLYPH_INDEX
;
6013 if (cGlyphs
!= count
)
6017 else if(flags
& ETO_GLYPH_INDEX
)
6018 glyphs
= reordered_str
;
6020 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
6021 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
6022 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->backgroundMode
, dc
->MapMode
);
6024 if(align
& TA_UPDATECP
)
6031 GetTextMetricsW(hdc
, &tm
);
6032 GetObjectW(dc
->hFont
, sizeof(lf
), &lf
);
6034 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
6035 lf
.lfEscapement
= 0;
6037 if ((dc
->GraphicsMode
== GM_COMPATIBLE
) &&
6038 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
6040 lf
.lfEscapement
= -lf
.lfEscapement
;
6043 if(lf
.lfEscapement
!= 0)
6045 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
6046 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
6054 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
6057 lp_to_dp(dc
, (POINT
*)&rc
, 2);
6059 if (flags
& ETO_OPAQUE
)
6060 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
6062 else flags
&= ~ETO_CLIPPED
;
6072 lp_to_dp(dc
, &pt
, 1);
6076 char_extra
= GetTextCharacterExtra(hdc
);
6077 if (char_extra
&& lpDx
&& GetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
6078 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
6080 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
6083 POINT total
= {0, 0}, desired
[2];
6085 deltas
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*deltas
));
6088 if (flags
& ETO_PDY
)
6090 for (i
= 0; i
< count
; i
++)
6092 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
6093 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
6098 for (i
= 0; i
< count
; i
++)
6100 deltas
[i
].x
= lpDx
[i
] + char_extra
;
6107 INT
*dx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*dx
) );
6109 if (flags
& ETO_GLYPH_INDEX
)
6110 GetTextExtentExPointI( hdc
, glyphs
, count
, -1, NULL
, dx
, &sz
);
6112 GetTextExtentExPointW( hdc
, reordered_str
, count
, -1, NULL
, dx
, &sz
);
6114 deltas
[0].x
= dx
[0];
6116 for (i
= 1; i
< count
; i
++)
6118 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
6121 HeapFree( GetProcessHeap(), 0, dx
);
6124 for(i
= 0; i
< count
; i
++)
6126 total
.x
+= deltas
[i
].x
;
6127 total
.y
+= deltas
[i
].y
;
6129 desired
[0].x
= desired
[0].y
= 0;
6131 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
6132 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
6134 lp_to_dp(dc
, desired
, 2);
6135 desired
[1].x
-= desired
[0].x
;
6136 desired
[1].y
-= desired
[0].y
;
6138 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
6140 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
6141 desired
[1].x
= -desired
[1].x
;
6142 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
6143 desired
[1].y
= -desired
[1].y
;
6146 deltas
[i
].x
= desired
[1].x
- width
.x
;
6147 deltas
[i
].y
= desired
[1].y
- width
.y
;
6157 if(flags
& ETO_GLYPH_INDEX
)
6158 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
6160 GetTextExtentPointW(hdc
, reordered_str
, count
, &sz
);
6161 desired
[0].x
= desired
[0].y
= 0;
6162 desired
[1].x
= sz
.cx
;
6164 lp_to_dp(dc
, desired
, 2);
6165 desired
[1].x
-= desired
[0].x
;
6166 desired
[1].y
-= desired
[0].y
;
6168 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
6170 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
6171 desired
[1].x
= -desired
[1].x
;
6172 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
6173 desired
[1].y
= -desired
[1].y
;
6178 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
6179 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
6180 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
6183 if (align
& TA_UPDATECP
)
6187 dp_to_lp(dc
, &pt
, 1);
6188 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
6200 if (align
& TA_UPDATECP
)
6204 dp_to_lp(dc
, &pt
, 1);
6205 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
6210 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
6213 y
+= tm
.tmAscent
* cosEsc
;
6214 x
+= tm
.tmAscent
* sinEsc
;
6218 y
-= tm
.tmDescent
* cosEsc
;
6219 x
-= tm
.tmDescent
* sinEsc
;
6226 if (dc
->backgroundMode
!= TRANSPARENT
)
6228 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
6230 if(!(flags
& ETO_OPAQUE
) || !lprect
||
6231 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
6232 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
6236 text_box
.right
= x
+ width
.x
;
6237 text_box
.top
= y
- tm
.tmAscent
;
6238 text_box
.bottom
= y
+ tm
.tmDescent
;
6240 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
6241 if (!is_rect_empty( &text_box
))
6242 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
6247 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
6248 glyphs
? glyphs
: reordered_str
, count
, (INT
*)deltas
);
6251 HeapFree(GetProcessHeap(), 0, deltas
);
6252 if(glyphs
!= reordered_str
)
6253 HeapFree(GetProcessHeap(), 0, glyphs
);
6254 if(reordered_str
!= str
)
6255 HeapFree(GetProcessHeap(), 0, reordered_str
);
6257 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
6259 int underlinePos
, strikeoutPos
;
6260 int underlineWidth
, strikeoutWidth
;
6261 UINT size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
6262 OUTLINETEXTMETRICW
* otm
= NULL
;
6264 HPEN hpen
= SelectObject(hdc
, GetStockObject(NULL_PEN
));
6265 HBRUSH hbrush
= CreateSolidBrush(dc
->textColor
);
6267 hbrush
= SelectObject(hdc
, hbrush
);
6272 underlineWidth
= tm
.tmAscent
/ 20 + 1;
6273 strikeoutPos
= tm
.tmAscent
/ 2;
6274 strikeoutWidth
= underlineWidth
;
6278 otm
= HeapAlloc(GetProcessHeap(), 0, size
);
6279 GetOutlineTextMetricsW(hdc
, size
, otm
);
6280 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
6281 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
6282 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
6283 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
6284 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
6285 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
6286 HeapFree(GetProcessHeap(), 0, otm
);
6292 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
6293 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
6294 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
6295 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
6296 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
6297 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
6298 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
6299 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
6300 pts
[4].x
= pts
[0].x
;
6301 pts
[4].y
= pts
[0].y
;
6302 dp_to_lp(dc
, pts
, 5);
6303 Polygon(hdc
, pts
, 5);
6308 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
6309 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
6310 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
6311 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
6312 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
6313 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
6314 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
6315 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
6316 pts
[4].x
= pts
[0].x
;
6317 pts
[4].y
= pts
[0].y
;
6318 dp_to_lp(dc
, pts
, 5);
6319 Polygon(hdc
, pts
, 5);
6322 SelectObject(hdc
, hpen
);
6323 hbrush
= SelectObject(hdc
, hbrush
);
6324 DeleteObject(hbrush
);
6327 release_dc_ptr( dc
);
6333 /***********************************************************************
6334 * TextOutA (GDI32.@)
6336 BOOL WINAPI
TextOutA( HDC hdc
, INT x
, INT y
, LPCSTR str
, INT count
)
6338 return ExtTextOutA( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
6342 /***********************************************************************
6343 * TextOutW (GDI32.@)
6345 BOOL WINAPI
TextOutW(HDC hdc
, INT x
, INT y
, LPCWSTR str
, INT count
)
6347 return ExtTextOutW( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
6351 /***********************************************************************
6352 * PolyTextOutA (GDI32.@)
6356 BOOL WINAPI
PolyTextOutA( HDC hdc
, const POLYTEXTA
*pptxt
, INT cStrings
)
6358 for (; cStrings
>0; cStrings
--, pptxt
++)
6359 if (!ExtTextOutA( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
6366 /***********************************************************************
6367 * PolyTextOutW (GDI32.@)
6369 * Draw several Strings
6375 BOOL WINAPI
PolyTextOutW( HDC hdc
, const POLYTEXTW
*pptxt
, INT cStrings
)
6377 for (; cStrings
>0; cStrings
--, pptxt
++)
6378 if (!ExtTextOutW( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
6384 /***********************************************************************
6385 * SetMapperFlags (GDI32.@)
6387 DWORD WINAPI
SetMapperFlags( HDC hdc
, DWORD flags
)
6389 DC
*dc
= get_dc_ptr( hdc
);
6390 DWORD ret
= GDI_ERROR
;
6394 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetMapperFlags
);
6395 flags
= physdev
->funcs
->pSetMapperFlags( physdev
, flags
);
6396 if (flags
!= GDI_ERROR
)
6398 ret
= dc
->mapperFlags
;
6399 dc
->mapperFlags
= flags
;
6401 release_dc_ptr( dc
);
6406 /***********************************************************************
6407 * GetAspectRatioFilterEx (GDI32.@)
6409 BOOL WINAPI
GetAspectRatioFilterEx( HDC hdc
, LPSIZE pAspectRatio
)
6411 FIXME("(%p, %p): -- Empty Stub !\n", hdc
, pAspectRatio
);
6416 /***********************************************************************
6417 * GetCharABCWidthsA (GDI32.@)
6419 * See GetCharABCWidthsW.
6421 BOOL WINAPI
GetCharABCWidthsA(HDC hdc
, UINT firstChar
, UINT lastChar
,
6429 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
6433 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
6436 HeapFree(GetProcessHeap(), 0, str
);
6440 for(i
= 0; i
< wlen
; i
++)
6442 if(!GetCharABCWidthsW(hdc
, wstr
[i
], wstr
[i
], abc
))
6450 HeapFree(GetProcessHeap(), 0, str
);
6451 HeapFree(GetProcessHeap(), 0, wstr
);
6457 /******************************************************************************
6458 * GetCharABCWidthsW [GDI32.@]
6460 * Retrieves widths of characters in range.
6463 * hdc [I] Handle of device context
6464 * firstChar [I] First character in range to query
6465 * lastChar [I] Last character in range to query
6466 * abc [O] Address of character-width structure
6469 * Only works with TrueType fonts
6475 BOOL WINAPI
GetCharABCWidthsW( HDC hdc
, UINT firstChar
, UINT lastChar
,
6478 DC
*dc
= get_dc_ptr(hdc
);
6484 if (!dc
) return FALSE
;
6488 release_dc_ptr( dc
);
6492 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
6493 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
6494 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
6496 release_dc_ptr( dc
);
6500 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
6501 ret
= dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, abc
);
6504 /* convert device units to logical */
6505 for( i
= firstChar
; i
<= lastChar
; i
++, abc
++ ) {
6506 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
6507 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
6508 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
6512 release_dc_ptr( dc
);
6517 /******************************************************************************
6518 * GetCharABCWidthsI [GDI32.@]
6520 * Retrieves widths of characters in range.
6523 * hdc [I] Handle of device context
6524 * firstChar [I] First glyphs in range to query
6525 * count [I] Last glyphs in range to query
6526 * pgi [i] Array of glyphs to query
6527 * abc [O] Address of character-width structure
6530 * Only works with TrueType fonts
6536 BOOL WINAPI
GetCharABCWidthsI( HDC hdc
, UINT firstChar
, UINT count
,
6537 LPWORD pgi
, LPABC abc
)
6539 DC
*dc
= get_dc_ptr(hdc
);
6544 if (!dc
) return FALSE
;
6548 release_dc_ptr( dc
);
6552 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
6553 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, abc
);
6556 /* convert device units to logical */
6557 for( i
= 0; i
< count
; i
++, abc
++ ) {
6558 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
6559 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
6560 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
6564 release_dc_ptr( dc
);
6569 /***********************************************************************
6570 * GetGlyphOutlineA (GDI32.@)
6572 DWORD WINAPI
GetGlyphOutlineA( HDC hdc
, UINT uChar
, UINT fuFormat
,
6573 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
6574 LPVOID lpBuffer
, const MAT2
*lpmat2
)
6576 if (!lpmat2
) return GDI_ERROR
;
6578 if(!(fuFormat
& GGO_GLYPH_INDEX
)) {
6584 cp
= GdiGetCodePage(hdc
);
6585 if (IsDBCSLeadByteEx(cp
, uChar
>> 8)) {
6587 mbchs
[0] = (uChar
& 0xff00) >> 8;
6588 mbchs
[1] = (uChar
& 0xff);
6591 mbchs
[0] = (uChar
& 0xff);
6594 MultiByteToWideChar(cp
, 0, mbchs
, len
, &wChar
, 1);
6598 return GetGlyphOutlineW(hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
,
6602 /***********************************************************************
6603 * GetGlyphOutlineW (GDI32.@)
6605 DWORD WINAPI
GetGlyphOutlineW( HDC hdc
, UINT uChar
, UINT fuFormat
,
6606 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
6607 LPVOID lpBuffer
, const MAT2
*lpmat2
)
6613 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
6614 hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
6616 if (!lpmat2
) return GDI_ERROR
;
6618 dc
= get_dc_ptr(hdc
);
6619 if(!dc
) return GDI_ERROR
;
6623 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
6624 ret
= dev
->funcs
->pGetGlyphOutline( dev
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
6625 release_dc_ptr( dc
);
6630 /***********************************************************************
6631 * CreateScalableFontResourceA (GDI32.@)
6633 BOOL WINAPI
CreateScalableFontResourceA( DWORD fHidden
,
6634 LPCSTR lpszResourceFile
,
6635 LPCSTR lpszFontFile
,
6636 LPCSTR lpszCurrentPath
)
6638 LPWSTR lpszResourceFileW
= NULL
;
6639 LPWSTR lpszFontFileW
= NULL
;
6640 LPWSTR lpszCurrentPathW
= NULL
;
6644 if (lpszResourceFile
)
6646 len
= MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, NULL
, 0);
6647 lpszResourceFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6648 MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, lpszResourceFileW
, len
);
6653 len
= MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, NULL
, 0);
6654 lpszFontFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6655 MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, lpszFontFileW
, len
);
6658 if (lpszCurrentPath
)
6660 len
= MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, NULL
, 0);
6661 lpszCurrentPathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6662 MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, lpszCurrentPathW
, len
);
6665 ret
= CreateScalableFontResourceW(fHidden
, lpszResourceFileW
,
6666 lpszFontFileW
, lpszCurrentPathW
);
6668 HeapFree(GetProcessHeap(), 0, lpszResourceFileW
);
6669 HeapFree(GetProcessHeap(), 0, lpszFontFileW
);
6670 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW
);
6675 #define NE_FFLAGS_LIBMODULE 0x8000
6676 #define NE_OSFLAGS_WINDOWS 0x02
6678 static const char dos_string
[0x40] = "This is a TrueType resource file";
6679 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
6681 #include <pshpack1.h>
6684 WORD num_of_resources
;
6688 CHAR dfCopyright
[60];
6694 WORD dfInternalLeading
;
6695 WORD dfExternalLeading
;
6703 BYTE dfPitchAndFamily
;
6714 CHAR szFaceName
[LF_FACESIZE
];
6716 #include <poppack.h>
6718 #include <pshpack2.h>
6739 struct ne_typeinfo fontdir_type
;
6740 struct ne_nameinfo fontdir_name
;
6741 struct ne_typeinfo scalable_type
;
6742 struct ne_nameinfo scalable_name
;
6744 BYTE fontdir_res_name
[8];
6747 #include <poppack.h>
6749 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
6753 DWORD size
, written
;
6755 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
6756 char *font_fileA
, *last_part
, *ext
;
6757 IMAGE_DOS_HEADER dos
;
6758 IMAGE_OS2_HEADER ne
=
6760 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
6762 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
6763 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
6765 struct rsrc_tab rsrc_tab
=
6769 { 0, 0, 0x0c50, 0x2c, 0 },
6771 { 0, 0, 0x0c50, 0x8001, 0 },
6773 { 7,'F','O','N','T','D','I','R'}
6776 memset( &dos
, 0, sizeof(dos
) );
6777 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
6778 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
6780 /* import name is last part\0, resident name is last part without extension
6781 non-resident name is "FONTRES:" + lfFaceName */
6783 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
6784 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
6785 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
6787 last_part
= strrchr( font_fileA
, '\\' );
6788 if (last_part
) last_part
++;
6789 else last_part
= font_fileA
;
6790 import_name_len
= strlen( last_part
) + 1;
6792 ext
= strchr( last_part
, '.' );
6793 if (ext
) res_name_len
= ext
- last_part
;
6794 else res_name_len
= import_name_len
- 1;
6796 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
6798 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
6799 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
6800 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
6801 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
6803 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
6805 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
6806 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
6807 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
6808 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
6810 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
6811 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
6815 HeapFree( GetProcessHeap(), 0, font_fileA
);
6819 memcpy( ptr
, &dos
, sizeof(dos
) );
6820 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
6821 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
6823 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
6824 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
6826 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
6827 *ptr
++ = res_name_len
;
6828 memcpy( ptr
, last_part
, res_name_len
);
6830 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
6831 *ptr
++ = import_name_len
;
6832 memcpy( ptr
, last_part
, import_name_len
);
6834 ptr
= start
+ ne
.ne_nrestab
;
6835 *ptr
++ = non_res_name_len
;
6836 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
6837 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
6839 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
6840 memcpy( ptr
, font_fileA
, font_file_len
);
6842 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
6843 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
6845 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
6846 if (file
!= INVALID_HANDLE_VALUE
)
6848 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
6850 CloseHandle( file
);
6853 HeapFree( GetProcessHeap(), 0, start
);
6854 HeapFree( GetProcessHeap(), 0, font_fileA
);
6859 /***********************************************************************
6860 * CreateScalableFontResourceW (GDI32.@)
6862 BOOL WINAPI
CreateScalableFontResourceW( DWORD hidden
, LPCWSTR resource_file
,
6863 LPCWSTR font_file
, LPCWSTR font_path
)
6865 struct fontdir fontdir
= { 0 };
6866 struct gdi_font
*font
= NULL
;
6867 WCHAR path
[MAX_PATH
];
6869 TRACE("(%d, %s, %s, %s)\n", hidden
, debugstr_w(resource_file
),
6870 debugstr_w(font_file
), debugstr_w(font_path
) );
6872 if (!font_funcs
) return FALSE
;
6874 if (!font_file
) goto done
;
6875 if (font_path
&& font_path
[0])
6877 int len
= lstrlenW( font_path
) + lstrlenW( font_file
) + 2;
6878 if (len
> MAX_PATH
) goto done
;
6879 lstrcpynW( path
, font_path
, MAX_PATH
);
6880 lstrcatW( path
, L
"\\" );
6881 lstrcatW( path
, font_file
);
6883 else if (!GetFullPathNameW( font_file
, MAX_PATH
, path
, NULL
)) goto done
;
6885 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
6886 font
->lf
.lfHeight
= 100;
6887 if (!font_funcs
->load_font( font
)) goto done
;
6888 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
6890 if (!(font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_TRUETYPE
)) goto done
;
6892 fontdir
.num_of_resources
= 1;
6894 fontdir
.dfVersion
= 0x200;
6895 fontdir
.dfSize
= sizeof(fontdir
);
6896 strcpy( fontdir
.dfCopyright
, "Wine fontdir" );
6897 fontdir
.dfType
= 0x4003; /* 0x0080 set if private */
6898 fontdir
.dfPoints
= font
->otm
.otmEMSquare
;
6899 fontdir
.dfVertRes
= 72;
6900 fontdir
.dfHorizRes
= 72;
6901 fontdir
.dfAscent
= font
->otm
.otmTextMetrics
.tmAscent
;
6902 fontdir
.dfInternalLeading
= font
->otm
.otmTextMetrics
.tmInternalLeading
;
6903 fontdir
.dfExternalLeading
= font
->otm
.otmTextMetrics
.tmExternalLeading
;
6904 fontdir
.dfItalic
= font
->otm
.otmTextMetrics
.tmItalic
;
6905 fontdir
.dfUnderline
= font
->otm
.otmTextMetrics
.tmUnderlined
;
6906 fontdir
.dfStrikeOut
= font
->otm
.otmTextMetrics
.tmStruckOut
;
6907 fontdir
.dfWeight
= font
->otm
.otmTextMetrics
.tmWeight
;
6908 fontdir
.dfCharSet
= font
->otm
.otmTextMetrics
.tmCharSet
;
6909 fontdir
.dfPixWidth
= 0;
6910 fontdir
.dfPixHeight
= font
->otm
.otmTextMetrics
.tmHeight
;
6911 fontdir
.dfPitchAndFamily
= font
->otm
.otmTextMetrics
.tmPitchAndFamily
;
6912 fontdir
.dfAvgWidth
= font
->otm
.otmTextMetrics
.tmAveCharWidth
;
6913 fontdir
.dfMaxWidth
= font
->otm
.otmTextMetrics
.tmMaxCharWidth
;
6914 fontdir
.dfFirstChar
= font
->otm
.otmTextMetrics
.tmFirstChar
;
6915 fontdir
.dfLastChar
= font
->otm
.otmTextMetrics
.tmLastChar
;
6916 fontdir
.dfDefaultChar
= font
->otm
.otmTextMetrics
.tmDefaultChar
;
6917 fontdir
.dfBreakChar
= font
->otm
.otmTextMetrics
.tmBreakChar
;
6918 fontdir
.dfWidthBytes
= 0;
6919 fontdir
.dfDevice
= 0;
6920 fontdir
.dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
6921 fontdir
.dfReserved
= 0;
6922 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)font
->otm
.otmpFamilyName
, -1,
6923 fontdir
.szFaceName
, LF_FACESIZE
, NULL
, NULL
);
6924 free_gdi_font( font
);
6926 if (hidden
) fontdir
.dfType
|= 0x80;
6927 return create_fot( resource_file
, font_file
, &fontdir
);
6930 if (font
) free_gdi_font( font
);
6931 SetLastError( ERROR_INVALID_PARAMETER
);
6935 /*************************************************************************
6936 * GetKerningPairsA (GDI32.@)
6938 DWORD WINAPI
GetKerningPairsA( HDC hDC
, DWORD cPairs
,
6939 LPKERNINGPAIR kern_pairA
)
6943 DWORD i
, total_kern_pairs
, kern_pairs_copied
= 0;
6944 KERNINGPAIR
*kern_pairW
;
6946 if (!cPairs
&& kern_pairA
)
6948 SetLastError(ERROR_INVALID_PARAMETER
);
6952 cp
= GdiGetCodePage(hDC
);
6954 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
6955 * to fail on an invalid character for CP_SYMBOL.
6957 cpi
.DefaultChar
[0] = 0;
6958 if (cp
!= CP_SYMBOL
&& !GetCPInfo(cp
, &cpi
))
6960 FIXME("Can't find codepage %u info\n", cp
);
6964 total_kern_pairs
= GetKerningPairsW(hDC
, 0, NULL
);
6965 if (!total_kern_pairs
) return 0;
6967 kern_pairW
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pairW
));
6968 GetKerningPairsW(hDC
, total_kern_pairs
, kern_pairW
);
6970 for (i
= 0; i
< total_kern_pairs
; i
++)
6974 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wFirst
, 1, &first
, 1, NULL
, NULL
))
6977 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wSecond
, 1, &second
, 1, NULL
, NULL
))
6980 if (first
== cpi
.DefaultChar
[0] || second
== cpi
.DefaultChar
[0])
6985 if (kern_pairs_copied
>= cPairs
) break;
6987 kern_pairA
->wFirst
= (BYTE
)first
;
6988 kern_pairA
->wSecond
= (BYTE
)second
;
6989 kern_pairA
->iKernAmount
= kern_pairW
[i
].iKernAmount
;
6992 kern_pairs_copied
++;
6995 HeapFree(GetProcessHeap(), 0, kern_pairW
);
6997 return kern_pairs_copied
;
7000 /*************************************************************************
7001 * GetKerningPairsW (GDI32.@)
7003 DWORD WINAPI
GetKerningPairsW( HDC hDC
, DWORD cPairs
,
7004 LPKERNINGPAIR lpKerningPairs
)
7010 TRACE("(%p,%d,%p)\n", hDC
, cPairs
, lpKerningPairs
);
7012 if (!cPairs
&& lpKerningPairs
)
7014 SetLastError(ERROR_INVALID_PARAMETER
);
7018 dc
= get_dc_ptr(hDC
);
7021 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
7022 ret
= dev
->funcs
->pGetKerningPairs( dev
, cPairs
, lpKerningPairs
);
7023 release_dc_ptr( dc
);
7027 /*************************************************************************
7028 * TranslateCharsetInfo [GDI32.@]
7030 * Fills a CHARSETINFO structure for a character set, code page, or
7031 * font. This allows making the correspondence between different labels
7032 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
7033 * of the same encoding.
7035 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
7036 * only one codepage should be set in *lpSrc.
7039 * TRUE on success, FALSE on failure.
7042 BOOL WINAPI
TranslateCharsetInfo(
7043 LPDWORD lpSrc
, /* [in]
7044 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
7045 if flags == TCI_SRCCHARSET: a character set value
7046 if flags == TCI_SRCCODEPAGE: a code page value
7048 LPCHARSETINFO lpCs
, /* [out] structure to receive charset information */
7049 DWORD flags
/* [in] determines interpretation of lpSrc */)
7053 case TCI_SRCFONTSIG
:
7054 while (index
< MAXTCIINDEX
&& !(*lpSrc
>>index
& 0x0001)) index
++;
7056 case TCI_SRCCODEPAGE
:
7057 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciACP
) index
++;
7059 case TCI_SRCCHARSET
:
7060 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciCharset
) index
++;
7065 if (index
>= MAXTCIINDEX
|| FONT_tci
[index
].ciCharset
== DEFAULT_CHARSET
) return FALSE
;
7066 *lpCs
= FONT_tci
[index
];
7070 /*************************************************************************
7071 * GetFontLanguageInfo (GDI32.@)
7073 DWORD WINAPI
GetFontLanguageInfo(HDC hdc
)
7075 FONTSIGNATURE fontsig
;
7076 static const DWORD GCP_DBCS_MASK
=FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
,
7077 GCP_DIACRITIC_MASK
=0x00000000,
7078 FLI_GLYPHS_MASK
=0x00000000,
7079 GCP_GLYPHSHAPE_MASK
=FS_ARABIC
,
7080 GCP_KASHIDA_MASK
=0x00000000,
7081 GCP_LIGATE_MASK
=0x00000000,
7082 GCP_REORDER_MASK
=FS_HEBREW
|FS_ARABIC
;
7086 GetTextCharsetInfo( hdc
, &fontsig
, 0 );
7087 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
7089 if( (fontsig
.fsCsb
[0]&GCP_DBCS_MASK
)!=0 )
7092 if( (fontsig
.fsCsb
[0]&GCP_DIACRITIC_MASK
)!=0 )
7093 result
|=GCP_DIACRITIC
;
7095 if( (fontsig
.fsCsb
[0]&FLI_GLYPHS_MASK
)!=0 )
7098 if( (fontsig
.fsCsb
[0]&GCP_GLYPHSHAPE_MASK
)!=0 )
7099 result
|=GCP_GLYPHSHAPE
;
7101 if( (fontsig
.fsCsb
[0]&GCP_KASHIDA_MASK
)!=0 )
7102 result
|=GCP_KASHIDA
;
7104 if( (fontsig
.fsCsb
[0]&GCP_LIGATE_MASK
)!=0 )
7107 if( GetKerningPairsW( hdc
, 0, NULL
) )
7108 result
|=GCP_USEKERNING
;
7110 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
7111 if( GetTextAlign( hdc
) & TA_RTLREADING
)
7112 if( (fontsig
.fsCsb
[0]&GCP_REORDER_MASK
)!=0 )
7113 result
|=GCP_REORDER
;
7119 /*************************************************************************
7120 * GetFontData [GDI32.@]
7122 * Retrieve data for TrueType font.
7126 * success: Number of bytes returned
7127 * failure: GDI_ERROR
7131 * Calls SetLastError()
7134 DWORD WINAPI
GetFontData(HDC hdc
, DWORD table
, DWORD offset
,
7135 LPVOID buffer
, DWORD length
)
7137 DC
*dc
= get_dc_ptr(hdc
);
7141 if(!dc
) return GDI_ERROR
;
7143 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
7144 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
7145 release_dc_ptr( dc
);
7149 /*************************************************************************
7150 * GetGlyphIndicesA [GDI32.@]
7152 DWORD WINAPI
GetGlyphIndicesA(HDC hdc
, LPCSTR lpstr
, INT count
,
7153 LPWORD pgi
, DWORD flags
)
7159 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7160 hdc
, debugstr_an(lpstr
, count
), count
, pgi
, flags
);
7162 lpstrW
= FONT_mbtowc(hdc
, lpstr
, count
, &countW
, NULL
);
7163 ret
= GetGlyphIndicesW(hdc
, lpstrW
, countW
, pgi
, flags
);
7164 HeapFree(GetProcessHeap(), 0, lpstrW
);
7169 /*************************************************************************
7170 * GetGlyphIndicesW [GDI32.@]
7172 DWORD WINAPI
GetGlyphIndicesW(HDC hdc
, LPCWSTR lpstr
, INT count
,
7173 LPWORD pgi
, DWORD flags
)
7175 DC
*dc
= get_dc_ptr(hdc
);
7179 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7180 hdc
, debugstr_wn(lpstr
, count
), count
, pgi
, flags
);
7182 if(!dc
) return GDI_ERROR
;
7184 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
7185 ret
= dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
7186 release_dc_ptr( dc
);
7190 /*************************************************************************
7191 * GetCharacterPlacementA [GDI32.@]
7193 * See GetCharacterPlacementW.
7196 * the web browser control of ie4 calls this with dwFlags=0
7199 GetCharacterPlacementA(HDC hdc
, LPCSTR lpString
, INT uCount
,
7200 INT nMaxExtent
, GCP_RESULTSA
*lpResults
,
7205 GCP_RESULTSW resultsW
;
7209 TRACE("%s, %d, %d, 0x%08x\n",
7210 debugstr_an(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
7212 lpStringW
= FONT_mbtowc(hdc
, lpString
, uCount
, &uCountW
, &font_cp
);
7216 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, NULL
, dwFlags
);
7217 HeapFree(GetProcessHeap(), 0, lpStringW
);
7221 /* both structs are equal in size */
7222 memcpy(&resultsW
, lpResults
, sizeof(resultsW
));
7224 if(lpResults
->lpOutString
)
7225 resultsW
.lpOutString
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*uCountW
);
7227 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, &resultsW
, dwFlags
);
7229 lpResults
->nGlyphs
= resultsW
.nGlyphs
;
7230 lpResults
->nMaxFit
= resultsW
.nMaxFit
;
7232 if(lpResults
->lpOutString
) {
7233 WideCharToMultiByte(font_cp
, 0, resultsW
.lpOutString
, uCountW
,
7234 lpResults
->lpOutString
, uCount
, NULL
, NULL
);
7237 HeapFree(GetProcessHeap(), 0, lpStringW
);
7238 HeapFree(GetProcessHeap(), 0, resultsW
.lpOutString
);
7243 static int kern_pair(const KERNINGPAIR
*kern
, int count
, WCHAR c1
, WCHAR c2
)
7247 for (i
= 0; i
< count
; i
++)
7249 if (kern
[i
].wFirst
== c1
&& kern
[i
].wSecond
== c2
)
7250 return kern
[i
].iKernAmount
;
7256 static int *kern_string(HDC hdc
, const WCHAR
*str
, int len
, int *kern_total
)
7259 KERNINGPAIR
*kern
= NULL
;
7264 ret
= heap_alloc(len
* sizeof(*ret
));
7265 if (!ret
) return NULL
;
7267 count
= GetKerningPairsW(hdc
, 0, NULL
);
7270 kern
= heap_alloc(count
* sizeof(*kern
));
7277 GetKerningPairsW(hdc
, count
, kern
);
7280 for (i
= 0; i
< len
- 1; i
++)
7282 ret
[i
] = kern_pair(kern
, count
, str
[i
], str
[i
+ 1]);
7283 *kern_total
+= ret
[i
];
7286 ret
[len
- 1] = 0; /* no kerning for last element */
7292 /*************************************************************************
7293 * GetCharacterPlacementW [GDI32.@]
7295 * Retrieve information about a string. This includes the width, reordering,
7296 * Glyphing and so on.
7300 * The width and height of the string if successful, 0 if failed.
7304 * All flags except GCP_REORDER are not yet implemented.
7305 * Reordering is not 100% compliant to the Windows BiDi method.
7306 * Caret positioning is not yet implemented for BiDi.
7307 * Classes are not yet implemented.
7311 GetCharacterPlacementW(
7312 HDC hdc
, /* [in] Device context for which the rendering is to be done */
7313 LPCWSTR lpString
, /* [in] The string for which information is to be returned */
7314 INT uCount
, /* [in] Number of WORDS in string. */
7315 INT nMaxExtent
, /* [in] Maximum extent the string is to take (in HDC logical units) */
7316 GCP_RESULTSW
*lpResults
, /* [in/out] A pointer to a GCP_RESULTSW struct */
7317 DWORD dwFlags
/* [in] Flags specifying how to process the string */
7323 int *kern
= NULL
, kern_total
= 0;
7325 TRACE("%s, %d, %d, 0x%08x\n",
7326 debugstr_wn(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
7332 return GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
) ? MAKELONG(size
.cx
, size
.cy
) : 0;
7334 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
7335 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
7336 lpResults
->lStructSize
, lpResults
->lpOutString
, lpResults
->lpOrder
,
7337 lpResults
->lpDx
, lpResults
->lpCaretPos
, lpResults
->lpClass
,
7338 lpResults
->lpGlyphs
, lpResults
->nGlyphs
, lpResults
->nMaxFit
);
7340 if (dwFlags
& ~(GCP_REORDER
| GCP_USEKERNING
))
7341 FIXME("flags 0x%08x ignored\n", dwFlags
);
7342 if (lpResults
->lpClass
)
7343 FIXME("classes not implemented\n");
7344 if (lpResults
->lpCaretPos
&& (dwFlags
& GCP_REORDER
))
7345 FIXME("Caret positions for complex scripts not implemented\n");
7347 nSet
= (UINT
)uCount
;
7348 if (nSet
> lpResults
->nGlyphs
)
7349 nSet
= lpResults
->nGlyphs
;
7351 /* return number of initialized fields */
7352 lpResults
->nGlyphs
= nSet
;
7354 if (!(dwFlags
& GCP_REORDER
))
7356 /* Treat the case where no special handling was requested in a fastpath way */
7357 /* copy will do if the GCP_REORDER flag is not set */
7358 if (lpResults
->lpOutString
)
7359 memcpy( lpResults
->lpOutString
, lpString
, nSet
* sizeof(WCHAR
));
7361 if (lpResults
->lpOrder
)
7363 for (i
= 0; i
< nSet
; i
++)
7364 lpResults
->lpOrder
[i
] = i
;
7369 BIDI_Reorder(NULL
, lpString
, uCount
, dwFlags
, WINE_GCPW_FORCE_LTR
, lpResults
->lpOutString
,
7370 nSet
, lpResults
->lpOrder
, NULL
, NULL
);
7373 if (dwFlags
& GCP_USEKERNING
)
7375 kern
= kern_string(hdc
, lpString
, nSet
, &kern_total
);
7378 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
7383 /* FIXME: Will use the placement chars */
7384 if (lpResults
->lpDx
)
7387 for (i
= 0; i
< nSet
; i
++)
7389 if (GetCharWidth32W(hdc
, lpString
[i
], lpString
[i
], &c
))
7391 lpResults
->lpDx
[i
] = c
;
7392 if (dwFlags
& GCP_USEKERNING
)
7393 lpResults
->lpDx
[i
] += kern
[i
];
7398 if (lpResults
->lpCaretPos
&& !(dwFlags
& GCP_REORDER
))
7402 lpResults
->lpCaretPos
[0] = 0;
7403 for (i
= 0; i
< nSet
- 1; i
++)
7405 if (dwFlags
& GCP_USEKERNING
)
7408 if (GetTextExtentPoint32W(hdc
, &lpString
[i
], 1, &size
))
7409 lpResults
->lpCaretPos
[i
+ 1] = (pos
+= size
.cx
);
7413 if (lpResults
->lpGlyphs
)
7414 GetGlyphIndicesW(hdc
, lpString
, nSet
, lpResults
->lpGlyphs
, 0);
7416 if (GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
))
7417 ret
= MAKELONG(size
.cx
+ kern_total
, size
.cy
);
7424 /*************************************************************************
7425 * GetCharABCWidthsFloatA [GDI32.@]
7427 * See GetCharABCWidthsFloatW.
7429 BOOL WINAPI
GetCharABCWidthsFloatA( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
7436 str
= FONT_GetCharsByRangeA(hdc
, first
, last
, &i
);
7440 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
7442 for (i
= 0; i
< wlen
; i
++)
7444 if (!GetCharABCWidthsFloatW( hdc
, wstr
[i
], wstr
[i
], abcf
))
7452 HeapFree( GetProcessHeap(), 0, str
);
7453 HeapFree( GetProcessHeap(), 0, wstr
);
7458 /*************************************************************************
7459 * GetCharABCWidthsFloatW [GDI32.@]
7461 * Retrieves widths of a range of characters.
7464 * hdc [I] Handle to device context.
7465 * first [I] First character in range to query.
7466 * last [I] Last character in range to query.
7467 * abcf [O] Array of LPABCFLOAT structures.
7473 BOOL WINAPI
GetCharABCWidthsFloatW( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
7479 DC
*dc
= get_dc_ptr( hdc
);
7481 TRACE("%p, %d, %d, %p\n", hdc
, first
, last
, abcf
);
7483 if (!dc
) return FALSE
;
7485 if (!abcf
) goto done
;
7486 if (!(abc
= HeapAlloc( GetProcessHeap(), 0, (last
- first
+ 1) * sizeof(*abc
) ))) goto done
;
7488 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
7489 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, abc
);
7492 /* convert device units to logical */
7493 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
7494 for (i
= first
; i
<= last
; i
++, abcf
++)
7496 abcf
->abcfA
= abc
[i
- first
].abcA
* scale
;
7497 abcf
->abcfB
= abc
[i
- first
].abcB
* scale
;
7498 abcf
->abcfC
= abc
[i
- first
].abcC
* scale
;
7501 HeapFree( GetProcessHeap(), 0, abc
);
7504 release_dc_ptr( dc
);
7508 /*************************************************************************
7509 * GetCharWidthFloatA [GDI32.@]
7511 BOOL WINAPI
GetCharWidthFloatA( HDC hdc
, UINT first
, UINT last
, float *buffer
)
7517 if (!(str
= FONT_GetCharsByRangeA( hdc
, first
, last
, &i
)))
7519 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
7522 for (i
= 0; i
< wlen
; ++i
)
7524 if (!GetCharWidthFloatW( hdc
, wstr
[i
], wstr
[i
], &buffer
[i
] ))
7534 /*************************************************************************
7535 * GetCharWidthFloatW [GDI32.@]
7537 BOOL WINAPI
GetCharWidthFloatW( HDC hdc
, UINT first
, UINT last
, float *buffer
)
7539 DC
*dc
= get_dc_ptr( hdc
);
7545 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc
, first
, last
, buffer
);
7547 if (!dc
) return FALSE
;
7549 if (!(ibuffer
= heap_alloc( (last
- first
+ 1) * sizeof(int) )))
7551 release_dc_ptr( dc
);
7555 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
7556 if ((ret
= dev
->funcs
->pGetCharWidth( dev
, first
, last
, ibuffer
)))
7558 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
7559 for (i
= first
; i
<= last
; ++i
)
7560 buffer
[i
- first
] = ibuffer
[i
- first
] * scale
;
7567 /***********************************************************************
7569 * Font Resource API *
7571 ***********************************************************************/
7573 /***********************************************************************
7574 * AddFontResourceA (GDI32.@)
7576 INT WINAPI
AddFontResourceA( LPCSTR str
)
7578 return AddFontResourceExA( str
, 0, NULL
);
7581 /***********************************************************************
7582 * AddFontResourceW (GDI32.@)
7584 INT WINAPI
AddFontResourceW( LPCWSTR str
)
7586 return AddFontResourceExW(str
, 0, NULL
);
7590 /***********************************************************************
7591 * AddFontResourceExA (GDI32.@)
7593 INT WINAPI
AddFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
7595 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
7596 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7599 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
7600 ret
= AddFontResourceExW(strW
, fl
, pdv
);
7601 HeapFree(GetProcessHeap(), 0, strW
);
7605 static BOOL CALLBACK
load_enumed_resource(HMODULE hModule
, LPCWSTR type
, LPWSTR name
, LONG_PTR lParam
)
7607 HRSRC rsrc
= FindResourceW(hModule
, name
, type
);
7608 HGLOBAL hMem
= LoadResource(hModule
, rsrc
);
7609 LPVOID
*pMem
= LockResource(hMem
);
7610 int *num_total
= (int *)lParam
;
7613 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type
));
7614 if (!AddFontMemResourceEx(pMem
, SizeofResource(hModule
, rsrc
), NULL
, &num_in_res
))
7616 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule
, hMem
);
7620 *num_total
+= num_in_res
;
7624 static void *map_file( const WCHAR
*filename
, LARGE_INTEGER
*size
)
7626 HANDLE file
, mapping
;
7629 file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7630 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
7632 if (!GetFileSizeEx( file
, size
) || size
->u
.HighPart
)
7634 CloseHandle( file
);
7638 mapping
= CreateFileMappingW( file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
7639 CloseHandle( file
);
7640 if (!mapping
) return NULL
;
7642 ptr
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
7643 CloseHandle( mapping
);
7648 static void *find_resource( BYTE
*ptr
, WORD type
, DWORD rsrc_off
, DWORD size
, DWORD
*len
)
7650 WORD align
, type_id
, count
;
7653 if (size
< rsrc_off
+ 10) return NULL
;
7654 align
= *(WORD
*)(ptr
+ rsrc_off
);
7656 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
7657 while (type_id
&& type_id
!= type
)
7659 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
7660 rsrc_off
+= 8 + count
* 12;
7661 if (size
< rsrc_off
+ 8) return NULL
;
7662 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
7664 if (!type_id
) return NULL
;
7665 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
7666 if (size
< rsrc_off
+ 8 + count
* 12) return NULL
;
7667 res_off
= *(WORD
*)(ptr
+ rsrc_off
+ 8) << align
;
7668 *len
= *(WORD
*)(ptr
+ rsrc_off
+ 10) << align
;
7669 if (size
< res_off
+ *len
) return NULL
;
7670 return ptr
+ res_off
;
7673 static WCHAR
*get_scalable_filename( const WCHAR
*res
, BOOL
*hidden
)
7676 BYTE
*ptr
= map_file( res
, &size
);
7677 const IMAGE_DOS_HEADER
*dos
;
7678 const IMAGE_OS2_HEADER
*ne
;
7684 if (!ptr
) return NULL
;
7686 if (size
.u
.LowPart
< sizeof( *dos
)) goto fail
;
7687 dos
= (const IMAGE_DOS_HEADER
*)ptr
;
7688 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto fail
;
7689 if (size
.u
.LowPart
< dos
->e_lfanew
+ sizeof( *ne
)) goto fail
;
7690 ne
= (const IMAGE_OS2_HEADER
*)(ptr
+ dos
->e_lfanew
);
7692 fontdir
= find_resource( ptr
, 0x8007, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
7693 if (!fontdir
) goto fail
;
7694 *hidden
= (fontdir
[35] & 0x80) != 0; /* fontdir->dfType */
7696 data
= find_resource( ptr
, 0x80cc, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
7697 if (!data
) goto fail
;
7698 if (!memchr( data
, 0, len
)) goto fail
;
7700 len
= MultiByteToWideChar( CP_ACP
, 0, data
, -1, NULL
, 0 );
7701 name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
7702 if (name
) MultiByteToWideChar( CP_ACP
, 0, data
, -1, name
, len
);
7705 UnmapViewOfFile( ptr
);
7709 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
7711 WCHAR path
[MAX_PATH
];
7714 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
7715 get_fonts_win_dir_path( file
, path
);
7716 EnterCriticalSection( &font_cs
);
7717 ret
= font_funcs
->add_font( path
, flags
);
7718 LeaveCriticalSection( &font_cs
);
7719 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
7722 get_fonts_data_dir_path( file
, path
);
7723 EnterCriticalSection( &font_cs
);
7724 ret
= font_funcs
->add_font( path
, flags
);
7725 LeaveCriticalSection( &font_cs
);
7730 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
7732 WCHAR path
[MAX_PATH
];
7735 get_fonts_win_dir_path( file
, path
);
7736 if (!(ret
= remove_font( path
, flags
)))
7738 get_fonts_data_dir_path( file
, path
);
7739 ret
= remove_font( path
, flags
);
7744 static int add_font_resource( LPCWSTR file
, DWORD flags
)
7746 WCHAR path
[MAX_PATH
];
7749 if (GetFullPathNameW( file
, MAX_PATH
, path
, NULL
))
7751 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
7753 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
7754 EnterCriticalSection( &font_cs
);
7755 ret
= font_funcs
->add_font( path
, addfont_flags
);
7756 LeaveCriticalSection( &font_cs
);
7759 if (!ret
&& !wcschr( file
, '\\' ))
7760 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
7765 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
7767 WCHAR path
[MAX_PATH
];
7770 if (GetFullPathNameW( file
, MAX_PATH
, path
, NULL
))
7772 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
7774 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
7775 ret
= remove_font( path
, addfont_flags
);
7778 if (!ret
&& !wcschr( file
, '\\' ))
7779 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
7784 static void load_system_bitmap_fonts(void)
7786 static const WCHAR
* const fonts
[] = { L
"FONTS.FON", L
"OEMFONT.FON", L
"FIXEDFON.FON" };
7788 WCHAR data
[MAX_PATH
];
7789 DWORD i
, dlen
, type
;
7791 if (RegOpenKeyW( HKEY_CURRENT_CONFIG
, L
"Software\\Fonts", &hkey
)) return;
7792 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
7794 dlen
= sizeof(data
);
7795 if (!RegQueryValueExW( hkey
, fonts
[i
], 0, &type
, (BYTE
*)data
, &dlen
) && type
== REG_SZ
)
7796 add_system_font_resource( data
, ADDFONT_ALLOW_BITMAP
);
7798 RegCloseKey( hkey
);
7801 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
7804 WIN32_FIND_DATAW data
;
7807 p
= path
+ lstrlenW(path
) - 1;
7808 TRACE( "loading fonts from %s\n", debugstr_w(path
) );
7809 handle
= FindFirstFileW( path
, &data
);
7810 if (handle
== INVALID_HANDLE_VALUE
) return;
7813 if (data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) continue;
7814 lstrcpyW( p
, data
.cFileName
);
7815 font_funcs
->add_font( path
, flags
);
7816 } while (FindNextFileW( handle
, &data
));
7817 FindClose( handle
);
7820 static void load_file_system_fonts(void)
7822 WCHAR
*ptr
, *next
, path
[MAX_PATH
], value
[1024];
7823 DWORD len
= ARRAY_SIZE(value
);
7825 /* Windows directory */
7826 get_fonts_win_dir_path( L
"*", path
);
7827 load_directory_fonts( path
, 0 );
7829 /* Wine data directory */
7830 get_fonts_data_dir_path( L
"*", path
);
7831 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
7834 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
7835 if (!RegQueryValueExW( wine_fonts_key
, L
"Path", NULL
, NULL
, (BYTE
*)value
, &len
))
7837 for (ptr
= value
; ptr
; ptr
= next
)
7839 if ((next
= wcschr( ptr
, ';' ))) *next
++ = 0;
7840 if (next
&& next
- ptr
< 2) continue;
7841 lstrcpynW( path
, ptr
, MAX_PATH
- 2 );
7842 lstrcatW( path
, L
"\\*" );
7843 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
7851 WCHAR value
[LF_FULLFACESIZE
+ 12];
7854 static void update_external_font_keys(void)
7856 struct list external_keys
= LIST_INIT(external_keys
);
7857 HKEY winnt_key
= 0, win9x_key
= 0;
7858 struct gdi_font_family
*family
;
7859 struct external_key
*key
, *next
;
7860 struct gdi_font_face
*face
;
7861 DWORD len
, i
= 0, type
, dlen
, vlen
;
7862 WCHAR value
[LF_FULLFACESIZE
+ 12], path
[MAX_PATH
], *tmp
;
7866 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
7867 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
);
7868 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
7869 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
);
7871 /* enumerate the fonts and add external ones to the two keys */
7873 if (RegCreateKeyW( wine_fonts_key
, L
"External Fonts", &hkey
)) return;
7875 vlen
= ARRAY_SIZE(value
);
7876 dlen
= sizeof(path
);
7877 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)path
, &dlen
))
7879 if (type
!= REG_SZ
) goto next
;
7880 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, L
" (TrueType)", -1 )) *tmp
= 0;
7881 if ((face
= find_face_from_full_name( value
)))
7883 if (!wcsicmp( face
->file
, path
)) face
->flags
|= ADDFONT_EXTERNAL_FOUND
;
7886 if (tmp
&& !*tmp
) *tmp
= ' ';
7887 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) ))) break;
7888 lstrcpyW( key
->value
, value
);
7889 list_add_tail( &external_keys
, &key
->entry
);
7891 vlen
= ARRAY_SIZE(value
);
7892 dlen
= sizeof(path
);
7895 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
7897 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
7899 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
7900 if ((face
->flags
& ADDFONT_EXTERNAL_FOUND
)) continue;
7902 lstrcpyW( value
, face
->full_name
);
7903 if (face
->scalable
) lstrcatW( value
, L
" (TrueType)" );
7905 if (GetFullPathNameW( face
->file
, MAX_PATH
, path
, NULL
))
7907 else if ((file
= wcsrchr( face
->file
, '\\' )))
7912 len
= (lstrlenW(file
) + 1) * sizeof(WCHAR
);
7913 RegSetValueExW( winnt_key
, value
, 0, REG_SZ
, (BYTE
*)file
, len
);
7914 RegSetValueExW( win9x_key
, value
, 0, REG_SZ
, (BYTE
*)file
, len
);
7915 RegSetValueExW( hkey
, value
, 0, REG_SZ
, (BYTE
*)file
, len
);
7918 LIST_FOR_EACH_ENTRY_SAFE( key
, next
, &external_keys
, struct external_key
, entry
)
7920 RegDeleteValueW( win9x_key
, key
->value
);
7921 RegDeleteValueW( winnt_key
, key
->value
);
7922 RegDeleteValueW( hkey
, key
->value
);
7923 list_remove( &key
->entry
);
7924 HeapFree( GetProcessHeap(), 0, key
);
7926 RegCloseKey( win9x_key
);
7927 RegCloseKey( winnt_key
);
7928 RegCloseKey( hkey
);
7931 static void load_registry_fonts(void)
7933 WCHAR value
[LF_FULLFACESIZE
+ 12], data
[MAX_PATH
], *tmp
;
7934 DWORD i
= 0, type
, dlen
, vlen
;
7937 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
7938 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
7939 full path as the entry. Also look for any .fon fonts, since ReadFontDir
7941 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
,
7942 is_win9x() ? L
"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts" :
7943 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey
))
7946 vlen
= ARRAY_SIZE(value
);
7947 dlen
= sizeof(data
);
7948 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, NULL
, NULL
))
7950 if (type
!= REG_SZ
) goto next
;
7951 dlen
/= sizeof(WCHAR
);
7952 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, L
" (TrueType)", -1 )) *tmp
= 0;
7953 if (find_face_from_full_name( value
)) goto next
;
7954 if (tmp
&& !*tmp
) *tmp
= ' ';
7956 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (LPBYTE
)data
, &dlen
))
7958 WARN( "Unable to get face path %s\n", debugstr_w(value
) );
7962 dlen
/= sizeof(WCHAR
);
7963 if (data
[0] && data
[1] == ':')
7964 add_font_resource( data
, ADDFONT_ALLOW_BITMAP
);
7965 else if (dlen
>= 6 && !wcsicmp( data
+ dlen
- 5, L
".fon" ))
7966 add_system_font_resource( data
, ADDFONT_ALLOW_BITMAP
);
7968 vlen
= ARRAY_SIZE(value
);
7969 dlen
= sizeof(data
);
7971 RegCloseKey( hkey
);
7974 static const struct font_callback_funcs callback_funcs
= { add_gdi_face
};
7976 /***********************************************************************
7979 void font_init(void)
7984 if (RegCreateKeyExW( HKEY_CURRENT_USER
, L
"Software\\Wine\\Fonts", 0, NULL
, 0,
7985 KEY_ALL_ACCESS
, NULL
, &wine_fonts_key
, NULL
))
7988 init_font_options();
7990 if (__wine_init_unix_lib( gdi32_module
, DLL_PROCESS_ATTACH
, &callback_funcs
, &font_funcs
)) return;
7992 load_system_bitmap_fonts();
7993 load_file_system_fonts();
7994 font_funcs
->load_fonts();
7996 if (!(mutex
= CreateMutexW( NULL
, FALSE
, L
"__WINE_FONT_MUTEX__" ))) return;
7997 WaitForSingleObject( mutex
, INFINITE
);
7999 RegCreateKeyExW( wine_fonts_key
, L
"Cache", 0, NULL
, REG_OPTION_VOLATILE
,
8000 KEY_ALL_ACCESS
, NULL
, &wine_fonts_cache_key
, &disposition
);
8002 if (disposition
== REG_CREATED_NEW_KEY
)
8004 load_registry_fonts();
8005 update_external_font_keys();
8008 ReleaseMutex( mutex
);
8010 if (disposition
!= REG_CREATED_NEW_KEY
)
8012 load_registry_fonts();
8013 load_font_list_from_cache();
8016 reorder_font_list();
8017 load_gdi_font_subst();
8018 load_gdi_font_replacements();
8019 load_system_links();
8020 dump_gdi_font_list();
8021 dump_gdi_font_subst();
8024 /***********************************************************************
8025 * AddFontResourceExW (GDI32.@)
8027 INT WINAPI
AddFontResourceExW( LPCWSTR str
, DWORD flags
, PVOID pdv
)
8033 if (!font_funcs
) return 1;
8034 if (!(ret
= add_font_resource( str
, flags
)))
8036 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8037 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
8038 if (hModule
!= NULL
)
8040 int num_resources
= 0;
8041 LPWSTR rt_font
= (LPWSTR
)((ULONG_PTR
)8); /* we don't want to include winuser.h */
8043 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
8044 wine_dbgstr_w(str
));
8045 if (EnumResourceNamesW(hModule
, rt_font
, load_enumed_resource
, (LONG_PTR
)&num_resources
))
8046 ret
= num_resources
;
8047 FreeLibrary(hModule
);
8049 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
8051 if (hidden
) flags
|= FR_PRIVATE
| FR_NOT_ENUM
;
8052 ret
= add_font_resource( filename
, flags
);
8053 HeapFree( GetProcessHeap(), 0, filename
);
8059 /***********************************************************************
8060 * RemoveFontResourceA (GDI32.@)
8062 BOOL WINAPI
RemoveFontResourceA( LPCSTR str
)
8064 return RemoveFontResourceExA(str
, 0, 0);
8067 /***********************************************************************
8068 * RemoveFontResourceW (GDI32.@)
8070 BOOL WINAPI
RemoveFontResourceW( LPCWSTR str
)
8072 return RemoveFontResourceExW(str
, 0, 0);
8075 /***********************************************************************
8076 * AddFontMemResourceEx (GDI32.@)
8078 HANDLE WINAPI
AddFontMemResourceEx( PVOID ptr
, DWORD size
, PVOID pdv
, DWORD
*pcFonts
)
8084 if (!ptr
|| !size
|| !pcFonts
)
8086 SetLastError(ERROR_INVALID_PARAMETER
);
8089 if (!font_funcs
) return NULL
;
8090 if (!(copy
= HeapAlloc( GetProcessHeap(), 0, size
))) return NULL
;
8091 memcpy( copy
, ptr
, size
);
8093 EnterCriticalSection( &font_cs
);
8094 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
8095 LeaveCriticalSection( &font_cs
);
8099 HeapFree( GetProcessHeap(), 0, copy
);
8103 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
8104 * For now return something unique but quite random
8106 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
8110 *pcFonts
= num_fonts
;
8114 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts
);
8115 RemoveFontMemResourceEx( ret
);
8119 TRACE( "Returning handle %p\n", ret
);
8123 /***********************************************************************
8124 * RemoveFontMemResourceEx (GDI32.@)
8126 BOOL WINAPI
RemoveFontMemResourceEx( HANDLE fh
)
8128 FIXME("(%p) stub\n", fh
);
8132 /***********************************************************************
8133 * RemoveFontResourceExA (GDI32.@)
8135 BOOL WINAPI
RemoveFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
8137 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
8138 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8141 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
8142 ret
= RemoveFontResourceExW(strW
, fl
, pdv
);
8143 HeapFree(GetProcessHeap(), 0, strW
);
8147 /***********************************************************************
8148 * RemoveFontResourceExW (GDI32.@)
8150 BOOL WINAPI
RemoveFontResourceExW( LPCWSTR str
, DWORD flags
, PVOID pdv
)
8156 if (!font_funcs
) return TRUE
;
8158 if (!(ret
= remove_font_resource( str
, flags
)))
8160 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8161 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
8162 if (hModule
!= NULL
)
8164 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str
));
8165 FreeLibrary(hModule
);
8167 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
8169 if (hidden
) flags
|= FR_PRIVATE
| FR_NOT_ENUM
;
8170 ret
= remove_font_resource( filename
, flags
);
8171 HeapFree( GetProcessHeap(), 0, filename
);
8177 /***********************************************************************
8178 * GetFontResourceInfoW (GDI32.@)
8180 BOOL WINAPI
GetFontResourceInfoW( LPCWSTR str
, LPDWORD size
, PVOID buffer
, DWORD type
)
8182 FIXME("%s %p(%d) %p %d\n", debugstr_w(str
), size
, size
? *size
: 0, buffer
, type
);
8186 /***********************************************************************
8187 * GetTextCharset (GDI32.@)
8189 UINT WINAPI
GetTextCharset(HDC hdc
)
8191 /* MSDN docs say this is equivalent */
8192 return GetTextCharsetInfo(hdc
, NULL
, 0);
8195 /***********************************************************************
8196 * GdiGetCharDimensions (GDI32.@)
8198 * Gets the average width of the characters in the English alphabet.
8201 * hdc [I] Handle to the device context to measure on.
8202 * lptm [O] Pointer to memory to store the text metrics into.
8203 * height [O] On exit, the maximum height of characters in the English alphabet.
8206 * The average width of characters in the English alphabet.
8209 * This function is used by the dialog manager to get the size of a dialog
8210 * unit. It should also be used by other pieces of code that need to know
8211 * the size of a dialog unit in logical units without having access to the
8212 * window handle of the dialog.
8213 * Windows caches the font metrics from this function, but we don't and
8214 * there doesn't appear to be an immediate advantage to do so.
8217 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
8219 LONG WINAPI
GdiGetCharDimensions(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
)
8223 if(lptm
&& !GetTextMetricsW(hdc
, lptm
)) return 0;
8225 if(!GetTextExtentPointW(hdc
, L
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52, &sz
))
8228 if (height
) *height
= sz
.cy
;
8229 return (sz
.cx
/ 26 + 1) / 2;
8232 BOOL WINAPI
EnableEUDC(BOOL fEnableEUDC
)
8234 FIXME("(%d): stub\n", fEnableEUDC
);
8238 /***********************************************************************
8239 * GetCharWidthI (GDI32.@)
8241 * Retrieve widths of characters.
8244 * hdc [I] Handle to a device context.
8245 * first [I] First glyph in range to query.
8246 * count [I] Number of glyph indices to query.
8247 * glyphs [I] Array of glyphs to query.
8248 * buffer [O] Buffer to receive character widths.
8251 * Only works with TrueType fonts.
8257 BOOL WINAPI
GetCharWidthI(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPINT buffer
)
8262 TRACE("(%p, %d, %d, %p, %p)\n", hdc
, first
, count
, glyphs
, buffer
);
8264 if (!(abc
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(ABC
))))
8267 if (!GetCharABCWidthsI(hdc
, first
, count
, glyphs
, abc
))
8269 HeapFree(GetProcessHeap(), 0, abc
);
8273 for (i
= 0; i
< count
; i
++)
8274 buffer
[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
8276 HeapFree(GetProcessHeap(), 0, abc
);
8280 /***********************************************************************
8281 * GetFontUnicodeRanges (GDI32.@)
8283 * Retrieve a list of supported Unicode characters in a font.
8286 * hdc [I] Handle to a device context.
8287 * lpgs [O] GLYPHSET structure specifying supported character ranges.
8290 * Success: Number of bytes written to the buffer pointed to by lpgs.
8294 DWORD WINAPI
GetFontUnicodeRanges(HDC hdc
, LPGLYPHSET lpgs
)
8298 DC
*dc
= get_dc_ptr(hdc
);
8300 TRACE("(%p, %p)\n", hdc
, lpgs
);
8304 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
8305 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
8311 /*************************************************************
8312 * FontIsLinked (GDI32.@)
8314 BOOL WINAPI
FontIsLinked(HDC hdc
)
8316 DC
*dc
= get_dc_ptr(hdc
);
8320 if (!dc
) return FALSE
;
8321 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
8322 ret
= dev
->funcs
->pFontIsLinked( dev
);
8324 TRACE("returning %d\n", ret
);
8328 /*************************************************************
8329 * GetFontRealizationInfo (GDI32.@)
8331 BOOL WINAPI
GetFontRealizationInfo(HDC hdc
, struct font_realization_info
*info
)
8333 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, unk
);
8338 if (info
->size
!= sizeof(*info
) && !is_v0
)
8341 dc
= get_dc_ptr(hdc
);
8342 if (!dc
) return FALSE
;
8343 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
8344 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
8349 /*************************************************************************
8350 * GetRasterizerCaps (GDI32.@)
8352 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8354 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8355 lprs
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
8356 lprs
->nLanguageID
= 0;
8360 /*************************************************************************
8361 * GetFontFileData (GDI32.@)
8363 BOOL WINAPI
GetFontFileData( DWORD instance_id
, DWORD unknown
, UINT64 offset
, void *buff
, DWORD buff_size
)
8365 struct gdi_font
*font
;
8366 DWORD tag
= 0, size
;
8369 if (!font_funcs
) return FALSE
;
8370 EnterCriticalSection( &font_cs
);
8371 if ((font
= get_font_from_handle( instance_id
)))
8373 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
8374 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
8375 if (size
!= GDI_ERROR
&& size
>= buff_size
&& offset
<= size
- buff_size
)
8376 ret
= font_funcs
->get_font_data( font
, tag
, offset
, buff
, buff_size
) != GDI_ERROR
;
8378 SetLastError( ERROR_INVALID_PARAMETER
);
8380 LeaveCriticalSection( &font_cs
);
8384 /* Undocumented structure filled in by GetFontFileInfo */
8385 struct font_fileinfo
8392 /*************************************************************************
8393 * GetFontFileInfo (GDI32.@)
8395 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
,
8396 SIZE_T size
, SIZE_T
*needed
)
8398 SIZE_T required_size
= 0;
8399 struct gdi_font
*font
;
8402 EnterCriticalSection( &font_cs
);
8404 if ((font
= get_font_from_handle( instance_id
)))
8406 required_size
= sizeof(*info
) + lstrlenW( font
->file
) * sizeof(WCHAR
);
8407 if (required_size
<= size
)
8409 info
->writetime
= font
->writetime
;
8410 info
->size
.QuadPart
= font
->data_size
;
8411 lstrcpyW( info
->path
, font
->file
);
8414 else SetLastError( ERROR_INSUFFICIENT_BUFFER
);
8417 LeaveCriticalSection( &font_cs
);
8418 if (needed
) *needed
= required_size
;
8422 struct realization_info
8424 DWORD flags
; /* 1 for bitmap fonts, 3 for scalable fonts */
8425 DWORD cache_num
; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
8426 DWORD instance_id
; /* identifies a realized font instance */
8429 /*************************************************************
8430 * GdiRealizationInfo (GDI32.@)
8432 * Returns a structure that contains some font information.
8434 BOOL WINAPI
GdiRealizationInfo(HDC hdc
, struct realization_info
*info
)
8436 struct font_realization_info ri
;
8439 ri
.size
= sizeof(ri
);
8440 ret
= GetFontRealizationInfo( hdc
, &ri
);
8443 info
->flags
= ri
.flags
;
8444 info
->cache_num
= ri
.cache_num
;
8445 info
->instance_id
= ri
.instance_id
;
8451 /*************************************************************
8452 * GetCharWidthInfo (GDI32.@)
8455 BOOL WINAPI
GetCharWidthInfo(HDC hdc
, struct char_width_info
*info
)
8461 dc
= get_dc_ptr(hdc
);
8462 if (!dc
) return FALSE
;
8463 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
8464 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
8468 info
->lsb
= width_to_LP( dc
, info
->lsb
);
8469 info
->rsb
= width_to_LP( dc
, info
->rsb
);