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 "ntgdi_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 INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
);
184 static BOOL
FONT_DeleteObject( HGDIOBJ handle
);
186 static const struct gdi_obj_funcs fontobj_funcs
=
188 FONT_GetObjectW
, /* pGetObjectW */
189 NULL
, /* pUnrealizeObject */
190 FONT_DeleteObject
/* pDeleteObject */
195 struct gdi_obj_header obj
;
201 LPLOGFONTW lpLogFontParam
;
202 FONTENUMPROCW lpEnumFunc
;
210 * For TranslateCharsetInfo
212 #define MAXTCIINDEX 32
213 static const CHARSETINFO FONT_tci
[MAXTCIINDEX
] = {
215 { ANSI_CHARSET
, 1252, {{0,0,0,0},{FS_LATIN1
,0}} },
216 { EASTEUROPE_CHARSET
, 1250, {{0,0,0,0},{FS_LATIN2
,0}} },
217 { RUSSIAN_CHARSET
, 1251, {{0,0,0,0},{FS_CYRILLIC
,0}} },
218 { GREEK_CHARSET
, 1253, {{0,0,0,0},{FS_GREEK
,0}} },
219 { TURKISH_CHARSET
, 1254, {{0,0,0,0},{FS_TURKISH
,0}} },
220 { HEBREW_CHARSET
, 1255, {{0,0,0,0},{FS_HEBREW
,0}} },
221 { ARABIC_CHARSET
, 1256, {{0,0,0,0},{FS_ARABIC
,0}} },
222 { BALTIC_CHARSET
, 1257, {{0,0,0,0},{FS_BALTIC
,0}} },
223 { VIETNAMESE_CHARSET
, 1258, {{0,0,0,0},{FS_VIETNAMESE
,0}} },
224 /* reserved by ANSI */
225 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
226 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
227 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
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}} },
233 { THAI_CHARSET
, 874, {{0,0,0,0},{FS_THAI
,0}} },
234 { SHIFTJIS_CHARSET
, 932, {{0,0,0,0},{FS_JISJAPAN
,0}} },
235 { GB2312_CHARSET
, 936, {{0,0,0,0},{FS_CHINESESIMP
,0}} },
236 { HANGEUL_CHARSET
, 949, {{0,0,0,0},{FS_WANSUNG
,0}} },
237 { CHINESEBIG5_CHARSET
, 950, {{0,0,0,0},{FS_CHINESETRAD
,0}} },
238 { JOHAB_CHARSET
, 1361, {{0,0,0,0},{FS_JOHAB
,0}} },
239 /* reserved for alternate ANSI and OEM */
240 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
241 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
242 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
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 /* reserved for system */
249 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
250 { SYMBOL_CHARSET
, CP_SYMBOL
, {{0,0,0,0},{FS_SYMBOL
,0}} }
253 static const WCHAR
* const default_serif_list
[3] =
257 L
"Bitstream Vera Serif"
259 static const WCHAR
* const default_fixed_list
[3] =
263 L
"Bitstream Vera Sans Mono"
265 static const WCHAR
* const default_sans_list
[3] =
269 L
"Bitstream Vera Sans"
271 static WCHAR ff_roman_default
[LF_FACESIZE
];
272 static WCHAR ff_modern_default
[LF_FACESIZE
];
273 static WCHAR ff_swiss_default
[LF_FACESIZE
];
275 static const struct nls_update_font_list
277 UINT ansi_cp
, oem_cp
;
278 const char *oem
, *fixed
, *system
;
279 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
280 /* these are for font substitutes */
281 const char *shelldlg
, *tmsrmn
;
282 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
, *helv_0
, *tmsrmn_0
;
283 struct subst
{ const char *from
, *to
; } arial_0
, courier_new_0
, times_new_roman_0
;
284 } nls_update_font_list
[] =
286 /* Latin 1 (United States) */
287 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
288 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
289 "Tahoma","Times New Roman"
291 /* Latin 1 (Multilingual) */
292 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
293 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
294 "Tahoma","Times New Roman" /* FIXME unverified */
297 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
298 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
299 "Tahoma","Times New Roman", /* FIXME unverified */
300 "Fixedsys,238", "System,238",
301 "Courier New,238", "MS Serif,238", "Small Fonts,238",
302 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
303 { "Arial CE,0", "Arial,238" },
304 { "Courier New CE,0", "Courier New,238" },
305 { "Times New Roman CE,0", "Times New Roman,238" }
308 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
309 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
310 "Tahoma","Times New Roman", /* FIXME unverified */
311 "Fixedsys,204", "System,204",
312 "Courier New,204", "MS Serif,204", "Small Fonts,204",
313 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
314 { "Arial Cyr,0", "Arial,204" },
315 { "Courier New Cyr,0", "Courier New,204" },
316 { "Times New Roman Cyr,0", "Times New Roman,204" }
319 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
320 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
321 "Tahoma","Times New Roman", /* FIXME unverified */
322 "Fixedsys,161", "System,161",
323 "Courier New,161", "MS Serif,161", "Small Fonts,161",
324 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
325 { "Arial Greek,0", "Arial,161" },
326 { "Courier New Greek,0", "Courier New,161" },
327 { "Times New Roman Greek,0", "Times New Roman,161" }
330 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
331 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
332 "Tahoma","Times New Roman", /* FIXME unverified */
333 "Fixedsys,162", "System,162",
334 "Courier New,162", "MS Serif,162", "Small Fonts,162",
335 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
336 { "Arial Tur,0", "Arial,162" },
337 { "Courier New Tur,0", "Courier New,162" },
338 { "Times New Roman Tur,0", "Times New Roman,162" }
341 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
342 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
343 "Tahoma","Times New Roman", /* FIXME unverified */
344 "Fixedsys,177", "System,177",
345 "Courier New,177", "MS Serif,177", "Small Fonts,177",
346 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
349 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
350 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
351 "Microsoft Sans Serif","Times New Roman",
352 "Fixedsys,178", "System,178",
353 "Courier New,178", "MS Serif,178", "Small Fonts,178",
354 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
357 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
358 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
359 "Tahoma","Times New Roman", /* FIXME unverified */
360 "Fixedsys,186", "System,186",
361 "Courier New,186", "MS Serif,186", "Small Fonts,186",
362 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
363 { "Arial Baltic,0", "Arial,186" },
364 { "Courier New Baltic,0", "Courier New,186" },
365 { "Times New Roman Baltic,0", "Times New Roman,186" }
368 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
369 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
370 "Tahoma","Times New Roman" /* FIXME unverified */
373 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
374 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
375 "Tahoma","Times New Roman" /* FIXME unverified */
378 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
379 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
380 "MS UI Gothic","MS Serif"
382 /* Chinese Simplified */
383 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
384 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
388 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
389 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
392 /* Chinese Traditional */
393 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
394 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
395 "PMingLiU", "MingLiU"
399 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
401 return ( ansi_cp
== 932 /* CP932 for Japanese */
402 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
403 || ansi_cp
== 949 /* CP949 for Korean */
404 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
407 static CRITICAL_SECTION font_cs
;
408 static CRITICAL_SECTION_DEBUG critsect_debug
=
411 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
412 0, 0, { (DWORD_PTR
)(__FILE__
": font_cs") }
414 static CRITICAL_SECTION font_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
416 #ifndef WINE_FONT_DIR
417 #define WINE_FONT_DIR "fonts"
420 #ifdef WORDS_BIGENDIAN
421 #define GET_BE_WORD(x) (x)
422 #define GET_BE_DWORD(x) (x)
424 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
425 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
428 static void get_fonts_data_dir_path( const WCHAR
*file
, WCHAR
*path
)
430 if (GetEnvironmentVariableW( L
"WINEDATADIR", path
, MAX_PATH
))
431 lstrcatW( path
, L
"\\" WINE_FONT_DIR
"\\" );
432 else if (GetEnvironmentVariableW( L
"WINEBUILDDIR", path
, MAX_PATH
))
433 lstrcatW( path
, L
"\\fonts\\" );
435 lstrcatW( path
, file
);
436 if (path
[5] == ':') memmove( path
, path
+ 4, (lstrlenW(path
) - 3) * sizeof(WCHAR
) );
437 else path
[1] = '\\'; /* change \??\ to \\?\ */
440 static void get_fonts_win_dir_path( const WCHAR
*file
, WCHAR
*path
)
442 GetWindowsDirectoryW( path
, MAX_PATH
);
443 lstrcatW( path
, L
"\\fonts\\" );
444 lstrcatW( path
, file
);
447 /* font substitutions */
449 struct gdi_font_subst
457 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
459 static inline WCHAR
*get_subst_to_name( struct gdi_font_subst
*subst
)
461 return subst
->names
+ lstrlenW( subst
->names
) + 1;
464 static void dump_gdi_font_subst(void)
466 struct gdi_font_subst
*subst
;
468 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
470 if (subst
->from_charset
!= -1 || subst
->to_charset
!= -1)
471 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst
->names
),
472 subst
->from_charset
, debugstr_w(get_subst_to_name(subst
)), subst
->to_charset
);
474 TRACE("%s -> %s\n", debugstr_w(subst
->names
), debugstr_w(get_subst_to_name(subst
)));
478 static const WCHAR
*get_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, int *to_charset
)
480 struct gdi_font_subst
*subst
;
482 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
484 if (!facename_compare( subst
->names
, from_name
, -1 ) &&
485 (subst
->from_charset
== from_charset
|| subst
->from_charset
== -1))
487 if (to_charset
) *to_charset
= subst
->to_charset
;
488 return get_subst_to_name( subst
);
494 static BOOL
add_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, const WCHAR
*to_name
, int to_charset
)
496 struct gdi_font_subst
*subst
;
497 int len
= lstrlenW( from_name
) + lstrlenW( to_name
) + 2;
499 if (get_gdi_font_subst( from_name
, from_charset
, NULL
)) return FALSE
; /* already exists */
501 if (!(subst
= HeapAlloc( GetProcessHeap(), 0,
502 offsetof( struct gdi_font_subst
, names
[len
] ))))
504 lstrcpyW( subst
->names
, from_name
);
505 lstrcpyW( get_subst_to_name(subst
), to_name
);
506 subst
->from_charset
= from_charset
;
507 subst
->to_charset
= to_charset
;
508 list_add_tail( &font_subst_list
, &subst
->entry
);
512 static void load_gdi_font_subst(void)
515 DWORD i
= 0, type
, dlen
, vlen
;
516 WCHAR value
[64], data
[64], *p
;
518 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
522 vlen
= ARRAY_SIZE(value
);
523 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)data
, &dlen
))
525 int from_charset
= -1, to_charset
= -1;
527 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
528 if ((p
= wcsrchr( value
, ',' )) && p
[1])
531 from_charset
= wcstol( p
, NULL
, 10 );
533 if ((p
= wcsrchr( data
, ',' )) && p
[1])
536 to_charset
= wcstol( p
, NULL
, 10 );
539 /* Win 2000 doesn't allow mapping between different charsets
540 or mapping of DEFAULT_CHARSET */
541 if ((!from_charset
|| to_charset
== from_charset
) && to_charset
!= DEFAULT_CHARSET
)
542 add_gdi_font_subst( value
, from_charset
, data
, to_charset
);
544 /* reset dlen and vlen */
546 vlen
= ARRAY_SIZE(value
);
553 static int family_namecmp( const WCHAR
*str1
, const WCHAR
*str2
)
555 int prio1
, prio2
, vert1
= (str1
[0] == '@' ? 1 : 0), vert2
= (str2
[0] == '@' ? 1 : 0);
557 if (!facename_compare( str1
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio1
= 0;
558 else if (!facename_compare( str1
, ff_modern_default
, LF_FACESIZE
- 1 )) prio1
= 1;
559 else if (!facename_compare( str1
, ff_roman_default
, LF_FACESIZE
- 1 )) prio1
= 2;
562 if (!facename_compare( str2
, ff_swiss_default
, LF_FACESIZE
- 1 )) prio2
= 0;
563 else if (!facename_compare( str2
, ff_modern_default
, LF_FACESIZE
- 1 )) prio2
= 1;
564 else if (!facename_compare( str2
, ff_roman_default
, LF_FACESIZE
- 1 )) prio2
= 2;
567 if (prio1
!= prio2
) return prio1
- prio2
;
568 if (vert1
!= vert2
) return vert1
- vert2
;
569 return facename_compare( str1
+ vert1
, str2
+ vert2
, LF_FACESIZE
- 1 );
572 static int family_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
574 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, name_entry
);
575 return family_namecmp( (const WCHAR
*)key
, family
->family_name
);
578 static int family_second_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
580 const struct gdi_font_family
*family
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_family
, second_name_entry
);
581 return family_namecmp( (const WCHAR
*)key
, family
->second_name
);
584 static int face_full_name_compare( const void *key
, const struct wine_rb_entry
*entry
)
586 const struct gdi_font_face
*face
= WINE_RB_ENTRY_VALUE( entry
, const struct gdi_font_face
, full_name_entry
);
587 return facename_compare( (const WCHAR
*)key
, face
->full_name
, LF_FULLFACESIZE
- 1 );
590 static struct wine_rb_tree family_name_tree
= { family_name_compare
};
591 static struct wine_rb_tree family_second_name_tree
= { family_second_name_compare
};
592 static struct wine_rb_tree face_full_name_tree
= { face_full_name_compare
};
594 static int face_is_in_full_name_tree( const struct gdi_font_face
*face
)
596 return face
->full_name_entry
.parent
|| face_full_name_tree
.root
== &face
->full_name_entry
;
599 static struct gdi_font_family
*create_family( const WCHAR
*name
, const WCHAR
*second_name
)
601 struct gdi_font_family
*family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
603 family
->refcount
= 1;
604 lstrcpynW( family
->family_name
, name
, LF_FACESIZE
);
605 if (second_name
&& second_name
[0] && wcsicmp( name
, second_name
))
607 lstrcpynW( family
->second_name
, second_name
, LF_FACESIZE
);
608 add_gdi_font_subst( second_name
, -1, name
, -1 );
610 else family
->second_name
[0] = 0;
611 list_init( &family
->faces
);
612 family
->replacement
= NULL
;
613 wine_rb_put( &family_name_tree
, family
->family_name
, &family
->name_entry
);
614 if (family
->second_name
[0]) wine_rb_put( &family_second_name_tree
, family
->second_name
, &family
->second_name_entry
);
618 static void release_family( struct gdi_font_family
*family
)
620 if (--family
->refcount
) return;
621 assert( list_empty( &family
->faces
));
622 wine_rb_remove( &family_name_tree
, &family
->name_entry
);
623 if (family
->second_name
[0]) wine_rb_remove( &family_second_name_tree
, &family
->second_name_entry
);
624 if (family
->replacement
) release_family( family
->replacement
);
625 HeapFree( GetProcessHeap(), 0, family
);
628 static struct gdi_font_family
*find_family_from_name( const WCHAR
*name
)
630 struct wine_rb_entry
*entry
;
631 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) return NULL
;
632 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, name_entry
);
635 static struct gdi_font_family
*find_family_from_any_name( const WCHAR
*name
)
637 struct wine_rb_entry
*entry
;
638 struct gdi_font_family
*family
;
639 if ((family
= find_family_from_name( name
))) return family
;
640 if (!(entry
= wine_rb_get( &family_second_name_tree
, name
))) return NULL
;
641 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_family
, second_name_entry
);
644 static struct gdi_font_face
*find_face_from_full_name( const WCHAR
*full_name
)
646 struct wine_rb_entry
*entry
;
647 if (!(entry
= wine_rb_get( &face_full_name_tree
, full_name
))) return NULL
;
648 return WINE_RB_ENTRY_VALUE( entry
, struct gdi_font_face
, full_name_entry
);
651 static const struct list
*get_family_face_list( const struct gdi_font_family
*family
)
653 return family
->replacement
? &family
->replacement
->faces
: &family
->faces
;
656 static struct gdi_font_face
*family_find_face_from_filename( struct gdi_font_family
*family
, const WCHAR
*file_name
)
658 struct gdi_font_face
*face
;
660 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
662 if (!face
->file
) continue;
663 file
= wcsrchr(face
->file
, '\\');
664 if (!file
) file
= face
->file
;
666 if (wcsicmp( file
, file_name
)) continue;
673 static struct gdi_font_face
*find_face_from_filename( const WCHAR
*file_name
, const WCHAR
*family_name
)
675 struct gdi_font_family
*family
;
676 struct gdi_font_face
*face
;
678 TRACE( "looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(family_name
) );
682 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
683 if ((face
= family_find_face_from_filename( family
, file_name
))) return face
;
687 if (!(family
= find_family_from_name( family_name
))) return NULL
;
688 return family_find_face_from_filename( family
, file_name
);
691 static BOOL
add_family_replacement( const WCHAR
*new_name
, const WCHAR
*replace
)
693 struct gdi_font_family
*new_family
, *family
;
694 struct gdi_font_face
*face
;
695 WCHAR new_name_vert
[LF_FACESIZE
], replace_vert
[LF_FACESIZE
];
697 if (!(family
= find_family_from_any_name( replace
)))
699 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace
) );
703 if (!(new_family
= create_family( new_name
, NULL
))) return FALSE
;
704 new_family
->replacement
= family
;
706 TRACE( "mapping %s to %s\n", debugstr_w(replace
), debugstr_w(new_name
) );
708 /* also add replacement for vertical font if necessary */
709 if (replace
[0] == '@') return TRUE
;
710 if (list_empty( &family
->faces
)) return TRUE
;
711 face
= LIST_ENTRY( list_head(&family
->faces
), struct gdi_font_face
, entry
);
712 if (!(face
->fs
.fsCsb
[0] & FS_DBCS_MASK
)) return TRUE
;
714 new_name_vert
[0] = '@';
715 lstrcpynW( new_name_vert
+ 1, new_name
, LF_FACESIZE
- 1 );
716 if (find_family_from_any_name( new_name_vert
)) return TRUE
; /* already exists */
718 replace_vert
[0] = '@';
719 lstrcpynW( replace_vert
+ 1, replace
, LF_FACESIZE
- 1 );
720 add_family_replacement( new_name_vert
, replace_vert
);
725 * The replacement list is a way to map an entire font
726 * family onto another family. For example adding
728 * [HKCU\Software\Wine\Fonts\Replacements]
729 * "Wingdings"="Winedings"
731 * would enumerate the Winedings font both as Winedings and
732 * Wingdings. However if a real Wingdings font is present the
733 * replacement does not take place.
735 static void load_gdi_font_replacements(void)
738 DWORD i
= 0, type
, dlen
, vlen
;
739 WCHAR value
[LF_FACESIZE
], data
[1024];
741 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
742 if (RegOpenKeyW( wine_fonts_key
, L
"Replacements", &hkey
)) return;
745 vlen
= ARRAY_SIZE(value
);
746 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)data
, &dlen
))
748 /* "NewName"="Oldname" */
749 if (!find_family_from_any_name( value
))
751 if (type
== REG_MULTI_SZ
)
753 WCHAR
*replace
= data
;
756 if (add_family_replacement( value
, replace
)) break;
757 replace
+= lstrlenW(replace
) + 1;
760 else if (type
== REG_SZ
) add_family_replacement( value
, data
);
762 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
764 /* reset dlen and vlen */
766 vlen
= ARRAY_SIZE(value
);
771 static void dump_gdi_font_list(void)
773 struct gdi_font_family
*family
;
774 struct gdi_font_face
*face
;
776 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
778 TRACE( "Family: %s\n", debugstr_w(family
->family_name
) );
779 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
781 TRACE( "\t%s\t%s\t%08x", debugstr_w(face
->style_name
), debugstr_w(face
->full_name
),
783 if (!face
->scalable
) TRACE(" %d", face
->size
.height
);
789 static BOOL
enum_fallbacks( DWORD pitch_and_family
, int index
, WCHAR buffer
[LF_FACESIZE
] )
793 const WCHAR
* const *defaults
;
795 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
)
796 defaults
= default_fixed_list
;
797 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
)
798 defaults
= default_serif_list
;
800 defaults
= default_sans_list
;
801 lstrcpynW( buffer
, defaults
[index
], LF_FACESIZE
);
804 return font_funcs
->enum_family_fallbacks( pitch_and_family
, index
- 3, buffer
);
807 static void set_default_family( DWORD pitch_and_family
, WCHAR
*default_name
)
809 struct wine_rb_entry
*entry
;
810 WCHAR name
[LF_FACESIZE
];
813 while (enum_fallbacks( pitch_and_family
, i
++, name
))
815 if (!(entry
= wine_rb_get( &family_name_tree
, name
))) continue;
816 wine_rb_remove( &family_name_tree
, entry
);
817 lstrcpynW( default_name
, name
, LF_FACESIZE
- 1 );
818 wine_rb_put( &family_name_tree
, name
, entry
);
823 static void reorder_font_list(void)
825 set_default_family( FF_ROMAN
, ff_roman_default
);
826 set_default_family( FF_MODERN
, ff_modern_default
);
827 set_default_family( FF_SWISS
, ff_swiss_default
);
830 static void release_face( struct gdi_font_face
*face
)
832 if (--face
->refcount
) return;
835 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
836 list_remove( &face
->entry
);
837 release_family( face
->family
);
839 if (face_is_in_full_name_tree( face
)) wine_rb_remove( &face_full_name_tree
, &face
->full_name_entry
);
840 HeapFree( GetProcessHeap(), 0, face
->file
);
841 HeapFree( GetProcessHeap(), 0, face
->style_name
);
842 HeapFree( GetProcessHeap(), 0, face
->full_name
);
843 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
844 HeapFree( GetProcessHeap(), 0, face
);
847 static int remove_font( const WCHAR
*file
, DWORD flags
)
849 struct gdi_font_family
*family
, *family_next
;
850 struct gdi_font_face
*face
, *face_next
;
853 EnterCriticalSection( &font_cs
);
854 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family
, family_next
, &family_name_tree
, struct gdi_font_family
, name_entry
)
857 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, struct gdi_font_face
, entry
)
859 if (!face
->file
) continue;
860 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
861 if (!wcsicmp( face
->file
, file
))
863 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
864 release_face( face
);
868 release_family( family
);
870 LeaveCriticalSection( &font_cs
);
874 static inline BOOL
faces_equal( const struct gdi_font_face
*f1
, const struct gdi_font_face
*f2
)
876 if (facename_compare( f1
->full_name
, f2
->full_name
, -1 )) return FALSE
;
877 if (f1
->scalable
) return TRUE
;
878 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
879 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
882 static inline int style_order( const struct gdi_font_face
*face
)
884 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
892 case NTM_BOLD
| NTM_ITALIC
:
895 WARN( "Don't know how to order face %s with flags 0x%08x\n",
896 debugstr_w(face
->full_name
), face
->ntmFlags
);
901 static BOOL
insert_face_in_family_list( struct gdi_font_face
*face
, struct gdi_font_family
*family
)
903 struct gdi_font_face
*cursor
;
905 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, struct gdi_font_face
, entry
)
907 if (faces_equal( face
, cursor
))
909 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
910 debugstr_w(face
->full_name
), debugstr_w(family
->family_name
),
911 cursor
->version
, face
->version
);
913 if (face
->file
&& cursor
->file
&& !wcsicmp( face
->file
, cursor
->file
))
916 TRACE("Font %s already in list, refcount now %d\n",
917 debugstr_w(face
->file
), cursor
->refcount
);
920 if (face
->version
<= cursor
->version
)
922 TRACE("Original font %s is newer so skipping %s\n",
923 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
928 TRACE("Replacing original %s with %s\n",
929 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
930 list_add_before( &cursor
->entry
, &face
->entry
);
931 face
->family
= family
;
934 if (face_is_in_full_name_tree( cursor
))
936 wine_rb_replace( &face_full_name_tree
, &cursor
->full_name_entry
, &face
->full_name_entry
);
937 memset( &cursor
->full_name_entry
, 0, sizeof(cursor
->full_name_entry
) );
939 release_face( cursor
);
943 if (style_order( face
) < style_order( cursor
)) break;
946 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face
->full_name
),
947 debugstr_w(family
->family_name
), debugstr_w(face
->file
) );
948 list_add_before( &cursor
->entry
, &face
->entry
);
949 if (face
->scalable
) wine_rb_put( &face_full_name_tree
, face
->full_name
, &face
->full_name_entry
);
950 face
->family
= family
;
956 static struct gdi_font_face
*create_face( struct gdi_font_family
*family
, const WCHAR
*style
,
957 const WCHAR
*fullname
, const WCHAR
*file
,
958 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
959 DWORD ntmflags
, DWORD version
, DWORD flags
,
960 const struct bitmap_font_size
*size
)
962 struct gdi_font_face
*face
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*face
) );
965 face
->style_name
= strdupW( style
);
966 face
->full_name
= strdupW( fullname
);
967 face
->face_index
= index
;
969 face
->ntmFlags
= ntmflags
;
970 face
->version
= version
;
972 face
->data_ptr
= data_ptr
;
973 face
->data_size
= data_size
;
974 if (file
) face
->file
= strdupW( file
);
975 if (size
) face
->size
= *size
;
976 else face
->scalable
= TRUE
;
977 if (insert_face_in_family_list( face
, family
)) return face
;
978 release_face( face
);
982 static int CDECL
add_gdi_face( const WCHAR
*family_name
, const WCHAR
*second_name
,
983 const WCHAR
*style
, const WCHAR
*fullname
, const WCHAR
*file
,
984 void *data_ptr
, SIZE_T data_size
, UINT index
, FONTSIGNATURE fs
,
985 DWORD ntmflags
, DWORD version
, DWORD flags
,
986 const struct bitmap_font_size
*size
)
988 struct gdi_font_face
*face
;
989 struct gdi_font_family
*family
;
992 if ((family
= find_family_from_name( family_name
))) family
->refcount
++;
993 else if (!(family
= create_family( family_name
, second_name
))) return ret
;
995 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
996 index
, fs
, ntmflags
, version
, flags
, size
)))
998 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
999 release_face( face
);
1001 release_family( family
);
1004 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
1006 WCHAR vert_family
[LF_FACESIZE
], vert_second
[LF_FACESIZE
], vert_full
[LF_FULLFACESIZE
];
1008 vert_family
[0] = '@';
1009 lstrcpynW( vert_family
+ 1, family_name
, LF_FACESIZE
- 1 );
1011 if (second_name
&& second_name
[0])
1013 vert_second
[0] = '@';
1014 lstrcpynW( vert_second
+ 1, second_name
, LF_FACESIZE
- 1 );
1016 else vert_second
[0] = 0;
1021 lstrcpynW( vert_full
+ 1, fullname
, LF_FULLFACESIZE
- 1 );
1022 fullname
= vert_full
;
1025 if ((family
= find_family_from_name( vert_family
))) family
->refcount
++;
1026 else if (!(family
= create_family( vert_family
, vert_second
))) return ret
;
1028 if ((face
= create_face( family
, style
, fullname
, file
, data_ptr
, data_size
,
1029 index
, fs
, ntmflags
, version
, flags
| ADDFONT_VERTICAL_FONT
, size
)))
1031 if (flags
& ADDFONT_ADD_TO_CACHE
) add_face_to_cache( face
);
1032 release_face( face
);
1034 release_family( family
);
1048 struct bitmap_font_size size
;
1051 /* WCHAR file_name[]; */
1054 static void load_face_from_cache( HKEY hkey_family
, struct gdi_font_family
*family
,
1055 void *buffer
, DWORD buffer_size
, BOOL scalable
)
1057 DWORD type
, size
, needed
, index
= 0;
1058 struct gdi_font_face
*face
;
1061 struct cached_face
*cached
= (struct cached_face
*)buffer
;
1063 size
= sizeof(name
);
1064 needed
= buffer_size
- sizeof(DWORD
);
1065 while (!RegEnumValueW( hkey_family
, index
++, name
, &size
, NULL
, &type
, buffer
, &needed
))
1067 if (type
== REG_BINARY
&& needed
> sizeof(*cached
))
1069 ((DWORD
*)buffer
)[needed
/ sizeof(DWORD
)] = 0;
1070 if ((face
= create_face( family
, name
, cached
->full_name
,
1071 cached
->full_name
+ lstrlenW(cached
->full_name
) + 1,
1072 NULL
, 0, cached
->index
, cached
->fs
, cached
->ntmflags
, cached
->version
,
1073 cached
->flags
, scalable
? NULL
: &cached
->size
)))
1076 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1077 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1078 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1080 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1081 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1082 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1083 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1085 release_face( face
);
1088 size
= sizeof(name
);
1089 needed
= buffer_size
- sizeof(DWORD
);
1092 /* load bitmap strikes */
1095 needed
= buffer_size
;
1096 while (!RegEnumKeyExW( hkey_family
, index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1098 if (!RegOpenKeyExW( hkey_family
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1100 load_face_from_cache( hkey_strike
, family
, buffer
, buffer_size
, FALSE
);
1101 RegCloseKey( hkey_strike
);
1103 needed
= buffer_size
;
1107 static void load_font_list_from_cache(void)
1109 DWORD size
, family_index
= 0;
1110 struct gdi_font_family
*family
;
1112 WCHAR buffer
[4096], second_name
[LF_FACESIZE
];
1114 size
= sizeof(buffer
);
1115 while (!RegEnumKeyExW( wine_fonts_cache_key
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1117 RegOpenKeyExW( wine_fonts_cache_key
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1118 TRACE("opened family key %s\n", debugstr_w(buffer
));
1119 size
= sizeof(second_name
);
1120 if (RegQueryValueExW( hkey_family
, NULL
, NULL
, NULL
, (BYTE
*)second_name
, &size
))
1123 family
= create_family( buffer
, second_name
);
1125 load_face_from_cache( hkey_family
, family
, buffer
, sizeof(buffer
), TRUE
);
1127 RegCloseKey( hkey_family
);
1128 release_family( family
);
1129 size
= sizeof(buffer
);
1133 static void add_face_to_cache( struct gdi_font_face
*face
)
1135 HKEY hkey_family
, hkey_face
;
1136 DWORD len
, buffer
[1024];
1137 struct cached_face
*cached
= (struct cached_face
*)buffer
;
1139 if (RegCreateKeyExW( wine_fonts_cache_key
, face
->family
->family_name
, 0, NULL
, REG_OPTION_VOLATILE
,
1140 KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
))
1143 if (face
->family
->second_name
[0])
1144 RegSetValueExW( hkey_family
, NULL
, 0, REG_SZ
, (BYTE
*)face
->family
->second_name
,
1145 (lstrlenW( face
->family
->second_name
) + 1) * sizeof(WCHAR
) );
1147 if (!face
->scalable
)
1151 swprintf( name
, ARRAY_SIZE(name
), L
"%d", face
->size
.y_ppem
);
1152 RegCreateKeyExW( hkey_family
, name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
,
1153 NULL
, &hkey_face
, NULL
);
1155 else hkey_face
= hkey_family
;
1157 memset( cached
, 0, sizeof(*cached
) );
1158 cached
->index
= face
->face_index
;
1159 cached
->flags
= face
->flags
;
1160 cached
->ntmflags
= face
->ntmFlags
;
1161 cached
->version
= face
->version
;
1162 cached
->fs
= face
->fs
;
1163 if (!face
->scalable
) cached
->size
= face
->size
;
1164 lstrcpyW( cached
->full_name
, face
->full_name
);
1165 len
= lstrlenW( face
->full_name
) + 1;
1166 lstrcpyW( cached
->full_name
+ len
, face
->file
);
1167 len
+= lstrlenW( face
->file
) + 1;
1169 RegSetValueExW( hkey_face
, face
->style_name
, 0, REG_BINARY
, (BYTE
*)cached
,
1170 offsetof( struct cached_face
, full_name
[len
] ));
1172 if (hkey_face
!= hkey_family
) RegCloseKey( hkey_face
);
1173 RegCloseKey( hkey_family
);
1176 static void remove_face_from_cache( struct gdi_font_face
*face
)
1180 if (RegOpenKeyExW( wine_fonts_cache_key
, face
->family
->family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
))
1183 if (!face
->scalable
)
1186 swprintf( name
, ARRAY_SIZE(name
), L
"%d", face
->size
.y_ppem
);
1187 RegDeleteKeyW( hkey_family
, name
);
1189 else RegDeleteValueW( hkey_family
, face
->style_name
);
1191 RegCloseKey( hkey_family
);
1196 struct gdi_font_link
1200 WCHAR name
[LF_FACESIZE
];
1204 struct gdi_font_link_entry
1208 WCHAR family_name
[LF_FACESIZE
];
1211 static struct list font_links
= LIST_INIT(font_links
);
1213 static struct gdi_font_link
*find_gdi_font_link( const WCHAR
*name
)
1215 struct gdi_font_link
*link
;
1217 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1218 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 )) return link
;
1222 static struct gdi_font_family
*find_family_from_font_links( const WCHAR
*name
, const WCHAR
*subst
,
1225 struct gdi_font_link
*link
;
1226 struct gdi_font_link_entry
*entry
;
1227 struct gdi_font_family
*family
;
1229 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
1231 if (!facename_compare( link
->name
, name
, LF_FACESIZE
- 1 ) ||
1232 (subst
&& !facename_compare( link
->name
, subst
, LF_FACESIZE
- 1 )))
1234 TRACE("found entry in system list\n");
1235 LIST_FOR_EACH_ENTRY( entry
, &link
->links
, struct gdi_font_link_entry
, entry
)
1237 const struct gdi_font_link
*links
;
1239 family
= find_family_from_name( entry
->family_name
);
1240 if (!fs
.fsCsb
[0]) return family
;
1241 if (fs
.fsCsb
[0] & entry
->fs
.fsCsb
[0]) return family
;
1242 if ((links
= find_gdi_font_link( family
->family_name
)) && fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
1250 static struct gdi_font_link
*add_gdi_font_link( const WCHAR
*name
)
1252 struct gdi_font_link
*link
= find_gdi_font_link( name
);
1254 if (link
) return link
;
1255 if ((link
= HeapAlloc( GetProcessHeap(), 0, sizeof(*link
) )))
1257 lstrcpynW( link
->name
, name
, LF_FACESIZE
);
1258 memset( &link
->fs
, 0, sizeof(link
->fs
) );
1259 list_init( &link
->links
);
1260 list_add_tail( &font_links
, &link
->entry
);
1265 static void add_gdi_font_link_entry( struct gdi_font_link
*link
, const WCHAR
*family_name
, FONTSIGNATURE fs
)
1267 struct gdi_font_link_entry
*entry
;
1269 entry
= HeapAlloc( GetProcessHeap(), 0, sizeof(*entry
) );
1270 lstrcpynW( entry
->family_name
, family_name
, LF_FACESIZE
);
1272 link
->fs
.fsCsb
[0] |= fs
.fsCsb
[0];
1273 link
->fs
.fsCsb
[1] |= fs
.fsCsb
[1];
1274 list_add_tail( &link
->links
, &entry
->entry
);
1277 static const WCHAR
* const font_links_list
[] =
1279 L
"Lucida Sans Unicode",
1280 L
"Microsoft Sans Serif",
1284 static const struct font_links_defaults_list
1286 /* Keyed off substitution for "MS Shell Dlg" */
1287 const WCHAR
*shelldlg
;
1288 /* Maximum of four substitutes, plus terminating NULL pointer */
1289 const WCHAR
*substitutes
[5];
1290 } font_links_defaults_list
[] =
1292 /* Non East-Asian */
1293 { L
"Tahoma", /* FIXME unverified ordering */
1294 { L
"MS UI Gothic", L
"SimSun", L
"Gulim", L
"PMingLiU", NULL
}
1296 /* Below lists are courtesy of
1297 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1301 { L
"MS UI Gothic", L
"PMingLiU", L
"SimSun", L
"Gulim", NULL
}
1303 /* Chinese Simplified */
1305 { L
"SimSun", L
"PMingLiU", L
"MS UI Gothic", L
"Batang", NULL
}
1309 { L
"Gulim", L
"PMingLiU", L
"MS UI Gothic", L
"SimSun", NULL
}
1311 /* Chinese Traditional */
1313 { L
"PMingLiU", L
"SimSun", L
"MS UI Gothic", L
"Batang", NULL
}
1317 static void populate_system_links( const WCHAR
*name
, const WCHAR
* const *values
)
1319 struct gdi_font_family
*family
;
1320 struct gdi_font_face
*face
;
1321 struct gdi_font_link
*font_link
;
1322 const WCHAR
*file
, *value
;
1324 /* Don't store fonts that are only substitutes for other fonts */
1325 if (get_gdi_font_subst( name
, -1, NULL
))
1327 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
) );
1330 font_link
= add_gdi_font_link( name
);
1331 for ( ; *values
; values
++)
1333 if (!facename_compare( name
, *values
, -1 )) continue;
1334 if (!(value
= get_gdi_font_subst( *values
, -1, NULL
))) value
= *values
;
1335 if (!(family
= find_family_from_name( value
))) continue;
1336 /* use first extant filename for this Family */
1337 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1339 if (!face
->file
) continue;
1340 file
= wcsrchr(face
->file
, '\\');
1341 if (!file
) file
= face
->file
;
1343 if ((face
= find_face_from_filename( file
, value
)))
1345 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1346 TRACE( "added internal SystemLink for %s to %s in %s\n",
1347 debugstr_w(name
), debugstr_w(value
), debugstr_w(file
) );
1349 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
) );
1355 static void load_system_links(void)
1359 const WCHAR
*shelldlg_name
;
1360 struct gdi_font_link
*font_link
, *system_font_link
;
1361 struct gdi_font_face
*face
;
1363 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE
,
1364 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey
))
1366 WCHAR value
[MAX_PATH
], data
[1024];
1367 DWORD type
, val_len
, data_len
;
1368 WCHAR
*entry
, *next
;
1370 val_len
= ARRAY_SIZE(value
);
1371 data_len
= sizeof(data
);
1373 while (!RegEnumValueW( hkey
, i
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
))
1375 /* Don't store fonts that are only substitutes for other fonts */
1376 if (!get_gdi_font_subst( value
, -1, NULL
))
1378 font_link
= add_gdi_font_link( value
);
1379 for (entry
= data
; (char *)entry
< (char *)data
+ data_len
&& *entry
; entry
= next
)
1381 const WCHAR
*family_name
= NULL
;
1384 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1386 next
= entry
+ lstrlenW(entry
) + 1;
1387 if ((p
= wcschr( entry
, ',' )))
1390 while (iswspace(*p
)) p
++;
1391 if (!(family_name
= get_gdi_font_subst( p
, -1, NULL
))) family_name
= p
;
1393 if ((face
= find_face_from_filename( entry
, family_name
)))
1395 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
1396 TRACE("Adding file %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1398 else TRACE( "Unable to find file %s family %s\n",
1399 debugstr_w(entry
), debugstr_w(family_name
) );
1402 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1404 val_len
= ARRAY_SIZE(value
);
1405 data_len
= sizeof(data
);
1407 RegCloseKey( hkey
);
1410 if ((shelldlg_name
= get_gdi_font_subst( L
"MS Shell Dlg", -1, NULL
)))
1412 for (i
= 0; i
< ARRAY_SIZE(font_links_defaults_list
); i
++)
1414 const WCHAR
*subst
= get_gdi_font_subst( font_links_defaults_list
[i
].shelldlg
, -1, NULL
);
1416 if ((!facename_compare( font_links_defaults_list
[i
].shelldlg
, shelldlg_name
, -1 ) ||
1417 (subst
&& !facename_compare( subst
, shelldlg_name
, -1 ))))
1419 for (j
= 0; j
< ARRAY_SIZE(font_links_list
); j
++)
1420 populate_system_links( font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
1421 if (!facename_compare(shelldlg_name
, font_links_defaults_list
[i
].substitutes
[0], -1))
1422 populate_system_links( shelldlg_name
, font_links_defaults_list
[i
].substitutes
);
1426 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1428 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1431 system_font_link
= add_gdi_font_link( L
"System" );
1432 if ((face
= find_face_from_filename( L
"tahoma.ttf", L
"Tahoma" )))
1434 add_gdi_font_link_entry( system_font_link
, face
->family
->family_name
, face
->fs
);
1435 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1437 if ((font_link
= find_gdi_font_link( L
"Tahoma" )))
1439 struct gdi_font_link_entry
*entry
;
1440 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1441 add_gdi_font_link_entry( system_font_link
, entry
->family_name
, entry
->fs
);
1447 static BOOL
can_select_face( const struct gdi_font_face
*face
, FONTSIGNATURE fs
, BOOL can_use_bitmap
)
1449 struct gdi_font_link
*font_link
;
1451 if (!face
->scalable
&& !can_use_bitmap
) return FALSE
;
1452 if (!fs
.fsCsb
[0]) return TRUE
;
1453 if (fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return TRUE
;
1454 if (!(font_link
= find_gdi_font_link( face
->family
->family_name
))) return FALSE
;
1455 if (fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) return TRUE
;
1459 static struct gdi_font_face
*find_best_matching_face( const struct gdi_font_family
*family
,
1460 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1461 BOOL can_use_bitmap
)
1463 struct gdi_font_face
*face
= NULL
, *best
= NULL
, *best_bitmap
= NULL
;
1464 unsigned int best_score
= 4;
1466 int it
= !!lf
->lfItalic
;
1467 int bd
= lf
->lfWeight
> 550;
1468 int height
= lf
->lfHeight
;
1470 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1472 int italic
= !!(face
->ntmFlags
& NTM_ITALIC
);
1473 int bold
= !!(face
->ntmFlags
& NTM_BOLD
);
1474 int score
= (italic
^ it
) + (bold
^ bd
);
1476 if (!can_select_face( face
, fs
, can_use_bitmap
)) continue;
1477 if (score
> best_score
) continue;
1478 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic
, bold
, it
, bd
);
1481 if (best
->scalable
&& best_score
== 0) break;
1482 if (!best
->scalable
)
1486 diff
= height
- (signed int)best
->size
.height
;
1488 diff
= -height
- ((signed int)best
->size
.height
- best
->size
.internal_leading
);
1490 (best_diff
> 0 && diff
>= 0 && diff
< best_diff
) ||
1491 (best_diff
< 0 && diff
> best_diff
))
1493 TRACE( "%d is better for %d diff was %d\n", best
->size
.height
, height
, best_diff
);
1496 if (best_score
== 0 && best_diff
== 0) break;
1500 if (!best
) return NULL
;
1501 return best
->scalable
? best
: best_bitmap
;
1504 static struct gdi_font_face
*find_matching_face_by_name( const WCHAR
*name
, const WCHAR
*subst
,
1505 const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1506 BOOL can_use_bitmap
)
1508 struct gdi_font_family
*family
;
1509 struct gdi_font_face
*face
;
1511 family
= find_family_from_any_name( name
);
1512 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1515 family
= find_family_from_any_name( subst
);
1516 if (family
&& (face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1519 /* search by full face name */
1520 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1521 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1522 if (!facename_compare( face
->full_name
, name
, LF_FACESIZE
- 1 ) &&
1523 can_select_face( face
, fs
, can_use_bitmap
))
1526 if ((family
= find_family_from_font_links( name
, subst
, fs
)))
1528 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1533 static struct gdi_font_face
*find_any_face( const LOGFONTW
*lf
, FONTSIGNATURE fs
,
1534 BOOL can_use_bitmap
, BOOL want_vertical
)
1536 struct gdi_font_family
*family
;
1537 struct gdi_font_face
*face
;
1538 WCHAR name
[LF_FACESIZE
+ 1];
1541 /* first try the family fallbacks */
1542 while (enum_fallbacks( lf
->lfPitchAndFamily
, i
++, name
))
1546 memmove(name
+ 1, name
, min(lstrlenW(name
), LF_FACESIZE
));
1550 if (!(family
= find_family_from_any_name(name
))) continue;
1551 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1553 /* otherwise try only scalable */
1554 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1556 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1557 if ((face
= find_best_matching_face( family
, lf
, fs
, FALSE
))) return face
;
1559 if (!can_use_bitmap
) return NULL
;
1560 /* then also bitmap fonts */
1561 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
1563 if ((family
->family_name
[0] == '@') == !want_vertical
) continue;
1564 if ((face
= find_best_matching_face( family
, lf
, fs
, can_use_bitmap
))) return face
;
1569 static struct gdi_font_face
*find_matching_face( const LOGFONTW
*lf
, CHARSETINFO
*csi
, BOOL can_use_bitmap
,
1570 const WCHAR
**orig_name
)
1572 BOOL want_vertical
= (lf
->lfFaceName
[0] == '@');
1573 struct gdi_font_face
*face
;
1575 if (!TranslateCharsetInfo( (DWORD
*)(INT_PTR
)lf
->lfCharSet
, csi
, TCI_SRCCHARSET
))
1577 if (lf
->lfCharSet
!= DEFAULT_CHARSET
) FIXME( "Untranslated charset %d\n", lf
->lfCharSet
);
1578 csi
->fs
.fsCsb
[0] = 0;
1581 if (lf
->lfFaceName
[0])
1584 const WCHAR
*subst
= get_gdi_font_subst( lf
->lfFaceName
, lf
->lfCharSet
, &subst_charset
);
1588 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf
->lfFaceName
), lf
->lfCharSet
,
1589 debugstr_w(subst
), (subst_charset
!= -1) ? subst_charset
: lf
->lfCharSet
);
1590 if (subst_charset
!= -1)
1591 TranslateCharsetInfo( (DWORD
*)(INT_PTR
)subst_charset
, csi
, TCI_SRCCHARSET
);
1592 *orig_name
= lf
->lfFaceName
;
1595 if ((face
= find_matching_face_by_name( lf
->lfFaceName
, subst
, lf
, csi
->fs
, can_use_bitmap
)))
1598 *orig_name
= NULL
; /* substitution is no longer relevant */
1600 /* If requested charset was DEFAULT_CHARSET then try using charset
1601 corresponding to the current ansi codepage */
1602 if (!csi
->fs
.fsCsb
[0])
1605 if (!TranslateCharsetInfo( (DWORD
*)(INT_PTR
)acp
, csi
, TCI_SRCCODEPAGE
))
1607 FIXME( "TCI failed on codepage %d\n", acp
);
1608 csi
->fs
.fsCsb
[0] = 0;
1612 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1613 if (csi
->fs
.fsCsb
[0])
1615 csi
->fs
.fsCsb
[0] = 0;
1616 if ((face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, want_vertical
))) return face
;
1618 if (want_vertical
&& (face
= find_any_face( lf
, csi
->fs
, can_use_bitmap
, FALSE
))) return face
;
1622 /* realized font objects */
1624 #define FIRST_FONT_HANDLE 1
1625 #define MAX_FONT_HANDLES 256
1627 struct font_handle_entry
1629 struct gdi_font
*font
;
1630 WORD generation
; /* generation count for reusing handle values */
1633 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
1634 static struct font_handle_entry
*next_free
;
1635 static struct font_handle_entry
*next_unused
= font_handles
;
1637 static struct font_handle_entry
*handle_entry( DWORD handle
)
1639 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
1641 if (idx
< MAX_FONT_HANDLES
)
1643 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
1644 return &font_handles
[idx
];
1646 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
1650 static struct gdi_font
*get_font_from_handle( DWORD handle
)
1652 struct font_handle_entry
*entry
= handle_entry( handle
);
1654 if (entry
) return entry
->font
;
1655 SetLastError( ERROR_INVALID_PARAMETER
);
1659 static DWORD
alloc_font_handle( struct gdi_font
*font
)
1661 struct font_handle_entry
*entry
;
1665 next_free
= (struct font_handle_entry
*)entry
->font
;
1666 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
1667 entry
= next_unused
++;
1670 ERR( "out of realized font handles\n" );
1674 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
1675 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
1678 static void free_font_handle( DWORD handle
)
1680 struct font_handle_entry
*entry
;
1682 if ((entry
= handle_entry( handle
)))
1684 entry
->font
= (struct gdi_font
*)next_free
;
1689 static struct gdi_font
*alloc_gdi_font( const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
)
1691 UINT len
= file
? lstrlenW(file
) : 0;
1692 struct gdi_font
*font
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1693 offsetof( struct gdi_font
, file
[len
+ 1] ));
1696 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
1698 font
->kern_count
= -1;
1699 list_init( &font
->child_fonts
);
1703 WIN32_FILE_ATTRIBUTE_DATA info
;
1704 if (GetFileAttributesExW( file
, GetFileExInfoStandard
, &info
))
1706 font
->writetime
= info
.ftLastWriteTime
;
1707 font
->data_size
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
1708 memcpy( font
->file
, file
, len
* sizeof(WCHAR
) );
1713 font
->data_ptr
= data_ptr
;
1714 font
->data_size
= data_size
;
1717 font
->handle
= alloc_font_handle( font
);
1721 static void free_gdi_font( struct gdi_font
*font
)
1724 struct gdi_font
*child
, *child_next
;
1726 if (font
->private) font_funcs
->destroy_font( font
);
1727 free_font_handle( font
->handle
);
1728 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, struct gdi_font
, entry
)
1730 list_remove( &child
->entry
);
1731 free_gdi_font( child
);
1733 for (i
= 0; i
< font
->gm_size
; i
++) HeapFree( GetProcessHeap(), 0, font
->gm
[i
] );
1734 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFamilyName
);
1735 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpStyleName
);
1736 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFaceName
);
1737 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFullName
);
1738 HeapFree( GetProcessHeap(), 0, font
->gm
);
1739 HeapFree( GetProcessHeap(), 0, font
->kern_pairs
);
1740 HeapFree( GetProcessHeap(), 0, font
->gsub_table
);
1741 HeapFree( GetProcessHeap(), 0, font
);
1744 static inline const WCHAR
*get_gdi_font_name( struct gdi_font
*font
)
1746 return (WCHAR
*)font
->otm
.otmpFamilyName
;
1749 static struct gdi_font
*create_gdi_font( const struct gdi_font_face
*face
, const WCHAR
*family_name
,
1750 const LOGFONTW
*lf
)
1752 struct gdi_font
*font
;
1754 if (!(font
= alloc_gdi_font( face
->file
, face
->data_ptr
, face
->data_size
))) return NULL
;
1755 font
->fs
= face
->fs
;
1757 font
->fake_italic
= (lf
->lfItalic
&& !(face
->ntmFlags
& NTM_ITALIC
));
1758 font
->fake_bold
= (lf
->lfWeight
> 550 && !(face
->ntmFlags
& NTM_BOLD
));
1759 font
->scalable
= face
->scalable
;
1760 font
->face_index
= face
->face_index
;
1761 font
->ntmFlags
= face
->ntmFlags
;
1762 font
->aa_flags
= HIWORD( face
->flags
);
1763 if (!family_name
) family_name
= face
->family
->family_name
;
1764 font
->otm
.otmpFamilyName
= (char *)strdupW( family_name
);
1765 font
->otm
.otmpStyleName
= (char *)strdupW( face
->style_name
);
1766 font
->otm
.otmpFaceName
= (char *)strdupW( face
->full_name
);
1770 struct glyph_metrics
1773 ABC abc
; /* metrics of the unrotated char */
1777 #define GM_BLOCK_SIZE 128
1779 /* TODO: GGO format support */
1780 static BOOL
get_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
, GLYPHMETRICS
*gm
, ABC
*abc
)
1782 UINT block
= index
/ GM_BLOCK_SIZE
;
1783 UINT entry
= index
% GM_BLOCK_SIZE
;
1785 if (block
< font
->gm_size
&& font
->gm
[block
] && font
->gm
[block
][entry
].init
)
1787 *gm
= font
->gm
[block
][entry
].gm
;
1788 *abc
= font
->gm
[block
][entry
].abc
;
1790 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
1791 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point( &gm
->gmptGlyphOrigin
),
1792 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
1799 static void set_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
,
1800 const GLYPHMETRICS
*gm
, const ABC
*abc
)
1802 UINT block
= index
/ GM_BLOCK_SIZE
;
1803 UINT entry
= index
% GM_BLOCK_SIZE
;
1805 if (block
>= font
->gm_size
)
1807 struct glyph_metrics
**ptr
;
1810 ptr
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
, (block
+ 1) * sizeof(*ptr
) );
1812 ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, (block
+ 1) * sizeof(*ptr
) );
1814 font
->gm_size
= block
+ 1;
1817 if (!font
->gm
[block
])
1819 font
->gm
[block
] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**font
->gm
) * GM_BLOCK_SIZE
);
1820 if (!font
->gm
[block
]) return;
1822 font
->gm
[block
][entry
].gm
= *gm
;
1823 font
->gm
[block
][entry
].abc
= *abc
;
1824 font
->gm
[block
][entry
].init
= TRUE
;
1828 /* GSUB table support */
1842 } GSUB_ScriptRecord
;
1847 GSUB_ScriptRecord ScriptRecord
[1];
1854 } GSUB_LangSysRecord
;
1858 WORD DefaultLangSys
;
1860 GSUB_LangSysRecord LangSysRecord
[1];
1865 WORD LookupOrder
; /* Reserved */
1866 WORD ReqFeatureIndex
;
1868 WORD FeatureIndex
[1];
1875 } GSUB_FeatureRecord
;
1880 GSUB_FeatureRecord FeatureRecord
[1];
1885 WORD FeatureParams
; /* Reserved */
1887 WORD LookupListIndex
[1];
1906 WORD CoverageFormat
;
1909 } GSUB_CoverageFormat1
;
1915 WORD StartCoverageIndex
;
1920 WORD CoverageFormat
;
1922 GSUB_RangeRecord RangeRecord
[1];
1923 } GSUB_CoverageFormat2
;
1927 WORD SubstFormat
; /* = 1 */
1930 } GSUB_SingleSubstFormat1
;
1934 WORD SubstFormat
; /* = 2 */
1938 } GSUB_SingleSubstFormat2
;
1940 static GSUB_Script
*GSUB_get_script_table( GSUB_Header
*header
, const char *tag
)
1942 GSUB_ScriptList
*script
;
1943 GSUB_Script
*deflt
= NULL
;
1946 script
= (GSUB_ScriptList
*)((BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1947 TRACE("%i scripts in this font\n", GET_BE_WORD(script
->ScriptCount
) );
1948 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
1950 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
1951 GSUB_Script
*scr
= (GSUB_Script
*)((BYTE
*)script
+ offset
);
1952 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, tag
, 4 )) return scr
;
1953 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, "dflt", 4 )) deflt
= scr
;
1958 static GSUB_LangSys
*GSUB_get_lang_table( GSUB_Script
*script
, const char *tag
)
1963 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
1965 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
1967 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
1968 lang
= (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
1969 if (!memcmp( script
->LangSysRecord
[i
].LangSysTag
, tag
, 4 )) return lang
;
1971 offset
= GET_BE_WORD(script
->DefaultLangSys
);
1972 if (offset
) return (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
1976 static GSUB_Feature
*GSUB_get_feature( GSUB_Header
*header
, GSUB_LangSys
*lang
, const char *tag
)
1979 const GSUB_FeatureList
*feature
;
1981 feature
= (GSUB_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1982 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
1983 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
1985 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
1986 if (!memcmp( feature
->FeatureRecord
[index
].FeatureTag
, tag
, 4 ))
1987 return (GSUB_Feature
*)((BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
1992 static const char *get_opentype_script( const struct gdi_font
*font
)
1995 * I am not sure if this is the correct way to generate our script tag
1997 switch (font
->charset
)
1999 case ANSI_CHARSET
: return "latn";
2000 case BALTIC_CHARSET
: return "latn"; /* ?? */
2001 case CHINESEBIG5_CHARSET
: return "hani";
2002 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
2003 case GB2312_CHARSET
: return "hani";
2004 case GREEK_CHARSET
: return "grek";
2005 case HANGUL_CHARSET
: return "hang";
2006 case RUSSIAN_CHARSET
: return "cyrl";
2007 case SHIFTJIS_CHARSET
: return "kana";
2008 case TURKISH_CHARSET
: return "latn"; /* ?? */
2009 case VIETNAMESE_CHARSET
: return "latn";
2010 case JOHAB_CHARSET
: return "latn"; /* ?? */
2011 case ARABIC_CHARSET
: return "arab";
2012 case HEBREW_CHARSET
: return "hebr";
2013 case THAI_CHARSET
: return "thai";
2014 default: return "latn";
2018 static void *get_GSUB_vert_feature( struct gdi_font
*font
)
2020 GSUB_Header
*header
;
2021 GSUB_Script
*script
;
2022 GSUB_LangSys
*language
;
2023 GSUB_Feature
*feature
;
2024 DWORD length
= font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, NULL
, 0 );
2026 if (length
== GDI_ERROR
) return NULL
;
2028 header
= HeapAlloc( GetProcessHeap(), 0, length
);
2029 font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, header
, length
);
2030 TRACE( "Loaded GSUB table of %i bytes\n", length
);
2032 if ((script
= GSUB_get_script_table( header
, get_opentype_script(font
) )))
2034 if ((language
= GSUB_get_lang_table( script
, "xxxx" ))) /* Need to get Lang tag */
2036 feature
= GSUB_get_feature( header
, language
, "vrt2" );
2037 if (!feature
) feature
= GSUB_get_feature( header
, language
, "vert" );
2040 font
->gsub_table
= header
;
2043 TRACE("vrt2/vert feature not found\n");
2045 else TRACE("Language not found\n");
2047 else TRACE("Script not found\n");
2049 HeapFree( GetProcessHeap(), 0, header
);
2053 static int GSUB_is_glyph_covered( void *table
, UINT glyph
)
2055 GSUB_CoverageFormat1
*cf1
= table
;
2057 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
2059 int i
, count
= GET_BE_WORD(cf1
->GlyphCount
);
2061 TRACE("Coverage Format 1, %i glyphs\n",count
);
2062 for (i
= 0; i
< count
; i
++) if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
])) return i
;
2065 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
2068 GSUB_CoverageFormat2
*cf2
= table
;
2070 count
= GET_BE_WORD(cf2
->RangeCount
);
2071 TRACE("Coverage Format 2, %i ranges\n",count
);
2072 for (i
= 0; i
< count
; i
++)
2074 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) return -1;
2075 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
2076 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
2078 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
2079 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
2084 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
2089 static UINT
GSUB_apply_feature( GSUB_Header
*header
, GSUB_Feature
*feature
, UINT glyph
)
2091 GSUB_LookupList
*lookup
= (GSUB_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2094 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
2095 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
2097 GSUB_LookupTable
*look
;
2098 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
2099 look
= (GSUB_LookupTable
*)((BYTE
*)lookup
+ offset
);
2100 TRACE("type %i, flag %x, subtables %i\n",
2101 GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
2102 if (GET_BE_WORD(look
->LookupType
) == 1)
2104 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
2106 GSUB_SingleSubstFormat1
*ssf1
;
2107 offset
= GET_BE_WORD(look
->SubTable
[j
]);
2108 ssf1
= (GSUB_SingleSubstFormat1
*)((BYTE
*)look
+ offset
);
2109 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
2111 int offset
= GET_BE_WORD(ssf1
->Coverage
);
2112 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
2113 if (GSUB_is_glyph_covered( (BYTE
*) ssf1
+ offset
, glyph
) != -1)
2115 TRACE(" Glyph 0x%x ->",glyph
);
2116 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
2117 TRACE(" 0x%x\n",glyph
);
2122 GSUB_SingleSubstFormat2
*ssf2
;
2125 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
2126 offset
= GET_BE_WORD(ssf1
->Coverage
);
2127 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
2128 index
= GSUB_is_glyph_covered( (BYTE
*)ssf2
+ offset
, glyph
);
2129 TRACE(" Coverage index %i\n",index
);
2132 TRACE(" Glyph is 0x%x ->",glyph
);
2133 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
2134 TRACE("0x%x\n",glyph
);
2139 else FIXME("We only handle SubType 1\n");
2144 static UINT
get_GSUB_vert_glyph( struct gdi_font
*font
, UINT glyph
)
2146 if (!glyph
) return glyph
;
2147 if (!font
->gsub_table
) return glyph
;
2148 return GSUB_apply_feature( font
->gsub_table
, font
->vert_feature
, glyph
);
2151 static void add_child_font( struct gdi_font
*font
, const WCHAR
*family_name
)
2153 FONTSIGNATURE fs
= {{0}};
2154 struct gdi_font
*child
;
2155 struct gdi_font_face
*face
;
2157 if (!(face
= find_matching_face_by_name( family_name
, NULL
, &font
->lf
, fs
, FALSE
))) return;
2159 if (!(child
= create_gdi_font( face
, family_name
, &font
->lf
))) return;
2160 child
->matrix
= font
->matrix
;
2161 child
->can_use_bitmap
= font
->can_use_bitmap
;
2162 child
->scale_y
= font
->scale_y
;
2163 child
->aveWidth
= font
->aveWidth
;
2164 child
->charset
= font
->charset
;
2165 child
->codepage
= font
->codepage
;
2166 child
->base_font
= font
;
2167 list_add_tail( &font
->child_fonts
, &child
->entry
);
2168 TRACE( "created child font %p for base %p\n", child
, font
);
2171 static void create_child_font_list( struct gdi_font
*font
)
2173 struct gdi_font_link
*font_link
;
2174 struct gdi_font_link_entry
*entry
;
2175 const WCHAR
* font_name
;
2177 if (!(font_name
= get_gdi_font_subst( get_gdi_font_name(font
), -1, NULL
)))
2178 font_name
= get_gdi_font_name( font
);
2180 if ((font_link
= find_gdi_font_link( font_name
)))
2182 TRACE("found entry in system list\n");
2183 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2184 add_child_font( font
, entry
->family_name
);
2187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2188 * Sans Serif. This is how asian windows get default fallbacks for fonts
2190 if (is_dbcs_ansi_cp(GetACP()) && font
->charset
!= SYMBOL_CHARSET
&& font
->charset
!= OEM_CHARSET
&&
2191 facename_compare( font_name
, L
"Microsoft Sans Serif", -1 ) != 0)
2193 if ((font_link
= find_gdi_font_link( L
"Microsoft Sans Serif" )))
2195 TRACE("found entry in default fallback list\n");
2196 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
2197 add_child_font( font
, entry
->family_name
);
2204 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
2205 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
2206 static unsigned int unused_font_count
;
2207 #define UNUSED_CACHE_SIZE 10
2209 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
2210 const FMAT2
*matrix
, BOOL can_use_bitmap
)
2212 if (font
->hash
!= hash
) return TRUE
;
2213 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
2214 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2215 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
2216 return facename_compare( font
->lf
.lfFaceName
, lf
->lfFaceName
, -1 );
2219 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2221 DWORD hash
= 0, *ptr
, two_chars
;
2225 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
2227 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
2229 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
2232 pwc
= (WCHAR
*)&two_chars
;
2234 *pwc
= towupper(*pwc
);
2236 *pwc
= towupper(*pwc
);
2240 hash
^= !can_use_bitmap
;
2244 static void cache_gdi_font( struct gdi_font
*font
)
2246 static DWORD cache_num
= 1;
2248 font
->cache_num
= cache_num
++;
2249 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
2250 list_add_head( &gdi_font_list
, &font
->entry
);
2251 TRACE( "font %p\n", font
);
2254 static struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
2256 struct gdi_font
*font
;
2257 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
2259 /* try the in-use list */
2260 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
2262 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
2263 list_remove( &font
->entry
);
2264 list_add_head( &gdi_font_list
, &font
->entry
);
2265 if (!font
->refcount
++)
2267 list_remove( &font
->unused_entry
);
2268 unused_font_count
--;
2275 static void release_gdi_font( struct gdi_font
*font
)
2278 if (--font
->refcount
) return;
2280 TRACE( "font %p\n", font
);
2282 /* add it to the unused list */
2283 EnterCriticalSection( &font_cs
);
2284 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
2285 if (unused_font_count
> UNUSED_CACHE_SIZE
)
2287 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
2288 TRACE( "freeing %p\n", font
);
2289 list_remove( &font
->entry
);
2290 list_remove( &font
->unused_entry
);
2291 free_gdi_font( font
);
2293 else unused_font_count
++;
2294 LeaveCriticalSection( &font_cs
);
2297 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
2299 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
2301 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2302 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2303 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
2304 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2307 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2310 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2312 RegDeleteValueA(hkey
, name
);
2315 static void update_font_association_info(UINT current_ansi_codepage
)
2317 if (is_dbcs_ansi_cp(current_ansi_codepage
))
2320 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\FontAssoc", &hkey
) == ERROR_SUCCESS
)
2323 if (RegCreateKeyW(hkey
, L
"Associated Charset", &hsubkey
) == ERROR_SUCCESS
)
2325 switch (current_ansi_codepage
)
2328 set_value_key(hsubkey
, "ANSI(00)", "NO");
2329 set_value_key(hsubkey
, "OEM(FF)", "NO");
2330 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2335 set_value_key(hsubkey
, "ANSI(00)", "YES");
2336 set_value_key(hsubkey
, "OEM(FF)", "YES");
2337 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
2340 RegCloseKey(hsubkey
);
2343 /* TODO: Associated DefaultFonts */
2349 RegDeleteTreeW(HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\FontAssoc");
2352 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
2355 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
2357 RegDeleteValueW(hkey
, name
);
2360 static void update_font_system_link_info(UINT current_ansi_codepage
)
2362 static const WCHAR system_link_simplified_chinese
[] =
2363 L
"SIMSUN.TTC,SimSun\0"
2364 L
"MINGLIU.TTC,PMingLiu\0"
2365 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2366 L
"BATANG.TTC,Batang\0";
2367 static const WCHAR system_link_traditional_chinese
[] =
2368 L
"MINGLIU.TTC,PMingLiu\0"
2369 L
"SIMSUN.TTC,SimSun\0"
2370 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2371 L
"BATANG.TTC,Batang\0";
2372 static const WCHAR system_link_japanese
[] =
2373 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2374 L
"MINGLIU.TTC,PMingLiU\0"
2375 L
"SIMSUN.TTC,SimSun\0"
2376 L
"GULIM.TTC,Gulim\0";
2377 static const WCHAR system_link_korean
[] =
2378 L
"GULIM.TTC,Gulim\0"
2379 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2380 L
"MINGLIU.TTC,PMingLiU\0"
2381 L
"SIMSUN.TTC,SimSun\0";
2382 static const WCHAR system_link_non_cjk
[] =
2383 L
"MSGOTHIC.TTC,MS UI Gothic\0"
2384 L
"MINGLIU.TTC,PMingLiU\0"
2385 L
"SIMSUN.TTC,SimSun\0"
2386 L
"GULIM.TTC,Gulim\0";
2389 if (!RegCreateKeyW(HKEY_LOCAL_MACHINE
,
2390 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey
))
2395 switch (current_ansi_codepage
)
2398 link
= system_link_japanese
;
2399 len
= sizeof(system_link_japanese
);
2402 link
= system_link_simplified_chinese
;
2403 len
= sizeof(system_link_simplified_chinese
);
2406 link
= system_link_korean
;
2407 len
= sizeof(system_link_korean
);
2410 link
= system_link_traditional_chinese
;
2411 len
= sizeof(system_link_traditional_chinese
);
2414 link
= system_link_non_cjk
;
2415 len
= sizeof(system_link_non_cjk
);
2417 set_multi_value_key(hkey
, L
"Lucida Sans Unicode", link
, len
);
2418 set_multi_value_key(hkey
, L
"Microsoft Sans Serif", link
, len
);
2419 set_multi_value_key(hkey
, L
"Tahoma", link
, len
);
2424 static void update_codepage(void)
2426 char buf
[40], cpbuf
[40];
2428 DWORD len
, type
, size
;
2429 UINT i
, ansi_cp
, oem_cp
;
2430 DWORD screen_dpi
, font_dpi
= 0;
2433 screen_dpi
= get_dpi();
2434 if (!screen_dpi
) screen_dpi
= 96;
2436 size
= sizeof(DWORD
);
2437 if (RegQueryValueExW(wine_fonts_key
, L
"LogPixels", NULL
, &type
, (BYTE
*)&font_dpi
, &size
) ||
2438 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
2442 oem_cp
= GetOEMCP();
2443 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2447 if (!RegQueryValueExA(wine_fonts_key
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) && type
== REG_SZ
)
2449 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) return; /* already set correctly */
2450 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2451 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
2453 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2454 ansi_cp
, oem_cp
, screen_dpi
);
2456 RegSetValueExA(wine_fonts_key
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2457 RegSetValueExW(wine_fonts_key
, L
"LogPixels", 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
2459 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
2461 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&& nls_update_font_list
[i
].oem_cp
== oem_cp
)
2463 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG
, L
"Software\\Fonts", &hkey
))
2465 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
,
2466 strlen(nls_update_font_list
[i
].oem
)+1);
2467 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
,
2468 strlen(nls_update_font_list
[i
].fixed
)+1);
2469 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
,
2470 strlen(nls_update_font_list
[i
].system
)+1);
2473 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
,
2474 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey
))
2476 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2479 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
,
2480 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey
))
2482 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
2485 /* Only update these if the Codepage changed. */
2486 if (strcmp( buf
, cpbuf
) && !RegCreateKeyW( HKEY_LOCAL_MACHINE
,
2487 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2489 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2490 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2491 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2492 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2494 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2495 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2496 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2497 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2498 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2499 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2500 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2501 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2503 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2504 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2505 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2513 /* Delete the FontSubstitutes from other locales */
2514 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2516 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2517 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2518 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2524 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2526 /* update locale dependent font association info and font system link info in registry.
2527 update only when codepages changed, not logpixels. */
2528 if (strcmp(buf
, cpbuf
) != 0)
2530 update_font_association_info(ansi_cp
);
2531 update_font_system_link_info(ansi_cp
);
2536 /*************************************************************
2539 static BOOL CDECL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
2540 LPCWSTR output
, const DEVMODEW
*devmode
)
2542 struct font_physdev
*physdev
;
2544 if (!font_funcs
) return TRUE
;
2545 if (!(physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) ))) return FALSE
;
2546 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
2551 /*************************************************************
2554 static BOOL CDECL
font_DeleteDC( PHYSDEV dev
)
2556 struct font_physdev
*physdev
= get_font_dev( dev
);
2558 release_gdi_font( physdev
->font
);
2559 HeapFree( GetProcessHeap(), 0, physdev
);
2564 struct gdi_font_enum_data
2567 NEWTEXTMETRICEXW ntm
;
2577 static int load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
2584 id
+= IDS_FIRST_SCRIPT
;
2585 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
2586 if (!rsrc
) return 0;
2587 hMem
= LoadResource( gdi32_module
, rsrc
);
2588 if (!hMem
) return 0;
2590 p
= LockResource( hMem
);
2592 while (id
--) p
+= *p
+ 1;
2594 i
= min(LF_FACESIZE
- 1, *p
);
2595 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
2600 static BOOL
is_complex_script_ansi_cp( UINT ansi_cp
)
2602 return (ansi_cp
== 874 /* Thai */
2603 || ansi_cp
== 1255 /* Hebrew */
2604 || ansi_cp
== 1256 /* Arabic */
2608 /***************************************************
2609 * create_enum_charset_list
2611 * This function creates charset enumeration list because in DEFAULT_CHARSET
2612 * case, the ANSI codepage's charset takes precedence over other charsets.
2613 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2614 * This function works as a filter other than DEFAULT_CHARSET case.
2616 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset
*list
)
2618 struct enum_charset
*start
= list
;
2622 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) && csi
.fs
.fsCsb
[0] != 0)
2624 list
->mask
= csi
.fs
.fsCsb
[0];
2625 list
->charset
= csi
.ciCharset
;
2626 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2629 else /* charset is DEFAULT_CHARSET or invalid. */
2634 /* Set the current codepage's charset as the first element. */
2635 if (!is_complex_script_ansi_cp(acp
) &&
2636 TranslateCharsetInfo( (DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
2637 csi
.fs
.fsCsb
[0] != 0)
2639 list
->mask
= csi
.fs
.fsCsb
[0];
2640 list
->charset
= csi
.ciCharset
;
2641 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2642 mask
|= csi
.fs
.fsCsb
[0];
2646 /* Fill out left elements. */
2647 for (i
= 0; i
< 32; i
++)
2650 fs
.fsCsb
[0] = 1u << i
;
2652 if (fs
.fsCsb
[0] & mask
) continue; /* skip, already added. */
2653 if (!TranslateCharsetInfo( fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
2654 continue; /* skip, this is an invalid fsCsb bit. */
2655 list
->mask
= fs
.fsCsb
[0];
2656 list
->charset
= csi
.ciCharset
;
2658 mask
|= fs
.fsCsb
[0];
2661 /* add catch all mask for remaining bits */
2665 list
->charset
= DEFAULT_CHARSET
;
2666 list
->script
= IDS_OTHER
- IDS_FIRST_SCRIPT
;
2670 return list
- start
;
2673 static UINT
get_font_type( const NEWTEXTMETRICEXW
*ntm
)
2677 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ret
|= TRUETYPE_FONTTYPE
;
2678 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
) ret
|= DEVICE_FONTTYPE
;
2679 if (!(ntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
)) ret
|= RASTER_FONTTYPE
;
2683 static BOOL
get_face_enum_data( struct gdi_font_face
*face
, ENUMLOGFONTEXW
*elf
, NEWTEXTMETRICEXW
*ntm
)
2685 struct gdi_font
*font
;
2686 LOGFONTW lf
= { .lfHeight
= -4096 /* preferable EM Square size */ };
2688 if (!face
->scalable
) lf
.lfHeight
= 0;
2690 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2692 if (!font_funcs
->load_font( font
))
2694 free_gdi_font( font
);
2698 if (font
->scalable
&& -lf
.lfHeight
% font
->otm
.otmEMSquare
!= 0)
2700 /* reload with the original EM Square size */
2701 lf
.lfHeight
= -font
->otm
.otmEMSquare
;
2702 free_gdi_font( font
);
2704 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2705 if (!font_funcs
->load_font( font
))
2707 free_gdi_font( font
);
2712 if (font_funcs
->set_outline_text_metrics( font
))
2714 static const DWORD ntm_ppem
= 32;
2717 #define TM font->otm.otmTextMetrics
2718 #define SCALE_NTM(value) (MulDiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
2719 cell_height
= TM
.tmHeight
/ ( -lf
.lfHeight
/ font
->otm
.otmEMSquare
);
2720 ntm
->ntmTm
.tmHeight
= MulDiv( ntm_ppem
, cell_height
, font
->otm
.otmEMSquare
);
2721 ntm
->ntmTm
.tmAscent
= SCALE_NTM( TM
.tmAscent
);
2722 ntm
->ntmTm
.tmDescent
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmAscent
;
2723 ntm
->ntmTm
.tmInternalLeading
= SCALE_NTM( TM
.tmInternalLeading
);
2724 ntm
->ntmTm
.tmExternalLeading
= SCALE_NTM( TM
.tmExternalLeading
);
2725 ntm
->ntmTm
.tmAveCharWidth
= SCALE_NTM( TM
.tmAveCharWidth
);
2726 ntm
->ntmTm
.tmMaxCharWidth
= SCALE_NTM( TM
.tmMaxCharWidth
);
2728 memcpy((char *)&ntm
->ntmTm
+ offsetof( TEXTMETRICW
, tmWeight
),
2729 (const char *)&TM
+ offsetof( TEXTMETRICW
, tmWeight
),
2730 sizeof(TEXTMETRICW
) - offsetof( TEXTMETRICW
, tmWeight
));
2731 ntm
->ntmTm
.ntmSizeEM
= font
->otm
.otmEMSquare
;
2732 ntm
->ntmTm
.ntmCellHeight
= cell_height
;
2733 ntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
2737 else if (font_funcs
->set_bitmap_text_metrics( font
))
2739 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
2740 ntm
->ntmTm
.ntmSizeEM
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmInternalLeading
;
2741 ntm
->ntmTm
.ntmCellHeight
= ntm
->ntmTm
.tmHeight
;
2742 ntm
->ntmTm
.ntmAvgWidth
= ntm
->ntmTm
.tmAveCharWidth
;
2744 ntm
->ntmTm
.ntmFlags
= font
->ntmFlags
;
2745 ntm
->ntmFontSig
= font
->fs
;
2747 elf
->elfLogFont
.lfEscapement
= 0;
2748 elf
->elfLogFont
.lfOrientation
= 0;
2749 elf
->elfLogFont
.lfHeight
= ntm
->ntmTm
.tmHeight
;
2750 elf
->elfLogFont
.lfWidth
= ntm
->ntmTm
.tmAveCharWidth
;
2751 elf
->elfLogFont
.lfWeight
= ntm
->ntmTm
.tmWeight
;
2752 elf
->elfLogFont
.lfItalic
= ntm
->ntmTm
.tmItalic
;
2753 elf
->elfLogFont
.lfUnderline
= ntm
->ntmTm
.tmUnderlined
;
2754 elf
->elfLogFont
.lfStrikeOut
= ntm
->ntmTm
.tmStruckOut
;
2755 elf
->elfLogFont
.lfCharSet
= ntm
->ntmTm
.tmCharSet
;
2756 elf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2757 elf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2758 elf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2759 elf
->elfLogFont
.lfPitchAndFamily
= (ntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
2760 lstrcpynW( elf
->elfLogFont
.lfFaceName
, (WCHAR
*)font
->otm
.otmpFamilyName
, LF_FACESIZE
);
2761 lstrcpynW( elf
->elfFullName
, (WCHAR
*)font
->otm
.otmpFaceName
, LF_FULLFACESIZE
);
2762 lstrcpynW( elf
->elfStyle
, (WCHAR
*)font
->otm
.otmpStyleName
, LF_FACESIZE
);
2764 free_gdi_font( font
);
2768 static BOOL
family_matches( struct gdi_font_family
*family
, const WCHAR
*face_name
)
2770 struct gdi_font_face
*face
;
2772 if (!facename_compare( face_name
, family
->family_name
, LF_FACESIZE
- 1 )) return TRUE
;
2773 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2774 if (!facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 )) return TRUE
;
2778 static BOOL
face_matches( const WCHAR
*family_name
, struct gdi_font_face
*face
, const WCHAR
*face_name
)
2780 if (!facename_compare( face_name
, family_name
, LF_FACESIZE
- 1)) return TRUE
;
2781 return !facename_compare( face_name
, face
->full_name
, LF_FACESIZE
- 1 );
2784 static BOOL
enum_face_charsets( const struct gdi_font_family
*family
, struct gdi_font_face
*face
,
2785 struct enum_charset
*list
, DWORD count
, FONTENUMPROCW proc
, LPARAM lparam
,
2786 const WCHAR
*subst
)
2789 NEWTEXTMETRICEXW ntm
;
2792 if (!face
->cached_enum_data
)
2794 struct gdi_font_enum_data
*data
;
2796 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) )) ||
2797 !get_face_enum_data( face
, &data
->elf
, &data
->ntm
))
2799 HeapFree( GetProcessHeap(), 0, data
);
2802 face
->cached_enum_data
= data
;
2805 elf
= face
->cached_enum_data
->elf
;
2806 ntm
= face
->cached_enum_data
->ntm
;
2807 type
= get_font_type( &ntm
);
2809 /* font replacement */
2810 if (family
!= face
->family
)
2812 lstrcpynW( elf
.elfLogFont
.lfFaceName
, family
->family_name
, LF_FACESIZE
);
2813 lstrcpynW( elf
.elfFullName
, face
->full_name
, LF_FULLFACESIZE
);
2815 if (subst
) lstrcpynW( elf
.elfLogFont
.lfFaceName
, subst
, LF_FACESIZE
);
2817 for (i
= 0; i
< count
; i
++)
2819 if (face
->fs
.fsCsb
[0] == 0) /* OEM */
2821 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2822 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
2823 i
= count
; /* break out of loop after enumeration */
2827 if (!(face
->fs
.fsCsb
[0] & list
[i
].mask
)) continue;
2828 /* use the DEFAULT_CHARSET case only if no other charset is present */
2829 if (list
[i
].charset
== DEFAULT_CHARSET
&& (face
->fs
.fsCsb
[0] & ~list
[i
].mask
)) continue;
2830 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
[i
].charset
;
2831 load_script_name( list
[i
].script
, elf
.elfScript
);
2832 if (!elf
.elfScript
[0]) FIXME("Unknown elfscript for id %u\n", list
[i
].script
);
2834 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2835 debugstr_w(elf
.elfLogFont
.lfFaceName
), debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2836 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
2837 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
, ntm
.ntmTm
.ntmFlags
);
2838 /* release section before callback (FIXME) */
2839 LeaveCriticalSection( &font_cs
);
2840 if (!proc( &elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
2841 EnterCriticalSection( &font_cs
);
2846 /*************************************************************
2849 static BOOL CDECL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, FONTENUMPROCW proc
, LPARAM lparam
)
2851 struct gdi_font_family
*family
;
2852 struct gdi_font_face
*face
;
2853 struct enum_charset enum_charsets
[32];
2854 DWORD count
, charset
;
2856 charset
= lf
? lf
->lfCharSet
: DEFAULT_CHARSET
;
2858 count
= create_enum_charset_list( charset
, enum_charsets
);
2860 EnterCriticalSection( &font_cs
);
2862 if (lf
&& lf
->lfFaceName
[0])
2864 const WCHAR
*face_name
= get_gdi_font_subst( lf
->lfFaceName
, charset
, NULL
);
2865 const WCHAR
*orig_name
= NULL
;
2867 TRACE( "facename = %s charset %d\n", debugstr_w(lf
->lfFaceName
), charset
);
2870 orig_name
= lf
->lfFaceName
;
2871 TRACE( "substituting %s -> %s\n", debugstr_w(lf
->lfFaceName
), debugstr_w(face_name
) );
2873 else face_name
= lf
->lfFaceName
;
2875 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2877 if (!family_matches(family
, face_name
)) continue;
2878 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2880 if (!face_matches( family
->family_name
, face
, face_name
)) continue;
2881 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, orig_name
))
2888 TRACE( "charset %d\n", charset
);
2889 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
2891 face
= LIST_ENTRY( list_head(get_family_face_list(family
)), struct gdi_font_face
, entry
);
2892 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, NULL
))
2896 LeaveCriticalSection( &font_cs
);
2901 static BOOL
check_unicode_tategaki( WCHAR ch
)
2903 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
2904 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[ch
>> 8]+((ch
>> 4) & 0x0f)]+ (ch
& 0xf)];
2906 /* We only reach this code if typographical substitution did not occur */
2907 /* Type: U or Type: Tu */
2908 return (orientation
== 1 || orientation
== 3);
2911 static UINT
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2915 if (glyph
< 0x100) glyph
+= 0xf000;
2916 /* there are a number of old pre-Unicode "broken" TTFs, which
2917 do have symbols at U+00XX instead of U+f0XX */
2919 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2922 index
= glyph
- 0xf000;
2923 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2928 static UINT
get_glyph_index( struct gdi_font
*font
, UINT glyph
)
2934 if (font_funcs
->get_glyph_index( font
, &glyph
, TRUE
)) return glyph
;
2936 if (font
->codepage
== CP_SYMBOL
)
2938 glyph
= get_glyph_index_symbol( font
, wc
);
2941 if (WideCharToMultiByte( CP_ACP
, WC_NO_BEST_FIT_CHARS
, &wc
, 1, &ch
, 1, NULL
, NULL
))
2942 glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2945 else if (WideCharToMultiByte( font
->codepage
, WC_NO_BEST_FIT_CHARS
, &wc
, 1, &ch
, 1, NULL
, &used
) && !used
)
2947 glyph
= (unsigned char)ch
;
2948 font_funcs
->get_glyph_index( font
, &glyph
, FALSE
);
2955 static UINT
get_glyph_index_linked( struct gdi_font
**font
, UINT glyph
)
2957 struct gdi_font
*child
;
2960 if ((res
= get_glyph_index( *font
, glyph
))) return res
;
2961 if (glyph
< 32) return 0; /* don't check linked fonts for control characters */
2963 LIST_FOR_EACH_ENTRY( child
, &(*font
)->child_fonts
, struct gdi_font
, entry
)
2965 if (!child
->private && !font_funcs
->load_font( child
)) continue;
2966 if ((res
= get_glyph_index( child
, glyph
)))
2975 static DWORD
get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
2976 GLYPHMETRICS
*gm_ret
, ABC
*abc_ret
, DWORD buflen
, void *buf
,
2983 BOOL tategaki
= (*get_gdi_font_name( font
) == '@');
2985 if (format
& GGO_GLYPH_INDEX
)
2987 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
2988 as glyph index. "Treasure Adventure Game" depends on this. */
2989 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2990 format
&= ~GGO_GLYPH_INDEX
;
2991 /* TODO: Window also turns off tategaki for glyphs passed in by index
2992 if their unicode code points fall outside of the range that is
2997 index
= get_glyph_index_linked( &font
, glyph
);
3001 index
= get_GSUB_vert_glyph( font
, index
);
3002 if (index
== orig
) tategaki
= check_unicode_tategaki( glyph
);
3006 if (mat
&& !memcmp( mat
, &identity
, sizeof(*mat
) )) mat
= NULL
;
3008 if (format
== GGO_METRICS
&& !mat
&& get_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
))
3011 ret
= font_funcs
->get_glyph_outline( font
, index
, format
, &gm
, &abc
, buflen
, buf
, mat
, tategaki
);
3012 if (ret
== GDI_ERROR
) return ret
;
3014 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) && !mat
)
3015 set_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
);
3018 if (gm_ret
) *gm_ret
= gm
;
3019 if (abc_ret
) *abc_ret
= abc
;
3024 /*************************************************************
3027 static BOOL CDECL
font_FontIsLinked( PHYSDEV dev
)
3029 struct font_physdev
*physdev
= get_font_dev( dev
);
3033 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
3034 return dev
->funcs
->pFontIsLinked( dev
);
3036 return !list_empty( &physdev
->font
->child_fonts
);
3040 /*************************************************************
3041 * font_GetCharABCWidths
3043 static BOOL CDECL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT last
, ABC
*buffer
)
3045 struct font_physdev
*physdev
= get_font_dev( dev
);
3050 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
3051 return dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, buffer
);
3054 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, last
, buffer
);
3056 EnterCriticalSection( &font_cs
);
3057 for (c
= first
; c
<= last
; c
++, buffer
++)
3058 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, buffer
, 0, NULL
, NULL
);
3059 LeaveCriticalSection( &font_cs
);
3064 /*************************************************************
3065 * font_GetCharABCWidthsI
3067 static BOOL CDECL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
3069 struct font_physdev
*physdev
= get_font_dev( dev
);
3074 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
3075 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
3078 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
3080 EnterCriticalSection( &font_cs
);
3081 for (c
= 0; c
< count
; c
++, buffer
++)
3082 get_glyph_outline( physdev
->font
, gi
? gi
[c
] : first
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3083 NULL
, buffer
, 0, NULL
, NULL
);
3084 LeaveCriticalSection( &font_cs
);
3089 /*************************************************************
3092 static BOOL CDECL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT last
, INT
*buffer
)
3094 struct font_physdev
*physdev
= get_font_dev( dev
);
3100 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
3101 return dev
->funcs
->pGetCharWidth( dev
, first
, last
, buffer
);
3104 TRACE( "%p, %d, %d, %p\n", physdev
->font
, first
, last
, buffer
);
3106 EnterCriticalSection( &font_cs
);
3107 for (c
= first
; c
<= last
; c
++)
3109 if (get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
) == GDI_ERROR
)
3110 buffer
[c
- first
] = 0;
3112 buffer
[c
- first
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3114 LeaveCriticalSection( &font_cs
);
3119 /*************************************************************
3120 * font_GetCharWidthInfo
3122 static BOOL CDECL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
3124 struct font_physdev
*physdev
= get_font_dev( dev
);
3125 struct char_width_info
*info
= ptr
;
3129 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
3130 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
3134 if (!physdev
->font
->scalable
|| !font_funcs
->get_char_width_info( physdev
->font
, info
))
3135 info
->lsb
= info
->rsb
= 0;
3141 /*************************************************************
3144 static DWORD CDECL
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
3146 struct font_physdev
*physdev
= get_font_dev( dev
);
3150 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
3151 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
3153 return font_funcs
->get_font_data( physdev
->font
, table
, offset
, buf
, size
);
3157 /*************************************************************
3158 * font_GetFontRealizationInfo
3160 static BOOL CDECL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
3162 struct font_physdev
*physdev
= get_font_dev( dev
);
3163 struct font_realization_info
*info
= ptr
;
3167 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
3168 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
3171 TRACE( "(%p, %p)\n", physdev
->font
, info
);
3174 if (physdev
->font
->scalable
) info
->flags
|= 2;
3176 info
->cache_num
= physdev
->font
->cache_num
;
3177 info
->instance_id
= physdev
->font
->handle
;
3178 if (info
->size
== sizeof(*info
))
3181 info
->face_index
= physdev
->font
->face_index
;
3182 info
->simulations
= 0;
3183 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
3184 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
3190 /*************************************************************
3191 * font_GetFontUnicodeRanges
3193 static DWORD CDECL
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
3195 struct font_physdev
*physdev
= get_font_dev( dev
);
3196 DWORD size
, num_ranges
;
3200 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
3201 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
3204 num_ranges
= font_funcs
->get_unicode_ranges( physdev
->font
, glyphset
);
3205 size
= offsetof( GLYPHSET
, ranges
[num_ranges
] );
3208 glyphset
->cbThis
= size
;
3209 glyphset
->cRanges
= num_ranges
;
3210 glyphset
->flAccel
= 0;
3216 /*************************************************************
3217 * font_GetGlyphIndices
3219 static DWORD CDECL
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
3221 struct font_physdev
*physdev
= get_font_dev( dev
);
3224 BOOL used
, got_default
= FALSE
;
3229 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
3230 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
3233 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
3235 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
3239 EnterCriticalSection( &font_cs
);
3241 for (i
= 0; i
< count
; i
++)
3243 UINT glyph
= str
[i
];
3245 if (!font_funcs
->get_glyph_index( physdev
->font
, &glyph
, TRUE
))
3248 if (physdev
->font
->codepage
== CP_SYMBOL
)
3250 if (str
[i
] >= 0xf020 && str
[i
] <= 0xf100) glyph
= str
[i
] - 0xf000;
3251 else if (str
[i
] < 0x100) glyph
= str
[i
];
3253 else if (WideCharToMultiByte( physdev
->font
->codepage
, WC_NO_BEST_FIT_CHARS
, &str
[i
], 1,
3254 &ch
, 1, NULL
, &used
) && !used
)
3255 glyph
= (unsigned char)ch
;
3261 default_char
= font_funcs
->get_default_glyph( physdev
->font
);
3264 gi
[i
] = default_char
;
3266 else gi
[i
] = get_GSUB_vert_glyph( physdev
->font
, glyph
);
3269 LeaveCriticalSection( &font_cs
);
3274 /*************************************************************
3275 * font_GetGlyphOutline
3277 static DWORD CDECL
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
3278 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
3280 struct font_physdev
*physdev
= get_font_dev( dev
);
3285 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
3286 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
3288 EnterCriticalSection( &font_cs
);
3289 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, gm
, NULL
, buflen
, buf
, mat
);
3290 LeaveCriticalSection( &font_cs
);
3295 /*************************************************************
3296 * font_GetKerningPairs
3298 static DWORD CDECL
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
3300 struct font_physdev
*physdev
= get_font_dev( dev
);
3304 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
3305 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
3308 EnterCriticalSection( &font_cs
);
3309 if (physdev
->font
->kern_count
== -1)
3310 physdev
->font
->kern_count
= font_funcs
->get_kerning_pairs( physdev
->font
,
3311 &physdev
->font
->kern_pairs
);
3312 LeaveCriticalSection( &font_cs
);
3316 count
= min( count
, physdev
->font
->kern_count
);
3317 memcpy( pairs
, physdev
->font
->kern_pairs
, count
* sizeof(*pairs
) );
3319 else count
= physdev
->font
->kern_count
;
3325 static void scale_outline_font_metrics( const struct gdi_font
*font
, OUTLINETEXTMETRICW
*otm
)
3327 double scale_x
, scale_y
;
3331 scale_x
= (double)font
->aveWidth
;
3332 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3335 scale_x
= font
->scale_y
;
3337 scale_x
*= fabs(font
->matrix
.eM11
);
3338 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3340 /* Windows scales these values as signed integers even if they are unsigned */
3341 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3342 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3344 SCALE_Y(otm
->otmTextMetrics
.tmHeight
);
3345 SCALE_Y(otm
->otmTextMetrics
.tmAscent
);
3346 SCALE_Y(otm
->otmTextMetrics
.tmDescent
);
3347 SCALE_Y(otm
->otmTextMetrics
.tmInternalLeading
);
3348 SCALE_Y(otm
->otmTextMetrics
.tmExternalLeading
);
3350 SCALE_X(otm
->otmTextMetrics
.tmOverhang
);
3351 if (font
->fake_bold
)
3353 if (!font
->scalable
) otm
->otmTextMetrics
.tmOverhang
++;
3354 otm
->otmTextMetrics
.tmAveCharWidth
++;
3355 otm
->otmTextMetrics
.tmMaxCharWidth
++;
3357 SCALE_X(otm
->otmTextMetrics
.tmAveCharWidth
);
3358 SCALE_X(otm
->otmTextMetrics
.tmMaxCharWidth
);
3360 SCALE_Y(otm
->otmAscent
);
3361 SCALE_Y(otm
->otmDescent
);
3362 SCALE_Y(otm
->otmLineGap
);
3363 SCALE_Y(otm
->otmsCapEmHeight
);
3364 SCALE_Y(otm
->otmsXHeight
);
3365 SCALE_Y(otm
->otmrcFontBox
.top
);
3366 SCALE_Y(otm
->otmrcFontBox
.bottom
);
3367 SCALE_X(otm
->otmrcFontBox
.left
);
3368 SCALE_X(otm
->otmrcFontBox
.right
);
3369 SCALE_Y(otm
->otmMacAscent
);
3370 SCALE_Y(otm
->otmMacDescent
);
3371 SCALE_Y(otm
->otmMacLineGap
);
3372 SCALE_X(otm
->otmptSubscriptSize
.x
);
3373 SCALE_Y(otm
->otmptSubscriptSize
.y
);
3374 SCALE_X(otm
->otmptSubscriptOffset
.x
);
3375 SCALE_Y(otm
->otmptSubscriptOffset
.y
);
3376 SCALE_X(otm
->otmptSuperscriptSize
.x
);
3377 SCALE_Y(otm
->otmptSuperscriptSize
.y
);
3378 SCALE_X(otm
->otmptSuperscriptOffset
.x
);
3379 SCALE_Y(otm
->otmptSuperscriptOffset
.y
);
3380 SCALE_Y(otm
->otmsStrikeoutSize
);
3381 SCALE_Y(otm
->otmsStrikeoutPosition
);
3382 SCALE_Y(otm
->otmsUnderscoreSize
);
3383 SCALE_Y(otm
->otmsUnderscorePosition
);
3389 /*************************************************************
3390 * font_GetOutlineTextMetrics
3392 static UINT CDECL
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
3394 struct font_physdev
*physdev
= get_font_dev( dev
);
3399 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
3400 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
3403 if (!physdev
->font
->scalable
) return 0;
3405 EnterCriticalSection( &font_cs
);
3406 if (font_funcs
->set_outline_text_metrics( physdev
->font
))
3408 ret
= physdev
->font
->otm
.otmSize
;
3409 if (metrics
&& size
>= physdev
->font
->otm
.otmSize
)
3411 WCHAR
*ptr
= (WCHAR
*)(metrics
+ 1);
3412 *metrics
= physdev
->font
->otm
;
3413 metrics
->otmpFamilyName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3414 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFamilyName
);
3415 ptr
+= lstrlenW(ptr
) + 1;
3416 metrics
->otmpStyleName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3417 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpStyleName
);
3418 ptr
+= lstrlenW(ptr
) + 1;
3419 metrics
->otmpFaceName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3420 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFaceName
);
3421 ptr
+= lstrlenW(ptr
) + 1;
3422 metrics
->otmpFullName
= (char *)ptr
- (ULONG_PTR
)metrics
;
3423 lstrcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFullName
);
3424 scale_outline_font_metrics( physdev
->font
, metrics
);
3427 LeaveCriticalSection( &font_cs
);
3432 /*************************************************************
3433 * font_GetTextCharsetInfo
3435 static UINT CDECL
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
3437 struct font_physdev
*physdev
= get_font_dev( dev
);
3441 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
3442 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
3444 if (fs
) *fs
= physdev
->font
->fs
;
3445 return physdev
->font
->charset
;
3449 /*************************************************************
3450 * font_GetTextExtentExPoint
3452 static BOOL CDECL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
3454 struct font_physdev
*physdev
= get_font_dev( dev
);
3460 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
3461 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
3464 TRACE( "%p, %s, %d\n", physdev
->font
, debugstr_wn(str
, count
), count
);
3466 EnterCriticalSection( &font_cs
);
3467 for (i
= pos
= 0; i
< count
; i
++)
3469 get_glyph_outline( physdev
->font
, str
[i
], GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
);
3470 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3473 LeaveCriticalSection( &font_cs
);
3478 /*************************************************************
3479 * font_GetTextExtentExPointI
3481 static BOOL CDECL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
3483 struct font_physdev
*physdev
= get_font_dev( dev
);
3489 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
3490 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
3493 TRACE( "%p, %p, %d\n", physdev
->font
, indices
, count
);
3495 EnterCriticalSection( &font_cs
);
3496 for (i
= pos
= 0; i
< count
; i
++)
3498 get_glyph_outline( physdev
->font
, indices
[i
], GGO_METRICS
| GGO_GLYPH_INDEX
,
3499 NULL
, &abc
, 0, NULL
, NULL
);
3500 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3503 LeaveCriticalSection( &font_cs
);
3508 /*************************************************************
3511 static INT CDECL
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
3513 struct font_physdev
*physdev
= get_font_dev( dev
);
3518 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
3519 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
3521 len
= lstrlenW( get_gdi_font_name(physdev
->font
) ) + 1;
3524 lstrcpynW( str
, get_gdi_font_name(physdev
->font
), count
);
3525 len
= min( count
, len
);
3531 static void scale_font_metrics( struct gdi_font
*font
, TEXTMETRICW
*tm
)
3533 double scale_x
, scale_y
;
3535 /* Make sure that the font has sane width/height ratio */
3536 if (font
->aveWidth
&& (font
->aveWidth
+ tm
->tmHeight
- 1) / tm
->tmHeight
> 100)
3538 WARN( "Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
3544 scale_x
= (double)font
->aveWidth
;
3545 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
3548 scale_x
= font
->scale_y
;
3550 scale_x
*= fabs(font
->matrix
.eM11
);
3551 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
3553 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3554 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3556 SCALE_Y(tm
->tmHeight
);
3557 SCALE_Y(tm
->tmAscent
);
3558 SCALE_Y(tm
->tmDescent
);
3559 SCALE_Y(tm
->tmInternalLeading
);
3560 SCALE_Y(tm
->tmExternalLeading
);
3562 SCALE_X(tm
->tmOverhang
);
3563 if (font
->fake_bold
)
3565 if (!font
->scalable
) tm
->tmOverhang
++;
3566 tm
->tmAveCharWidth
++;
3567 tm
->tmMaxCharWidth
++;
3569 SCALE_X(tm
->tmAveCharWidth
);
3570 SCALE_X(tm
->tmMaxCharWidth
);
3576 /*************************************************************
3577 * font_GetTextMetrics
3579 static BOOL CDECL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
3581 struct font_physdev
*physdev
= get_font_dev( dev
);
3586 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
3587 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
3590 EnterCriticalSection( &font_cs
);
3591 if (font_funcs
->set_outline_text_metrics( physdev
->font
) ||
3592 font_funcs
->set_bitmap_text_metrics( physdev
->font
))
3594 *metrics
= physdev
->font
->otm
.otmTextMetrics
;
3595 scale_font_metrics( physdev
->font
, metrics
);
3598 LeaveCriticalSection( &font_cs
);
3603 static void get_nearest_charset( const WCHAR
*family_name
, struct gdi_font_face
*face
, CHARSETINFO
*csi
)
3605 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3606 a single face with the requested charset. The idea is to check if
3607 the selected font supports the current ANSI codepage, if it does
3608 return the corresponding charset, else return the first charset */
3612 if (TranslateCharsetInfo( (DWORD
*)(INT_PTR
)GetACP(), csi
, TCI_SRCCODEPAGE
))
3614 const struct gdi_font_link
*font_link
;
3616 if (csi
->fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) return;
3617 font_link
= find_gdi_font_link(family_name
);
3618 if (font_link
&& (csi
->fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])) return;
3620 for (i
= 0; i
< 32; i
++)
3622 DWORD fs0
= 1u << i
;
3623 if (face
->fs
.fsCsb
[0] & fs0
)
3625 if (TranslateCharsetInfo(&fs0
, csi
, TCI_SRCFONTSIG
)) return;
3626 FIXME("TCI failing on %x\n", fs0
);
3630 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3631 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
3632 csi
->ciACP
= GetACP();
3633 csi
->ciCharset
= DEFAULT_CHARSET
;
3636 static struct gdi_font
*select_font( LOGFONTW
*lf
, FMAT2 dcmat
, BOOL can_use_bitmap
)
3638 struct gdi_font
*font
;
3639 struct gdi_font_face
*face
;
3642 const WCHAR
*orig_name
= NULL
;
3644 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3645 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3646 original value lfCharSet. Note this is a special case for
3647 Symbol and doesn't happen at least for "Wingdings*" */
3648 if (!facename_compare( lf
->lfFaceName
, L
"Symbol", -1 )) lf
->lfCharSet
= SYMBOL_CHARSET
;
3650 /* check the cache first */
3651 if ((font
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
3653 TRACE( "returning cached gdiFont(%p)\n", font
);
3656 if (!(face
= find_matching_face( lf
, &csi
, can_use_bitmap
, &orig_name
)))
3658 FIXME( "can't find a single appropriate font - bailing\n" );
3661 height
= lf
->lfHeight
;
3663 font
= create_gdi_font( face
, orig_name
, lf
);
3664 font
->matrix
= dcmat
;
3665 font
->can_use_bitmap
= can_use_bitmap
;
3666 if (!csi
.fs
.fsCsb
[0]) get_nearest_charset( face
->family
->family_name
, face
, &csi
);
3667 font
->charset
= csi
.ciCharset
;
3668 font
->codepage
= csi
.ciACP
;
3670 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face
->full_name
), debugstr_w(face
->file
),
3671 face
->data_ptr
, face
->face_index
);
3673 font
->aveWidth
= height
? lf
->lfWidth
: 0;
3674 if (!face
->scalable
)
3676 /* Windows uses integer scaling factors for bitmap fonts */
3677 INT scale
, scaled_height
, diff
;
3678 struct gdi_font
*cachedfont
;
3681 diff
= height
- (signed int)face
->size
.height
;
3683 diff
= -height
- ((signed int)face
->size
.height
- face
->size
.internal_leading
);
3685 /* FIXME: rotation of bitmap fonts is ignored */
3686 height
= abs(GDI_ROUND( (double)height
* font
->matrix
.eM22
));
3688 font
->aveWidth
= (double)font
->aveWidth
* font
->matrix
.eM11
;
3689 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
3690 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3691 /* As we changed the matrix, we need to search the cache for the font again,
3692 * otherwise we might explode the cache. */
3693 if ((cachedfont
= find_cached_gdi_font( lf
, &dcmat
, can_use_bitmap
)))
3695 TRACE("Found cached font after non-scalable matrix rescale!\n");
3696 free_gdi_font( font
);
3700 if (height
!= 0) height
= diff
;
3701 height
+= face
->size
.height
;
3703 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3704 scaled_height
= scale
* face
->size
.height
;
3705 /* Only jump to the next height if the difference <= 25% original height */
3706 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3707 /* The jump between unscaled and doubled is delayed by 1 */
3708 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3709 font
->scale_y
= scale
;
3710 TRACE("font scale y: %d\n", font
->scale_y
);
3713 if (!font_funcs
->load_font( font
))
3715 free_gdi_font( font
);
3719 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
3720 font
->vert_feature
= get_GSUB_vert_feature( font
);
3722 create_child_font_list( font
);
3724 TRACE( "caching: gdiFont=%p\n", font
);
3725 cache_gdi_font( font
);
3729 /*************************************************************
3732 static HFONT CDECL
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
3734 struct font_physdev
*physdev
= get_font_dev( dev
);
3735 struct gdi_font
*font
= NULL
, *prev
= physdev
->font
;
3736 DC
*dc
= get_physdev_dc( dev
);
3742 BOOL can_use_bitmap
= !!(GetDeviceCaps( dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
);
3744 GetObjectW( hfont
, sizeof(lf
), &lf
);
3745 switch (lf
.lfQuality
)
3747 case NONANTIALIASED_QUALITY
:
3748 if (!*aa_flags
) *aa_flags
= GGO_BITMAP
;
3750 case ANTIALIASED_QUALITY
:
3751 if (!*aa_flags
) *aa_flags
= GGO_GRAY4_BITMAP
;
3755 lf
.lfWidth
= abs(lf
.lfWidth
);
3757 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3758 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3759 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3762 if (dc
->attr
->graphics_mode
== GM_ADVANCED
)
3764 memcpy( &dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
) );
3765 /* try to avoid not necessary glyph transformations */
3766 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3768 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3769 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3770 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
3775 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
3776 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3777 dcmat
.eM21
= dcmat
.eM12
= 0;
3778 lf
.lfOrientation
= lf
.lfEscapement
;
3779 if (dc
->vport2WorldValid
)
3781 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
3782 lf
.lfOrientation
= -lf
.lfOrientation
;
3783 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
3784 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
3787 TRACE( "DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
, dcmat
.eM21
, dcmat
.eM22
);
3789 EnterCriticalSection( &font_cs
);
3791 font
= select_font( &lf
, dcmat
, can_use_bitmap
);
3795 if (!*aa_flags
) *aa_flags
= font
->aa_flags
;
3798 if (lf
.lfQuality
== CLEARTYPE_QUALITY
|| lf
.lfQuality
== CLEARTYPE_NATURAL_QUALITY
)
3799 *aa_flags
= subpixel_orientation
;
3801 *aa_flags
= font_smoothing
;
3803 *aa_flags
= font_funcs
->get_aa_flags( font
, *aa_flags
, antialias_fakes
);
3805 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
3806 LeaveCriticalSection( &font_cs
);
3808 physdev
->font
= font
;
3809 if (prev
) release_gdi_font( prev
);
3810 return font
? hfont
: 0;
3814 const struct gdi_dc_funcs font_driver
=
3816 NULL
, /* pAbortDoc */
3817 NULL
, /* pAbortPath */
3818 NULL
, /* pAlphaBlend */
3819 NULL
, /* pAngleArc */
3822 NULL
, /* pBeginPath */
3823 NULL
, /* pBlendImage */
3825 NULL
, /* pCloseFigure */
3826 NULL
, /* pCreateCompatibleDC */
3827 font_CreateDC
, /* pCreateDC */
3828 font_DeleteDC
, /* pDeleteDC */
3829 NULL
, /* pDeleteObject */
3830 NULL
, /* pDeviceCapabilities */
3831 NULL
, /* pEllipse */
3833 NULL
, /* pEndPage */
3834 NULL
, /* pEndPath */
3835 font_EnumFonts
, /* pEnumFonts */
3836 NULL
, /* pEnumICMProfiles */
3837 NULL
, /* pExcludeClipRect */
3838 NULL
, /* pExtDeviceMode */
3839 NULL
, /* pExtEscape */
3840 NULL
, /* pExtFloodFill */
3841 NULL
, /* pExtSelectClipRgn */
3842 NULL
, /* pExtTextOut */
3843 NULL
, /* pFillPath */
3844 NULL
, /* pFillRgn */
3845 NULL
, /* pFlattenPath */
3846 font_FontIsLinked
, /* pFontIsLinked */
3847 NULL
, /* pFrameRgn */
3848 NULL
, /* pGdiComment */
3849 NULL
, /* pGetBoundsRect */
3850 font_GetCharABCWidths
, /* pGetCharABCWidths */
3851 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
3852 font_GetCharWidth
, /* pGetCharWidth */
3853 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
3854 NULL
, /* pGetDeviceCaps */
3855 NULL
, /* pGetDeviceGammaRamp */
3856 font_GetFontData
, /* pGetFontData */
3857 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
3858 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
3859 font_GetGlyphIndices
, /* pGetGlyphIndices */
3860 font_GetGlyphOutline
, /* pGetGlyphOutline */
3861 NULL
, /* pGetICMProfile */
3862 NULL
, /* pGetImage */
3863 font_GetKerningPairs
, /* pGetKerningPairs */
3864 NULL
, /* pGetNearestColor */
3865 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
3866 NULL
, /* pGetPixel */
3867 NULL
, /* pGetSystemPaletteEntries */
3868 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
3869 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
3870 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
3871 font_GetTextFace
, /* pGetTextFace */
3872 font_GetTextMetrics
, /* pGetTextMetrics */
3873 NULL
, /* pGradientFill */
3874 NULL
, /* pIntersectClipRect */
3875 NULL
, /* pInvertRgn */
3877 NULL
, /* pModifyWorldTransform */
3879 NULL
, /* pOffsetClipRgn */
3880 NULL
, /* pOffsetViewportOrg */
3881 NULL
, /* pOffsetWindowOrg */
3882 NULL
, /* pPaintRgn */
3885 NULL
, /* pPolyBezier */
3886 NULL
, /* pPolyBezierTo */
3887 NULL
, /* pPolyDraw */
3888 NULL
, /* pPolyPolygon */
3889 NULL
, /* pPolyPolyline */
3890 NULL
, /* pPolylineTo */
3891 NULL
, /* pPutImage */
3892 NULL
, /* pRealizeDefaultPalette */
3893 NULL
, /* pRealizePalette */
3894 NULL
, /* pRectangle */
3895 NULL
, /* pResetDC */
3896 NULL
, /* pRestoreDC */
3897 NULL
, /* pRoundRect */
3899 NULL
, /* pScaleViewportExt */
3900 NULL
, /* pScaleWindowExt */
3901 NULL
, /* pSelectBitmap */
3902 NULL
, /* pSelectBrush */
3903 NULL
, /* pSelectClipPath */
3904 font_SelectFont
, /* pSelectFont */
3905 NULL
, /* pSelectPalette */
3906 NULL
, /* pSelectPen */
3907 NULL
, /* pSetArcDirection */
3908 NULL
, /* pSetBkColor */
3909 NULL
, /* pSetBkMode */
3910 NULL
, /* pSetBoundsRect */
3911 NULL
, /* pSetDCBrushColor */
3912 NULL
, /* pSetDCPenColor */
3913 NULL
, /* pSetDIBitsToDevice */
3914 NULL
, /* pSetDeviceClipping */
3915 NULL
, /* pSetDeviceGammaRamp */
3916 NULL
, /* pSetLayout */
3917 NULL
, /* pSetMapMode */
3918 NULL
, /* pSetMapperFlags */
3919 NULL
, /* pSetPixel */
3920 NULL
, /* pSetPolyFillMode */
3921 NULL
, /* pSetROP2 */
3922 NULL
, /* pSetRelAbs */
3923 NULL
, /* pSetStretchBltMode */
3924 NULL
, /* pSetTextAlign */
3925 NULL
, /* pSetTextCharacterExtra */
3926 NULL
, /* pSetTextColor */
3927 NULL
, /* pSetTextJustification */
3928 NULL
, /* pSetViewportExt */
3929 NULL
, /* pSetViewportOrg */
3930 NULL
, /* pSetWindowExt */
3931 NULL
, /* pSetWindowOrg */
3932 NULL
, /* pSetWorldTransform */
3933 NULL
, /* pStartDoc */
3934 NULL
, /* pStartPage */
3935 NULL
, /* pStretchBlt */
3936 NULL
, /* pStretchDIBits */
3937 NULL
, /* pStrokeAndFillPath */
3938 NULL
, /* pStrokePath */
3939 NULL
, /* pUnrealizePalette */
3940 NULL
, /* pWidenPath */
3941 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
3942 NULL
, /* pD3DKMTSetVidPnSourceOwner */
3943 NULL
, /* wine_get_wgl_driver */
3944 NULL
, /* wine_get_vulkan_driver */
3945 GDI_PRIORITY_FONT_DRV
/* priority */
3948 static DWORD
get_key_value( HKEY key
, const WCHAR
*name
, DWORD
*value
)
3951 DWORD count
= sizeof(buf
), type
, err
;
3953 err
= RegQueryValueExW( key
, name
, NULL
, &type
, (BYTE
*)buf
, &count
);
3956 if (type
== REG_DWORD
) memcpy( value
, buf
, sizeof(*value
) );
3957 else *value
= wcstol( buf
, NULL
, 10 );
3962 static void init_font_options(void)
3965 DWORD i
, type
, size
, val
, gamma
= 1400;
3968 size
= sizeof(buffer
);
3969 if (!RegQueryValueExW( wine_fonts_key
, L
"AntialiasFakeBoldOrItalic", NULL
,
3970 &type
, (BYTE
*)buffer
, &size
) && type
== REG_SZ
&& size
>= 1)
3972 antialias_fakes
= (wcschr(L
"yYtT1", buffer
[0]) != NULL
);
3975 if (!RegOpenKeyW( HKEY_CURRENT_USER
, L
"Control Panel\\Desktop", &key
))
3977 /* FIXME: handle vertical orientations even though Windows doesn't */
3978 if (!get_key_value( key
, L
"FontSmoothingOrientation", &val
))
3982 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
3983 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
3985 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
3986 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
3990 if (!get_key_value( key
, L
"FontSmoothing", &val
) && val
/* enabled */)
3992 if (!get_key_value( key
, L
"FontSmoothingType", &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
3993 font_smoothing
= subpixel_orientation
;
3995 font_smoothing
= GGO_GRAY4_BITMAP
;
3997 if (!get_key_value( key
, L
"FontSmoothingGamma", &val
) && val
)
3999 gamma
= min( max( val
, 1000 ), 2200 );
4004 /* Calibrating the difference between the registry value and the Wine gamma value.
4005 This looks roughly similar to Windows Native with the same registry value.
4006 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4007 gamma
= 1000 * gamma
/ 1400;
4010 for (i
= 0; i
< 256; i
++)
4012 font_gamma_ramp
.encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
4013 font_gamma_ramp
.decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
4016 font_gamma_ramp
.gamma
= gamma
;
4017 TRACE("gamma %d\n", font_gamma_ramp
.gamma
);
4021 static void FONT_LogFontAToW( const LOGFONTA
*fontA
, LPLOGFONTW fontW
)
4023 memcpy(fontW
, fontA
, sizeof(LOGFONTA
) - LF_FACESIZE
);
4024 MultiByteToWideChar(CP_ACP
, 0, fontA
->lfFaceName
, -1, fontW
->lfFaceName
,
4026 fontW
->lfFaceName
[LF_FACESIZE
-1] = 0;
4029 static void FONT_LogFontWToA( const LOGFONTW
*fontW
, LPLOGFONTA fontA
)
4031 memcpy(fontA
, fontW
, sizeof(LOGFONTA
) - LF_FACESIZE
);
4032 WideCharToMultiByte(CP_ACP
, 0, fontW
->lfFaceName
, -1, fontA
->lfFaceName
,
4033 LF_FACESIZE
, NULL
, NULL
);
4034 fontA
->lfFaceName
[LF_FACESIZE
-1] = 0;
4037 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW
*fontW
, LPENUMLOGFONTEXA fontA
)
4039 FONT_LogFontWToA( &fontW
->elfLogFont
, &fontA
->elfLogFont
);
4041 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfFullName
, -1,
4042 (LPSTR
) fontA
->elfFullName
, LF_FULLFACESIZE
, NULL
, NULL
);
4043 fontA
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
4044 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfStyle
, -1,
4045 (LPSTR
) fontA
->elfStyle
, LF_FACESIZE
, NULL
, NULL
);
4046 fontA
->elfStyle
[LF_FACESIZE
-1] = '\0';
4047 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfScript
, -1,
4048 (LPSTR
) fontA
->elfScript
, LF_FACESIZE
, NULL
, NULL
);
4049 fontA
->elfScript
[LF_FACESIZE
-1] = '\0';
4052 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA
*fontA
, LPENUMLOGFONTEXW fontW
)
4054 FONT_LogFontAToW( &fontA
->elfLogFont
, &fontW
->elfLogFont
);
4056 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfFullName
, -1,
4057 fontW
->elfFullName
, LF_FULLFACESIZE
);
4058 fontW
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
4059 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfStyle
, -1,
4060 fontW
->elfStyle
, LF_FACESIZE
);
4061 fontW
->elfStyle
[LF_FACESIZE
-1] = '\0';
4062 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfScript
, -1,
4063 fontW
->elfScript
, LF_FACESIZE
);
4064 fontW
->elfScript
[LF_FACESIZE
-1] = '\0';
4067 /***********************************************************************
4068 * TEXTMETRIC conversion functions.
4070 static void FONT_TextMetricWToA(const TEXTMETRICW
*ptmW
, LPTEXTMETRICA ptmA
)
4072 ptmA
->tmHeight
= ptmW
->tmHeight
;
4073 ptmA
->tmAscent
= ptmW
->tmAscent
;
4074 ptmA
->tmDescent
= ptmW
->tmDescent
;
4075 ptmA
->tmInternalLeading
= ptmW
->tmInternalLeading
;
4076 ptmA
->tmExternalLeading
= ptmW
->tmExternalLeading
;
4077 ptmA
->tmAveCharWidth
= ptmW
->tmAveCharWidth
;
4078 ptmA
->tmMaxCharWidth
= ptmW
->tmMaxCharWidth
;
4079 ptmA
->tmWeight
= ptmW
->tmWeight
;
4080 ptmA
->tmOverhang
= ptmW
->tmOverhang
;
4081 ptmA
->tmDigitizedAspectX
= ptmW
->tmDigitizedAspectX
;
4082 ptmA
->tmDigitizedAspectY
= ptmW
->tmDigitizedAspectY
;
4083 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 255);
4084 if (ptmW
->tmCharSet
== SYMBOL_CHARSET
)
4086 ptmA
->tmFirstChar
= 0x1e;
4087 ptmA
->tmLastChar
= 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
4089 else if (ptmW
->tmPitchAndFamily
& TMPF_TRUETYPE
)
4091 ptmA
->tmFirstChar
= ptmW
->tmDefaultChar
- 1;
4092 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
4096 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 0xff);
4097 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
4099 ptmA
->tmDefaultChar
= ptmW
->tmDefaultChar
;
4100 ptmA
->tmBreakChar
= ptmW
->tmBreakChar
;
4101 ptmA
->tmItalic
= ptmW
->tmItalic
;
4102 ptmA
->tmUnderlined
= ptmW
->tmUnderlined
;
4103 ptmA
->tmStruckOut
= ptmW
->tmStruckOut
;
4104 ptmA
->tmPitchAndFamily
= ptmW
->tmPitchAndFamily
;
4105 ptmA
->tmCharSet
= ptmW
->tmCharSet
;
4109 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW
*ptmW
, NEWTEXTMETRICEXA
*ptmA
)
4111 FONT_TextMetricWToA((const TEXTMETRICW
*)ptmW
, (LPTEXTMETRICA
)ptmA
);
4112 ptmA
->ntmTm
.ntmFlags
= ptmW
->ntmTm
.ntmFlags
;
4113 ptmA
->ntmTm
.ntmSizeEM
= ptmW
->ntmTm
.ntmSizeEM
;
4114 ptmA
->ntmTm
.ntmCellHeight
= ptmW
->ntmTm
.ntmCellHeight
;
4115 ptmA
->ntmTm
.ntmAvgWidth
= ptmW
->ntmTm
.ntmAvgWidth
;
4116 memcpy(&ptmA
->ntmFontSig
, &ptmW
->ntmFontSig
, sizeof(FONTSIGNATURE
));
4119 /* compute positions for text rendering, in device coords */
4120 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
4125 size
->cx
= size
->cy
= 0;
4126 if (!count
) return TRUE
;
4128 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4129 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4131 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
4132 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
4134 if (dc
->breakExtra
|| dc
->breakRem
)
4136 int i
, space
= 0, rem
= dc
->breakRem
;
4138 for (i
= 0; i
< count
; i
++)
4140 if (str
[i
] == tm
.tmBreakChar
)
4142 space
+= dc
->breakExtra
;
4152 size
->cx
= dx
[count
- 1];
4153 size
->cy
= tm
.tmHeight
;
4157 /* compute positions for text rendering, in device coords */
4158 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
4163 size
->cx
= size
->cy
= 0;
4164 if (!count
) return TRUE
;
4166 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4167 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
4169 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
4170 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
4172 if (dc
->breakExtra
|| dc
->breakRem
)
4175 int i
, space
= 0, rem
= dc
->breakRem
;
4177 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4178 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
4180 for (i
= 0; i
< count
; i
++)
4182 if (indices
[i
] == space_index
)
4184 space
+= dc
->breakExtra
;
4194 size
->cx
= dx
[count
- 1];
4195 size
->cy
= tm
.tmHeight
;
4199 /***********************************************************************
4200 * GdiGetCodePage (GDI32.@)
4202 DWORD WINAPI
GdiGetCodePage( HDC hdc
)
4205 DC
*dc
= get_dc_ptr( hdc
);
4209 cp
= dc
->font_code_page
;
4210 release_dc_ptr( dc
);
4215 /***********************************************************************
4216 * get_text_charset_info
4218 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4220 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
4222 UINT ret
= DEFAULT_CHARSET
;
4225 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
4226 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
4228 if (ret
== DEFAULT_CHARSET
&& fs
)
4229 memset(fs
, 0, sizeof(FONTSIGNATURE
));
4233 /***********************************************************************
4234 * GetTextCharsetInfo (GDI32.@)
4236 UINT WINAPI
GetTextCharsetInfo(HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
4238 UINT ret
= DEFAULT_CHARSET
;
4239 DC
*dc
= get_dc_ptr(hdc
);
4243 ret
= get_text_charset_info( dc
, fs
, flags
);
4244 release_dc_ptr( dc
);
4249 /***********************************************************************
4252 * Returns a Unicode translation of str using the charset of the
4253 * currently selected font in hdc. If count is -1 then str is assumed
4254 * to be '\0' terminated, otherwise it contains the number of bytes to
4255 * convert. If plenW is non-NULL, on return it will point to the
4256 * number of WCHARs that have been written. If pCP is non-NULL, on
4257 * return it will point to the codepage used in the conversion. The
4258 * caller should free the returned LPWSTR from the process heap
4261 static LPWSTR
FONT_mbtowc(HDC hdc
, LPCSTR str
, INT count
, INT
*plenW
, UINT
*pCP
)
4267 cp
= GdiGetCodePage( hdc
);
4269 if(count
== -1) count
= strlen(str
);
4270 lenW
= MultiByteToWideChar(cp
, 0, str
, count
, NULL
, 0);
4271 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
*sizeof(WCHAR
));
4272 MultiByteToWideChar(cp
, 0, str
, count
, strW
, lenW
);
4273 TRACE("mapped %s -> %s\n", debugstr_an(str
, count
), debugstr_wn(strW
, lenW
));
4274 if(plenW
) *plenW
= lenW
;
4279 /***********************************************************************
4280 * CreateFontIndirectExA (GDI32.@)
4282 HFONT WINAPI
CreateFontIndirectExA( const ENUMLOGFONTEXDVA
*penumexA
)
4284 ENUMLOGFONTEXDVW enumexW
;
4286 if (!penumexA
) return 0;
4288 FONT_EnumLogFontExAToW( &penumexA
->elfEnumLogfontEx
, &enumexW
.elfEnumLogfontEx
);
4289 enumexW
.elfDesignVector
= penumexA
->elfDesignVector
;
4290 return CreateFontIndirectExW( &enumexW
);
4293 /***********************************************************************
4294 * CreateFontIndirectExW (GDI32.@)
4296 HFONT WINAPI
CreateFontIndirectExW( const ENUMLOGFONTEXDVW
*penumex
)
4300 const LOGFONTW
*plf
;
4302 if (!penumex
) return 0;
4304 if (penumex
->elfEnumLogfontEx
.elfFullName
[0] ||
4305 penumex
->elfEnumLogfontEx
.elfStyle
[0] ||
4306 penumex
->elfEnumLogfontEx
.elfScript
[0])
4308 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4309 debugstr_w(penumex
->elfEnumLogfontEx
.elfFullName
),
4310 debugstr_w(penumex
->elfEnumLogfontEx
.elfStyle
),
4311 debugstr_w(penumex
->elfEnumLogfontEx
.elfScript
));
4314 plf
= &penumex
->elfEnumLogfontEx
.elfLogFont
;
4315 if (!(fontPtr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr
) ))) return 0;
4317 fontPtr
->logfont
= *plf
;
4319 if (!(hFont
= alloc_gdi_handle( &fontPtr
->obj
, NTGDI_OBJ_FONT
, &fontobj_funcs
)))
4321 HeapFree( GetProcessHeap(), 0, fontPtr
);
4325 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4326 plf
->lfHeight
, plf
->lfWidth
,
4327 plf
->lfEscapement
, plf
->lfOrientation
,
4328 plf
->lfPitchAndFamily
,
4329 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
4330 plf
->lfQuality
, plf
->lfCharSet
,
4331 debugstr_w(plf
->lfFaceName
),
4332 plf
->lfWeight
> 400 ? "Bold" : "",
4333 plf
->lfItalic
? "Italic" : "",
4334 plf
->lfUnderline
? "Underline" : "", hFont
);
4339 /***********************************************************************
4340 * CreateFontIndirectA (GDI32.@)
4342 HFONT WINAPI
CreateFontIndirectA( const LOGFONTA
*plfA
)
4346 if (!plfA
) return 0;
4348 FONT_LogFontAToW( plfA
, &lfW
);
4349 return CreateFontIndirectW( &lfW
);
4352 /***********************************************************************
4353 * CreateFontIndirectW (GDI32.@)
4355 HFONT WINAPI
CreateFontIndirectW( const LOGFONTW
*plf
)
4357 ENUMLOGFONTEXDVW exdv
;
4361 exdv
.elfEnumLogfontEx
.elfLogFont
= *plf
;
4362 exdv
.elfEnumLogfontEx
.elfFullName
[0] = 0;
4363 exdv
.elfEnumLogfontEx
.elfStyle
[0] = 0;
4364 exdv
.elfEnumLogfontEx
.elfScript
[0] = 0;
4365 return CreateFontIndirectExW( &exdv
);
4368 /*************************************************************************
4369 * CreateFontA (GDI32.@)
4371 HFONT WINAPI
CreateFontA( INT height
, INT width
, INT esc
,
4372 INT orient
, INT weight
, DWORD italic
,
4373 DWORD underline
, DWORD strikeout
, DWORD charset
,
4374 DWORD outpres
, DWORD clippres
, DWORD quality
,
4375 DWORD pitch
, LPCSTR name
)
4379 logfont
.lfHeight
= height
;
4380 logfont
.lfWidth
= width
;
4381 logfont
.lfEscapement
= esc
;
4382 logfont
.lfOrientation
= orient
;
4383 logfont
.lfWeight
= weight
;
4384 logfont
.lfItalic
= italic
;
4385 logfont
.lfUnderline
= underline
;
4386 logfont
.lfStrikeOut
= strikeout
;
4387 logfont
.lfCharSet
= charset
;
4388 logfont
.lfOutPrecision
= outpres
;
4389 logfont
.lfClipPrecision
= clippres
;
4390 logfont
.lfQuality
= quality
;
4391 logfont
.lfPitchAndFamily
= pitch
;
4394 lstrcpynA(logfont
.lfFaceName
,name
,sizeof(logfont
.lfFaceName
));
4396 logfont
.lfFaceName
[0] = '\0';
4398 return CreateFontIndirectA( &logfont
);
4401 /*************************************************************************
4402 * CreateFontW (GDI32.@)
4404 HFONT WINAPI
CreateFontW( INT height
, INT width
, INT esc
,
4405 INT orient
, INT weight
, DWORD italic
,
4406 DWORD underline
, DWORD strikeout
, DWORD charset
,
4407 DWORD outpres
, DWORD clippres
, DWORD quality
,
4408 DWORD pitch
, LPCWSTR name
)
4412 logfont
.lfHeight
= height
;
4413 logfont
.lfWidth
= width
;
4414 logfont
.lfEscapement
= esc
;
4415 logfont
.lfOrientation
= orient
;
4416 logfont
.lfWeight
= weight
;
4417 logfont
.lfItalic
= italic
;
4418 logfont
.lfUnderline
= underline
;
4419 logfont
.lfStrikeOut
= strikeout
;
4420 logfont
.lfCharSet
= charset
;
4421 logfont
.lfOutPrecision
= outpres
;
4422 logfont
.lfClipPrecision
= clippres
;
4423 logfont
.lfQuality
= quality
;
4424 logfont
.lfPitchAndFamily
= pitch
;
4427 lstrcpynW(logfont
.lfFaceName
, name
, ARRAY_SIZE(logfont
.lfFaceName
));
4429 logfont
.lfFaceName
[0] = '\0';
4431 return CreateFontIndirectW( &logfont
);
4434 #define ASSOC_CHARSET_OEM 1
4435 #define ASSOC_CHARSET_ANSI 2
4436 #define ASSOC_CHARSET_SYMBOL 4
4438 static DWORD
get_associated_charset_info(void)
4440 static DWORD associated_charset
= -1;
4442 if (associated_charset
== -1)
4446 DWORD type
, data_len
;
4448 associated_charset
= 0;
4450 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
,
4451 L
"System\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset", &hkey
))
4454 data_len
= sizeof(dataW
);
4455 if (!RegQueryValueExW(hkey
, L
"ANSI(00)", NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
4456 type
== REG_SZ
&& !wcsicmp(dataW
, L
"yes"))
4457 associated_charset
|= ASSOC_CHARSET_ANSI
;
4459 data_len
= sizeof(dataW
);
4460 if (!RegQueryValueExW(hkey
, L
"OEM(FF)", NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
4461 type
== REG_SZ
&& !wcsicmp(dataW
, L
"yes"))
4462 associated_charset
|= ASSOC_CHARSET_OEM
;
4464 data_len
= sizeof(dataW
);
4465 if (!RegQueryValueExW(hkey
, L
"SYMBOL(02)", NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
4466 type
== REG_SZ
&& !wcsicmp(dataW
, L
"yes"))
4467 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
4471 TRACE("associated_charset = %d\n", associated_charset
);
4474 return associated_charset
;
4477 static void update_font_code_page( DC
*dc
, HANDLE font
)
4480 int charset
= get_text_charset_info( dc
, NULL
, 0 );
4482 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
4486 GetObjectW( font
, sizeof(lf
), &lf
);
4487 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
4488 charset
= DEFAULT_CHARSET
;
4491 /* Hmm, nicely designed api this one! */
4492 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
4493 dc
->font_code_page
= csi
.ciACP
;
4497 dc
->font_code_page
= GetOEMCP();
4499 case DEFAULT_CHARSET
:
4500 dc
->font_code_page
= GetACP();
4503 case VISCII_CHARSET
:
4509 case CELTIC_CHARSET
:
4510 /* FIXME: These have no place here, but because x11drv
4511 enumerates fonts with these (made up) charsets some apps
4512 might use them and then the FIXME below would become
4513 annoying. Now we could pick the intended codepage for
4514 each of these, but since it's broken anyway we'll just
4515 use CP_ACP and hope it'll go away...
4517 dc
->font_code_page
= CP_ACP
;
4521 FIXME("Can't find codepage for charset %d\n", charset
);
4522 dc
->font_code_page
= CP_ACP
;
4527 TRACE("charset %d => cp %d\n", charset
, dc
->font_code_page
);
4530 /***********************************************************************
4531 * NtGdiSelectFont (win32u.@)
4533 HGDIOBJ WINAPI
NtGdiSelectFont( HDC hdc
, HGDIOBJ handle
)
4536 DC
*dc
= get_dc_ptr( hdc
);
4542 if (!GDI_inc_ref_count( handle
))
4544 release_dc_ptr( dc
);
4548 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
4549 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
4553 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
4554 update_font_code_page( dc
, handle
);
4555 if (dc
->font_gamma_ramp
== NULL
)
4556 dc
->font_gamma_ramp
= &font_gamma_ramp
;
4557 GDI_dec_ref_count( ret
);
4559 else GDI_dec_ref_count( handle
);
4561 release_dc_ptr( dc
);
4566 /***********************************************************************
4569 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
4571 FONTOBJ
*font
= GDI_GetObjPtr( handle
, NTGDI_OBJ_FONT
);
4573 if (!font
) return 0;
4576 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
4577 memcpy( buffer
, &font
->logfont
, count
);
4579 else count
= sizeof(LOGFONTW
);
4580 GDI_ReleaseObj( handle
);
4585 /***********************************************************************
4588 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
4592 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
4593 HeapFree( GetProcessHeap(), 0, obj
);
4598 /***********************************************************************
4601 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
4602 * We have to use other types because of the FONTENUMPROCW definition.
4604 static INT CALLBACK
FONT_EnumInstance( const LOGFONTW
*plf
, const TEXTMETRICW
*ptm
,
4605 DWORD fType
, LPARAM lp
)
4607 struct font_enum
*pfe
= (struct font_enum
*)lp
;
4610 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
4611 if ((!pfe
->lpLogFontParam
||
4612 pfe
->lpLogFontParam
->lfCharSet
== DEFAULT_CHARSET
||
4613 pfe
->lpLogFontParam
->lfCharSet
== plf
->lfCharSet
) &&
4614 (!(fType
& RASTER_FONTTYPE
) || GetDeviceCaps(pfe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
) )
4616 /* convert font metrics */
4617 ENUMLOGFONTEXA logfont
;
4618 NEWTEXTMETRICEXA tmA
;
4622 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW
*)plf
, &logfont
);
4623 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW
*)ptm
, &tmA
);
4624 plf
= (LOGFONTW
*)&logfont
.elfLogFont
;
4625 ptm
= (TEXTMETRICW
*)&tmA
;
4627 ret
= pfe
->lpEnumFunc( plf
, ptm
, fType
, pfe
->lpData
);
4633 /***********************************************************************
4634 * FONT_EnumFontFamiliesEx
4636 static INT
FONT_EnumFontFamiliesEx( HDC hDC
, LPLOGFONTW plf
, FONTENUMPROCW efproc
,
4637 LPARAM lParam
, BOOL unicode
)
4640 DC
*dc
= get_dc_ptr( hDC
);
4641 struct font_enum fe
;
4645 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
4647 if (plf
) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4648 fe
.lpLogFontParam
= plf
;
4649 fe
.lpEnumFunc
= efproc
;
4651 fe
.unicode
= unicode
;
4654 ret
= physdev
->funcs
->pEnumFonts( physdev
, plf
, FONT_EnumInstance
, (LPARAM
)&fe
);
4655 release_dc_ptr( dc
);
4657 return ret
? fe
.retval
: 0;
4660 /***********************************************************************
4661 * EnumFontFamiliesExW (GDI32.@)
4663 INT WINAPI
EnumFontFamiliesExW( HDC hDC
, LPLOGFONTW plf
,
4664 FONTENUMPROCW efproc
,
4665 LPARAM lParam
, DWORD dwFlags
)
4667 return FONT_EnumFontFamiliesEx( hDC
, plf
, efproc
, lParam
, TRUE
);
4670 /***********************************************************************
4671 * EnumFontFamiliesExA (GDI32.@)
4673 INT WINAPI
EnumFontFamiliesExA( HDC hDC
, LPLOGFONTA plf
,
4674 FONTENUMPROCA efproc
,
4675 LPARAM lParam
, DWORD dwFlags
)
4677 LOGFONTW lfW
, *plfW
;
4681 FONT_LogFontAToW( plf
, &lfW
);
4686 return FONT_EnumFontFamiliesEx( hDC
, plfW
, (FONTENUMPROCW
)efproc
, lParam
, FALSE
);
4689 /***********************************************************************
4690 * EnumFontFamiliesA (GDI32.@)
4692 INT WINAPI
EnumFontFamiliesA( HDC hDC
, LPCSTR lpFamily
,
4693 FONTENUMPROCA efproc
, LPARAM lpData
)
4699 if (!*lpFamily
) return 1;
4700 lstrcpynA( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
4701 lf
.lfCharSet
= DEFAULT_CHARSET
;
4702 lf
.lfPitchAndFamily
= 0;
4707 return EnumFontFamiliesExA( hDC
, plf
, efproc
, lpData
, 0 );
4710 /***********************************************************************
4711 * EnumFontFamiliesW (GDI32.@)
4713 INT WINAPI
EnumFontFamiliesW( HDC hDC
, LPCWSTR lpFamily
,
4714 FONTENUMPROCW efproc
, LPARAM lpData
)
4720 if (!*lpFamily
) return 1;
4721 lstrcpynW( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
4722 lf
.lfCharSet
= DEFAULT_CHARSET
;
4723 lf
.lfPitchAndFamily
= 0;
4728 return EnumFontFamiliesExW( hDC
, plf
, efproc
, lpData
, 0 );
4731 /***********************************************************************
4732 * EnumFontsA (GDI32.@)
4734 INT WINAPI
EnumFontsA( HDC hDC
, LPCSTR lpName
, FONTENUMPROCA efproc
,
4737 return EnumFontFamiliesA( hDC
, lpName
, efproc
, lpData
);
4740 /***********************************************************************
4741 * EnumFontsW (GDI32.@)
4743 INT WINAPI
EnumFontsW( HDC hDC
, LPCWSTR lpName
, FONTENUMPROCW efproc
,
4746 return EnumFontFamiliesW( hDC
, lpName
, efproc
, lpData
);
4750 /***********************************************************************
4751 * GetTextCharacterExtra (GDI32.@)
4753 INT WINAPI
GetTextCharacterExtra( HDC hdc
)
4756 DC
*dc
= get_dc_ptr( hdc
);
4757 if (!dc
) return 0x80000000;
4758 ret
= dc
->charExtra
;
4759 release_dc_ptr( dc
);
4764 /***********************************************************************
4765 * SetTextCharacterExtra (GDI32.@)
4767 INT WINAPI
SetTextCharacterExtra( HDC hdc
, INT extra
)
4769 INT ret
= 0x80000000;
4770 DC
* dc
= get_dc_ptr( hdc
);
4774 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetTextCharacterExtra
);
4775 extra
= physdev
->funcs
->pSetTextCharacterExtra( physdev
, extra
);
4776 if (extra
!= 0x80000000)
4778 ret
= dc
->charExtra
;
4779 dc
->charExtra
= extra
;
4781 release_dc_ptr( dc
);
4787 /***********************************************************************
4788 * SetTextJustification (GDI32.@)
4790 BOOL WINAPI
SetTextJustification( HDC hdc
, INT extra
, INT breaks
)
4794 DC
* dc
= get_dc_ptr( hdc
);
4796 if (!dc
) return FALSE
;
4798 physdev
= GET_DC_PHYSDEV( dc
, pSetTextJustification
);
4799 ret
= physdev
->funcs
->pSetTextJustification( physdev
, extra
, breaks
);
4802 extra
= abs((extra
* dc
->vport_ext
.cx
+ dc
->wnd_ext
.cx
/ 2) / dc
->wnd_ext
.cx
);
4803 if (!extra
) breaks
= 0;
4806 dc
->breakExtra
= extra
/ breaks
;
4807 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
4815 release_dc_ptr( dc
);
4820 /***********************************************************************
4821 * GetTextFaceA (GDI32.@)
4823 INT WINAPI
GetTextFaceA( HDC hdc
, INT count
, LPSTR name
)
4825 INT res
= GetTextFaceW(hdc
, 0, NULL
);
4826 LPWSTR nameW
= HeapAlloc( GetProcessHeap(), 0, res
* 2 );
4827 GetTextFaceW( hdc
, res
, nameW
);
4833 res
= WideCharToMultiByte(CP_ACP
, 0, nameW
, -1, name
, count
, NULL
, NULL
);
4837 /* GetTextFaceA does NOT include the nul byte in the return count. */
4844 res
= WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, NULL
, 0, NULL
, NULL
);
4845 HeapFree( GetProcessHeap(), 0, nameW
);
4849 /***********************************************************************
4850 * GetTextFaceW (GDI32.@)
4852 INT WINAPI
GetTextFaceW( HDC hdc
, INT count
, LPWSTR name
)
4857 DC
* dc
= get_dc_ptr( hdc
);
4860 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
4861 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
4862 release_dc_ptr( dc
);
4867 /***********************************************************************
4868 * GetTextExtentPoint32A (GDI32.@)
4870 * See GetTextExtentPoint32W.
4872 BOOL WINAPI
GetTextExtentPoint32A( HDC hdc
, LPCSTR str
, INT count
,
4879 if (count
< 0) return FALSE
;
4881 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
4885 ret
= GetTextExtentPoint32W( hdc
, p
, wlen
, size
);
4886 HeapFree( GetProcessHeap(), 0, p
);
4889 TRACE("(%p %s %d %p): returning %d x %d\n",
4890 hdc
, debugstr_an (str
, count
), count
, size
, size
->cx
, size
->cy
);
4895 /***********************************************************************
4896 * GetTextExtentPoint32W [GDI32.@]
4898 * Computes width/height for a string.
4900 * Computes width and height of the specified string.
4906 BOOL WINAPI
GetTextExtentPoint32W(
4907 HDC hdc
, /* [in] Handle of device context */
4908 LPCWSTR str
, /* [in] Address of text string */
4909 INT count
, /* [in] Number of characters in string */
4910 LPSIZE size
) /* [out] Address of structure for string size */
4912 return GetTextExtentExPointW(hdc
, str
, count
, 0, NULL
, NULL
, size
);
4915 /***********************************************************************
4916 * GetTextExtentExPointI [GDI32.@]
4918 * Computes width and height of the array of glyph indices.
4921 * hdc [I] Handle of device context.
4922 * indices [I] Glyph index array.
4923 * count [I] Number of glyphs in array.
4924 * max_ext [I] Maximum width in glyphs.
4925 * nfit [O] Maximum number of characters.
4926 * dxs [O] Partial string widths.
4927 * size [O] Returned string size.
4933 BOOL WINAPI
GetTextExtentExPointI( HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
4934 LPINT nfit
, LPINT dxs
, LPSIZE size
)
4939 INT buffer
[256], *pos
= dxs
;
4941 if (count
< 0) return FALSE
;
4943 dc
= get_dc_ptr( hdc
);
4944 if (!dc
) return FALSE
;
4949 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
4951 release_dc_ptr( dc
);
4956 ret
= get_char_positions_indices( dc
, indices
, count
, pos
, size
);
4961 for (i
= 0; i
< count
; i
++)
4963 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
4964 if (nfit
&& dx
> (unsigned int)max_ext
) break;
4965 if (dxs
) dxs
[i
] = dx
;
4967 if (nfit
) *nfit
= i
;
4970 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
4971 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
4974 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
4975 release_dc_ptr( dc
);
4977 TRACE("(%p %p %d %p): returning %d x %d\n",
4978 hdc
, indices
, count
, size
, size
->cx
, size
->cy
);
4982 /***********************************************************************
4983 * GetTextExtentPointI [GDI32.@]
4985 * Computes width and height of the array of glyph indices.
4988 * hdc [I] Handle of device context.
4989 * indices [I] Glyph index array.
4990 * count [I] Number of glyphs in array.
4991 * size [O] Returned string size.
4997 BOOL WINAPI
GetTextExtentPointI( HDC hdc
, const WORD
*indices
, INT count
, LPSIZE size
)
4999 return GetTextExtentExPointI( hdc
, indices
, count
, 0, NULL
, NULL
, size
);
5003 /***********************************************************************
5004 * GetTextExtentPointA (GDI32.@)
5006 BOOL WINAPI
GetTextExtentPointA( HDC hdc
, LPCSTR str
, INT count
,
5009 TRACE("not bug compatible.\n");
5010 return GetTextExtentPoint32A( hdc
, str
, count
, size
);
5013 /***********************************************************************
5014 * GetTextExtentPointW (GDI32.@)
5016 BOOL WINAPI
GetTextExtentPointW( HDC hdc
, LPCWSTR str
, INT count
,
5019 TRACE("not bug compatible.\n");
5020 return GetTextExtentPoint32W( hdc
, str
, count
, size
);
5024 /***********************************************************************
5025 * GetTextExtentExPointA (GDI32.@)
5027 BOOL WINAPI
GetTextExtentExPointA( HDC hdc
, LPCSTR str
, INT count
,
5028 INT maxExt
, LPINT lpnFit
,
5029 LPINT alpDx
, LPSIZE size
)
5036 if (count
< 0) return FALSE
;
5037 if (maxExt
< -1) return FALSE
;
5041 walpDx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(INT
) );
5042 if (!walpDx
) return FALSE
;
5045 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
5046 ret
= GetTextExtentExPointW( hdc
, p
, wlen
, maxExt
, lpnFit
, walpDx
, size
);
5049 INT n
= lpnFit
? *lpnFit
: wlen
;
5051 for(i
= 0, j
= 0; i
< n
; i
++, j
++)
5053 alpDx
[j
] = walpDx
[i
];
5054 if (IsDBCSLeadByte(str
[j
])) alpDx
[++j
] = walpDx
[i
];
5057 if (lpnFit
) *lpnFit
= WideCharToMultiByte(CP_ACP
,0,p
,*lpnFit
,NULL
,0,NULL
,NULL
);
5058 HeapFree( GetProcessHeap(), 0, p
);
5059 HeapFree( GetProcessHeap(), 0, walpDx
);
5064 /***********************************************************************
5065 * GetTextExtentExPointW (GDI32.@)
5067 * Return the size of the string as it would be if it was output properly by
5070 BOOL WINAPI
GetTextExtentExPointW( HDC hdc
, LPCWSTR str
, INT count
, INT max_ext
,
5071 LPINT nfit
, LPINT dxs
, LPSIZE size
)
5076 INT buffer
[256], *pos
= dxs
;
5078 if (count
< 0) return FALSE
;
5080 dc
= get_dc_ptr(hdc
);
5081 if (!dc
) return FALSE
;
5086 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
5088 release_dc_ptr( dc
);
5093 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
5098 for (i
= 0; i
< count
; i
++)
5100 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
5101 if (nfit
&& dx
> (unsigned int)max_ext
) break;
5102 if (dxs
) dxs
[i
] = dx
;
5104 if (nfit
) *nfit
= i
;
5107 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
5108 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
5111 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
5112 release_dc_ptr( dc
);
5114 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
5118 /***********************************************************************
5119 * GetTextMetricsA (GDI32.@)
5121 BOOL WINAPI
GetTextMetricsA( HDC hdc
, TEXTMETRICA
*metrics
)
5125 if (!GetTextMetricsW( hdc
, &tm32
)) return FALSE
;
5126 FONT_TextMetricWToA( &tm32
, metrics
);
5130 /***********************************************************************
5131 * GetTextMetricsW (GDI32.@)
5133 BOOL WINAPI
GetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
)
5137 DC
* dc
= get_dc_ptr( hdc
);
5138 if (!dc
) return FALSE
;
5140 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5141 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
5145 /* device layer returns values in device units
5146 * therefore we have to convert them to logical */
5148 metrics
->tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
5149 metrics
->tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
5150 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
5151 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
5152 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
5153 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
5154 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
5155 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
5156 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
5157 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
5160 TRACE("text metrics:\n"
5161 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5162 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5163 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5164 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5165 " PitchAndFamily = %02x\n"
5166 " --------------------\n"
5167 " InternalLeading = %i\n"
5171 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
5172 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
5173 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
5174 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
5175 metrics
->tmPitchAndFamily
,
5176 metrics
->tmInternalLeading
,
5179 metrics
->tmHeight
);
5181 release_dc_ptr( dc
);
5186 /***********************************************************************
5187 * GetOutlineTextMetricsA (GDI32.@)
5188 * Gets metrics for TrueType fonts.
5191 * If the supplied buffer isn't big enough Windows partially fills it up to
5192 * its given length and returns that length.
5195 * Success: Non-zero or size of required buffer
5198 UINT WINAPI
GetOutlineTextMetricsA(
5199 HDC hdc
, /* [in] Handle of device context */
5200 UINT cbData
, /* [in] Size of metric data array */
5201 LPOUTLINETEXTMETRICA lpOTM
) /* [out] Address of metric data array */
5203 char buf
[512], *ptr
;
5205 OUTLINETEXTMETRICW
*lpOTMW
= (OUTLINETEXTMETRICW
*)buf
;
5206 OUTLINETEXTMETRICA
*output
= lpOTM
;
5209 if((ret
= GetOutlineTextMetricsW(hdc
, 0, NULL
)) == 0)
5211 if(ret
> sizeof(buf
))
5212 lpOTMW
= HeapAlloc(GetProcessHeap(), 0, ret
);
5213 GetOutlineTextMetricsW(hdc
, ret
, lpOTMW
);
5215 needed
= sizeof(OUTLINETEXTMETRICA
);
5216 if(lpOTMW
->otmpFamilyName
)
5217 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5218 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
5219 NULL
, 0, NULL
, NULL
);
5220 if(lpOTMW
->otmpFaceName
)
5221 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5222 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
5223 NULL
, 0, NULL
, NULL
);
5224 if(lpOTMW
->otmpStyleName
)
5225 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5226 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
5227 NULL
, 0, NULL
, NULL
);
5228 if(lpOTMW
->otmpFullName
)
5229 needed
+= WideCharToMultiByte(CP_ACP
, 0,
5230 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
5231 NULL
, 0, NULL
, NULL
);
5238 TRACE("needed = %d\n", needed
);
5240 /* Since the supplied buffer isn't big enough, we'll alloc one
5241 that is and memcpy the first cbData bytes into the lpOTM at
5243 output
= HeapAlloc(GetProcessHeap(), 0, needed
);
5245 ret
= output
->otmSize
= min(needed
, cbData
);
5246 FONT_TextMetricWToA( &lpOTMW
->otmTextMetrics
, &output
->otmTextMetrics
);
5247 output
->otmFiller
= 0;
5248 output
->otmPanoseNumber
= lpOTMW
->otmPanoseNumber
;
5249 output
->otmfsSelection
= lpOTMW
->otmfsSelection
;
5250 output
->otmfsType
= lpOTMW
->otmfsType
;
5251 output
->otmsCharSlopeRise
= lpOTMW
->otmsCharSlopeRise
;
5252 output
->otmsCharSlopeRun
= lpOTMW
->otmsCharSlopeRun
;
5253 output
->otmItalicAngle
= lpOTMW
->otmItalicAngle
;
5254 output
->otmEMSquare
= lpOTMW
->otmEMSquare
;
5255 output
->otmAscent
= lpOTMW
->otmAscent
;
5256 output
->otmDescent
= lpOTMW
->otmDescent
;
5257 output
->otmLineGap
= lpOTMW
->otmLineGap
;
5258 output
->otmsCapEmHeight
= lpOTMW
->otmsCapEmHeight
;
5259 output
->otmsXHeight
= lpOTMW
->otmsXHeight
;
5260 output
->otmrcFontBox
= lpOTMW
->otmrcFontBox
;
5261 output
->otmMacAscent
= lpOTMW
->otmMacAscent
;
5262 output
->otmMacDescent
= lpOTMW
->otmMacDescent
;
5263 output
->otmMacLineGap
= lpOTMW
->otmMacLineGap
;
5264 output
->otmusMinimumPPEM
= lpOTMW
->otmusMinimumPPEM
;
5265 output
->otmptSubscriptSize
= lpOTMW
->otmptSubscriptSize
;
5266 output
->otmptSubscriptOffset
= lpOTMW
->otmptSubscriptOffset
;
5267 output
->otmptSuperscriptSize
= lpOTMW
->otmptSuperscriptSize
;
5268 output
->otmptSuperscriptOffset
= lpOTMW
->otmptSuperscriptOffset
;
5269 output
->otmsStrikeoutSize
= lpOTMW
->otmsStrikeoutSize
;
5270 output
->otmsStrikeoutPosition
= lpOTMW
->otmsStrikeoutPosition
;
5271 output
->otmsUnderscoreSize
= lpOTMW
->otmsUnderscoreSize
;
5272 output
->otmsUnderscorePosition
= lpOTMW
->otmsUnderscorePosition
;
5275 ptr
= (char*)(output
+ 1);
5276 left
= needed
- sizeof(*output
);
5278 if(lpOTMW
->otmpFamilyName
) {
5279 output
->otmpFamilyName
= (LPSTR
)(ptr
- (char*)output
);
5280 len
= WideCharToMultiByte(CP_ACP
, 0,
5281 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
5282 ptr
, left
, NULL
, NULL
);
5286 output
->otmpFamilyName
= 0;
5288 if(lpOTMW
->otmpFaceName
) {
5289 output
->otmpFaceName
= (LPSTR
)(ptr
- (char*)output
);
5290 len
= WideCharToMultiByte(CP_ACP
, 0,
5291 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
5292 ptr
, left
, NULL
, NULL
);
5296 output
->otmpFaceName
= 0;
5298 if(lpOTMW
->otmpStyleName
) {
5299 output
->otmpStyleName
= (LPSTR
)(ptr
- (char*)output
);
5300 len
= WideCharToMultiByte(CP_ACP
, 0,
5301 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
5302 ptr
, left
, NULL
, NULL
);
5306 output
->otmpStyleName
= 0;
5308 if(lpOTMW
->otmpFullName
) {
5309 output
->otmpFullName
= (LPSTR
)(ptr
- (char*)output
);
5310 len
= WideCharToMultiByte(CP_ACP
, 0,
5311 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
5312 ptr
, left
, NULL
, NULL
);
5315 output
->otmpFullName
= 0;
5319 if(output
!= lpOTM
) {
5320 memcpy(lpOTM
, output
, cbData
);
5321 HeapFree(GetProcessHeap(), 0, output
);
5323 /* check if the string offsets really fit into the provided size */
5324 /* FIXME: should we check string length as well? */
5325 /* make sure that we don't read/write beyond the provided buffer */
5326 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFamilyName
) + sizeof(LPSTR
))
5328 if ((UINT_PTR
)lpOTM
->otmpFamilyName
>= lpOTM
->otmSize
)
5329 lpOTM
->otmpFamilyName
= 0; /* doesn't fit */
5332 /* make sure that we don't read/write beyond the provided buffer */
5333 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFaceName
) + sizeof(LPSTR
))
5335 if ((UINT_PTR
)lpOTM
->otmpFaceName
>= lpOTM
->otmSize
)
5336 lpOTM
->otmpFaceName
= 0; /* doesn't fit */
5339 /* make sure that we don't read/write beyond the provided buffer */
5340 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpStyleName
) + sizeof(LPSTR
))
5342 if ((UINT_PTR
)lpOTM
->otmpStyleName
>= lpOTM
->otmSize
)
5343 lpOTM
->otmpStyleName
= 0; /* doesn't fit */
5346 /* make sure that we don't read/write beyond the provided buffer */
5347 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFullName
) + sizeof(LPSTR
))
5349 if ((UINT_PTR
)lpOTM
->otmpFullName
>= lpOTM
->otmSize
)
5350 lpOTM
->otmpFullName
= 0; /* doesn't fit */
5355 if(lpOTMW
!= (OUTLINETEXTMETRICW
*)buf
)
5356 HeapFree(GetProcessHeap(), 0, lpOTMW
);
5362 /***********************************************************************
5363 * GetOutlineTextMetricsW [GDI32.@]
5365 UINT WINAPI
GetOutlineTextMetricsW(
5366 HDC hdc
, /* [in] Handle of device context */
5367 UINT cbData
, /* [in] Size of metric data array */
5368 LPOUTLINETEXTMETRICW lpOTM
) /* [out] Address of metric data array */
5370 DC
*dc
= get_dc_ptr( hdc
);
5371 OUTLINETEXTMETRICW
*output
= lpOTM
;
5375 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
5378 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
5379 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
5381 if (lpOTM
&& ret
> cbData
)
5383 output
= HeapAlloc(GetProcessHeap(), 0, ret
);
5384 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
5389 output
->otmTextMetrics
.tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
5390 output
->otmTextMetrics
.tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
5391 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
5392 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
5393 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
5394 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
5395 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
5396 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
5397 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
5398 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
5399 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
5400 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
5401 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
5402 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
5403 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
5404 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
5405 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
5406 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
5407 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
5408 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
5409 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
5410 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
5411 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
5412 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
5413 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
5414 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
5415 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
5416 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
5417 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
5418 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
5419 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
5420 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
5421 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
5422 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
5426 memcpy(lpOTM
, output
, cbData
);
5427 HeapFree(GetProcessHeap(), 0, output
);
5435 static LPSTR
FONT_GetCharsByRangeA(HDC hdc
, UINT firstChar
, UINT lastChar
, PINT pByteLen
)
5437 INT i
, count
= lastChar
- firstChar
+ 1;
5445 mbcp
= GdiGetCodePage(hdc
);
5453 if (lastChar
> 0xffff)
5455 if ((firstChar
^ lastChar
) > 0xff)
5459 if (lastChar
> 0xff)
5465 str
= HeapAlloc(GetProcessHeap(), 0, count
* 2 + 1);
5469 for(i
= 0, c
= firstChar
; c
<= lastChar
; i
++, c
++)
5473 str
[i
++] = (BYTE
)(c
>> 8);
5474 if (c
<= 0xff && IsDBCSLeadByteEx(mbcp
, c
))
5475 str
[i
] = 0x1f; /* FIXME: use default character */
5489 /***********************************************************************
5490 * GetCharWidthW (GDI32.@)
5491 * GetCharWidth32W (GDI32.@)
5493 BOOL WINAPI
GetCharWidth32W( HDC hdc
, UINT firstChar
, UINT lastChar
,
5499 DC
* dc
= get_dc_ptr( hdc
);
5501 if (!dc
) return FALSE
;
5503 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
5504 ret
= dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
5508 /* convert device units to logical */
5509 for( i
= firstChar
; i
<= lastChar
; i
++, buffer
++ )
5510 *buffer
= width_to_LP( dc
, *buffer
);
5512 release_dc_ptr( dc
);
5517 /***********************************************************************
5518 * GetCharWidthA (GDI32.@)
5519 * GetCharWidth32A (GDI32.@)
5521 BOOL WINAPI
GetCharWidth32A( HDC hdc
, UINT firstChar
, UINT lastChar
,
5529 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
5533 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
5535 for(i
= 0; i
< wlen
; i
++)
5537 if(!GetCharWidth32W(hdc
, wstr
[i
], wstr
[i
], buffer
))
5545 HeapFree(GetProcessHeap(), 0, str
);
5546 HeapFree(GetProcessHeap(), 0, wstr
);
5552 /* helper for nulldrv_ExtTextOut */
5553 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
5554 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
5556 UINT indices
[3] = {0, 0, 0x20};
5562 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
5564 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
5567 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
);
5568 if (ret
!= GDI_ERROR
) break;
5571 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
5572 if (!image
) return ERROR_SUCCESS
;
5576 if (!ret
) /* empty glyph */
5578 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
5579 return ERROR_SUCCESS
;
5582 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5583 size
= metrics
->gmBlackBoxY
* stride
;
5585 if (!(image
->ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
5586 image
->is_copy
= TRUE
;
5587 image
->free
= free_heap_bits
;
5589 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
, &identity
);
5590 if (ret
== GDI_ERROR
)
5592 HeapFree( GetProcessHeap(), 0, image
->ptr
);
5593 return ERROR_NOT_FOUND
;
5595 return ERROR_SUCCESS
;
5598 /* helper for nulldrv_ExtTextOut */
5599 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
5600 LPCWSTR str
, UINT count
, const INT
*dx
)
5605 reset_bounds( &bounds
);
5606 for (i
= 0; i
< count
; i
++)
5608 GLYPHMETRICS metrics
;
5610 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
5612 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
5613 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
5614 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
5615 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
5616 add_bounds_rect( &bounds
, &rect
);
5620 if (flags
& ETO_PDY
)
5623 y
+= dx
[ i
* 2 + 1];
5629 x
+= metrics
.gmCellIncX
;
5630 y
+= metrics
.gmCellIncY
;
5636 /* helper for nulldrv_ExtTextOut */
5637 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
5638 const struct gdi_image_bits
*image
, const RECT
*clip
)
5640 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5641 UINT i
, count
, max_count
;
5643 BYTE
*ptr
= image
->ptr
;
5644 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
5646 RECT rect
, clipped_rect
;
5648 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
5649 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
5650 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
5651 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
5652 if (!clip
) clipped_rect
= rect
;
5653 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
5655 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
5656 pts
= HeapAlloc( GetProcessHeap(), 0, max_count
* sizeof(*pts
) );
5660 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
5661 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
5663 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
5665 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5666 pts
[count
].x
= rect
.left
+ x
;
5667 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
5668 pts
[count
+ 1].x
= rect
.left
+ x
;
5669 if (pts
[count
+ 1].x
> pts
[count
].x
)
5671 pts
[count
].y
= pts
[count
+ 1].y
= y
;
5676 assert( count
<= max_count
);
5677 dp_to_lp( dc
, pts
, count
);
5678 for (i
= 0; i
< count
; i
+= 2) Polyline( dc
->hSelf
, pts
+ i
, 2 );
5679 HeapFree( GetProcessHeap(), 0, pts
);
5682 /***********************************************************************
5683 * nulldrv_ExtTextOut
5685 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5686 LPCWSTR str
, UINT count
, const INT
*dx
)
5688 DC
*dc
= get_nulldrv_dc( dev
);
5694 if (flags
& ETO_OPAQUE
)
5697 HBRUSH brush
= CreateSolidBrush( GetNearestColor( dev
->hdc
, dc
->backgroundColor
) );
5701 orig
= NtGdiSelectBrush( dev
->hdc
, brush
);
5702 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5703 PatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5704 NtGdiSelectBrush( dev
->hdc
, orig
);
5705 DeleteObject( brush
);
5709 if (!count
) return TRUE
;
5711 if (dc
->aa_flags
!= GGO_BITMAP
)
5713 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5714 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5715 struct gdi_image_bits bits
;
5716 struct bitblt_coords src
, dst
;
5718 /* FIXME Subpixel modes */
5719 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5721 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5722 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5723 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5724 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5726 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5727 src
.x
= src
.visrect
.left
;
5728 src
.y
= src
.visrect
.top
;
5729 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5730 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5732 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5733 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5735 /* we can avoid the GetImage, just query the needed format */
5736 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5737 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5738 info
->bmiHeader
.biWidth
= src
.width
;
5739 info
->bmiHeader
.biHeight
= -src
.height
;
5740 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5741 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5742 if (!err
|| err
== ERROR_BAD_FORMAT
)
5744 /* make the source rectangle relative to the source bits */
5746 src
.visrect
.left
= src
.visrect
.top
= 0;
5747 src
.visrect
.right
= src
.width
;
5748 src
.visrect
.bottom
= src
.height
;
5750 bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
5751 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5752 bits
.is_copy
= TRUE
;
5753 bits
.free
= free_heap_bits
;
5754 err
= ERROR_SUCCESS
;
5759 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5760 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5761 if (!err
&& !bits
.is_copy
)
5763 void *ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
5766 if (bits
.free
) bits
.free( &bits
);
5767 return ERROR_OUTOFMEMORY
;
5769 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5770 if (bits
.free
) bits
.free( &bits
);
5772 bits
.is_copy
= TRUE
;
5773 bits
.free
= free_heap_bits
;
5778 /* make x,y relative to the image bits */
5779 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5780 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5781 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5782 aa_flags
, str
, count
, dx
);
5783 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5784 if (bits
.free
) bits
.free( &bits
);
5789 pen
= CreatePen( PS_SOLID
, 1, dc
->textColor
);
5790 orig
= NtGdiSelectPen( dev
->hdc
, pen
);
5792 for (i
= 0; i
< count
; i
++)
5794 GLYPHMETRICS metrics
;
5795 struct gdi_image_bits image
;
5797 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5800 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5801 if (image
.free
) image
.free( &image
);
5805 if (flags
& ETO_PDY
)
5808 y
+= dx
[ i
* 2 + 1];
5814 x
+= metrics
.gmCellIncX
;
5815 y
+= metrics
.gmCellIncY
;
5819 NtGdiSelectPen( dev
->hdc
, orig
);
5820 DeleteObject( pen
);
5825 /***********************************************************************
5826 * ExtTextOutA (GDI32.@)
5830 BOOL WINAPI
ExtTextOutA( HDC hdc
, INT x
, INT y
, UINT flags
,
5831 const RECT
*lprect
, LPCSTR str
, UINT count
, const INT
*lpDx
)
5839 if (count
> INT_MAX
) return FALSE
;
5841 if (flags
& ETO_GLYPH_INDEX
)
5842 return ExtTextOutW( hdc
, x
, y
, flags
, lprect
, (LPCWSTR
)str
, count
, lpDx
);
5844 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, &codepage
);
5847 unsigned int i
= 0, j
= 0;
5849 /* allocate enough for a ETO_PDY */
5850 lpDxW
= HeapAlloc( GetProcessHeap(), 0, 2*wlen
*sizeof(INT
));
5852 if(IsDBCSLeadByteEx(codepage
, str
[i
]))
5856 lpDxW
[j
++] = lpDx
[i
* 2] + lpDx
[(i
+ 1) * 2];
5857 lpDxW
[j
++] = lpDx
[i
* 2 + 1] + lpDx
[(i
+ 1) * 2 + 1];
5860 lpDxW
[j
++] = lpDx
[i
] + lpDx
[i
+ 1];
5867 lpDxW
[j
++] = lpDx
[i
* 2];
5868 lpDxW
[j
++] = lpDx
[i
* 2 + 1];
5871 lpDxW
[j
++] = lpDx
[i
];
5877 ret
= ExtTextOutW( hdc
, x
, y
, flags
, lprect
, p
, wlen
, lpDxW
);
5879 HeapFree( GetProcessHeap(), 0, p
);
5880 HeapFree( GetProcessHeap(), 0, lpDxW
);
5884 /***********************************************************************
5887 * Scale the underline / strikeout line width.
5889 static inline int get_line_width( DC
*dc
, int metric_size
)
5891 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5892 if (width
== 0) width
= 1;
5893 if (metric_size
< 0) width
= -width
;
5897 /***********************************************************************
5898 * ExtTextOutW (GDI32.@)
5900 * Draws text using the currently selected font, background color, and text color.
5904 * x,y [I] coordinates of string
5906 * ETO_GRAYED - undocumented on MSDN
5907 * ETO_OPAQUE - use background color for fill the rectangle
5908 * ETO_CLIPPED - clipping text to the rectangle
5909 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5910 * than encoded characters. Implies ETO_IGNORELANGUAGE
5911 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5912 * Affects BiDi ordering
5913 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5914 * ETO_PDY - unimplemented
5915 * ETO_NUMERICSLATIN - unimplemented always assumed -
5916 * do not translate numbers into locale representations
5917 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5918 * lprect [I] dimensions for clipping or/and opaquing
5919 * str [I] text string
5920 * count [I] number of symbols in string
5921 * lpDx [I] optional parameter with distance between drawing characters
5927 BOOL WINAPI
ExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
,
5928 const RECT
*lprect
, LPCWSTR str
, UINT count
, const INT
*lpDx
)
5931 LPWSTR reordered_str
= (LPWSTR
)str
;
5932 WORD
*glyphs
= NULL
;
5938 double cosEsc
, sinEsc
;
5942 POINT
*deltas
= NULL
, width
= {0, 0};
5944 DC
* dc
= get_dc_ptr( hdc
);
5947 static int quietfixme
= 0;
5949 if (!dc
) return FALSE
;
5950 if (count
> INT_MAX
) return FALSE
;
5952 align
= dc
->textAlign
;
5953 breakRem
= dc
->breakRem
;
5954 layout
= dc
->layout
;
5956 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5958 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5963 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5964 type
= GetObjectType(hdc
);
5965 if(type
== OBJ_METADC
|| type
== OBJ_ENHMETADC
)
5967 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, flags
, lprect
, str
, count
, lpDx
);
5968 release_dc_ptr( dc
);
5972 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5973 if (layout
& LAYOUT_RTL
)
5975 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5976 align
^= TA_RTLREADING
;
5979 if( !(flags
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)) && count
> 0 )
5982 reordered_str
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
5984 BIDI_Reorder( hdc
, str
, count
, GCP_REORDER
,
5985 (align
& TA_RTLREADING
) ? WINE_GCPW_FORCE_RTL
: WINE_GCPW_FORCE_LTR
,
5986 reordered_str
, count
, NULL
, &glyphs
, &cGlyphs
);
5988 flags
|= ETO_IGNORELANGUAGE
;
5991 flags
|= ETO_GLYPH_INDEX
;
5992 if (cGlyphs
!= count
)
5996 else if(flags
& ETO_GLYPH_INDEX
)
5997 glyphs
= reordered_str
;
5999 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
6000 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
6001 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->backgroundMode
, dc
->MapMode
);
6003 if(align
& TA_UPDATECP
)
6005 pt
= dc
->attr
->cur_pos
;
6010 GetTextMetricsW(hdc
, &tm
);
6011 GetObjectW(dc
->hFont
, sizeof(lf
), &lf
);
6013 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
6014 lf
.lfEscapement
= 0;
6016 if ((dc
->attr
->graphics_mode
== GM_COMPATIBLE
) &&
6017 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
6019 lf
.lfEscapement
= -lf
.lfEscapement
;
6022 if(lf
.lfEscapement
!= 0)
6024 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
6025 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
6033 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
6036 lp_to_dp(dc
, (POINT
*)&rc
, 2);
6038 if (flags
& ETO_OPAQUE
)
6039 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
6041 else flags
&= ~ETO_CLIPPED
;
6051 lp_to_dp(dc
, &pt
, 1);
6055 char_extra
= GetTextCharacterExtra(hdc
);
6056 if (char_extra
&& lpDx
&& GetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
6057 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
6059 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
6062 POINT total
= {0, 0}, desired
[2];
6064 deltas
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*deltas
));
6067 if (flags
& ETO_PDY
)
6069 for (i
= 0; i
< count
; i
++)
6071 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
6072 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
6077 for (i
= 0; i
< count
; i
++)
6079 deltas
[i
].x
= lpDx
[i
] + char_extra
;
6086 INT
*dx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*dx
) );
6088 if (flags
& ETO_GLYPH_INDEX
)
6089 GetTextExtentExPointI( hdc
, glyphs
, count
, -1, NULL
, dx
, &sz
);
6091 GetTextExtentExPointW( hdc
, reordered_str
, count
, -1, NULL
, dx
, &sz
);
6093 deltas
[0].x
= dx
[0];
6095 for (i
= 1; i
< count
; i
++)
6097 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
6100 HeapFree( GetProcessHeap(), 0, dx
);
6103 for(i
= 0; i
< count
; i
++)
6105 total
.x
+= deltas
[i
].x
;
6106 total
.y
+= deltas
[i
].y
;
6108 desired
[0].x
= desired
[0].y
= 0;
6110 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
6111 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
6113 lp_to_dp(dc
, desired
, 2);
6114 desired
[1].x
-= desired
[0].x
;
6115 desired
[1].y
-= desired
[0].y
;
6117 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
6119 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
6120 desired
[1].x
= -desired
[1].x
;
6121 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
6122 desired
[1].y
= -desired
[1].y
;
6125 deltas
[i
].x
= desired
[1].x
- width
.x
;
6126 deltas
[i
].y
= desired
[1].y
- width
.y
;
6136 if(flags
& ETO_GLYPH_INDEX
)
6137 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
6139 GetTextExtentPointW(hdc
, reordered_str
, count
, &sz
);
6140 desired
[0].x
= desired
[0].y
= 0;
6141 desired
[1].x
= sz
.cx
;
6143 lp_to_dp(dc
, desired
, 2);
6144 desired
[1].x
-= desired
[0].x
;
6145 desired
[1].y
-= desired
[0].y
;
6147 if (dc
->attr
->graphics_mode
== GM_COMPATIBLE
)
6149 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
6150 desired
[1].x
= -desired
[1].x
;
6151 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
6152 desired
[1].y
= -desired
[1].y
;
6157 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
6158 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
6159 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
6162 if (align
& TA_UPDATECP
)
6166 dp_to_lp(dc
, &pt
, 1);
6167 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
6179 if (align
& TA_UPDATECP
)
6183 dp_to_lp(dc
, &pt
, 1);
6184 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
6189 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
6192 y
+= tm
.tmAscent
* cosEsc
;
6193 x
+= tm
.tmAscent
* sinEsc
;
6197 y
-= tm
.tmDescent
* cosEsc
;
6198 x
-= tm
.tmDescent
* sinEsc
;
6205 if (dc
->backgroundMode
!= TRANSPARENT
)
6207 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
6209 if(!(flags
& ETO_OPAQUE
) || !lprect
||
6210 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
6211 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
6215 text_box
.right
= x
+ width
.x
;
6216 text_box
.top
= y
- tm
.tmAscent
;
6217 text_box
.bottom
= y
+ tm
.tmDescent
;
6219 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
6220 if (!is_rect_empty( &text_box
))
6221 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
6226 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
6227 glyphs
? glyphs
: reordered_str
, count
, (INT
*)deltas
);
6230 HeapFree(GetProcessHeap(), 0, deltas
);
6231 if(glyphs
!= reordered_str
)
6232 HeapFree(GetProcessHeap(), 0, glyphs
);
6233 if(reordered_str
!= str
)
6234 HeapFree(GetProcessHeap(), 0, reordered_str
);
6236 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
6238 int underlinePos
, strikeoutPos
;
6239 int underlineWidth
, strikeoutWidth
;
6240 UINT size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
6241 OUTLINETEXTMETRICW
* otm
= NULL
;
6243 HPEN hpen
= NtGdiSelectPen(hdc
, GetStockObject(NULL_PEN
));
6244 HBRUSH hbrush
= CreateSolidBrush(dc
->textColor
);
6246 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
6251 underlineWidth
= tm
.tmAscent
/ 20 + 1;
6252 strikeoutPos
= tm
.tmAscent
/ 2;
6253 strikeoutWidth
= underlineWidth
;
6257 otm
= HeapAlloc(GetProcessHeap(), 0, size
);
6258 GetOutlineTextMetricsW(hdc
, size
, otm
);
6259 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
6260 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
6261 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
6262 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
6263 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
6264 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
6265 HeapFree(GetProcessHeap(), 0, otm
);
6272 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
6273 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
6274 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
6275 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
6276 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
6277 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
6278 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
6279 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
6280 pts
[4].x
= pts
[0].x
;
6281 pts
[4].y
= pts
[0].y
;
6282 dp_to_lp(dc
, pts
, 5);
6283 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
6289 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
6290 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
6291 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
6292 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
6293 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
6294 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
6295 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
6296 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
6297 pts
[4].x
= pts
[0].x
;
6298 pts
[4].y
= pts
[0].y
;
6299 dp_to_lp(dc
, pts
, 5);
6300 NtGdiPolyPolyDraw( hdc
, pts
, &cnt
, 1, NtGdiPolyPolygon
);
6303 NtGdiSelectPen(hdc
, hpen
);
6304 hbrush
= NtGdiSelectBrush(hdc
, hbrush
);
6305 DeleteObject(hbrush
);
6308 release_dc_ptr( dc
);
6314 /***********************************************************************
6315 * TextOutA (GDI32.@)
6317 BOOL WINAPI
TextOutA( HDC hdc
, INT x
, INT y
, LPCSTR str
, INT count
)
6319 return ExtTextOutA( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
6323 /***********************************************************************
6324 * TextOutW (GDI32.@)
6326 BOOL WINAPI
TextOutW(HDC hdc
, INT x
, INT y
, LPCWSTR str
, INT count
)
6328 return ExtTextOutW( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
6332 /***********************************************************************
6333 * PolyTextOutA (GDI32.@)
6337 BOOL WINAPI
PolyTextOutA( HDC hdc
, const POLYTEXTA
*pptxt
, INT cStrings
)
6339 for (; cStrings
>0; cStrings
--, pptxt
++)
6340 if (!ExtTextOutA( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
6347 /***********************************************************************
6348 * PolyTextOutW (GDI32.@)
6350 * Draw several Strings
6356 BOOL WINAPI
PolyTextOutW( HDC hdc
, const POLYTEXTW
*pptxt
, INT cStrings
)
6358 for (; cStrings
>0; cStrings
--, pptxt
++)
6359 if (!ExtTextOutW( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
6365 /***********************************************************************
6366 * SetMapperFlags (GDI32.@)
6368 DWORD WINAPI
SetMapperFlags( HDC hdc
, DWORD flags
)
6370 DC
*dc
= get_dc_ptr( hdc
);
6371 DWORD ret
= GDI_ERROR
;
6375 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetMapperFlags
);
6376 flags
= physdev
->funcs
->pSetMapperFlags( physdev
, flags
);
6377 if (flags
!= GDI_ERROR
)
6379 ret
= dc
->mapperFlags
;
6380 dc
->mapperFlags
= flags
;
6382 release_dc_ptr( dc
);
6387 /***********************************************************************
6388 * GetAspectRatioFilterEx (GDI32.@)
6390 BOOL WINAPI
GetAspectRatioFilterEx( HDC hdc
, LPSIZE pAspectRatio
)
6392 FIXME("(%p, %p): -- Empty Stub !\n", hdc
, pAspectRatio
);
6397 /***********************************************************************
6398 * GetCharABCWidthsA (GDI32.@)
6400 * See GetCharABCWidthsW.
6402 BOOL WINAPI
GetCharABCWidthsA(HDC hdc
, UINT firstChar
, UINT lastChar
,
6410 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
6414 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
6417 HeapFree(GetProcessHeap(), 0, str
);
6421 for(i
= 0; i
< wlen
; i
++)
6423 if(!GetCharABCWidthsW(hdc
, wstr
[i
], wstr
[i
], abc
))
6431 HeapFree(GetProcessHeap(), 0, str
);
6432 HeapFree(GetProcessHeap(), 0, wstr
);
6438 /******************************************************************************
6439 * GetCharABCWidthsW [GDI32.@]
6441 * Retrieves widths of characters in range.
6444 * hdc [I] Handle of device context
6445 * firstChar [I] First character in range to query
6446 * lastChar [I] Last character in range to query
6447 * abc [O] Address of character-width structure
6450 * Only works with TrueType fonts
6456 BOOL WINAPI
GetCharABCWidthsW( HDC hdc
, UINT firstChar
, UINT lastChar
,
6459 DC
*dc
= get_dc_ptr(hdc
);
6465 if (!dc
) return FALSE
;
6469 release_dc_ptr( dc
);
6473 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
6474 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
6475 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
6477 release_dc_ptr( dc
);
6481 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
6482 ret
= dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, abc
);
6485 /* convert device units to logical */
6486 for( i
= firstChar
; i
<= lastChar
; i
++, abc
++ ) {
6487 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
6488 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
6489 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
6493 release_dc_ptr( dc
);
6498 /******************************************************************************
6499 * GetCharABCWidthsI [GDI32.@]
6501 * Retrieves widths of characters in range.
6504 * hdc [I] Handle of device context
6505 * firstChar [I] First glyphs in range to query
6506 * count [I] Last glyphs in range to query
6507 * pgi [i] Array of glyphs to query
6508 * abc [O] Address of character-width structure
6511 * Only works with TrueType fonts
6517 BOOL WINAPI
GetCharABCWidthsI( HDC hdc
, UINT firstChar
, UINT count
,
6518 LPWORD pgi
, LPABC abc
)
6520 DC
*dc
= get_dc_ptr(hdc
);
6525 if (!dc
) return FALSE
;
6529 release_dc_ptr( dc
);
6533 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
6534 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, abc
);
6537 /* convert device units to logical */
6538 for( i
= 0; i
< count
; i
++, abc
++ ) {
6539 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
6540 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
6541 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
6545 release_dc_ptr( dc
);
6550 /***********************************************************************
6551 * GetGlyphOutlineA (GDI32.@)
6553 DWORD WINAPI
GetGlyphOutlineA( HDC hdc
, UINT uChar
, UINT fuFormat
,
6554 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
6555 LPVOID lpBuffer
, const MAT2
*lpmat2
)
6557 if (!lpmat2
) return GDI_ERROR
;
6559 if(!(fuFormat
& GGO_GLYPH_INDEX
)) {
6565 cp
= GdiGetCodePage(hdc
);
6566 if (IsDBCSLeadByteEx(cp
, uChar
>> 8)) {
6568 mbchs
[0] = (uChar
& 0xff00) >> 8;
6569 mbchs
[1] = (uChar
& 0xff);
6572 mbchs
[0] = (uChar
& 0xff);
6575 MultiByteToWideChar(cp
, 0, mbchs
, len
, &wChar
, 1);
6579 return GetGlyphOutlineW(hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
,
6583 /***********************************************************************
6584 * GetGlyphOutlineW (GDI32.@)
6586 DWORD WINAPI
GetGlyphOutlineW( HDC hdc
, UINT uChar
, UINT fuFormat
,
6587 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
6588 LPVOID lpBuffer
, const MAT2
*lpmat2
)
6594 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
6595 hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
6597 if (!lpmat2
) return GDI_ERROR
;
6599 dc
= get_dc_ptr(hdc
);
6600 if(!dc
) return GDI_ERROR
;
6604 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
6605 ret
= dev
->funcs
->pGetGlyphOutline( dev
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
6606 release_dc_ptr( dc
);
6611 /***********************************************************************
6612 * CreateScalableFontResourceA (GDI32.@)
6614 BOOL WINAPI
CreateScalableFontResourceA( DWORD fHidden
,
6615 LPCSTR lpszResourceFile
,
6616 LPCSTR lpszFontFile
,
6617 LPCSTR lpszCurrentPath
)
6619 LPWSTR lpszResourceFileW
= NULL
;
6620 LPWSTR lpszFontFileW
= NULL
;
6621 LPWSTR lpszCurrentPathW
= NULL
;
6625 if (lpszResourceFile
)
6627 len
= MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, NULL
, 0);
6628 lpszResourceFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6629 MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, lpszResourceFileW
, len
);
6634 len
= MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, NULL
, 0);
6635 lpszFontFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6636 MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, lpszFontFileW
, len
);
6639 if (lpszCurrentPath
)
6641 len
= MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, NULL
, 0);
6642 lpszCurrentPathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6643 MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, lpszCurrentPathW
, len
);
6646 ret
= CreateScalableFontResourceW(fHidden
, lpszResourceFileW
,
6647 lpszFontFileW
, lpszCurrentPathW
);
6649 HeapFree(GetProcessHeap(), 0, lpszResourceFileW
);
6650 HeapFree(GetProcessHeap(), 0, lpszFontFileW
);
6651 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW
);
6656 #define NE_FFLAGS_LIBMODULE 0x8000
6657 #define NE_OSFLAGS_WINDOWS 0x02
6659 static const char dos_string
[0x40] = "This is a TrueType resource file";
6660 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
6662 #include <pshpack1.h>
6665 WORD num_of_resources
;
6669 CHAR dfCopyright
[60];
6675 WORD dfInternalLeading
;
6676 WORD dfExternalLeading
;
6684 BYTE dfPitchAndFamily
;
6695 CHAR szFaceName
[LF_FACESIZE
];
6697 #include <poppack.h>
6699 #include <pshpack2.h>
6720 struct ne_typeinfo fontdir_type
;
6721 struct ne_nameinfo fontdir_name
;
6722 struct ne_typeinfo scalable_type
;
6723 struct ne_nameinfo scalable_name
;
6725 BYTE fontdir_res_name
[8];
6728 #include <poppack.h>
6730 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
6734 DWORD size
, written
;
6736 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
6737 char *font_fileA
, *last_part
, *ext
;
6738 IMAGE_DOS_HEADER dos
;
6739 IMAGE_OS2_HEADER ne
=
6741 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
6743 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
6744 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
6746 struct rsrc_tab rsrc_tab
=
6750 { 0, 0, 0x0c50, 0x2c, 0 },
6752 { 0, 0, 0x0c50, 0x8001, 0 },
6754 { 7,'F','O','N','T','D','I','R'}
6757 memset( &dos
, 0, sizeof(dos
) );
6758 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
6759 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
6761 /* import name is last part\0, resident name is last part without extension
6762 non-resident name is "FONTRES:" + lfFaceName */
6764 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
6765 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
6766 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
6768 last_part
= strrchr( font_fileA
, '\\' );
6769 if (last_part
) last_part
++;
6770 else last_part
= font_fileA
;
6771 import_name_len
= strlen( last_part
) + 1;
6773 ext
= strchr( last_part
, '.' );
6774 if (ext
) res_name_len
= ext
- last_part
;
6775 else res_name_len
= import_name_len
- 1;
6777 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
6779 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
6780 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
6781 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
6782 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
6784 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
6786 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
6787 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
6788 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
6789 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
6791 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
6792 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
6796 HeapFree( GetProcessHeap(), 0, font_fileA
);
6800 memcpy( ptr
, &dos
, sizeof(dos
) );
6801 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
6802 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
6804 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
6805 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
6807 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
6808 *ptr
++ = res_name_len
;
6809 memcpy( ptr
, last_part
, res_name_len
);
6811 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
6812 *ptr
++ = import_name_len
;
6813 memcpy( ptr
, last_part
, import_name_len
);
6815 ptr
= start
+ ne
.ne_nrestab
;
6816 *ptr
++ = non_res_name_len
;
6817 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
6818 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
6820 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
6821 memcpy( ptr
, font_fileA
, font_file_len
);
6823 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
6824 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
6826 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
6827 if (file
!= INVALID_HANDLE_VALUE
)
6829 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
6831 CloseHandle( file
);
6834 HeapFree( GetProcessHeap(), 0, start
);
6835 HeapFree( GetProcessHeap(), 0, font_fileA
);
6840 /***********************************************************************
6841 * CreateScalableFontResourceW (GDI32.@)
6843 BOOL WINAPI
CreateScalableFontResourceW( DWORD hidden
, LPCWSTR resource_file
,
6844 LPCWSTR font_file
, LPCWSTR font_path
)
6846 struct fontdir fontdir
= { 0 };
6847 struct gdi_font
*font
= NULL
;
6848 WCHAR path
[MAX_PATH
];
6850 TRACE("(%d, %s, %s, %s)\n", hidden
, debugstr_w(resource_file
),
6851 debugstr_w(font_file
), debugstr_w(font_path
) );
6853 if (!font_funcs
) return FALSE
;
6855 if (!font_file
) goto done
;
6856 if (font_path
&& font_path
[0])
6858 int len
= lstrlenW( font_path
) + lstrlenW( font_file
) + 2;
6859 if (len
> MAX_PATH
) goto done
;
6860 lstrcpynW( path
, font_path
, MAX_PATH
);
6861 lstrcatW( path
, L
"\\" );
6862 lstrcatW( path
, font_file
);
6864 else if (!GetFullPathNameW( font_file
, MAX_PATH
, path
, NULL
)) goto done
;
6866 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
6867 font
->lf
.lfHeight
= 100;
6868 if (!font_funcs
->load_font( font
)) goto done
;
6869 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
6871 if (!(font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_TRUETYPE
)) goto done
;
6873 fontdir
.num_of_resources
= 1;
6875 fontdir
.dfVersion
= 0x200;
6876 fontdir
.dfSize
= sizeof(fontdir
);
6877 strcpy( fontdir
.dfCopyright
, "Wine fontdir" );
6878 fontdir
.dfType
= 0x4003; /* 0x0080 set if private */
6879 fontdir
.dfPoints
= font
->otm
.otmEMSquare
;
6880 fontdir
.dfVertRes
= 72;
6881 fontdir
.dfHorizRes
= 72;
6882 fontdir
.dfAscent
= font
->otm
.otmTextMetrics
.tmAscent
;
6883 fontdir
.dfInternalLeading
= font
->otm
.otmTextMetrics
.tmInternalLeading
;
6884 fontdir
.dfExternalLeading
= font
->otm
.otmTextMetrics
.tmExternalLeading
;
6885 fontdir
.dfItalic
= font
->otm
.otmTextMetrics
.tmItalic
;
6886 fontdir
.dfUnderline
= font
->otm
.otmTextMetrics
.tmUnderlined
;
6887 fontdir
.dfStrikeOut
= font
->otm
.otmTextMetrics
.tmStruckOut
;
6888 fontdir
.dfWeight
= font
->otm
.otmTextMetrics
.tmWeight
;
6889 fontdir
.dfCharSet
= font
->otm
.otmTextMetrics
.tmCharSet
;
6890 fontdir
.dfPixWidth
= 0;
6891 fontdir
.dfPixHeight
= font
->otm
.otmTextMetrics
.tmHeight
;
6892 fontdir
.dfPitchAndFamily
= font
->otm
.otmTextMetrics
.tmPitchAndFamily
;
6893 fontdir
.dfAvgWidth
= font
->otm
.otmTextMetrics
.tmAveCharWidth
;
6894 fontdir
.dfMaxWidth
= font
->otm
.otmTextMetrics
.tmMaxCharWidth
;
6895 fontdir
.dfFirstChar
= font
->otm
.otmTextMetrics
.tmFirstChar
;
6896 fontdir
.dfLastChar
= font
->otm
.otmTextMetrics
.tmLastChar
;
6897 fontdir
.dfDefaultChar
= font
->otm
.otmTextMetrics
.tmDefaultChar
;
6898 fontdir
.dfBreakChar
= font
->otm
.otmTextMetrics
.tmBreakChar
;
6899 fontdir
.dfWidthBytes
= 0;
6900 fontdir
.dfDevice
= 0;
6901 fontdir
.dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
6902 fontdir
.dfReserved
= 0;
6903 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)font
->otm
.otmpFamilyName
, -1,
6904 fontdir
.szFaceName
, LF_FACESIZE
, NULL
, NULL
);
6905 free_gdi_font( font
);
6907 if (hidden
) fontdir
.dfType
|= 0x80;
6908 return create_fot( resource_file
, font_file
, &fontdir
);
6911 if (font
) free_gdi_font( font
);
6912 SetLastError( ERROR_INVALID_PARAMETER
);
6916 /*************************************************************************
6917 * GetKerningPairsA (GDI32.@)
6919 DWORD WINAPI
GetKerningPairsA( HDC hDC
, DWORD cPairs
,
6920 LPKERNINGPAIR kern_pairA
)
6924 DWORD i
, total_kern_pairs
, kern_pairs_copied
= 0;
6925 KERNINGPAIR
*kern_pairW
;
6927 if (!cPairs
&& kern_pairA
)
6929 SetLastError(ERROR_INVALID_PARAMETER
);
6933 cp
= GdiGetCodePage(hDC
);
6935 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
6936 * to fail on an invalid character for CP_SYMBOL.
6938 cpi
.DefaultChar
[0] = 0;
6939 if (cp
!= CP_SYMBOL
&& !GetCPInfo(cp
, &cpi
))
6941 FIXME("Can't find codepage %u info\n", cp
);
6945 total_kern_pairs
= GetKerningPairsW(hDC
, 0, NULL
);
6946 if (!total_kern_pairs
) return 0;
6948 kern_pairW
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pairW
));
6949 GetKerningPairsW(hDC
, total_kern_pairs
, kern_pairW
);
6951 for (i
= 0; i
< total_kern_pairs
; i
++)
6955 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wFirst
, 1, &first
, 1, NULL
, NULL
))
6958 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wSecond
, 1, &second
, 1, NULL
, NULL
))
6961 if (first
== cpi
.DefaultChar
[0] || second
== cpi
.DefaultChar
[0])
6966 if (kern_pairs_copied
>= cPairs
) break;
6968 kern_pairA
->wFirst
= (BYTE
)first
;
6969 kern_pairA
->wSecond
= (BYTE
)second
;
6970 kern_pairA
->iKernAmount
= kern_pairW
[i
].iKernAmount
;
6973 kern_pairs_copied
++;
6976 HeapFree(GetProcessHeap(), 0, kern_pairW
);
6978 return kern_pairs_copied
;
6981 /*************************************************************************
6982 * GetKerningPairsW (GDI32.@)
6984 DWORD WINAPI
GetKerningPairsW( HDC hDC
, DWORD cPairs
,
6985 LPKERNINGPAIR lpKerningPairs
)
6991 TRACE("(%p,%d,%p)\n", hDC
, cPairs
, lpKerningPairs
);
6993 if (!cPairs
&& lpKerningPairs
)
6995 SetLastError(ERROR_INVALID_PARAMETER
);
6999 dc
= get_dc_ptr(hDC
);
7002 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
7003 ret
= dev
->funcs
->pGetKerningPairs( dev
, cPairs
, lpKerningPairs
);
7004 release_dc_ptr( dc
);
7008 /*************************************************************************
7009 * TranslateCharsetInfo [GDI32.@]
7011 * Fills a CHARSETINFO structure for a character set, code page, or
7012 * font. This allows making the correspondence between different labels
7013 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
7014 * of the same encoding.
7016 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
7017 * only one codepage should be set in *lpSrc.
7020 * TRUE on success, FALSE on failure.
7023 BOOL WINAPI
TranslateCharsetInfo(
7024 LPDWORD lpSrc
, /* [in]
7025 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
7026 if flags == TCI_SRCCHARSET: a character set value
7027 if flags == TCI_SRCCODEPAGE: a code page value
7029 LPCHARSETINFO lpCs
, /* [out] structure to receive charset information */
7030 DWORD flags
/* [in] determines interpretation of lpSrc */)
7034 case TCI_SRCFONTSIG
:
7035 while (index
< MAXTCIINDEX
&& !(*lpSrc
>>index
& 0x0001)) index
++;
7037 case TCI_SRCCODEPAGE
:
7038 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciACP
) index
++;
7040 case TCI_SRCCHARSET
:
7041 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciCharset
) index
++;
7046 if (index
>= MAXTCIINDEX
|| FONT_tci
[index
].ciCharset
== DEFAULT_CHARSET
) return FALSE
;
7047 *lpCs
= FONT_tci
[index
];
7051 /*************************************************************************
7052 * GetFontLanguageInfo (GDI32.@)
7054 DWORD WINAPI
GetFontLanguageInfo(HDC hdc
)
7056 FONTSIGNATURE fontsig
;
7057 static const DWORD GCP_DBCS_MASK
=FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
,
7058 GCP_DIACRITIC_MASK
=0x00000000,
7059 FLI_GLYPHS_MASK
=0x00000000,
7060 GCP_GLYPHSHAPE_MASK
=FS_ARABIC
,
7061 GCP_KASHIDA_MASK
=0x00000000,
7062 GCP_LIGATE_MASK
=0x00000000,
7063 GCP_REORDER_MASK
=FS_HEBREW
|FS_ARABIC
;
7067 GetTextCharsetInfo( hdc
, &fontsig
, 0 );
7068 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
7070 if( (fontsig
.fsCsb
[0]&GCP_DBCS_MASK
)!=0 )
7073 if( (fontsig
.fsCsb
[0]&GCP_DIACRITIC_MASK
)!=0 )
7074 result
|=GCP_DIACRITIC
;
7076 if( (fontsig
.fsCsb
[0]&FLI_GLYPHS_MASK
)!=0 )
7079 if( (fontsig
.fsCsb
[0]&GCP_GLYPHSHAPE_MASK
)!=0 )
7080 result
|=GCP_GLYPHSHAPE
;
7082 if( (fontsig
.fsCsb
[0]&GCP_KASHIDA_MASK
)!=0 )
7083 result
|=GCP_KASHIDA
;
7085 if( (fontsig
.fsCsb
[0]&GCP_LIGATE_MASK
)!=0 )
7088 if( GetKerningPairsW( hdc
, 0, NULL
) )
7089 result
|=GCP_USEKERNING
;
7091 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
7092 if( GetTextAlign( hdc
) & TA_RTLREADING
)
7093 if( (fontsig
.fsCsb
[0]&GCP_REORDER_MASK
)!=0 )
7094 result
|=GCP_REORDER
;
7100 /*************************************************************************
7101 * GetFontData [GDI32.@]
7103 * Retrieve data for TrueType font.
7107 * success: Number of bytes returned
7108 * failure: GDI_ERROR
7112 * Calls SetLastError()
7115 DWORD WINAPI
GetFontData(HDC hdc
, DWORD table
, DWORD offset
,
7116 LPVOID buffer
, DWORD length
)
7118 DC
*dc
= get_dc_ptr(hdc
);
7122 if(!dc
) return GDI_ERROR
;
7124 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
7125 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
7126 release_dc_ptr( dc
);
7130 /*************************************************************************
7131 * GetGlyphIndicesA [GDI32.@]
7133 DWORD WINAPI
GetGlyphIndicesA(HDC hdc
, LPCSTR lpstr
, INT count
,
7134 LPWORD pgi
, DWORD flags
)
7140 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7141 hdc
, debugstr_an(lpstr
, count
), count
, pgi
, flags
);
7143 lpstrW
= FONT_mbtowc(hdc
, lpstr
, count
, &countW
, NULL
);
7144 ret
= GetGlyphIndicesW(hdc
, lpstrW
, countW
, pgi
, flags
);
7145 HeapFree(GetProcessHeap(), 0, lpstrW
);
7150 /*************************************************************************
7151 * GetGlyphIndicesW [GDI32.@]
7153 DWORD WINAPI
GetGlyphIndicesW(HDC hdc
, LPCWSTR lpstr
, INT count
,
7154 LPWORD pgi
, DWORD flags
)
7156 DC
*dc
= get_dc_ptr(hdc
);
7160 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7161 hdc
, debugstr_wn(lpstr
, count
), count
, pgi
, flags
);
7163 if(!dc
) return GDI_ERROR
;
7165 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
7166 ret
= dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
7167 release_dc_ptr( dc
);
7171 /*************************************************************************
7172 * GetCharacterPlacementA [GDI32.@]
7174 * See GetCharacterPlacementW.
7177 * the web browser control of ie4 calls this with dwFlags=0
7180 GetCharacterPlacementA(HDC hdc
, LPCSTR lpString
, INT uCount
,
7181 INT nMaxExtent
, GCP_RESULTSA
*lpResults
,
7186 GCP_RESULTSW resultsW
;
7190 TRACE("%s, %d, %d, 0x%08x\n",
7191 debugstr_an(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
7193 lpStringW
= FONT_mbtowc(hdc
, lpString
, uCount
, &uCountW
, &font_cp
);
7197 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, NULL
, dwFlags
);
7198 HeapFree(GetProcessHeap(), 0, lpStringW
);
7202 /* both structs are equal in size */
7203 memcpy(&resultsW
, lpResults
, sizeof(resultsW
));
7205 if(lpResults
->lpOutString
)
7206 resultsW
.lpOutString
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*uCountW
);
7208 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, &resultsW
, dwFlags
);
7210 lpResults
->nGlyphs
= resultsW
.nGlyphs
;
7211 lpResults
->nMaxFit
= resultsW
.nMaxFit
;
7213 if(lpResults
->lpOutString
) {
7214 WideCharToMultiByte(font_cp
, 0, resultsW
.lpOutString
, uCountW
,
7215 lpResults
->lpOutString
, uCount
, NULL
, NULL
);
7218 HeapFree(GetProcessHeap(), 0, lpStringW
);
7219 HeapFree(GetProcessHeap(), 0, resultsW
.lpOutString
);
7224 static int kern_pair(const KERNINGPAIR
*kern
, int count
, WCHAR c1
, WCHAR c2
)
7228 for (i
= 0; i
< count
; i
++)
7230 if (kern
[i
].wFirst
== c1
&& kern
[i
].wSecond
== c2
)
7231 return kern
[i
].iKernAmount
;
7237 static int *kern_string(HDC hdc
, const WCHAR
*str
, int len
, int *kern_total
)
7240 KERNINGPAIR
*kern
= NULL
;
7245 ret
= heap_alloc(len
* sizeof(*ret
));
7246 if (!ret
) return NULL
;
7248 count
= GetKerningPairsW(hdc
, 0, NULL
);
7251 kern
= heap_alloc(count
* sizeof(*kern
));
7258 GetKerningPairsW(hdc
, count
, kern
);
7261 for (i
= 0; i
< len
- 1; i
++)
7263 ret
[i
] = kern_pair(kern
, count
, str
[i
], str
[i
+ 1]);
7264 *kern_total
+= ret
[i
];
7267 ret
[len
- 1] = 0; /* no kerning for last element */
7273 /*************************************************************************
7274 * GetCharacterPlacementW [GDI32.@]
7276 * Retrieve information about a string. This includes the width, reordering,
7277 * Glyphing and so on.
7281 * The width and height of the string if successful, 0 if failed.
7285 * All flags except GCP_REORDER are not yet implemented.
7286 * Reordering is not 100% compliant to the Windows BiDi method.
7287 * Caret positioning is not yet implemented for BiDi.
7288 * Classes are not yet implemented.
7292 GetCharacterPlacementW(
7293 HDC hdc
, /* [in] Device context for which the rendering is to be done */
7294 LPCWSTR lpString
, /* [in] The string for which information is to be returned */
7295 INT uCount
, /* [in] Number of WORDS in string. */
7296 INT nMaxExtent
, /* [in] Maximum extent the string is to take (in HDC logical units) */
7297 GCP_RESULTSW
*lpResults
, /* [in/out] A pointer to a GCP_RESULTSW struct */
7298 DWORD dwFlags
/* [in] Flags specifying how to process the string */
7304 int *kern
= NULL
, kern_total
= 0;
7306 TRACE("%s, %d, %d, 0x%08x\n",
7307 debugstr_wn(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
7313 return GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
) ? MAKELONG(size
.cx
, size
.cy
) : 0;
7315 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
7316 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
7317 lpResults
->lStructSize
, lpResults
->lpOutString
, lpResults
->lpOrder
,
7318 lpResults
->lpDx
, lpResults
->lpCaretPos
, lpResults
->lpClass
,
7319 lpResults
->lpGlyphs
, lpResults
->nGlyphs
, lpResults
->nMaxFit
);
7321 if (dwFlags
& ~(GCP_REORDER
| GCP_USEKERNING
))
7322 FIXME("flags 0x%08x ignored\n", dwFlags
);
7323 if (lpResults
->lpClass
)
7324 FIXME("classes not implemented\n");
7325 if (lpResults
->lpCaretPos
&& (dwFlags
& GCP_REORDER
))
7326 FIXME("Caret positions for complex scripts not implemented\n");
7328 nSet
= (UINT
)uCount
;
7329 if (nSet
> lpResults
->nGlyphs
)
7330 nSet
= lpResults
->nGlyphs
;
7332 /* return number of initialized fields */
7333 lpResults
->nGlyphs
= nSet
;
7335 if (!(dwFlags
& GCP_REORDER
))
7337 /* Treat the case where no special handling was requested in a fastpath way */
7338 /* copy will do if the GCP_REORDER flag is not set */
7339 if (lpResults
->lpOutString
)
7340 memcpy( lpResults
->lpOutString
, lpString
, nSet
* sizeof(WCHAR
));
7342 if (lpResults
->lpOrder
)
7344 for (i
= 0; i
< nSet
; i
++)
7345 lpResults
->lpOrder
[i
] = i
;
7350 BIDI_Reorder(NULL
, lpString
, uCount
, dwFlags
, WINE_GCPW_FORCE_LTR
, lpResults
->lpOutString
,
7351 nSet
, lpResults
->lpOrder
, NULL
, NULL
);
7354 if (dwFlags
& GCP_USEKERNING
)
7356 kern
= kern_string(hdc
, lpString
, nSet
, &kern_total
);
7359 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
7364 /* FIXME: Will use the placement chars */
7365 if (lpResults
->lpDx
)
7368 for (i
= 0; i
< nSet
; i
++)
7370 if (GetCharWidth32W(hdc
, lpString
[i
], lpString
[i
], &c
))
7372 lpResults
->lpDx
[i
] = c
;
7373 if (dwFlags
& GCP_USEKERNING
)
7374 lpResults
->lpDx
[i
] += kern
[i
];
7379 if (lpResults
->lpCaretPos
&& !(dwFlags
& GCP_REORDER
))
7383 lpResults
->lpCaretPos
[0] = 0;
7384 for (i
= 0; i
< nSet
- 1; i
++)
7386 if (dwFlags
& GCP_USEKERNING
)
7389 if (GetTextExtentPoint32W(hdc
, &lpString
[i
], 1, &size
))
7390 lpResults
->lpCaretPos
[i
+ 1] = (pos
+= size
.cx
);
7394 if (lpResults
->lpGlyphs
)
7395 GetGlyphIndicesW(hdc
, lpString
, nSet
, lpResults
->lpGlyphs
, 0);
7397 if (GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
))
7398 ret
= MAKELONG(size
.cx
+ kern_total
, size
.cy
);
7405 /*************************************************************************
7406 * GetCharABCWidthsFloatA [GDI32.@]
7408 * See GetCharABCWidthsFloatW.
7410 BOOL WINAPI
GetCharABCWidthsFloatA( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
7417 str
= FONT_GetCharsByRangeA(hdc
, first
, last
, &i
);
7421 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
7423 for (i
= 0; i
< wlen
; i
++)
7425 if (!GetCharABCWidthsFloatW( hdc
, wstr
[i
], wstr
[i
], abcf
))
7433 HeapFree( GetProcessHeap(), 0, str
);
7434 HeapFree( GetProcessHeap(), 0, wstr
);
7439 /*************************************************************************
7440 * GetCharABCWidthsFloatW [GDI32.@]
7442 * Retrieves widths of a range of characters.
7445 * hdc [I] Handle to device context.
7446 * first [I] First character in range to query.
7447 * last [I] Last character in range to query.
7448 * abcf [O] Array of LPABCFLOAT structures.
7454 BOOL WINAPI
GetCharABCWidthsFloatW( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
7460 DC
*dc
= get_dc_ptr( hdc
);
7462 TRACE("%p, %d, %d, %p\n", hdc
, first
, last
, abcf
);
7464 if (!dc
) return FALSE
;
7466 if (!abcf
) goto done
;
7467 if (!(abc
= HeapAlloc( GetProcessHeap(), 0, (last
- first
+ 1) * sizeof(*abc
) ))) goto done
;
7469 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
7470 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, abc
);
7473 /* convert device units to logical */
7474 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
7475 for (i
= first
; i
<= last
; i
++, abcf
++)
7477 abcf
->abcfA
= abc
[i
- first
].abcA
* scale
;
7478 abcf
->abcfB
= abc
[i
- first
].abcB
* scale
;
7479 abcf
->abcfC
= abc
[i
- first
].abcC
* scale
;
7482 HeapFree( GetProcessHeap(), 0, abc
);
7485 release_dc_ptr( dc
);
7489 /*************************************************************************
7490 * GetCharWidthFloatA [GDI32.@]
7492 BOOL WINAPI
GetCharWidthFloatA( HDC hdc
, UINT first
, UINT last
, float *buffer
)
7498 if (!(str
= FONT_GetCharsByRangeA( hdc
, first
, last
, &i
)))
7500 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
7503 for (i
= 0; i
< wlen
; ++i
)
7505 if (!GetCharWidthFloatW( hdc
, wstr
[i
], wstr
[i
], &buffer
[i
] ))
7515 /*************************************************************************
7516 * GetCharWidthFloatW [GDI32.@]
7518 BOOL WINAPI
GetCharWidthFloatW( HDC hdc
, UINT first
, UINT last
, float *buffer
)
7520 DC
*dc
= get_dc_ptr( hdc
);
7526 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc
, first
, last
, buffer
);
7528 if (!dc
) return FALSE
;
7530 if (!(ibuffer
= heap_alloc( (last
- first
+ 1) * sizeof(int) )))
7532 release_dc_ptr( dc
);
7536 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
7537 if ((ret
= dev
->funcs
->pGetCharWidth( dev
, first
, last
, ibuffer
)))
7539 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
7540 for (i
= first
; i
<= last
; ++i
)
7541 buffer
[i
- first
] = ibuffer
[i
- first
] * scale
;
7548 /***********************************************************************
7550 * Font Resource API *
7552 ***********************************************************************/
7554 /***********************************************************************
7555 * AddFontResourceA (GDI32.@)
7557 INT WINAPI
AddFontResourceA( LPCSTR str
)
7559 return AddFontResourceExA( str
, 0, NULL
);
7562 /***********************************************************************
7563 * AddFontResourceW (GDI32.@)
7565 INT WINAPI
AddFontResourceW( LPCWSTR str
)
7567 return AddFontResourceExW(str
, 0, NULL
);
7571 /***********************************************************************
7572 * AddFontResourceExA (GDI32.@)
7574 INT WINAPI
AddFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
7576 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
7577 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7580 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
7581 ret
= AddFontResourceExW(strW
, fl
, pdv
);
7582 HeapFree(GetProcessHeap(), 0, strW
);
7586 static BOOL CALLBACK
load_enumed_resource(HMODULE hModule
, LPCWSTR type
, LPWSTR name
, LONG_PTR lParam
)
7588 HRSRC rsrc
= FindResourceW(hModule
, name
, type
);
7589 HGLOBAL hMem
= LoadResource(hModule
, rsrc
);
7590 LPVOID
*pMem
= LockResource(hMem
);
7591 int *num_total
= (int *)lParam
;
7594 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type
));
7595 if (!AddFontMemResourceEx(pMem
, SizeofResource(hModule
, rsrc
), NULL
, &num_in_res
))
7597 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule
, hMem
);
7601 *num_total
+= num_in_res
;
7605 static void *map_file( const WCHAR
*filename
, LARGE_INTEGER
*size
)
7607 HANDLE file
, mapping
;
7610 file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7611 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
7613 if (!GetFileSizeEx( file
, size
) || size
->u
.HighPart
)
7615 CloseHandle( file
);
7619 mapping
= CreateFileMappingW( file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
7620 CloseHandle( file
);
7621 if (!mapping
) return NULL
;
7623 ptr
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
7624 CloseHandle( mapping
);
7629 static void *find_resource( BYTE
*ptr
, WORD type
, DWORD rsrc_off
, DWORD size
, DWORD
*len
)
7631 WORD align
, type_id
, count
;
7634 if (size
< rsrc_off
+ 10) return NULL
;
7635 align
= *(WORD
*)(ptr
+ rsrc_off
);
7637 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
7638 while (type_id
&& type_id
!= type
)
7640 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
7641 rsrc_off
+= 8 + count
* 12;
7642 if (size
< rsrc_off
+ 8) return NULL
;
7643 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
7645 if (!type_id
) return NULL
;
7646 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
7647 if (size
< rsrc_off
+ 8 + count
* 12) return NULL
;
7648 res_off
= *(WORD
*)(ptr
+ rsrc_off
+ 8) << align
;
7649 *len
= *(WORD
*)(ptr
+ rsrc_off
+ 10) << align
;
7650 if (size
< res_off
+ *len
) return NULL
;
7651 return ptr
+ res_off
;
7654 static WCHAR
*get_scalable_filename( const WCHAR
*res
, BOOL
*hidden
)
7657 BYTE
*ptr
= map_file( res
, &size
);
7658 const IMAGE_DOS_HEADER
*dos
;
7659 const IMAGE_OS2_HEADER
*ne
;
7665 if (!ptr
) return NULL
;
7667 if (size
.u
.LowPart
< sizeof( *dos
)) goto fail
;
7668 dos
= (const IMAGE_DOS_HEADER
*)ptr
;
7669 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto fail
;
7670 if (size
.u
.LowPart
< dos
->e_lfanew
+ sizeof( *ne
)) goto fail
;
7671 ne
= (const IMAGE_OS2_HEADER
*)(ptr
+ dos
->e_lfanew
);
7673 fontdir
= find_resource( ptr
, 0x8007, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
7674 if (!fontdir
) goto fail
;
7675 *hidden
= (fontdir
[35] & 0x80) != 0; /* fontdir->dfType */
7677 data
= find_resource( ptr
, 0x80cc, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
7678 if (!data
) goto fail
;
7679 if (!memchr( data
, 0, len
)) goto fail
;
7681 len
= MultiByteToWideChar( CP_ACP
, 0, data
, -1, NULL
, 0 );
7682 name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
7683 if (name
) MultiByteToWideChar( CP_ACP
, 0, data
, -1, name
, len
);
7686 UnmapViewOfFile( ptr
);
7690 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
7692 WCHAR path
[MAX_PATH
];
7695 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
7696 get_fonts_win_dir_path( file
, path
);
7697 EnterCriticalSection( &font_cs
);
7698 ret
= font_funcs
->add_font( path
, flags
);
7699 LeaveCriticalSection( &font_cs
);
7700 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
7703 get_fonts_data_dir_path( file
, path
);
7704 EnterCriticalSection( &font_cs
);
7705 ret
= font_funcs
->add_font( path
, flags
);
7706 LeaveCriticalSection( &font_cs
);
7711 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
7713 WCHAR path
[MAX_PATH
];
7716 get_fonts_win_dir_path( file
, path
);
7717 if (!(ret
= remove_font( path
, flags
)))
7719 get_fonts_data_dir_path( file
, path
);
7720 ret
= remove_font( path
, flags
);
7725 static int add_font_resource( LPCWSTR file
, DWORD flags
)
7727 WCHAR path
[MAX_PATH
];
7730 if (GetFullPathNameW( file
, MAX_PATH
, path
, NULL
))
7732 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
7734 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
7735 EnterCriticalSection( &font_cs
);
7736 ret
= font_funcs
->add_font( path
, addfont_flags
);
7737 LeaveCriticalSection( &font_cs
);
7740 if (!ret
&& !wcschr( file
, '\\' ))
7741 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
7746 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
7748 WCHAR path
[MAX_PATH
];
7751 if (GetFullPathNameW( file
, MAX_PATH
, path
, NULL
))
7753 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
7755 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
7756 ret
= remove_font( path
, addfont_flags
);
7759 if (!ret
&& !wcschr( file
, '\\' ))
7760 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
7765 static void load_system_bitmap_fonts(void)
7767 static const WCHAR
* const fonts
[] = { L
"FONTS.FON", L
"OEMFONT.FON", L
"FIXEDFON.FON" };
7769 WCHAR data
[MAX_PATH
];
7770 DWORD i
, dlen
, type
;
7772 if (RegOpenKeyW( HKEY_CURRENT_CONFIG
, L
"Software\\Fonts", &hkey
)) return;
7773 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
7775 dlen
= sizeof(data
);
7776 if (!RegQueryValueExW( hkey
, fonts
[i
], 0, &type
, (BYTE
*)data
, &dlen
) && type
== REG_SZ
)
7777 add_system_font_resource( data
, ADDFONT_ALLOW_BITMAP
);
7779 RegCloseKey( hkey
);
7782 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
7785 WIN32_FIND_DATAW data
;
7788 p
= path
+ lstrlenW(path
) - 1;
7789 TRACE( "loading fonts from %s\n", debugstr_w(path
) );
7790 handle
= FindFirstFileW( path
, &data
);
7791 if (handle
== INVALID_HANDLE_VALUE
) return;
7794 if (data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) continue;
7795 lstrcpyW( p
, data
.cFileName
);
7796 font_funcs
->add_font( path
, flags
);
7797 } while (FindNextFileW( handle
, &data
));
7798 FindClose( handle
);
7801 static void load_file_system_fonts(void)
7803 WCHAR
*ptr
, *next
, path
[MAX_PATH
], value
[1024];
7804 DWORD len
= ARRAY_SIZE(value
);
7806 /* Windows directory */
7807 get_fonts_win_dir_path( L
"*", path
);
7808 load_directory_fonts( path
, 0 );
7810 /* Wine data directory */
7811 get_fonts_data_dir_path( L
"*", path
);
7812 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
7815 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
7816 if (!RegQueryValueExW( wine_fonts_key
, L
"Path", NULL
, NULL
, (BYTE
*)value
, &len
))
7818 for (ptr
= value
; ptr
; ptr
= next
)
7820 if ((next
= wcschr( ptr
, ';' ))) *next
++ = 0;
7821 if (next
&& next
- ptr
< 2) continue;
7822 lstrcpynW( path
, ptr
, MAX_PATH
- 2 );
7823 lstrcatW( path
, L
"\\*" );
7824 load_directory_fonts( path
, ADDFONT_EXTERNAL_FONT
);
7832 WCHAR value
[LF_FULLFACESIZE
+ 12];
7835 static void update_external_font_keys(void)
7837 struct list external_keys
= LIST_INIT(external_keys
);
7838 HKEY winnt_key
= 0, win9x_key
= 0;
7839 struct gdi_font_family
*family
;
7840 struct external_key
*key
, *next
;
7841 struct gdi_font_face
*face
;
7842 DWORD len
, i
= 0, type
, dlen
, vlen
;
7843 WCHAR value
[LF_FULLFACESIZE
+ 12], path
[MAX_PATH
], *tmp
;
7847 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
7848 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
);
7849 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
7850 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
);
7852 /* enumerate the fonts and add external ones to the two keys */
7854 if (RegCreateKeyW( wine_fonts_key
, L
"External Fonts", &hkey
)) return;
7856 vlen
= ARRAY_SIZE(value
);
7857 dlen
= sizeof(path
);
7858 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)path
, &dlen
))
7860 if (type
!= REG_SZ
) goto next
;
7861 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, L
" (TrueType)", -1 )) *tmp
= 0;
7862 if ((face
= find_face_from_full_name( value
)) && !wcsicmp( face
->file
, path
))
7864 face
->flags
|= ADDFONT_EXTERNAL_FOUND
;
7867 if (tmp
&& !*tmp
) *tmp
= ' ';
7868 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) ))) break;
7869 lstrcpyW( key
->value
, value
);
7870 list_add_tail( &external_keys
, &key
->entry
);
7872 vlen
= ARRAY_SIZE(value
);
7873 dlen
= sizeof(path
);
7876 WINE_RB_FOR_EACH_ENTRY( family
, &family_name_tree
, struct gdi_font_family
, name_entry
)
7878 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
7880 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
7881 if ((face
->flags
& ADDFONT_EXTERNAL_FOUND
)) continue;
7883 lstrcpyW( value
, face
->full_name
);
7884 if (face
->scalable
) lstrcatW( value
, L
" (TrueType)" );
7886 if (GetFullPathNameW( face
->file
, MAX_PATH
, path
, NULL
))
7888 else if ((file
= wcsrchr( face
->file
, '\\' )))
7893 len
= (lstrlenW(file
) + 1) * sizeof(WCHAR
);
7894 RegSetValueExW( winnt_key
, value
, 0, REG_SZ
, (BYTE
*)file
, len
);
7895 RegSetValueExW( win9x_key
, value
, 0, REG_SZ
, (BYTE
*)file
, len
);
7896 RegSetValueExW( hkey
, value
, 0, REG_SZ
, (BYTE
*)file
, len
);
7899 LIST_FOR_EACH_ENTRY_SAFE( key
, next
, &external_keys
, struct external_key
, entry
)
7901 RegDeleteValueW( win9x_key
, key
->value
);
7902 RegDeleteValueW( winnt_key
, key
->value
);
7903 RegDeleteValueW( hkey
, key
->value
);
7904 list_remove( &key
->entry
);
7905 HeapFree( GetProcessHeap(), 0, key
);
7907 RegCloseKey( win9x_key
);
7908 RegCloseKey( winnt_key
);
7909 RegCloseKey( hkey
);
7912 static void load_registry_fonts(void)
7914 WCHAR value
[LF_FULLFACESIZE
+ 12], data
[MAX_PATH
], *tmp
;
7915 DWORD i
= 0, type
, dlen
, vlen
;
7918 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
7919 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
7920 full path as the entry. Also look for any .fon fonts, since ReadFontDir
7922 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
,
7923 is_win9x() ? L
"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts" :
7924 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey
))
7927 vlen
= ARRAY_SIZE(value
);
7928 dlen
= sizeof(data
);
7929 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, NULL
, NULL
))
7931 if (type
!= REG_SZ
) goto next
;
7932 dlen
/= sizeof(WCHAR
);
7933 if ((tmp
= wcsrchr( value
, ' ' )) && !facename_compare( tmp
, L
" (TrueType)", -1 )) *tmp
= 0;
7934 if (find_face_from_full_name( value
)) goto next
;
7935 if (tmp
&& !*tmp
) *tmp
= ' ';
7937 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (LPBYTE
)data
, &dlen
))
7939 WARN( "Unable to get face path %s\n", debugstr_w(value
) );
7943 dlen
/= sizeof(WCHAR
);
7944 if (data
[0] && data
[1] == ':')
7945 add_font_resource( data
, ADDFONT_ALLOW_BITMAP
);
7946 else if (dlen
>= 6 && !wcsicmp( data
+ dlen
- 5, L
".fon" ))
7947 add_system_font_resource( data
, ADDFONT_ALLOW_BITMAP
);
7949 vlen
= ARRAY_SIZE(value
);
7950 dlen
= sizeof(data
);
7952 RegCloseKey( hkey
);
7955 static const struct font_callback_funcs callback_funcs
= { add_gdi_face
};
7957 /***********************************************************************
7960 void font_init(void)
7965 if (RegCreateKeyExW( HKEY_CURRENT_USER
, L
"Software\\Wine\\Fonts", 0, NULL
, 0,
7966 KEY_ALL_ACCESS
, NULL
, &wine_fonts_key
, NULL
))
7969 init_font_options();
7971 if (__wine_init_unix_lib( gdi32_module
, DLL_PROCESS_ATTACH
, &callback_funcs
, &font_funcs
)) return;
7973 load_system_bitmap_fonts();
7974 load_file_system_fonts();
7975 font_funcs
->load_fonts();
7977 if (!(mutex
= CreateMutexW( NULL
, FALSE
, L
"__WINE_FONT_MUTEX__" ))) return;
7978 WaitForSingleObject( mutex
, INFINITE
);
7980 RegCreateKeyExW( wine_fonts_key
, L
"Cache", 0, NULL
, REG_OPTION_VOLATILE
,
7981 KEY_ALL_ACCESS
, NULL
, &wine_fonts_cache_key
, &disposition
);
7983 if (disposition
== REG_CREATED_NEW_KEY
)
7985 load_registry_fonts();
7986 update_external_font_keys();
7989 ReleaseMutex( mutex
);
7991 if (disposition
!= REG_CREATED_NEW_KEY
)
7993 load_registry_fonts();
7994 load_font_list_from_cache();
7997 reorder_font_list();
7998 load_gdi_font_subst();
7999 load_gdi_font_replacements();
8000 load_system_links();
8001 dump_gdi_font_list();
8002 dump_gdi_font_subst();
8005 /***********************************************************************
8006 * AddFontResourceExW (GDI32.@)
8008 INT WINAPI
AddFontResourceExW( LPCWSTR str
, DWORD flags
, PVOID pdv
)
8014 if (!font_funcs
) return 1;
8015 if (!(ret
= add_font_resource( str
, flags
)))
8017 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8018 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
8019 if (hModule
!= NULL
)
8021 int num_resources
= 0;
8022 LPWSTR rt_font
= (LPWSTR
)((ULONG_PTR
)8); /* we don't want to include winuser.h */
8024 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
8025 wine_dbgstr_w(str
));
8026 if (EnumResourceNamesW(hModule
, rt_font
, load_enumed_resource
, (LONG_PTR
)&num_resources
))
8027 ret
= num_resources
;
8028 FreeLibrary(hModule
);
8030 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
8032 if (hidden
) flags
|= FR_PRIVATE
| FR_NOT_ENUM
;
8033 ret
= add_font_resource( filename
, flags
);
8034 HeapFree( GetProcessHeap(), 0, filename
);
8040 /***********************************************************************
8041 * RemoveFontResourceA (GDI32.@)
8043 BOOL WINAPI
RemoveFontResourceA( LPCSTR str
)
8045 return RemoveFontResourceExA(str
, 0, 0);
8048 /***********************************************************************
8049 * RemoveFontResourceW (GDI32.@)
8051 BOOL WINAPI
RemoveFontResourceW( LPCWSTR str
)
8053 return RemoveFontResourceExW(str
, 0, 0);
8056 /***********************************************************************
8057 * AddFontMemResourceEx (GDI32.@)
8059 HANDLE WINAPI
AddFontMemResourceEx( PVOID ptr
, DWORD size
, PVOID pdv
, DWORD
*pcFonts
)
8065 if (!ptr
|| !size
|| !pcFonts
)
8067 SetLastError(ERROR_INVALID_PARAMETER
);
8070 if (!font_funcs
) return NULL
;
8071 if (!(copy
= HeapAlloc( GetProcessHeap(), 0, size
))) return NULL
;
8072 memcpy( copy
, ptr
, size
);
8074 EnterCriticalSection( &font_cs
);
8075 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
8076 LeaveCriticalSection( &font_cs
);
8080 HeapFree( GetProcessHeap(), 0, copy
);
8084 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
8085 * For now return something unique but quite random
8087 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
8091 *pcFonts
= num_fonts
;
8095 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts
);
8096 RemoveFontMemResourceEx( ret
);
8100 TRACE( "Returning handle %p\n", ret
);
8104 /***********************************************************************
8105 * RemoveFontMemResourceEx (GDI32.@)
8107 BOOL WINAPI
RemoveFontMemResourceEx( HANDLE fh
)
8109 FIXME("(%p) stub\n", fh
);
8113 /***********************************************************************
8114 * RemoveFontResourceExA (GDI32.@)
8116 BOOL WINAPI
RemoveFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
8118 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
8119 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8122 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
8123 ret
= RemoveFontResourceExW(strW
, fl
, pdv
);
8124 HeapFree(GetProcessHeap(), 0, strW
);
8128 /***********************************************************************
8129 * RemoveFontResourceExW (GDI32.@)
8131 BOOL WINAPI
RemoveFontResourceExW( LPCWSTR str
, DWORD flags
, PVOID pdv
)
8137 if (!font_funcs
) return TRUE
;
8139 if (!(ret
= remove_font_resource( str
, flags
)))
8141 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8142 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
8143 if (hModule
!= NULL
)
8145 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str
));
8146 FreeLibrary(hModule
);
8148 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
8150 if (hidden
) flags
|= FR_PRIVATE
| FR_NOT_ENUM
;
8151 ret
= remove_font_resource( filename
, flags
);
8152 HeapFree( GetProcessHeap(), 0, filename
);
8158 /***********************************************************************
8159 * GetFontResourceInfoW (GDI32.@)
8161 BOOL WINAPI
GetFontResourceInfoW( LPCWSTR str
, LPDWORD size
, PVOID buffer
, DWORD type
)
8163 FIXME("%s %p(%d) %p %d\n", debugstr_w(str
), size
, size
? *size
: 0, buffer
, type
);
8167 /***********************************************************************
8168 * GetTextCharset (GDI32.@)
8170 UINT WINAPI
GetTextCharset(HDC hdc
)
8172 /* MSDN docs say this is equivalent */
8173 return GetTextCharsetInfo(hdc
, NULL
, 0);
8176 /***********************************************************************
8177 * GdiGetCharDimensions (GDI32.@)
8179 * Gets the average width of the characters in the English alphabet.
8182 * hdc [I] Handle to the device context to measure on.
8183 * lptm [O] Pointer to memory to store the text metrics into.
8184 * height [O] On exit, the maximum height of characters in the English alphabet.
8187 * The average width of characters in the English alphabet.
8190 * This function is used by the dialog manager to get the size of a dialog
8191 * unit. It should also be used by other pieces of code that need to know
8192 * the size of a dialog unit in logical units without having access to the
8193 * window handle of the dialog.
8194 * Windows caches the font metrics from this function, but we don't and
8195 * there doesn't appear to be an immediate advantage to do so.
8198 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
8200 LONG WINAPI
GdiGetCharDimensions(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
)
8204 if(lptm
&& !GetTextMetricsW(hdc
, lptm
)) return 0;
8206 if(!GetTextExtentPointW(hdc
, L
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52, &sz
))
8209 if (height
) *height
= sz
.cy
;
8210 return (sz
.cx
/ 26 + 1) / 2;
8213 BOOL WINAPI
EnableEUDC(BOOL fEnableEUDC
)
8215 FIXME("(%d): stub\n", fEnableEUDC
);
8219 /***********************************************************************
8220 * GetCharWidthI (GDI32.@)
8222 * Retrieve widths of characters.
8225 * hdc [I] Handle to a device context.
8226 * first [I] First glyph in range to query.
8227 * count [I] Number of glyph indices to query.
8228 * glyphs [I] Array of glyphs to query.
8229 * buffer [O] Buffer to receive character widths.
8232 * Only works with TrueType fonts.
8238 BOOL WINAPI
GetCharWidthI(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPINT buffer
)
8243 TRACE("(%p, %d, %d, %p, %p)\n", hdc
, first
, count
, glyphs
, buffer
);
8245 if (!(abc
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(ABC
))))
8248 if (!GetCharABCWidthsI(hdc
, first
, count
, glyphs
, abc
))
8250 HeapFree(GetProcessHeap(), 0, abc
);
8254 for (i
= 0; i
< count
; i
++)
8255 buffer
[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
8257 HeapFree(GetProcessHeap(), 0, abc
);
8261 /***********************************************************************
8262 * GetFontUnicodeRanges (GDI32.@)
8264 * Retrieve a list of supported Unicode characters in a font.
8267 * hdc [I] Handle to a device context.
8268 * lpgs [O] GLYPHSET structure specifying supported character ranges.
8271 * Success: Number of bytes written to the buffer pointed to by lpgs.
8275 DWORD WINAPI
GetFontUnicodeRanges(HDC hdc
, LPGLYPHSET lpgs
)
8279 DC
*dc
= get_dc_ptr(hdc
);
8281 TRACE("(%p, %p)\n", hdc
, lpgs
);
8285 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
8286 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
8292 /*************************************************************
8293 * FontIsLinked (GDI32.@)
8295 BOOL WINAPI
FontIsLinked(HDC hdc
)
8297 DC
*dc
= get_dc_ptr(hdc
);
8301 if (!dc
) return FALSE
;
8302 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
8303 ret
= dev
->funcs
->pFontIsLinked( dev
);
8305 TRACE("returning %d\n", ret
);
8309 /*************************************************************
8310 * GetFontRealizationInfo (GDI32.@)
8312 BOOL WINAPI
GetFontRealizationInfo(HDC hdc
, struct font_realization_info
*info
)
8314 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, unk
);
8319 if (info
->size
!= sizeof(*info
) && !is_v0
)
8322 dc
= get_dc_ptr(hdc
);
8323 if (!dc
) return FALSE
;
8324 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
8325 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
8330 /*************************************************************************
8331 * GetRasterizerCaps (GDI32.@)
8333 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8335 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8336 lprs
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
8337 lprs
->nLanguageID
= 0;
8341 /*************************************************************************
8342 * GetFontFileData (GDI32.@)
8344 BOOL WINAPI
GetFontFileData( DWORD instance_id
, DWORD unknown
, UINT64 offset
, void *buff
, DWORD buff_size
)
8346 struct gdi_font
*font
;
8347 DWORD tag
= 0, size
;
8350 if (!font_funcs
) return FALSE
;
8351 EnterCriticalSection( &font_cs
);
8352 if ((font
= get_font_from_handle( instance_id
)))
8354 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
8355 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
8356 if (size
!= GDI_ERROR
&& size
>= buff_size
&& offset
<= size
- buff_size
)
8357 ret
= font_funcs
->get_font_data( font
, tag
, offset
, buff
, buff_size
) != GDI_ERROR
;
8359 SetLastError( ERROR_INVALID_PARAMETER
);
8361 LeaveCriticalSection( &font_cs
);
8365 /* Undocumented structure filled in by GetFontFileInfo */
8366 struct font_fileinfo
8373 /*************************************************************************
8374 * GetFontFileInfo (GDI32.@)
8376 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
,
8377 SIZE_T size
, SIZE_T
*needed
)
8379 SIZE_T required_size
= 0;
8380 struct gdi_font
*font
;
8383 EnterCriticalSection( &font_cs
);
8385 if ((font
= get_font_from_handle( instance_id
)))
8387 required_size
= sizeof(*info
) + lstrlenW( font
->file
) * sizeof(WCHAR
);
8388 if (required_size
<= size
)
8390 info
->writetime
= font
->writetime
;
8391 info
->size
.QuadPart
= font
->data_size
;
8392 lstrcpyW( info
->path
, font
->file
);
8395 else SetLastError( ERROR_INSUFFICIENT_BUFFER
);
8398 LeaveCriticalSection( &font_cs
);
8399 if (needed
) *needed
= required_size
;
8403 struct realization_info
8405 DWORD flags
; /* 1 for bitmap fonts, 3 for scalable fonts */
8406 DWORD cache_num
; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
8407 DWORD instance_id
; /* identifies a realized font instance */
8410 /*************************************************************
8411 * GdiRealizationInfo (GDI32.@)
8413 * Returns a structure that contains some font information.
8415 BOOL WINAPI
GdiRealizationInfo(HDC hdc
, struct realization_info
*info
)
8417 struct font_realization_info ri
;
8420 ri
.size
= sizeof(ri
);
8421 ret
= GetFontRealizationInfo( hdc
, &ri
);
8424 info
->flags
= ri
.flags
;
8425 info
->cache_num
= ri
.cache_num
;
8426 info
->instance_id
= ri
.instance_id
;
8432 /*************************************************************
8433 * GetCharWidthInfo (GDI32.@)
8436 BOOL WINAPI
GetCharWidthInfo(HDC hdc
, struct char_width_info
*info
)
8442 dc
= get_dc_ptr(hdc
);
8443 if (!dc
) return FALSE
;
8444 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
8445 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
8449 info
->lsb
= width_to_LP( dc
, info
->lsb
);
8450 info
->rsb
= width_to_LP( dc
, info
->rsb
);