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
24 #include "wine/port.h"
37 #include "gdi_private.h"
39 #include "wine/exception.h"
40 #include "wine/heap.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(font
);
46 static HKEY wine_fonts_key
;
50 struct gdi_physdev dev
;
51 struct gdi_font
*font
;
54 static inline struct font_physdev
*get_font_dev( PHYSDEV dev
)
56 return (struct font_physdev
*)dev
;
59 static const struct font_backend_funcs
*font_funcs
;
61 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
63 static UINT font_smoothing
= GGO_BITMAP
;
64 static UINT subpixel_orientation
= GGO_GRAY4_BITMAP
;
65 static BOOL antialias_fakes
= TRUE
;
67 /* Device -> World size conversion */
69 /* Performs a device to world transformation on the specified width (which
70 * is in integer format).
72 static inline INT
INTERNAL_XDSTOWS(DC
*dc
, INT width
)
76 /* Perform operation with floating point */
77 floatWidth
= (double)width
* dc
->xformVport2World
.eM11
;
78 /* Round to integers */
79 return GDI_ROUND(floatWidth
);
82 /* Performs a device to world transformation on the specified size (which
83 * is in integer format).
85 static inline INT
INTERNAL_YDSTOWS(DC
*dc
, INT height
)
89 /* Perform operation with floating point */
90 floatHeight
= (double)height
* dc
->xformVport2World
.eM22
;
91 /* Round to integers */
92 return GDI_ROUND(floatHeight
);
95 /* scale width and height but don't mirror them */
97 static inline INT
width_to_LP( DC
*dc
, INT width
)
99 return GDI_ROUND( (double)width
* fabs( dc
->xformVport2World
.eM11
));
102 static inline INT
height_to_LP( DC
*dc
, INT height
)
104 return GDI_ROUND( (double)height
* fabs( dc
->xformVport2World
.eM22
));
107 static inline INT
INTERNAL_YWSTODS(DC
*dc
, INT height
)
110 pt
[0].x
= pt
[0].y
= 0;
114 return pt
[1].y
- pt
[0].y
;
117 static inline BOOL
is_win9x(void)
119 return GetVersion() & 0x80000000;
122 static inline WCHAR
*strdupW( const WCHAR
*p
)
125 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
126 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
131 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
);
132 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
);
133 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
);
134 static BOOL
FONT_DeleteObject( HGDIOBJ handle
);
136 static const struct gdi_obj_funcs fontobj_funcs
=
138 FONT_SelectObject
, /* pSelectObject */
139 FONT_GetObjectA
, /* pGetObjectA */
140 FONT_GetObjectW
, /* pGetObjectW */
141 NULL
, /* pUnrealizeObject */
142 FONT_DeleteObject
/* pDeleteObject */
152 LPLOGFONTW lpLogFontParam
;
153 FONTENUMPROCW lpEnumFunc
;
161 * For TranslateCharsetInfo
163 #define MAXTCIINDEX 32
164 static const CHARSETINFO FONT_tci
[MAXTCIINDEX
] = {
166 { ANSI_CHARSET
, 1252, {{0,0,0,0},{FS_LATIN1
,0}} },
167 { EASTEUROPE_CHARSET
, 1250, {{0,0,0,0},{FS_LATIN2
,0}} },
168 { RUSSIAN_CHARSET
, 1251, {{0,0,0,0},{FS_CYRILLIC
,0}} },
169 { GREEK_CHARSET
, 1253, {{0,0,0,0},{FS_GREEK
,0}} },
170 { TURKISH_CHARSET
, 1254, {{0,0,0,0},{FS_TURKISH
,0}} },
171 { HEBREW_CHARSET
, 1255, {{0,0,0,0},{FS_HEBREW
,0}} },
172 { ARABIC_CHARSET
, 1256, {{0,0,0,0},{FS_ARABIC
,0}} },
173 { BALTIC_CHARSET
, 1257, {{0,0,0,0},{FS_BALTIC
,0}} },
174 { VIETNAMESE_CHARSET
, 1258, {{0,0,0,0},{FS_VIETNAMESE
,0}} },
175 /* reserved by ANSI */
176 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
177 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
178 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
179 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
180 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
181 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
182 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
184 { THAI_CHARSET
, 874, {{0,0,0,0},{FS_THAI
,0}} },
185 { SHIFTJIS_CHARSET
, 932, {{0,0,0,0},{FS_JISJAPAN
,0}} },
186 { GB2312_CHARSET
, 936, {{0,0,0,0},{FS_CHINESESIMP
,0}} },
187 { HANGEUL_CHARSET
, 949, {{0,0,0,0},{FS_WANSUNG
,0}} },
188 { CHINESEBIG5_CHARSET
, 950, {{0,0,0,0},{FS_CHINESETRAD
,0}} },
189 { JOHAB_CHARSET
, 1361, {{0,0,0,0},{FS_JOHAB
,0}} },
190 /* reserved for alternate ANSI and OEM */
191 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
192 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
193 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
194 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
195 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
196 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
197 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
198 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
199 /* reserved for system */
200 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
201 { SYMBOL_CHARSET
, CP_SYMBOL
, {{0,0,0,0},{FS_SYMBOL
,0}} }
204 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
205 'W','i','n','d','o','w','s','\\',
206 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
207 'F','o','n','t','s','\0'};
209 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
210 'W','i','n','d','o','w','s',' ','N','T','\\',
211 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
212 'F','o','n','t','s','\0'};
214 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
215 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
216 'W','i','n','d','o','w','s',' ','N','T','\\',
217 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
218 'S','y','s','t','e','m','L','i','n','k',0};
219 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
220 static const WCHAR Microsoft_Sans_Serif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
221 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
222 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
223 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
224 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
225 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
226 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
228 static const WCHAR arial
[] = {'A','r','i','a','l',0};
229 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
230 static const WCHAR bitstream_vera_sans_mono
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
231 static const WCHAR bitstream_vera_serif
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
232 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
233 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
234 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
235 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
236 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
238 static const WCHAR
* const default_serif_list
[] =
242 bitstream_vera_serif
,
245 static const WCHAR
* const default_fixed_list
[] =
249 bitstream_vera_sans_mono
,
252 static const WCHAR
* const default_sans_list
[] =
260 const WCHAR
*default_serif
= times_new_roman
;
261 const WCHAR
*default_fixed
= courier_new
;
262 const WCHAR
*default_sans
= arial
;
264 static const struct nls_update_font_list
266 UINT ansi_cp
, oem_cp
;
267 const char *oem
, *fixed
, *system
;
268 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
269 /* these are for font substitutes */
270 const char *shelldlg
, *tmsrmn
;
271 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
, *helv_0
, *tmsrmn_0
;
272 struct subst
{ const char *from
, *to
; } arial_0
, courier_new_0
, times_new_roman_0
;
273 } nls_update_font_list
[] =
275 /* Latin 1 (United States) */
276 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
277 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
278 "Tahoma","Times New Roman"
280 /* Latin 1 (Multilingual) */
281 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
282 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
283 "Tahoma","Times New Roman" /* FIXME unverified */
286 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
287 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
288 "Tahoma","Times New Roman", /* FIXME unverified */
289 "Fixedsys,238", "System,238",
290 "Courier New,238", "MS Serif,238", "Small Fonts,238",
291 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
292 { "Arial CE,0", "Arial,238" },
293 { "Courier New CE,0", "Courier New,238" },
294 { "Times New Roman CE,0", "Times New Roman,238" }
297 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
298 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
299 "Tahoma","Times New Roman", /* FIXME unverified */
300 "Fixedsys,204", "System,204",
301 "Courier New,204", "MS Serif,204", "Small Fonts,204",
302 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
303 { "Arial Cyr,0", "Arial,204" },
304 { "Courier New Cyr,0", "Courier New,204" },
305 { "Times New Roman Cyr,0", "Times New Roman,204" }
308 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
309 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
310 "Tahoma","Times New Roman", /* FIXME unverified */
311 "Fixedsys,161", "System,161",
312 "Courier New,161", "MS Serif,161", "Small Fonts,161",
313 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
314 { "Arial Greek,0", "Arial,161" },
315 { "Courier New Greek,0", "Courier New,161" },
316 { "Times New Roman Greek,0", "Times New Roman,161" }
319 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
320 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
321 "Tahoma","Times New Roman", /* FIXME unverified */
322 "Fixedsys,162", "System,162",
323 "Courier New,162", "MS Serif,162", "Small Fonts,162",
324 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
325 { "Arial Tur,0", "Arial,162" },
326 { "Courier New Tur,0", "Courier New,162" },
327 { "Times New Roman Tur,0", "Times New Roman,162" }
330 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
331 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
332 "Tahoma","Times New Roman", /* FIXME unverified */
333 "Fixedsys,177", "System,177",
334 "Courier New,177", "MS Serif,177", "Small Fonts,177",
335 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
338 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
339 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
340 "Microsoft Sans Serif","Times New Roman",
341 "Fixedsys,178", "System,178",
342 "Courier New,178", "MS Serif,178", "Small Fonts,178",
343 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
346 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
347 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
348 "Tahoma","Times New Roman", /* FIXME unverified */
349 "Fixedsys,186", "System,186",
350 "Courier New,186", "MS Serif,186", "Small Fonts,186",
351 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
352 { "Arial Baltic,0", "Arial,186" },
353 { "Courier New Baltic,0", "Courier New,186" },
354 { "Times New Roman Baltic,0", "Times New Roman,186" }
357 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
358 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
359 "Tahoma","Times New Roman" /* FIXME unverified */
362 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
363 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
364 "Tahoma","Times New Roman" /* FIXME unverified */
367 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
368 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
369 "MS UI Gothic","MS Serif"
371 /* Chinese Simplified */
372 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
373 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
377 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
378 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
381 /* Chinese Traditional */
382 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
383 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
384 "PMingLiU", "MingLiU"
388 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
390 return ( ansi_cp
== 932 /* CP932 for Japanese */
391 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
392 || ansi_cp
== 949 /* CP949 for Korean */
393 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
396 static CRITICAL_SECTION font_cs
;
397 static CRITICAL_SECTION_DEBUG critsect_debug
=
400 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
401 0, 0, { (DWORD_PTR
)(__FILE__
": font_cs") }
403 static CRITICAL_SECTION font_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
405 #ifndef WINE_FONT_DIR
406 #define WINE_FONT_DIR "fonts"
409 #ifdef WORDS_BIGENDIAN
410 #define GET_BE_WORD(x) (x)
411 #define GET_BE_DWORD(x) (x)
413 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
414 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
417 static void get_fonts_data_dir_path( const WCHAR
*file
, WCHAR
*path
)
419 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\\',0};
420 static const WCHAR winedatadirW
[] = {'W','I','N','E','D','A','T','A','D','I','R',0};
421 static const WCHAR winebuilddirW
[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0};
423 if (GetEnvironmentVariableW( winedatadirW
, path
, MAX_PATH
))
425 const char fontdir
[] = "\\" WINE_FONT_DIR
"\\";
426 MultiByteToWideChar( CP_ACP
, 0, fontdir
, -1, path
+ strlenW(path
), MAX_PATH
- strlenW(path
) );
428 else if (GetEnvironmentVariableW( winebuilddirW
, path
, MAX_PATH
))
430 strcatW( path
, fontsW
);
432 strcatW( path
, file
);
433 if (path
[5] == ':') memmove( path
, path
+ 4, (strlenW(path
) - 3) * sizeof(WCHAR
) );
434 else path
[1] = '\\'; /* change \??\ to \\?\ */
437 static void get_fonts_win_dir_path( const WCHAR
*file
, WCHAR
*path
)
439 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\\',0};
441 GetWindowsDirectoryW( path
, MAX_PATH
);
442 strcatW( path
, fontsW
);
443 strcatW( path
, file
);
446 /* font substitutions */
448 struct gdi_font_subst
456 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
458 static inline WCHAR
*get_subst_to_name( struct gdi_font_subst
*subst
)
460 return subst
->names
+ strlenW( subst
->names
) + 1;
463 static void dump_gdi_font_subst(void)
465 struct gdi_font_subst
*subst
;
467 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
469 if (subst
->from_charset
!= -1 || subst
->to_charset
!= -1)
470 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst
->names
),
471 subst
->from_charset
, debugstr_w(get_subst_to_name(subst
)), subst
->to_charset
);
473 TRACE("%s -> %s\n", debugstr_w(subst
->names
), debugstr_w(get_subst_to_name(subst
)));
477 const WCHAR
*get_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, int *to_charset
)
479 struct gdi_font_subst
*subst
;
481 LIST_FOR_EACH_ENTRY( subst
, &font_subst_list
, struct gdi_font_subst
, entry
)
483 if (!strcmpiW(subst
->names
, from_name
) &&
484 (subst
->from_charset
== from_charset
|| subst
->from_charset
== -1))
486 if (to_charset
) *to_charset
= subst
->to_charset
;
487 return get_subst_to_name( subst
);
493 static BOOL
add_gdi_font_subst( const WCHAR
*from_name
, int from_charset
, const WCHAR
*to_name
, int to_charset
)
495 struct gdi_font_subst
*subst
;
496 int len
= strlenW( from_name
) + strlenW( to_name
) + 2;
498 if (get_gdi_font_subst( from_name
, from_charset
, NULL
)) return FALSE
; /* already exists */
500 if (!(subst
= HeapAlloc( GetProcessHeap(), 0,
501 offsetof( struct gdi_font_subst
, names
[len
] ))))
503 strcpyW( subst
->names
, from_name
);
504 strcpyW( get_subst_to_name(subst
), to_name
);
505 subst
->from_charset
= from_charset
;
506 subst
->to_charset
= to_charset
;
507 list_add_tail( &font_subst_list
, &subst
->entry
);
511 static void load_gdi_font_subst(void)
514 DWORD i
= 0, type
, dlen
, vlen
;
515 WCHAR value
[64], data
[64], *p
;
517 if (RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
521 vlen
= ARRAY_SIZE(value
);
522 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)data
, &dlen
))
524 int from_charset
= -1, to_charset
= -1;
526 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
527 if ((p
= strrchrW( value
, ',' )) && p
[1])
530 from_charset
= strtolW( p
, NULL
, 10 );
532 if ((p
= strrchrW( data
, ',' )) && p
[1])
535 to_charset
= strtolW( p
, NULL
, 10 );
538 /* Win 2000 doesn't allow mapping between different charsets
539 or mapping of DEFAULT_CHARSET */
540 if ((!from_charset
|| to_charset
== from_charset
) && to_charset
!= DEFAULT_CHARSET
)
541 add_gdi_font_subst( value
, from_charset
, data
, to_charset
);
543 /* reset dlen and vlen */
545 vlen
= ARRAY_SIZE(value
);
552 struct list font_list
= LIST_INIT(font_list
);
554 struct gdi_font_family
*create_family( const WCHAR
*name
, const WCHAR
*second_name
)
556 struct gdi_font_family
*family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
558 family
->refcount
= 1;
559 lstrcpynW( family
->family_name
, name
, LF_FACESIZE
);
560 if (second_name
&& second_name
[0])
562 lstrcpynW( family
->second_name
, second_name
, LF_FACESIZE
);
563 add_gdi_font_subst( second_name
, -1, name
, -1 );
565 else family
->second_name
[0] = 0;
566 list_init( &family
->faces
);
567 family
->replacement
= NULL
;
568 list_add_tail( &font_list
, &family
->entry
);
572 void release_family( struct gdi_font_family
*family
)
574 if (--family
->refcount
) return;
575 assert( list_empty( &family
->faces
));
576 list_remove( &family
->entry
);
577 if (family
->replacement
) release_family( family
->replacement
);
578 HeapFree( GetProcessHeap(), 0, family
);
581 struct gdi_font_family
*find_family_from_name( const WCHAR
*name
)
583 struct gdi_font_family
*family
;
585 LIST_FOR_EACH_ENTRY( family
, &font_list
, struct gdi_font_family
, entry
)
586 if (!strncmpiW( family
->family_name
, name
, LF_FACESIZE
- 1 )) return family
;
590 struct gdi_font_family
*find_family_from_any_name( const WCHAR
*name
)
592 struct gdi_font_family
*family
;
594 LIST_FOR_EACH_ENTRY( family
, &font_list
, struct gdi_font_family
, entry
)
596 if (!strncmpiW( family
->family_name
, name
, LF_FACESIZE
- 1 )) return family
;
597 if (!strncmpiW( family
->second_name
, name
, LF_FACESIZE
- 1 )) return family
;
602 static const struct list
*get_family_face_list( const struct gdi_font_family
*family
)
604 return family
->replacement
? &family
->replacement
->faces
: &family
->faces
;
607 static struct gdi_font_face
*find_face_from_filename( const WCHAR
*file_name
, const WCHAR
*family_name
)
609 struct gdi_font_family
*family
;
610 struct gdi_font_face
*face
;
613 TRACE( "looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(family_name
) );
615 LIST_FOR_EACH_ENTRY( family
, &font_list
, struct gdi_font_family
, entry
)
617 if (family_name
&& strncmpiW( family_name
, family
->family_name
, LF_FACESIZE
- 1 )) continue;
618 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
620 if (!face
->file
) continue;
621 file
= strrchrW(face
->file
, '\\');
622 if (!file
) file
= face
->file
;
624 if (strcmpiW( file
, file_name
)) continue;
632 static BOOL
add_family_replacement( const WCHAR
*new_name
, const WCHAR
*replace
)
634 struct gdi_font_family
*new_family
, *family
;
635 struct gdi_font_face
*face
;
636 WCHAR new_name_vert
[LF_FACESIZE
], replace_vert
[LF_FACESIZE
];
638 if (!(family
= find_family_from_any_name( replace
)))
640 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace
) );
644 if (!(new_family
= create_family( new_name
, NULL
))) return FALSE
;
645 new_family
->replacement
= family
;
647 TRACE( "mapping %s to %s\n", debugstr_w(replace
), debugstr_w(new_name
) );
649 /* also add replacement for vertical font if necessary */
650 if (replace
[0] == '@') return TRUE
;
651 if (list_empty( &family
->faces
)) return TRUE
;
652 face
= LIST_ENTRY( list_head(&family
->faces
), struct gdi_font_face
, entry
);
653 if (!(face
->fs
.fsCsb
[0] & FS_DBCS_MASK
)) return TRUE
;
655 new_name_vert
[0] = '@';
656 lstrcpynW( new_name_vert
+ 1, new_name
, LF_FACESIZE
- 1 );
657 if (find_family_from_any_name( new_name_vert
)) return TRUE
; /* already exists */
659 replace_vert
[0] = '@';
660 lstrcpynW( replace_vert
+ 1, replace
, LF_FACESIZE
- 1 );
661 add_family_replacement( new_name_vert
, replace_vert
);
666 * The replacement list is a way to map an entire font
667 * family onto another family. For example adding
669 * [HKCU\Software\Wine\Fonts\Replacements]
670 * "Wingdings"="Winedings"
672 * would enumerate the Winedings font both as Winedings and
673 * Wingdings. However if a real Wingdings font is present the
674 * replacement does not take place.
676 static void load_gdi_font_replacements(void)
679 DWORD i
= 0, type
, dlen
, vlen
;
680 WCHAR value
[LF_FACESIZE
], data
[1024];
682 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
683 if (RegOpenKeyA( wine_fonts_key
, "Replacements", &hkey
)) return;
686 vlen
= ARRAY_SIZE(value
);
687 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (BYTE
*)data
, &dlen
))
689 /* "NewName"="Oldname" */
690 if (!find_family_from_any_name( value
))
692 if (type
== REG_MULTI_SZ
)
694 WCHAR
*replace
= data
;
697 if (add_family_replacement( value
, replace
)) break;
698 replace
+= strlenW(replace
) + 1;
701 else if (type
== REG_SZ
) add_family_replacement( value
, data
);
703 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
705 /* reset dlen and vlen */
707 vlen
= ARRAY_SIZE(value
);
712 static void dump_gdi_font_list(void)
714 struct gdi_font_family
*family
;
715 struct gdi_font_face
*face
;
717 LIST_FOR_EACH_ENTRY( family
, &font_list
, struct gdi_font_family
, entry
)
719 TRACE( "Family: %s\n", debugstr_w(family
->family_name
) );
720 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, struct gdi_font_face
, entry
)
722 TRACE( "\t%s\t%s\t%08x", debugstr_w(face
->style_name
), debugstr_w(face
->full_name
),
724 if (!face
->scalable
) TRACE(" %d", face
->size
.height
);
730 static const WCHAR
*set_default_family( const WCHAR
* const *name_list
)
732 struct gdi_font_family
*family
;
733 const WCHAR
* const *entry
;
735 for (entry
= name_list
; *entry
; entry
++)
737 if (!(family
= find_family_from_name( *entry
))) continue;
738 list_remove( &family
->entry
);
739 list_add_head( &font_list
, &family
->entry
);
745 static void reorder_font_list(void)
747 default_serif
= set_default_family( default_serif_list
);
748 default_fixed
= set_default_family( default_fixed_list
);
749 default_sans
= set_default_family( default_sans_list
);
752 struct gdi_font_face
*create_face( const WCHAR
*style
, const WCHAR
*fullname
, const WCHAR
*file
,
753 UINT index
, FONTSIGNATURE fs
, DWORD ntmflags
, DWORD version
,
754 DWORD flags
, const struct bitmap_font_size
*size
)
756 struct gdi_font_face
*face
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*face
) );
759 face
->style_name
= strdupW( style
);
760 face
->full_name
= strdupW( fullname
);
761 face
->face_index
= index
;
763 face
->ntmFlags
= ntmflags
;
764 face
->version
= version
;
766 if (file
) face
->file
= strdupW( file
);
767 if (size
) face
->size
= *size
;
768 else face
->scalable
= TRUE
;
774 static struct list font_links
= LIST_INIT(font_links
);
776 struct gdi_font_link
*find_gdi_font_link( const WCHAR
*name
)
778 struct gdi_font_link
*link
;
780 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
781 if (!strncmpiW( link
->name
, name
, LF_FACESIZE
- 1 )) return link
;
785 struct gdi_font_family
*find_family_from_font_links( const WCHAR
*name
, const WCHAR
*subst
,
788 struct gdi_font_link
*link
;
789 struct gdi_font_link_entry
*entry
;
790 struct gdi_font_family
*family
;
792 LIST_FOR_EACH_ENTRY( link
, &font_links
, struct gdi_font_link
, entry
)
794 if (!strncmpiW( link
->name
, name
, LF_FACESIZE
- 1) ||
795 (subst
&& !strncmpiW( link
->name
, subst
, LF_FACESIZE
- 1 )))
797 TRACE("found entry in system list\n");
798 LIST_FOR_EACH_ENTRY( entry
, &link
->links
, struct gdi_font_link_entry
, entry
)
800 const struct gdi_font_link
*links
;
802 family
= find_family_from_name( entry
->family_name
);
803 if (!fs
.fsCsb
[0]) return family
;
804 if (fs
.fsCsb
[0] & entry
->fs
.fsCsb
[0]) return family
;
805 if ((links
= find_gdi_font_link( family
->family_name
)) && fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
813 static struct gdi_font_link
*add_gdi_font_link( const WCHAR
*name
)
815 struct gdi_font_link
*link
= find_gdi_font_link( name
);
817 if (link
) return link
;
818 if ((link
= HeapAlloc( GetProcessHeap(), 0, sizeof(*link
) )))
820 lstrcpynW( link
->name
, name
, LF_FACESIZE
);
821 memset( &link
->fs
, 0, sizeof(link
->fs
) );
822 list_init( &link
->links
);
823 list_add_tail( &font_links
, &link
->entry
);
828 static void add_gdi_font_link_entry( struct gdi_font_link
*link
, const WCHAR
*family_name
, FONTSIGNATURE fs
)
830 struct gdi_font_link_entry
*entry
;
832 entry
= HeapAlloc( GetProcessHeap(), 0, sizeof(*entry
) );
833 lstrcpynW( entry
->family_name
, family_name
, LF_FACESIZE
);
835 link
->fs
.fsCsb
[0] |= fs
.fsCsb
[0];
836 link
->fs
.fsCsb
[1] |= fs
.fsCsb
[1];
837 list_add_tail( &link
->links
, &entry
->entry
);
840 static const WCHAR
* const font_links_list
[] =
843 Microsoft_Sans_Serif
,
847 static const struct font_links_defaults_list
849 /* Keyed off substitution for "MS Shell Dlg" */
850 const WCHAR
*shelldlg
;
851 /* Maximum of four substitutes, plus terminating NULL pointer */
852 const WCHAR
*substitutes
[5];
853 } font_links_defaults_list
[] =
856 { Tahoma
, /* FIXME unverified ordering */
857 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
859 /* Below lists are courtesy of
860 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
864 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
866 /* Chinese Simplified */
868 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
872 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
874 /* Chinese Traditional */
876 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
880 static void populate_system_links( const WCHAR
*name
, const WCHAR
* const *values
)
882 struct gdi_font_family
*family
;
883 struct gdi_font_face
*face
;
884 struct gdi_font_link
*font_link
;
885 const WCHAR
*file
, *value
;
887 /* Don't store fonts that are only substitutes for other fonts */
888 if (get_gdi_font_subst( name
, -1, NULL
))
890 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
) );
893 font_link
= add_gdi_font_link( name
);
894 for ( ; *values
; values
++)
896 if (!strcmpiW( name
, *values
)) continue;
897 if (!(value
= get_gdi_font_subst( *values
, -1, NULL
))) value
= *values
;
898 if (!(family
= find_family_from_name( value
))) continue;
899 /* use first extant filename for this Family */
900 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
902 if (!face
->file
) continue;
903 file
= strrchrW(face
->file
, '\\');
904 if (!file
) file
= face
->file
;
906 if ((face
= find_face_from_filename( file
, value
)))
908 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
909 TRACE( "added internal SystemLink for %s to %s in %s\n",
910 debugstr_w(name
), debugstr_w(value
), debugstr_w(file
) );
912 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
) );
918 static void load_system_links(void)
920 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\',
921 'M','i','c','r','o','s','o','f','t','\\',
922 'W','i','n','d','o','w','s',' ','N','T','\\',
923 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
924 'F','o','n','t','L','i','n','k','\\',
925 'S','y','s','t','e','m','L','i','n','k',0};
926 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
927 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
928 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
931 const WCHAR
*shelldlg_name
;
932 struct gdi_font_link
*font_link
, *system_font_link
;
933 struct gdi_font_face
*face
;
935 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE
, system_link
, &hkey
))
937 WCHAR value
[MAX_PATH
], data
[1024];
938 DWORD type
, val_len
, data_len
;
941 val_len
= ARRAY_SIZE(value
);
942 data_len
= sizeof(data
);
944 while (!RegEnumValueW( hkey
, i
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
))
946 /* Don't store fonts that are only substitutes for other fonts */
947 if (!get_gdi_font_subst( value
, -1, NULL
))
949 font_link
= add_gdi_font_link( value
);
950 for (entry
= data
; (char *)entry
< (char *)data
+ data_len
&& *entry
; entry
= next
)
952 const WCHAR
*family_name
= NULL
;
955 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
957 next
= entry
+ strlenW(entry
) + 1;
958 if ((p
= strchrW( entry
, ',' )))
961 while (isspaceW(*p
)) p
++;
962 if (!(family_name
= get_gdi_font_subst( p
, -1, NULL
))) family_name
= p
;
964 if ((face
= find_face_from_filename( entry
, family_name
)))
966 add_gdi_font_link_entry( font_link
, face
->family
->family_name
, face
->fs
);
967 TRACE("Adding file %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
969 else TRACE( "Unable to find file %s family %s\n",
970 debugstr_w(entry
), debugstr_w(family_name
) );
973 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
975 val_len
= ARRAY_SIZE(value
);
976 data_len
= sizeof(data
);
981 if ((shelldlg_name
= get_gdi_font_subst( MS_Shell_Dlg
, -1, NULL
)))
983 for (i
= 0; i
< ARRAY_SIZE(font_links_defaults_list
); i
++)
985 const WCHAR
*subst
= get_gdi_font_subst( font_links_defaults_list
[i
].shelldlg
, -1, NULL
);
987 if ((!strcmpiW( font_links_defaults_list
[i
].shelldlg
, shelldlg_name
) ||
988 (subst
&& !strcmpiW( subst
, shelldlg_name
))))
990 for (j
= 0; j
< ARRAY_SIZE(font_links_list
); j
++)
991 populate_system_links( font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
992 if (!strcmpiW(shelldlg_name
, font_links_defaults_list
[i
].substitutes
[0]))
993 populate_system_links( shelldlg_name
, font_links_defaults_list
[i
].substitutes
);
997 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
999 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1002 system_font_link
= add_gdi_font_link( System
);
1003 if ((face
= find_face_from_filename( tahoma_ttf
, Tahoma
)))
1005 add_gdi_font_link_entry( system_font_link
, face
->family
->family_name
, face
->fs
);
1006 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face
->file
), face
->face_index
);
1008 if ((font_link
= find_gdi_font_link( Tahoma
)))
1010 struct gdi_font_link_entry
*entry
;
1011 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1012 add_gdi_font_link_entry( system_font_link
, entry
->family_name
, entry
->fs
);
1016 /* realized font objects */
1018 #define FIRST_FONT_HANDLE 1
1019 #define MAX_FONT_HANDLES 256
1021 struct font_handle_entry
1023 struct gdi_font
*font
;
1024 WORD generation
; /* generation count for reusing handle values */
1027 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
1028 static struct font_handle_entry
*next_free
;
1029 static struct font_handle_entry
*next_unused
= font_handles
;
1031 static struct font_handle_entry
*handle_entry( DWORD handle
)
1033 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
1035 if (idx
< MAX_FONT_HANDLES
)
1037 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
1038 return &font_handles
[idx
];
1040 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
1044 static struct gdi_font
*get_font_from_handle( DWORD handle
)
1046 struct font_handle_entry
*entry
= handle_entry( handle
);
1048 if (entry
) return entry
->font
;
1049 SetLastError( ERROR_INVALID_PARAMETER
);
1053 static DWORD
alloc_font_handle( struct gdi_font
*font
)
1055 struct font_handle_entry
*entry
;
1059 next_free
= (struct font_handle_entry
*)entry
->font
;
1060 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
1061 entry
= next_unused
++;
1064 ERR( "out of realized font handles\n" );
1068 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
1069 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
1072 static void free_font_handle( DWORD handle
)
1074 struct font_handle_entry
*entry
;
1076 if ((entry
= handle_entry( handle
)))
1078 entry
->font
= (struct gdi_font
*)next_free
;
1083 static struct gdi_font
*alloc_gdi_font( const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
)
1085 UINT len
= file
? strlenW(file
) : 0;
1086 struct gdi_font
*font
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1087 offsetof( struct gdi_font
, file
[len
+ 1] ));
1090 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
1091 font
->scale_y
= 1.0;
1092 font
->kern_count
= -1;
1093 list_init( &font
->child_fonts
);
1097 WIN32_FILE_ATTRIBUTE_DATA info
;
1098 if (GetFileAttributesExW( file
, GetFileExInfoStandard
, &info
))
1100 font
->writetime
= info
.ftLastWriteTime
;
1101 font
->data_size
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
1102 memcpy( font
->file
, file
, len
* sizeof(WCHAR
) );
1107 font
->data_ptr
= data_ptr
;
1108 font
->data_size
= data_size
;
1111 if (!(font
->handle
= alloc_font_handle( font
)))
1113 HeapFree( GetProcessHeap(), 0, font
);
1119 void free_gdi_font( struct gdi_font
*font
)
1122 struct gdi_font
*child
, *child_next
;
1124 if (font
->private) font_funcs
->destroy_font( font
);
1125 free_font_handle( font
->handle
);
1126 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, struct gdi_font
, entry
)
1128 list_remove( &child
->entry
);
1129 free_gdi_font( child
);
1131 for (i
= 0; i
< font
->gm_size
; i
++) HeapFree( GetProcessHeap(), 0, font
->gm
[i
] );
1132 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFamilyName
);
1133 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpStyleName
);
1134 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFaceName
);
1135 HeapFree( GetProcessHeap(), 0, font
->otm
.otmpFullName
);
1136 HeapFree( GetProcessHeap(), 0, font
->gm
);
1137 HeapFree( GetProcessHeap(), 0, font
->kern_pairs
);
1138 HeapFree( GetProcessHeap(), 0, font
->gsub_table
);
1139 HeapFree( GetProcessHeap(), 0, font
);
1142 void set_gdi_font_names( struct gdi_font
*font
, const WCHAR
*family_name
, const WCHAR
*style_name
,
1143 const WCHAR
*full_name
)
1145 font
->otm
.otmpFamilyName
= (char *)strdupW( family_name
);
1146 font
->otm
.otmpStyleName
= (char *)strdupW( style_name
);
1147 font
->otm
.otmpFaceName
= (char *)strdupW( full_name
);
1150 struct gdi_font
*create_gdi_font( const struct gdi_font_face
*face
, const WCHAR
*family_name
,
1151 const LOGFONTW
*lf
)
1153 struct gdi_font
*font
;
1155 if (!(font
= alloc_gdi_font( face
->file
, face
->data_ptr
, face
->data_size
))) return NULL
;
1156 font
->fs
= face
->fs
;
1158 font
->fake_italic
= (lf
->lfItalic
&& !(face
->ntmFlags
& NTM_ITALIC
));
1159 font
->fake_bold
= (lf
->lfWeight
> 550 && !(face
->ntmFlags
& NTM_BOLD
));
1160 font
->scalable
= face
->scalable
;
1161 font
->face_index
= face
->face_index
;
1162 font
->ntmFlags
= face
->ntmFlags
;
1163 font
->aa_flags
= HIWORD( face
->flags
);
1164 if (!family_name
) family_name
= face
->family
->family_name
;
1165 set_gdi_font_names( font
, family_name
, face
->style_name
, face
->full_name
);
1169 struct glyph_metrics
1172 ABC abc
; /* metrics of the unrotated char */
1176 #define GM_BLOCK_SIZE 128
1178 /* TODO: GGO format support */
1179 static BOOL
get_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
, GLYPHMETRICS
*gm
, ABC
*abc
)
1181 UINT block
= index
/ GM_BLOCK_SIZE
;
1182 UINT entry
= index
% GM_BLOCK_SIZE
;
1184 if (block
< font
->gm_size
&& font
->gm
[block
] && font
->gm
[block
][entry
].init
)
1186 *gm
= font
->gm
[block
][entry
].gm
;
1187 *abc
= font
->gm
[block
][entry
].abc
;
1189 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
1190 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point( &gm
->gmptGlyphOrigin
),
1191 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
1198 static void set_gdi_font_glyph_metrics( struct gdi_font
*font
, UINT index
,
1199 const GLYPHMETRICS
*gm
, const ABC
*abc
)
1201 UINT block
= index
/ GM_BLOCK_SIZE
;
1202 UINT entry
= index
% GM_BLOCK_SIZE
;
1204 if (block
>= font
->gm_size
)
1206 struct glyph_metrics
**ptr
;
1209 ptr
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
, (block
+ 1) * sizeof(*ptr
) );
1211 ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, (block
+ 1) * sizeof(*ptr
) );
1213 font
->gm_size
= block
+ 1;
1216 if (!font
->gm
[block
])
1218 font
->gm
[block
] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**font
->gm
) * GM_BLOCK_SIZE
);
1219 if (!font
->gm
[block
]) return;
1221 font
->gm
[block
][entry
].gm
= *gm
;
1222 font
->gm
[block
][entry
].abc
= *abc
;
1223 font
->gm
[block
][entry
].init
= TRUE
;
1227 /* GSUB table support */
1241 } GSUB_ScriptRecord
;
1246 GSUB_ScriptRecord ScriptRecord
[1];
1253 } GSUB_LangSysRecord
;
1257 WORD DefaultLangSys
;
1259 GSUB_LangSysRecord LangSysRecord
[1];
1264 WORD LookupOrder
; /* Reserved */
1265 WORD ReqFeatureIndex
;
1267 WORD FeatureIndex
[1];
1274 } GSUB_FeatureRecord
;
1279 GSUB_FeatureRecord FeatureRecord
[1];
1284 WORD FeatureParams
; /* Reserved */
1286 WORD LookupListIndex
[1];
1305 WORD CoverageFormat
;
1308 } GSUB_CoverageFormat1
;
1314 WORD StartCoverageIndex
;
1319 WORD CoverageFormat
;
1321 GSUB_RangeRecord RangeRecord
[1];
1322 } GSUB_CoverageFormat2
;
1326 WORD SubstFormat
; /* = 1 */
1329 } GSUB_SingleSubstFormat1
;
1333 WORD SubstFormat
; /* = 2 */
1337 } GSUB_SingleSubstFormat2
;
1339 static GSUB_Script
*GSUB_get_script_table( GSUB_Header
*header
, const char *tag
)
1341 GSUB_ScriptList
*script
;
1342 GSUB_Script
*deflt
= NULL
;
1345 script
= (GSUB_ScriptList
*)((BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1346 TRACE("%i scripts in this font\n", GET_BE_WORD(script
->ScriptCount
) );
1347 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
1349 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
1350 GSUB_Script
*scr
= (GSUB_Script
*)((BYTE
*)script
+ offset
);
1351 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, tag
, 4 )) return scr
;
1352 if (!memcmp( script
->ScriptRecord
[i
].ScriptTag
, "dflt", 4 )) deflt
= scr
;
1357 static GSUB_LangSys
*GSUB_get_lang_table( GSUB_Script
*script
, const char *tag
)
1362 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
1364 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
1366 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
1367 lang
= (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
1368 if (!memcmp( script
->LangSysRecord
[i
].LangSysTag
, tag
, 4 )) return lang
;
1370 offset
= GET_BE_WORD(script
->DefaultLangSys
);
1371 if (offset
) return (GSUB_LangSys
*)((BYTE
*)script
+ offset
);
1375 static GSUB_Feature
*GSUB_get_feature( GSUB_Header
*header
, GSUB_LangSys
*lang
, const char *tag
)
1378 const GSUB_FeatureList
*feature
;
1380 feature
= (GSUB_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1381 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
1382 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
1384 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
1385 if (!memcmp( feature
->FeatureRecord
[index
].FeatureTag
, tag
, 4 ))
1386 return (GSUB_Feature
*)((BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
1391 static const char *get_opentype_script( const struct gdi_font
*font
)
1394 * I am not sure if this is the correct way to generate our script tag
1396 switch (font
->charset
)
1398 case ANSI_CHARSET
: return "latn";
1399 case BALTIC_CHARSET
: return "latn"; /* ?? */
1400 case CHINESEBIG5_CHARSET
: return "hani";
1401 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
1402 case GB2312_CHARSET
: return "hani";
1403 case GREEK_CHARSET
: return "grek";
1404 case HANGUL_CHARSET
: return "hang";
1405 case RUSSIAN_CHARSET
: return "cyrl";
1406 case SHIFTJIS_CHARSET
: return "kana";
1407 case TURKISH_CHARSET
: return "latn"; /* ?? */
1408 case VIETNAMESE_CHARSET
: return "latn";
1409 case JOHAB_CHARSET
: return "latn"; /* ?? */
1410 case ARABIC_CHARSET
: return "arab";
1411 case HEBREW_CHARSET
: return "hebr";
1412 case THAI_CHARSET
: return "thai";
1413 default: return "latn";
1417 void *get_GSUB_vert_feature( struct gdi_font
*font
)
1419 GSUB_Header
*header
;
1420 GSUB_Script
*script
;
1421 GSUB_LangSys
*language
;
1422 GSUB_Feature
*feature
;
1423 DWORD length
= font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, NULL
, 0 );
1425 if (length
== GDI_ERROR
) return NULL
;
1427 header
= HeapAlloc( GetProcessHeap(), 0, length
);
1428 font_funcs
->get_font_data( font
, MS_GSUB_TAG
, 0, header
, length
);
1429 TRACE( "Loaded GSUB table of %i bytes\n", length
);
1431 if ((script
= GSUB_get_script_table( header
, get_opentype_script(font
) )))
1433 if ((language
= GSUB_get_lang_table( script
, "xxxx" ))) /* Need to get Lang tag */
1435 feature
= GSUB_get_feature( header
, language
, "vrt2" );
1436 if (!feature
) feature
= GSUB_get_feature( header
, language
, "vert" );
1439 font
->gsub_table
= header
;
1442 TRACE("vrt2/vert feature not found\n");
1444 else TRACE("Language not found\n");
1446 else TRACE("Script not found\n");
1448 HeapFree( GetProcessHeap(), 0, header
);
1452 static int GSUB_is_glyph_covered( void *table
, UINT glyph
)
1454 GSUB_CoverageFormat1
*cf1
= table
;
1456 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
1458 int i
, count
= GET_BE_WORD(cf1
->GlyphCount
);
1460 TRACE("Coverage Format 1, %i glyphs\n",count
);
1461 for (i
= 0; i
< count
; i
++) if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
])) return i
;
1464 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
1467 GSUB_CoverageFormat2
*cf2
= table
;
1469 count
= GET_BE_WORD(cf2
->RangeCount
);
1470 TRACE("Coverage Format 2, %i ranges\n",count
);
1471 for (i
= 0; i
< count
; i
++)
1473 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) return -1;
1474 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
1475 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
1477 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
1478 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
1483 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
1488 static UINT
GSUB_apply_feature( GSUB_Header
*header
, GSUB_Feature
*feature
, UINT glyph
)
1490 GSUB_LookupList
*lookup
= (GSUB_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
1493 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
1494 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
1496 GSUB_LookupTable
*look
;
1497 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
1498 look
= (GSUB_LookupTable
*)((BYTE
*)lookup
+ offset
);
1499 TRACE("type %i, flag %x, subtables %i\n",
1500 GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
1501 if (GET_BE_WORD(look
->LookupType
) == 1)
1503 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
1505 GSUB_SingleSubstFormat1
*ssf1
;
1506 offset
= GET_BE_WORD(look
->SubTable
[j
]);
1507 ssf1
= (GSUB_SingleSubstFormat1
*)((BYTE
*)look
+ offset
);
1508 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
1510 int offset
= GET_BE_WORD(ssf1
->Coverage
);
1511 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
1512 if (GSUB_is_glyph_covered( (BYTE
*) ssf1
+ offset
, glyph
) != -1)
1514 TRACE(" Glyph 0x%x ->",glyph
);
1515 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
1516 TRACE(" 0x%x\n",glyph
);
1521 GSUB_SingleSubstFormat2
*ssf2
;
1524 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
1525 offset
= GET_BE_WORD(ssf1
->Coverage
);
1526 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
1527 index
= GSUB_is_glyph_covered( (BYTE
*)ssf2
+ offset
, glyph
);
1528 TRACE(" Coverage index %i\n",index
);
1531 TRACE(" Glyph is 0x%x ->",glyph
);
1532 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
1533 TRACE("0x%x\n",glyph
);
1538 else FIXME("We only handle SubType 1\n");
1543 static UINT
get_GSUB_vert_glyph( struct gdi_font
*font
, UINT glyph
)
1545 if (!glyph
) return glyph
;
1546 if (!font
->gsub_table
) return glyph
;
1547 return GSUB_apply_feature( font
->gsub_table
, font
->vert_feature
, glyph
);
1550 static void add_child_font( struct gdi_font
*font
, const WCHAR
*family_name
)
1552 struct gdi_font
*child
;
1553 struct gdi_font_family
*family
;
1554 struct gdi_font_face
*child_face
, *best_face
= NULL
;
1555 UINT penalty
= 0, new_penalty
= 0;
1556 BOOL bold
, italic
, bd
, it
;
1558 italic
= !!font
->lf
.lfItalic
;
1559 bold
= font
->lf
.lfWeight
> FW_MEDIUM
;
1561 if (!(family
= find_family_from_name( family_name
))) return;
1563 LIST_FOR_EACH_ENTRY( child_face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
1565 it
= !!(child_face
->ntmFlags
& NTM_ITALIC
);
1566 bd
= !!(child_face
->ntmFlags
& NTM_BOLD
);
1567 new_penalty
= ( it
^ italic
) + ( bd
^ bold
);
1568 if (!best_face
|| new_penalty
< penalty
)
1570 penalty
= new_penalty
;
1571 best_face
= child_face
;
1574 if (!best_face
) return;
1576 if (!(child
= create_gdi_font( best_face
, family_name
, &font
->lf
))) return;
1577 child
->matrix
= font
->matrix
;
1578 child
->can_use_bitmap
= font
->can_use_bitmap
;
1579 child
->scale_y
= font
->scale_y
;
1580 child
->aveWidth
= font
->aveWidth
;
1581 child
->charset
= font
->charset
;
1582 child
->codepage
= font
->codepage
;
1583 child
->base_font
= font
;
1584 list_add_tail( &font
->child_fonts
, &child
->entry
);
1585 TRACE( "created child font %p for base %p\n", child
, font
);
1588 void create_child_font_list( struct gdi_font
*font
)
1590 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
1591 struct gdi_font_link
*font_link
;
1592 struct gdi_font_link_entry
*entry
;
1593 const WCHAR
* font_name
;
1595 if (!(font_name
= get_gdi_font_subst( get_gdi_font_name(font
), -1, NULL
)))
1596 font_name
= get_gdi_font_name( font
);
1598 if ((font_link
= find_gdi_font_link( font_name
)))
1600 TRACE("found entry in system list\n");
1601 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1602 add_child_font( font
, entry
->family_name
);
1605 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
1606 * Sans Serif. This is how asian windows get default fallbacks for fonts
1608 if (is_dbcs_ansi_cp(GetACP()) && font
->charset
!= SYMBOL_CHARSET
&& font
->charset
!= OEM_CHARSET
&&
1609 strcmpiW( font_name
, szDefaultFallbackLink
) != 0)
1611 if ((font_link
= find_gdi_font_link( szDefaultFallbackLink
)))
1613 TRACE("found entry in default fallback list\n");
1614 LIST_FOR_EACH_ENTRY( entry
, &font_link
->links
, struct gdi_font_link_entry
, entry
)
1615 add_child_font( font
, entry
->family_name
);
1622 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
1623 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
1624 static unsigned int unused_font_count
;
1625 #define UNUSED_CACHE_SIZE 10
1627 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
1628 const FMAT2
*matrix
, BOOL can_use_bitmap
)
1630 if (font
->hash
!= hash
) return TRUE
;
1631 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
1632 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
1633 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
1634 return strcmpiW( font
->lf
.lfFaceName
, lf
->lfFaceName
);
1637 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
1639 DWORD hash
= 0, *ptr
, two_chars
;
1643 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
1645 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
1647 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
1650 pwc
= (WCHAR
*)&two_chars
;
1652 *pwc
= toupperW(*pwc
);
1654 *pwc
= toupperW(*pwc
);
1658 hash
^= !can_use_bitmap
;
1662 void cache_gdi_font( struct gdi_font
*font
)
1664 static DWORD cache_num
= 1;
1666 font
->cache_num
= cache_num
++;
1667 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
1668 list_add_head( &gdi_font_list
, &font
->entry
);
1669 TRACE( "font %p\n", font
);
1672 struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
1674 struct gdi_font
*font
;
1675 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
1677 /* try the in-use list */
1678 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
1680 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
1681 list_remove( &font
->entry
);
1682 list_add_head( &gdi_font_list
, &font
->entry
);
1683 if (!font
->refcount
++)
1685 list_remove( &font
->unused_entry
);
1686 unused_font_count
--;
1693 static void release_gdi_font( struct gdi_font
*font
)
1696 if (--font
->refcount
) return;
1698 TRACE( "font %p\n", font
);
1700 /* add it to the unused list */
1701 EnterCriticalSection( &font_cs
);
1702 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
1703 if (unused_font_count
> UNUSED_CACHE_SIZE
)
1705 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
1706 TRACE( "freeing %p\n", font
);
1707 list_remove( &font
->entry
);
1708 list_remove( &font
->unused_entry
);
1709 free_gdi_font( font
);
1711 else unused_font_count
++;
1712 LeaveCriticalSection( &font_cs
);
1715 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
1717 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
1719 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1720 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1721 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
1722 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1725 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
1728 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
1730 RegDeleteValueA(hkey
, name
);
1733 static void update_font_association_info(UINT current_ansi_codepage
)
1735 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
1736 static const char *assoc_charset_subkey
= "Associated Charset";
1738 if (is_dbcs_ansi_cp(current_ansi_codepage
))
1741 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
1744 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
1746 switch (current_ansi_codepage
)
1749 set_value_key(hsubkey
, "ANSI(00)", "NO");
1750 set_value_key(hsubkey
, "OEM(FF)", "NO");
1751 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
1756 set_value_key(hsubkey
, "ANSI(00)", "YES");
1757 set_value_key(hsubkey
, "OEM(FF)", "YES");
1758 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
1761 RegCloseKey(hsubkey
);
1764 /* TODO: Associated DefaultFonts */
1770 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
1773 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
1776 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
1778 RegDeleteValueW(hkey
, name
);
1781 static void update_font_system_link_info(UINT current_ansi_codepage
)
1783 static const WCHAR system_link_simplified_chinese
[] =
1784 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
1785 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
1786 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
1787 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
1789 static const WCHAR system_link_traditional_chinese
[] =
1790 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
1791 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
1792 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
1793 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
1795 static const WCHAR system_link_japanese
[] =
1796 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
1797 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
1798 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
1799 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
1801 static const WCHAR system_link_korean
[] =
1802 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
1803 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
1804 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
1805 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
1807 static const WCHAR system_link_non_cjk
[] =
1808 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
1809 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
1810 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
1811 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
1815 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1820 switch (current_ansi_codepage
)
1823 link
= system_link_japanese
;
1824 len
= sizeof(system_link_japanese
);
1827 link
= system_link_simplified_chinese
;
1828 len
= sizeof(system_link_simplified_chinese
);
1831 link
= system_link_korean
;
1832 len
= sizeof(system_link_korean
);
1835 link
= system_link_traditional_chinese
;
1836 len
= sizeof(system_link_traditional_chinese
);
1839 link
= system_link_non_cjk
;
1840 len
= sizeof(system_link_non_cjk
);
1842 set_multi_value_key(hkey
, Lucida_Sans_Unicode
, link
, len
);
1843 set_multi_value_key(hkey
, Microsoft_Sans_Serif
, link
, len
);
1844 set_multi_value_key(hkey
, Tahoma
, link
, len
);
1849 static void update_codepage(void)
1851 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
1852 char buf
[40], cpbuf
[40];
1854 DWORD len
, type
, size
;
1855 UINT i
, ansi_cp
, oem_cp
;
1856 DWORD screen_dpi
, font_dpi
= 0;
1859 screen_dpi
= get_dpi();
1860 if (!screen_dpi
) screen_dpi
= 96;
1862 size
= sizeof(DWORD
);
1863 if (RegQueryValueExW(wine_fonts_key
, logpixels
, NULL
, &type
, (BYTE
*)&font_dpi
, &size
) ||
1864 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1868 oem_cp
= GetOEMCP();
1869 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
1873 if (!RegQueryValueExA(wine_fonts_key
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) && type
== REG_SZ
)
1875 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) return; /* already set correctly */
1876 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
1877 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
1879 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
1880 ansi_cp
, oem_cp
, screen_dpi
);
1882 RegSetValueExA(wine_fonts_key
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
1883 RegSetValueExW(wine_fonts_key
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
1885 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
1887 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&& nls_update_font_list
[i
].oem_cp
== oem_cp
)
1889 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
))
1891 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
,
1892 strlen(nls_update_font_list
[i
].oem
)+1);
1893 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
,
1894 strlen(nls_update_font_list
[i
].fixed
)+1);
1895 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
,
1896 strlen(nls_update_font_list
[i
].system
)+1);
1899 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, &hkey
))
1901 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
1904 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, &hkey
))
1906 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
1909 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
1911 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
1912 strlen(nls_update_font_list
[i
].shelldlg
)+1);
1913 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
1914 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
1916 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
1917 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
1918 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
1919 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
1920 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
1921 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
1922 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
1923 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
1925 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
1926 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
1927 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
1935 /* Delete the FontSubstitutes from other locales */
1936 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
1938 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
1939 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
1940 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
1946 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
1948 /* update locale dependent font association info and font system link info in registry.
1949 update only when codepages changed, not logpixels. */
1950 if (strcmp(buf
, cpbuf
) != 0)
1952 update_font_association_info(ansi_cp
);
1953 update_font_system_link_info(ansi_cp
);
1958 /*************************************************************
1961 static BOOL CDECL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
1962 LPCWSTR output
, const DEVMODEW
*devmode
)
1964 struct font_physdev
*physdev
;
1966 if (!font_funcs
) return TRUE
;
1967 if (!(physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) ))) return FALSE
;
1968 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
1973 /*************************************************************
1976 static BOOL CDECL
font_DeleteDC( PHYSDEV dev
)
1978 struct font_physdev
*physdev
= get_font_dev( dev
);
1980 release_gdi_font( physdev
->font
);
1981 HeapFree( GetProcessHeap(), 0, physdev
);
1986 struct gdi_font_enum_data
1989 NEWTEXTMETRICEXW ntm
;
1999 static int load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
2006 id
+= IDS_FIRST_SCRIPT
;
2007 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
2008 if (!rsrc
) return 0;
2009 hMem
= LoadResource( gdi32_module
, rsrc
);
2010 if (!hMem
) return 0;
2012 p
= LockResource( hMem
);
2014 while (id
--) p
+= *p
+ 1;
2016 i
= min(LF_FACESIZE
- 1, *p
);
2017 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
2022 static BOOL
is_complex_script_ansi_cp( UINT ansi_cp
)
2024 return (ansi_cp
== 874 /* Thai */
2025 || ansi_cp
== 1255 /* Hebrew */
2026 || ansi_cp
== 1256 /* Arabic */
2030 /***************************************************
2031 * create_enum_charset_list
2033 * This function creates charset enumeration list because in DEFAULT_CHARSET
2034 * case, the ANSI codepage's charset takes precedence over other charsets.
2035 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2036 * This function works as a filter other than DEFAULT_CHARSET case.
2038 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset
*list
)
2040 struct enum_charset
*start
= list
;
2044 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) && csi
.fs
.fsCsb
[0] != 0)
2046 list
->mask
= csi
.fs
.fsCsb
[0];
2047 list
->charset
= csi
.ciCharset
;
2048 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2051 else /* charset is DEFAULT_CHARSET or invalid. */
2056 /* Set the current codepage's charset as the first element. */
2057 if (!is_complex_script_ansi_cp(acp
) &&
2058 TranslateCharsetInfo( (DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
2059 csi
.fs
.fsCsb
[0] != 0)
2061 list
->mask
= csi
.fs
.fsCsb
[0];
2062 list
->charset
= csi
.ciCharset
;
2063 for (i
= 0; i
< 32; i
++) if (csi
.fs
.fsCsb
[0] & (1u << i
)) list
->script
= i
;
2064 mask
|= csi
.fs
.fsCsb
[0];
2068 /* Fill out left elements. */
2069 for (i
= 0; i
< 32; i
++)
2072 fs
.fsCsb
[0] = 1u << i
;
2074 if (fs
.fsCsb
[0] & mask
) continue; /* skip, already added. */
2075 if (!TranslateCharsetInfo( fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
2076 continue; /* skip, this is an invalid fsCsb bit. */
2077 list
->mask
= fs
.fsCsb
[0];
2078 list
->charset
= csi
.ciCharset
;
2080 mask
|= fs
.fsCsb
[0];
2083 /* add catch all mask for remaining bits */
2087 list
->charset
= DEFAULT_CHARSET
;
2088 list
->script
= IDS_OTHER
- IDS_FIRST_SCRIPT
;
2092 return list
- start
;
2095 static UINT
get_font_type( const NEWTEXTMETRICEXW
*ntm
)
2099 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ret
|= TRUETYPE_FONTTYPE
;
2100 if (ntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
) ret
|= DEVICE_FONTTYPE
;
2101 if (!(ntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
)) ret
|= RASTER_FONTTYPE
;
2105 static BOOL
get_face_enum_data( struct gdi_font_face
*face
, ENUMLOGFONTEXW
*elf
, NEWTEXTMETRICEXW
*ntm
)
2107 struct gdi_font
*font
;
2108 LOGFONTW lf
= { .lfHeight
= 100 };
2110 if (!(font
= create_gdi_font( face
, NULL
, &lf
))) return FALSE
;
2112 if (!font_funcs
->load_font( font
))
2114 free_gdi_font( font
);
2118 if (font_funcs
->set_outline_text_metrics( font
))
2120 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
2121 ntm
->ntmTm
.ntmSizeEM
= font
->otm
.otmEMSquare
;
2122 ntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
2123 ntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
2125 else if (font_funcs
->set_bitmap_text_metrics( font
))
2127 memcpy( &ntm
->ntmTm
, &font
->otm
.otmTextMetrics
, sizeof(TEXTMETRICW
) );
2128 ntm
->ntmTm
.ntmSizeEM
= ntm
->ntmTm
.tmHeight
- ntm
->ntmTm
.tmInternalLeading
;
2129 ntm
->ntmTm
.ntmCellHeight
= ntm
->ntmTm
.tmHeight
;
2130 ntm
->ntmTm
.ntmAvgWidth
= ntm
->ntmTm
.tmAveCharWidth
;
2132 ntm
->ntmTm
.ntmFlags
= font
->ntmFlags
;
2133 ntm
->ntmFontSig
= font
->fs
;
2135 elf
->elfLogFont
.lfEscapement
= 0;
2136 elf
->elfLogFont
.lfOrientation
= 0;
2137 elf
->elfLogFont
.lfHeight
= ntm
->ntmTm
.tmHeight
;
2138 elf
->elfLogFont
.lfWidth
= ntm
->ntmTm
.tmAveCharWidth
;
2139 elf
->elfLogFont
.lfWeight
= ntm
->ntmTm
.tmWeight
;
2140 elf
->elfLogFont
.lfItalic
= ntm
->ntmTm
.tmItalic
;
2141 elf
->elfLogFont
.lfUnderline
= ntm
->ntmTm
.tmUnderlined
;
2142 elf
->elfLogFont
.lfStrikeOut
= ntm
->ntmTm
.tmStruckOut
;
2143 elf
->elfLogFont
.lfCharSet
= ntm
->ntmTm
.tmCharSet
;
2144 elf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2145 elf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2146 elf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2147 elf
->elfLogFont
.lfPitchAndFamily
= (ntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
2148 lstrcpynW( elf
->elfLogFont
.lfFaceName
, (WCHAR
*)font
->otm
.otmpFamilyName
, LF_FACESIZE
);
2149 lstrcpynW( elf
->elfFullName
, (WCHAR
*)font
->otm
.otmpFaceName
, LF_FULLFACESIZE
);
2150 lstrcpynW( elf
->elfStyle
, (WCHAR
*)font
->otm
.otmpStyleName
, LF_FACESIZE
);
2152 free_gdi_font( font
);
2156 static BOOL
family_matches( struct gdi_font_family
*family
, const WCHAR
*face_name
)
2158 struct gdi_font_face
*face
;
2160 if (!strncmpiW( face_name
, family
->family_name
, LF_FACESIZE
- 1 )) return TRUE
;
2161 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2162 if (!strncmpiW( face_name
, face
->full_name
, LF_FACESIZE
- 1 )) return TRUE
;
2166 static BOOL
face_matches( const WCHAR
*family_name
, struct gdi_font_face
*face
, const WCHAR
*face_name
)
2168 if (!strncmpiW( face_name
, family_name
, LF_FACESIZE
- 1)) return TRUE
;
2169 return !strncmpiW( face_name
, face
->full_name
, LF_FACESIZE
- 1 );
2172 static BOOL
enum_face_charsets( const struct gdi_font_family
*family
, struct gdi_font_face
*face
,
2173 struct enum_charset
*list
, DWORD count
, FONTENUMPROCW proc
, LPARAM lparam
,
2174 const WCHAR
*subst
)
2177 NEWTEXTMETRICEXW ntm
;
2180 if (!face
->cached_enum_data
)
2182 struct gdi_font_enum_data
*data
;
2184 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return FALSE
;
2185 if (!get_face_enum_data( face
, &data
->elf
, &data
->ntm
))
2187 HeapFree( GetProcessHeap(), 0, data
);
2190 face
->cached_enum_data
= data
;
2193 elf
= face
->cached_enum_data
->elf
;
2194 ntm
= face
->cached_enum_data
->ntm
;
2195 type
= get_font_type( &ntm
);
2197 /* font replacement */
2198 if (family
!= face
->family
)
2200 lstrcpynW( elf
.elfLogFont
.lfFaceName
, family
->family_name
, LF_FACESIZE
);
2201 lstrcpynW( elf
.elfFullName
, face
->full_name
, LF_FULLFACESIZE
);
2203 if (subst
) lstrcpynW( elf
.elfLogFont
.lfFaceName
, subst
, LF_FACESIZE
);
2205 for (i
= 0; i
< count
; i
++)
2207 if (!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) /* OEM bitmap */
2209 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2210 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
2211 i
= count
; /* break out of loop after enumeration */
2215 if (!(face
->fs
.fsCsb
[0] & list
[i
].mask
)) continue;
2216 /* use the DEFAULT_CHARSET case only if no other charset is present */
2217 if (list
[i
].charset
== DEFAULT_CHARSET
&& (face
->fs
.fsCsb
[0] & ~list
[i
].mask
)) continue;
2218 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
[i
].charset
;
2219 load_script_name( list
[i
].script
, elf
.elfScript
);
2220 if (!elf
.elfScript
[0]) FIXME("Unknown elfscript for id %u\n", list
[i
].script
);
2222 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2223 debugstr_w(elf
.elfLogFont
.lfFaceName
), debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2224 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
2225 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
, ntm
.ntmTm
.ntmFlags
);
2226 /* release section before callback (FIXME) */
2227 LeaveCriticalSection( &font_cs
);
2228 if (!proc( &elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
2229 EnterCriticalSection( &font_cs
);
2234 /*************************************************************
2237 static BOOL CDECL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, FONTENUMPROCW proc
, LPARAM lparam
)
2239 struct gdi_font_family
*family
;
2240 struct gdi_font_face
*face
;
2241 struct enum_charset enum_charsets
[32];
2242 DWORD count
, charset
;
2244 charset
= lf
? lf
->lfCharSet
: DEFAULT_CHARSET
;
2246 count
= create_enum_charset_list( charset
, enum_charsets
);
2248 EnterCriticalSection( &font_cs
);
2250 if (lf
&& lf
->lfFaceName
[0])
2252 const WCHAR
*face_name
= get_gdi_font_subst( lf
->lfFaceName
, charset
, NULL
);
2253 const WCHAR
*orig_name
= NULL
;
2255 TRACE( "facename = %s charset %d\n", debugstr_w(lf
->lfFaceName
), charset
);
2258 orig_name
= lf
->lfFaceName
;
2259 TRACE( "substituting %s -> %s\n", debugstr_w(lf
->lfFaceName
), debugstr_w(face_name
) );
2261 else face_name
= lf
->lfFaceName
;
2263 LIST_FOR_EACH_ENTRY( family
, &font_list
, struct gdi_font_family
, entry
)
2265 if (!family_matches(family
, face_name
)) continue;
2266 LIST_FOR_EACH_ENTRY( face
, get_family_face_list(family
), struct gdi_font_face
, entry
)
2268 if (!face_matches( family
->family_name
, face
, face_name
)) continue;
2269 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, orig_name
))
2276 TRACE( "charset %d\n", charset
);
2277 LIST_FOR_EACH_ENTRY( family
, &font_list
, struct gdi_font_family
, entry
)
2279 face
= LIST_ENTRY( list_head(get_family_face_list(family
)), struct gdi_font_face
, entry
);
2280 if (!enum_face_charsets( family
, face
, enum_charsets
, count
, proc
, lparam
, NULL
))
2284 LeaveCriticalSection( &font_cs
);
2289 static BOOL
check_unicode_tategaki( WCHAR ch
)
2291 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
2292 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[ch
>> 8]+((ch
>> 4) & 0x0f)]+ (ch
& 0xf)];
2294 /* We only reach this code if typographical substitution did not occur */
2295 /* Type: U or Type: Tu */
2296 return (orientation
== 1 || orientation
== 3);
2299 static UINT
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2303 if (glyph
< 0x100) glyph
+= 0xf000;
2304 /* there are a number of old pre-Unicode "broken" TTFs, which
2305 do have symbols at U+00XX instead of U+f0XX */
2307 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2310 index
= glyph
- 0xf000;
2311 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2316 static UINT
get_glyph_index( struct gdi_font
*font
, UINT glyph
)
2322 if (font_funcs
->get_glyph_index( font
, &glyph
, TRUE
)) return glyph
;
2324 if (font
->codepage
== CP_SYMBOL
)
2326 glyph
= get_glyph_index_symbol( font
, wc
);
2329 if (WideCharToMultiByte( CP_ACP
, 0, &wc
, 1, &ch
, 1, NULL
, NULL
))
2330 glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2333 else if (WideCharToMultiByte( font
->codepage
, 0, &wc
, 1, &ch
, 1, NULL
, &used
) && !used
)
2335 glyph
= (unsigned char)ch
;
2336 font_funcs
->get_glyph_index( font
, &glyph
, FALSE
);
2341 static UINT
get_glyph_index_linked( struct gdi_font
**font
, UINT glyph
)
2343 struct gdi_font
*child
;
2346 if ((res
= get_glyph_index( *font
, glyph
))) return res
;
2347 if (glyph
< 32) return 0; /* don't check linked fonts for control characters */
2349 LIST_FOR_EACH_ENTRY( child
, &(*font
)->child_fonts
, struct gdi_font
, entry
)
2351 if (!child
->private && !font_funcs
->load_font( child
)) continue;
2352 if ((res
= get_glyph_index( child
, glyph
)))
2361 static DWORD
get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
2362 GLYPHMETRICS
*gm_ret
, ABC
*abc_ret
, DWORD buflen
, void *buf
,
2369 BOOL tategaki
= (*get_gdi_font_name( font
) == '@');
2371 if (format
& GGO_GLYPH_INDEX
)
2373 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
2374 as glyph index. "Treasure Adventure Game" depends on this. */
2375 font_funcs
->get_glyph_index( font
, &index
, FALSE
);
2376 /* TODO: Window also turns off tategaki for glyphs passed in by index
2377 if their unicode code points fall outside of the range that is
2382 index
= get_glyph_index_linked( &font
, glyph
);
2386 index
= get_GSUB_vert_glyph( font
, index
);
2387 if (index
== orig
) tategaki
= check_unicode_tategaki( glyph
);
2391 format
&= ~(GGO_GLYPH_INDEX
| GGO_UNHINTED
);
2393 if (mat
&& !memcmp( mat
, &identity
, sizeof(*mat
) )) mat
= NULL
;
2395 if (format
== GGO_METRICS
&& !mat
&& get_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
))
2398 ret
= font_funcs
->get_glyph_outline( font
, index
, format
, &gm
, &abc
, buflen
, buf
, mat
, tategaki
);
2399 if (ret
== GDI_ERROR
) return ret
;
2401 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) && !mat
)
2402 set_gdi_font_glyph_metrics( font
, index
, &gm
, &abc
);
2405 if (gm_ret
) *gm_ret
= gm
;
2406 if (abc_ret
) *abc_ret
= abc
;
2411 /*************************************************************
2414 static BOOL CDECL
font_FontIsLinked( PHYSDEV dev
)
2416 struct font_physdev
*physdev
= get_font_dev( dev
);
2420 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
2421 return dev
->funcs
->pFontIsLinked( dev
);
2423 return !list_empty( &physdev
->font
->child_fonts
);
2427 /*************************************************************
2428 * font_GetCharABCWidths
2430 static BOOL CDECL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT last
, ABC
*buffer
)
2432 struct font_physdev
*physdev
= get_font_dev( dev
);
2437 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
2438 return dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, buffer
);
2441 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, last
, buffer
);
2443 EnterCriticalSection( &font_cs
);
2444 for (c
= first
; c
<= last
; c
++, buffer
++)
2445 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, buffer
, 0, NULL
, NULL
);
2446 LeaveCriticalSection( &font_cs
);
2451 /*************************************************************
2452 * font_GetCharABCWidthsI
2454 static BOOL CDECL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
2456 struct font_physdev
*physdev
= get_font_dev( dev
);
2461 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
2462 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
2465 TRACE( "%p, %u, %u, %p\n", physdev
->font
, first
, count
, buffer
);
2467 EnterCriticalSection( &font_cs
);
2468 for (c
= 0; c
< count
; c
++, buffer
++)
2469 get_glyph_outline( physdev
->font
, gi
? gi
[c
] : first
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2470 NULL
, buffer
, 0, NULL
, NULL
);
2471 LeaveCriticalSection( &font_cs
);
2476 /*************************************************************
2479 static BOOL CDECL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT last
, INT
*buffer
)
2481 struct font_physdev
*physdev
= get_font_dev( dev
);
2487 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
2488 return dev
->funcs
->pGetCharWidth( dev
, first
, last
, buffer
);
2491 TRACE( "%p, %d, %d, %p\n", physdev
->font
, first
, last
, buffer
);
2493 EnterCriticalSection( &font_cs
);
2494 for (c
= first
; c
<= last
; c
++)
2496 if (get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
) == GDI_ERROR
)
2497 buffer
[c
- first
] = 0;
2499 buffer
[c
- first
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
2501 LeaveCriticalSection( &font_cs
);
2506 /*************************************************************
2507 * font_GetCharWidthInfo
2509 static BOOL CDECL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
2511 struct font_physdev
*physdev
= get_font_dev( dev
);
2512 struct char_width_info
*info
= ptr
;
2516 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
2517 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
2521 if (!physdev
->font
->scalable
|| !font_funcs
->get_char_width_info( physdev
->font
, info
))
2522 info
->lsb
= info
->rsb
= 0;
2528 /*************************************************************
2531 static DWORD CDECL
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
2533 struct font_physdev
*physdev
= get_font_dev( dev
);
2537 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
2538 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
2540 return font_funcs
->get_font_data( physdev
->font
, table
, offset
, buf
, size
);
2544 /*************************************************************
2545 * font_GetFontRealizationInfo
2547 static BOOL CDECL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
2549 struct font_physdev
*physdev
= get_font_dev( dev
);
2550 struct font_realization_info
*info
= ptr
;
2554 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
2555 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
2558 TRACE( "(%p, %p)\n", physdev
->font
, info
);
2561 if (physdev
->font
->scalable
) info
->flags
|= 2;
2563 info
->cache_num
= physdev
->font
->cache_num
;
2564 info
->instance_id
= physdev
->font
->handle
;
2565 if (info
->size
== sizeof(*info
))
2568 info
->face_index
= physdev
->font
->face_index
;
2569 info
->simulations
= 0;
2570 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
2571 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
2577 /*************************************************************
2578 * font_GetFontUnicodeRanges
2580 static DWORD CDECL
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
2582 struct font_physdev
*physdev
= get_font_dev( dev
);
2583 DWORD size
, num_ranges
;
2587 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
2588 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
2591 num_ranges
= font_funcs
->get_unicode_ranges( physdev
->font
, glyphset
);
2592 size
= offsetof( GLYPHSET
, ranges
[num_ranges
] );
2595 glyphset
->cbThis
= size
;
2596 glyphset
->cRanges
= num_ranges
;
2597 glyphset
->flAccel
= 0;
2603 /*************************************************************
2604 * font_GetGlyphIndices
2606 static DWORD CDECL
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
2608 struct font_physdev
*physdev
= get_font_dev( dev
);
2611 BOOL used
, got_default
= FALSE
;
2616 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
2617 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
2620 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
2622 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
2626 EnterCriticalSection( &font_cs
);
2628 for (i
= 0; i
< count
; i
++)
2630 UINT glyph
= str
[i
];
2632 if (!font_funcs
->get_glyph_index( physdev
->font
, &glyph
, TRUE
))
2635 if (physdev
->font
->codepage
== CP_SYMBOL
)
2637 if (str
[i
] >= 0xf020 && str
[i
] <= 0xf100) glyph
= str
[i
] - 0xf000;
2638 else if (str
[i
] < 0x100) glyph
= str
[i
];
2640 else if (WideCharToMultiByte( physdev
->font
->codepage
, 0, &str
[i
], 1,
2641 &ch
, 1, NULL
, &used
) && !used
)
2642 glyph
= (unsigned char)ch
;
2648 default_char
= font_funcs
->get_default_glyph( physdev
->font
);
2651 gi
[i
] = default_char
;
2653 else gi
[i
] = get_GSUB_vert_glyph( physdev
->font
, glyph
);
2656 LeaveCriticalSection( &font_cs
);
2661 /*************************************************************
2662 * font_GetGlyphOutline
2664 static DWORD CDECL
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
2665 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
2667 struct font_physdev
*physdev
= get_font_dev( dev
);
2672 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
2673 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
2675 EnterCriticalSection( &font_cs
);
2676 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, gm
, NULL
, buflen
, buf
, mat
);
2677 LeaveCriticalSection( &font_cs
);
2682 /*************************************************************
2683 * font_GetKerningPairs
2685 static DWORD CDECL
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
2687 struct font_physdev
*physdev
= get_font_dev( dev
);
2691 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
2692 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
2695 EnterCriticalSection( &font_cs
);
2696 if (physdev
->font
->kern_count
== -1)
2697 physdev
->font
->kern_count
= font_funcs
->get_kerning_pairs( physdev
->font
,
2698 &physdev
->font
->kern_pairs
);
2699 LeaveCriticalSection( &font_cs
);
2703 count
= min( count
, physdev
->font
->kern_count
);
2704 memcpy( pairs
, physdev
->font
->kern_pairs
, count
* sizeof(*pairs
) );
2706 else count
= physdev
->font
->kern_count
;
2712 static void scale_outline_font_metrics( const struct gdi_font
*font
, OUTLINETEXTMETRICW
*otm
)
2714 double scale_x
, scale_y
;
2718 scale_x
= (double)font
->aveWidth
;
2719 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2722 scale_x
= font
->scale_y
;
2724 scale_x
*= fabs(font
->matrix
.eM11
);
2725 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
2727 /* Windows scales these values as signed integers even if they are unsigned */
2728 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
2729 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
2731 SCALE_Y(otm
->otmTextMetrics
.tmHeight
);
2732 SCALE_Y(otm
->otmTextMetrics
.tmAscent
);
2733 SCALE_Y(otm
->otmTextMetrics
.tmDescent
);
2734 SCALE_Y(otm
->otmTextMetrics
.tmInternalLeading
);
2735 SCALE_Y(otm
->otmTextMetrics
.tmExternalLeading
);
2737 SCALE_X(otm
->otmTextMetrics
.tmOverhang
);
2738 if (font
->fake_bold
)
2740 if (!font
->scalable
) otm
->otmTextMetrics
.tmOverhang
++;
2741 otm
->otmTextMetrics
.tmAveCharWidth
++;
2742 otm
->otmTextMetrics
.tmMaxCharWidth
++;
2744 SCALE_X(otm
->otmTextMetrics
.tmAveCharWidth
);
2745 SCALE_X(otm
->otmTextMetrics
.tmMaxCharWidth
);
2747 SCALE_Y(otm
->otmAscent
);
2748 SCALE_Y(otm
->otmDescent
);
2749 SCALE_Y(otm
->otmLineGap
);
2750 SCALE_Y(otm
->otmsCapEmHeight
);
2751 SCALE_Y(otm
->otmsXHeight
);
2752 SCALE_Y(otm
->otmrcFontBox
.top
);
2753 SCALE_Y(otm
->otmrcFontBox
.bottom
);
2754 SCALE_X(otm
->otmrcFontBox
.left
);
2755 SCALE_X(otm
->otmrcFontBox
.right
);
2756 SCALE_Y(otm
->otmMacAscent
);
2757 SCALE_Y(otm
->otmMacDescent
);
2758 SCALE_Y(otm
->otmMacLineGap
);
2759 SCALE_X(otm
->otmptSubscriptSize
.x
);
2760 SCALE_Y(otm
->otmptSubscriptSize
.y
);
2761 SCALE_X(otm
->otmptSubscriptOffset
.x
);
2762 SCALE_Y(otm
->otmptSubscriptOffset
.y
);
2763 SCALE_X(otm
->otmptSuperscriptSize
.x
);
2764 SCALE_Y(otm
->otmptSuperscriptSize
.y
);
2765 SCALE_X(otm
->otmptSuperscriptOffset
.x
);
2766 SCALE_Y(otm
->otmptSuperscriptOffset
.y
);
2767 SCALE_Y(otm
->otmsStrikeoutSize
);
2768 SCALE_Y(otm
->otmsStrikeoutPosition
);
2769 SCALE_Y(otm
->otmsUnderscoreSize
);
2770 SCALE_Y(otm
->otmsUnderscorePosition
);
2776 /*************************************************************
2777 * font_GetOutlineTextMetrics
2779 static UINT CDECL
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
2781 struct font_physdev
*physdev
= get_font_dev( dev
);
2786 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
2787 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
2790 if (!physdev
->font
->scalable
) return 0;
2792 EnterCriticalSection( &font_cs
);
2793 if (font_funcs
->set_outline_text_metrics( physdev
->font
))
2795 ret
= physdev
->font
->otm
.otmSize
;
2796 if (metrics
&& size
>= physdev
->font
->otm
.otmSize
)
2798 WCHAR
*ptr
= (WCHAR
*)(metrics
+ 1);
2799 *metrics
= physdev
->font
->otm
;
2800 metrics
->otmpFamilyName
= (char *)ptr
- (ULONG_PTR
)metrics
;
2801 strcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFamilyName
);
2802 ptr
+= strlenW(ptr
) + 1;
2803 metrics
->otmpStyleName
= (char *)ptr
- (ULONG_PTR
)metrics
;
2804 strcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpStyleName
);
2805 ptr
+= strlenW(ptr
) + 1;
2806 metrics
->otmpFaceName
= (char *)ptr
- (ULONG_PTR
)metrics
;
2807 strcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFaceName
);
2808 ptr
+= strlenW(ptr
) + 1;
2809 metrics
->otmpFullName
= (char *)ptr
- (ULONG_PTR
)metrics
;
2810 strcpyW( ptr
, (WCHAR
*)physdev
->font
->otm
.otmpFullName
);
2811 scale_outline_font_metrics( physdev
->font
, metrics
);
2814 LeaveCriticalSection( &font_cs
);
2819 /*************************************************************
2820 * font_GetTextCharsetInfo
2822 static UINT CDECL
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
2824 struct font_physdev
*physdev
= get_font_dev( dev
);
2828 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
2829 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
2831 if (fs
) *fs
= physdev
->font
->fs
;
2832 return physdev
->font
->charset
;
2836 /*************************************************************
2837 * font_GetTextExtentExPoint
2839 static BOOL CDECL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
2841 struct font_physdev
*physdev
= get_font_dev( dev
);
2847 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
2848 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
2851 TRACE( "%p, %s, %d\n", physdev
->font
, debugstr_wn(str
, count
), count
);
2853 EnterCriticalSection( &font_cs
);
2854 for (i
= pos
= 0; i
< count
; i
++)
2856 get_glyph_outline( physdev
->font
, str
[i
], GGO_METRICS
, NULL
, &abc
, 0, NULL
, NULL
);
2857 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
2860 LeaveCriticalSection( &font_cs
);
2865 /*************************************************************
2866 * font_GetTextExtentExPointI
2868 static BOOL CDECL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
2870 struct font_physdev
*physdev
= get_font_dev( dev
);
2876 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
2877 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
2880 TRACE( "%p, %p, %d\n", physdev
->font
, indices
, count
);
2882 EnterCriticalSection( &font_cs
);
2883 for (i
= pos
= 0; i
< count
; i
++)
2885 get_glyph_outline( physdev
->font
, indices
[i
], GGO_METRICS
| GGO_GLYPH_INDEX
,
2886 NULL
, &abc
, 0, NULL
, NULL
);
2887 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
2890 LeaveCriticalSection( &font_cs
);
2895 /*************************************************************
2898 static INT CDECL
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
2900 struct font_physdev
*physdev
= get_font_dev( dev
);
2905 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
2906 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
2908 len
= strlenW( get_gdi_font_name(physdev
->font
) ) + 1;
2911 lstrcpynW( str
, get_gdi_font_name(physdev
->font
), count
);
2912 len
= min( count
, len
);
2918 static void scale_font_metrics( struct gdi_font
*font
, TEXTMETRICW
*tm
)
2920 double scale_x
, scale_y
;
2922 /* Make sure that the font has sane width/height ratio */
2923 if (font
->aveWidth
&& (font
->aveWidth
+ tm
->tmHeight
- 1) / tm
->tmHeight
> 100)
2925 WARN( "Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
2931 scale_x
= (double)font
->aveWidth
;
2932 scale_x
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2935 scale_x
= font
->scale_y
;
2937 scale_x
*= fabs(font
->matrix
.eM11
);
2938 scale_y
= font
->scale_y
* fabs(font
->matrix
.eM22
);
2940 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
2941 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
2943 SCALE_Y(tm
->tmHeight
);
2944 SCALE_Y(tm
->tmAscent
);
2945 SCALE_Y(tm
->tmDescent
);
2946 SCALE_Y(tm
->tmInternalLeading
);
2947 SCALE_Y(tm
->tmExternalLeading
);
2949 SCALE_X(tm
->tmOverhang
);
2950 if (font
->fake_bold
)
2952 if (!font
->scalable
) tm
->tmOverhang
++;
2953 tm
->tmAveCharWidth
++;
2954 tm
->tmMaxCharWidth
++;
2956 SCALE_X(tm
->tmAveCharWidth
);
2957 SCALE_X(tm
->tmMaxCharWidth
);
2963 /*************************************************************
2964 * font_GetTextMetrics
2966 static BOOL CDECL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
2968 struct font_physdev
*physdev
= get_font_dev( dev
);
2973 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
2974 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
2977 EnterCriticalSection( &font_cs
);
2978 if (font_funcs
->set_outline_text_metrics( physdev
->font
) ||
2979 font_funcs
->set_bitmap_text_metrics( physdev
->font
))
2981 *metrics
= physdev
->font
->otm
.otmTextMetrics
;
2982 scale_font_metrics( physdev
->font
, metrics
);
2985 LeaveCriticalSection( &font_cs
);
2990 /*************************************************************
2993 static HFONT CDECL
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
2995 struct font_physdev
*physdev
= get_font_dev( dev
);
2996 struct gdi_font
*font
= NULL
, *prev
= physdev
->font
;
2997 DC
*dc
= get_physdev_dc( dev
);
3003 GetObjectW( hfont
, sizeof(lf
), &lf
);
3004 switch (lf
.lfQuality
)
3006 case NONANTIALIASED_QUALITY
:
3007 if (!*aa_flags
) *aa_flags
= GGO_BITMAP
;
3009 case ANTIALIASED_QUALITY
:
3010 if (!*aa_flags
) *aa_flags
= GGO_GRAY4_BITMAP
;
3014 EnterCriticalSection( &font_cs
);
3016 font
= font_funcs
->pSelectFont( dc
, hfont
);
3017 if (font
&& !*aa_flags
)
3019 *aa_flags
= font
->aa_flags
;
3022 if (lf
.lfQuality
== CLEARTYPE_QUALITY
|| lf
.lfQuality
== CLEARTYPE_NATURAL_QUALITY
)
3023 *aa_flags
= subpixel_orientation
;
3025 *aa_flags
= font_smoothing
;
3027 *aa_flags
= font_funcs
->get_aa_flags( font
, *aa_flags
, antialias_fakes
);
3029 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
3030 LeaveCriticalSection( &font_cs
);
3032 physdev
->font
= font
;
3033 if (prev
) release_gdi_font( prev
);
3034 return font
? hfont
: 0;
3038 const struct gdi_dc_funcs font_driver
=
3040 NULL
, /* pAbortDoc */
3041 NULL
, /* pAbortPath */
3042 NULL
, /* pAlphaBlend */
3043 NULL
, /* pAngleArc */
3046 NULL
, /* pBeginPath */
3047 NULL
, /* pBlendImage */
3049 NULL
, /* pCloseFigure */
3050 NULL
, /* pCreateCompatibleDC */
3051 font_CreateDC
, /* pCreateDC */
3052 font_DeleteDC
, /* pDeleteDC */
3053 NULL
, /* pDeleteObject */
3054 NULL
, /* pDeviceCapabilities */
3055 NULL
, /* pEllipse */
3057 NULL
, /* pEndPage */
3058 NULL
, /* pEndPath */
3059 font_EnumFonts
, /* pEnumFonts */
3060 NULL
, /* pEnumICMProfiles */
3061 NULL
, /* pExcludeClipRect */
3062 NULL
, /* pExtDeviceMode */
3063 NULL
, /* pExtEscape */
3064 NULL
, /* pExtFloodFill */
3065 NULL
, /* pExtSelectClipRgn */
3066 NULL
, /* pExtTextOut */
3067 NULL
, /* pFillPath */
3068 NULL
, /* pFillRgn */
3069 NULL
, /* pFlattenPath */
3070 font_FontIsLinked
, /* pFontIsLinked */
3071 NULL
, /* pFrameRgn */
3072 NULL
, /* pGdiComment */
3073 NULL
, /* pGetBoundsRect */
3074 font_GetCharABCWidths
, /* pGetCharABCWidths */
3075 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
3076 font_GetCharWidth
, /* pGetCharWidth */
3077 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
3078 NULL
, /* pGetDeviceCaps */
3079 NULL
, /* pGetDeviceGammaRamp */
3080 font_GetFontData
, /* pGetFontData */
3081 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
3082 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
3083 font_GetGlyphIndices
, /* pGetGlyphIndices */
3084 font_GetGlyphOutline
, /* pGetGlyphOutline */
3085 NULL
, /* pGetICMProfile */
3086 NULL
, /* pGetImage */
3087 font_GetKerningPairs
, /* pGetKerningPairs */
3088 NULL
, /* pGetNearestColor */
3089 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
3090 NULL
, /* pGetPixel */
3091 NULL
, /* pGetSystemPaletteEntries */
3092 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
3093 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
3094 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
3095 font_GetTextFace
, /* pGetTextFace */
3096 font_GetTextMetrics
, /* pGetTextMetrics */
3097 NULL
, /* pGradientFill */
3098 NULL
, /* pIntersectClipRect */
3099 NULL
, /* pInvertRgn */
3101 NULL
, /* pModifyWorldTransform */
3103 NULL
, /* pOffsetClipRgn */
3104 NULL
, /* pOffsetViewportOrg */
3105 NULL
, /* pOffsetWindowOrg */
3106 NULL
, /* pPaintRgn */
3109 NULL
, /* pPolyBezier */
3110 NULL
, /* pPolyBezierTo */
3111 NULL
, /* pPolyDraw */
3112 NULL
, /* pPolyPolygon */
3113 NULL
, /* pPolyPolyline */
3114 NULL
, /* pPolygon */
3115 NULL
, /* pPolyline */
3116 NULL
, /* pPolylineTo */
3117 NULL
, /* pPutImage */
3118 NULL
, /* pRealizeDefaultPalette */
3119 NULL
, /* pRealizePalette */
3120 NULL
, /* pRectangle */
3121 NULL
, /* pResetDC */
3122 NULL
, /* pRestoreDC */
3123 NULL
, /* pRoundRect */
3125 NULL
, /* pScaleViewportExt */
3126 NULL
, /* pScaleWindowExt */
3127 NULL
, /* pSelectBitmap */
3128 NULL
, /* pSelectBrush */
3129 NULL
, /* pSelectClipPath */
3130 font_SelectFont
, /* pSelectFont */
3131 NULL
, /* pSelectPalette */
3132 NULL
, /* pSelectPen */
3133 NULL
, /* pSetArcDirection */
3134 NULL
, /* pSetBkColor */
3135 NULL
, /* pSetBkMode */
3136 NULL
, /* pSetBoundsRect */
3137 NULL
, /* pSetDCBrushColor */
3138 NULL
, /* pSetDCPenColor */
3139 NULL
, /* pSetDIBitsToDevice */
3140 NULL
, /* pSetDeviceClipping */
3141 NULL
, /* pSetDeviceGammaRamp */
3142 NULL
, /* pSetLayout */
3143 NULL
, /* pSetMapMode */
3144 NULL
, /* pSetMapperFlags */
3145 NULL
, /* pSetPixel */
3146 NULL
, /* pSetPolyFillMode */
3147 NULL
, /* pSetROP2 */
3148 NULL
, /* pSetRelAbs */
3149 NULL
, /* pSetStretchBltMode */
3150 NULL
, /* pSetTextAlign */
3151 NULL
, /* pSetTextCharacterExtra */
3152 NULL
, /* pSetTextColor */
3153 NULL
, /* pSetTextJustification */
3154 NULL
, /* pSetViewportExt */
3155 NULL
, /* pSetViewportOrg */
3156 NULL
, /* pSetWindowExt */
3157 NULL
, /* pSetWindowOrg */
3158 NULL
, /* pSetWorldTransform */
3159 NULL
, /* pStartDoc */
3160 NULL
, /* pStartPage */
3161 NULL
, /* pStretchBlt */
3162 NULL
, /* pStretchDIBits */
3163 NULL
, /* pStrokeAndFillPath */
3164 NULL
, /* pStrokePath */
3165 NULL
, /* pUnrealizePalette */
3166 NULL
, /* pWidenPath */
3167 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
3168 NULL
, /* pD3DKMTSetVidPnSourceOwner */
3169 NULL
, /* wine_get_wgl_driver */
3170 NULL
, /* wine_get_vulkan_driver */
3171 GDI_PRIORITY_FONT_DRV
/* priority */
3174 static DWORD
get_key_value( HKEY key
, const WCHAR
*name
, DWORD
*value
)
3177 DWORD count
= sizeof(buf
), type
, err
;
3179 err
= RegQueryValueExW( key
, name
, NULL
, &type
, (BYTE
*)buf
, &count
);
3182 if (type
== REG_DWORD
) memcpy( value
, buf
, sizeof(*value
) );
3183 else *value
= atoiW( buf
);
3188 static void init_font_options(void)
3190 static const WCHAR antialias_fake_bold_or_italic
[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
3191 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
3192 static const WCHAR true_options
[] = { 'y','Y','t','T','1',0 };
3193 static const WCHAR desktopW
[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
3194 'D','e','s','k','t','o','p',0 };
3195 static const WCHAR smoothing
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
3196 static const WCHAR smoothing_type
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
3197 static const WCHAR smoothing_orientation
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
3198 'O','r','i','e','n','t','a','t','i','o','n',0};
3200 DWORD type
, size
, val
;
3203 size
= sizeof(buffer
);
3204 if (!RegQueryValueExW( wine_fonts_key
, antialias_fake_bold_or_italic
, NULL
,
3205 &type
, (BYTE
*)buffer
, &size
) && type
== REG_SZ
&& size
>= 1)
3207 antialias_fakes
= (strchrW(true_options
, buffer
[0]) != NULL
);
3210 if (!RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
))
3212 /* FIXME: handle vertical orientations even though Windows doesn't */
3213 if (!get_key_value( key
, smoothing_orientation
, &val
))
3217 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
3218 subpixel_orientation
= WINE_GGO_HBGR_BITMAP
;
3220 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
3221 subpixel_orientation
= WINE_GGO_HRGB_BITMAP
;
3225 if (!get_key_value( key
, smoothing
, &val
) && val
/* enabled */)
3227 if (!get_key_value( key
, smoothing_type
, &val
) && val
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
3228 font_smoothing
= subpixel_orientation
;
3230 font_smoothing
= GGO_GRAY4_BITMAP
;
3236 /***********************************************************************
3239 void font_init(void)
3241 static const WCHAR mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_',0};
3244 if (RegCreateKeyExA( HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0,
3245 KEY_ALL_ACCESS
, NULL
, &wine_fonts_key
, NULL
))
3248 init_font_options();
3250 if (!WineEngInit( &font_funcs
)) return;
3252 if (!(mutex
= CreateMutexW( NULL
, FALSE
, mutex_nameW
))) return;
3253 WaitForSingleObject( mutex
, INFINITE
);
3254 font_funcs
->load_fonts();
3255 ReleaseMutex( mutex
);
3257 reorder_font_list();
3258 load_gdi_font_subst();
3259 load_gdi_font_replacements();
3260 load_system_links();
3261 dump_gdi_font_list();
3262 dump_gdi_font_subst();
3266 static void FONT_LogFontAToW( const LOGFONTA
*fontA
, LPLOGFONTW fontW
)
3268 memcpy(fontW
, fontA
, sizeof(LOGFONTA
) - LF_FACESIZE
);
3269 MultiByteToWideChar(CP_ACP
, 0, fontA
->lfFaceName
, -1, fontW
->lfFaceName
,
3271 fontW
->lfFaceName
[LF_FACESIZE
-1] = 0;
3274 static void FONT_LogFontWToA( const LOGFONTW
*fontW
, LPLOGFONTA fontA
)
3276 memcpy(fontA
, fontW
, sizeof(LOGFONTA
) - LF_FACESIZE
);
3277 WideCharToMultiByte(CP_ACP
, 0, fontW
->lfFaceName
, -1, fontA
->lfFaceName
,
3278 LF_FACESIZE
, NULL
, NULL
);
3279 fontA
->lfFaceName
[LF_FACESIZE
-1] = 0;
3282 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW
*fontW
, LPENUMLOGFONTEXA fontA
)
3284 FONT_LogFontWToA( &fontW
->elfLogFont
, &fontA
->elfLogFont
);
3286 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfFullName
, -1,
3287 (LPSTR
) fontA
->elfFullName
, LF_FULLFACESIZE
, NULL
, NULL
);
3288 fontA
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
3289 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfStyle
, -1,
3290 (LPSTR
) fontA
->elfStyle
, LF_FACESIZE
, NULL
, NULL
);
3291 fontA
->elfStyle
[LF_FACESIZE
-1] = '\0';
3292 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfScript
, -1,
3293 (LPSTR
) fontA
->elfScript
, LF_FACESIZE
, NULL
, NULL
);
3294 fontA
->elfScript
[LF_FACESIZE
-1] = '\0';
3297 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA
*fontA
, LPENUMLOGFONTEXW fontW
)
3299 FONT_LogFontAToW( &fontA
->elfLogFont
, &fontW
->elfLogFont
);
3301 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfFullName
, -1,
3302 fontW
->elfFullName
, LF_FULLFACESIZE
);
3303 fontW
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
3304 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfStyle
, -1,
3305 fontW
->elfStyle
, LF_FACESIZE
);
3306 fontW
->elfStyle
[LF_FACESIZE
-1] = '\0';
3307 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfScript
, -1,
3308 fontW
->elfScript
, LF_FACESIZE
);
3309 fontW
->elfScript
[LF_FACESIZE
-1] = '\0';
3312 /***********************************************************************
3313 * TEXTMETRIC conversion functions.
3315 static void FONT_TextMetricWToA(const TEXTMETRICW
*ptmW
, LPTEXTMETRICA ptmA
)
3317 ptmA
->tmHeight
= ptmW
->tmHeight
;
3318 ptmA
->tmAscent
= ptmW
->tmAscent
;
3319 ptmA
->tmDescent
= ptmW
->tmDescent
;
3320 ptmA
->tmInternalLeading
= ptmW
->tmInternalLeading
;
3321 ptmA
->tmExternalLeading
= ptmW
->tmExternalLeading
;
3322 ptmA
->tmAveCharWidth
= ptmW
->tmAveCharWidth
;
3323 ptmA
->tmMaxCharWidth
= ptmW
->tmMaxCharWidth
;
3324 ptmA
->tmWeight
= ptmW
->tmWeight
;
3325 ptmA
->tmOverhang
= ptmW
->tmOverhang
;
3326 ptmA
->tmDigitizedAspectX
= ptmW
->tmDigitizedAspectX
;
3327 ptmA
->tmDigitizedAspectY
= ptmW
->tmDigitizedAspectY
;
3328 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 255);
3329 if (ptmW
->tmCharSet
== SYMBOL_CHARSET
)
3331 ptmA
->tmFirstChar
= 0x1e;
3332 ptmA
->tmLastChar
= 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
3334 else if (ptmW
->tmPitchAndFamily
& TMPF_TRUETYPE
)
3336 ptmA
->tmFirstChar
= ptmW
->tmDefaultChar
- 1;
3337 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
3341 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 0xff);
3342 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
3344 ptmA
->tmDefaultChar
= ptmW
->tmDefaultChar
;
3345 ptmA
->tmBreakChar
= ptmW
->tmBreakChar
;
3346 ptmA
->tmItalic
= ptmW
->tmItalic
;
3347 ptmA
->tmUnderlined
= ptmW
->tmUnderlined
;
3348 ptmA
->tmStruckOut
= ptmW
->tmStruckOut
;
3349 ptmA
->tmPitchAndFamily
= ptmW
->tmPitchAndFamily
;
3350 ptmA
->tmCharSet
= ptmW
->tmCharSet
;
3354 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW
*ptmW
, NEWTEXTMETRICEXA
*ptmA
)
3356 FONT_TextMetricWToA((const TEXTMETRICW
*)ptmW
, (LPTEXTMETRICA
)ptmA
);
3357 ptmA
->ntmTm
.ntmFlags
= ptmW
->ntmTm
.ntmFlags
;
3358 ptmA
->ntmTm
.ntmSizeEM
= ptmW
->ntmTm
.ntmSizeEM
;
3359 ptmA
->ntmTm
.ntmCellHeight
= ptmW
->ntmTm
.ntmCellHeight
;
3360 ptmA
->ntmTm
.ntmAvgWidth
= ptmW
->ntmTm
.ntmAvgWidth
;
3361 memcpy(&ptmA
->ntmFontSig
, &ptmW
->ntmFontSig
, sizeof(FONTSIGNATURE
));
3364 /* compute positions for text rendering, in device coords */
3365 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
3370 size
->cx
= size
->cy
= 0;
3371 if (!count
) return TRUE
;
3373 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
3374 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
3376 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
3377 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
3379 if (dc
->breakExtra
|| dc
->breakRem
)
3381 int i
, space
= 0, rem
= dc
->breakRem
;
3383 for (i
= 0; i
< count
; i
++)
3385 if (str
[i
] == tm
.tmBreakChar
)
3387 space
+= dc
->breakExtra
;
3397 size
->cx
= dx
[count
- 1];
3398 size
->cy
= tm
.tmHeight
;
3402 /* compute positions for text rendering, in device coords */
3403 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
3408 size
->cx
= size
->cy
= 0;
3409 if (!count
) return TRUE
;
3411 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
3412 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
3414 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
3415 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
3417 if (dc
->breakExtra
|| dc
->breakRem
)
3420 int i
, space
= 0, rem
= dc
->breakRem
;
3422 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
3423 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
3425 for (i
= 0; i
< count
; i
++)
3427 if (indices
[i
] == space_index
)
3429 space
+= dc
->breakExtra
;
3439 size
->cx
= dx
[count
- 1];
3440 size
->cy
= tm
.tmHeight
;
3444 /***********************************************************************
3445 * GdiGetCodePage (GDI32.@)
3447 DWORD WINAPI
GdiGetCodePage( HDC hdc
)
3450 DC
*dc
= get_dc_ptr( hdc
);
3454 cp
= dc
->font_code_page
;
3455 release_dc_ptr( dc
);
3460 /***********************************************************************
3461 * get_text_charset_info
3463 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
3465 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
3467 UINT ret
= DEFAULT_CHARSET
;
3470 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
3471 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
3473 if (ret
== DEFAULT_CHARSET
&& fs
)
3474 memset(fs
, 0, sizeof(FONTSIGNATURE
));
3478 /***********************************************************************
3479 * GetTextCharsetInfo (GDI32.@)
3481 UINT WINAPI
GetTextCharsetInfo(HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
3483 UINT ret
= DEFAULT_CHARSET
;
3484 DC
*dc
= get_dc_ptr(hdc
);
3488 ret
= get_text_charset_info( dc
, fs
, flags
);
3489 release_dc_ptr( dc
);
3494 /***********************************************************************
3497 * Returns a Unicode translation of str using the charset of the
3498 * currently selected font in hdc. If count is -1 then str is assumed
3499 * to be '\0' terminated, otherwise it contains the number of bytes to
3500 * convert. If plenW is non-NULL, on return it will point to the
3501 * number of WCHARs that have been written. If pCP is non-NULL, on
3502 * return it will point to the codepage used in the conversion. The
3503 * caller should free the returned LPWSTR from the process heap
3506 static LPWSTR
FONT_mbtowc(HDC hdc
, LPCSTR str
, INT count
, INT
*plenW
, UINT
*pCP
)
3512 cp
= GdiGetCodePage( hdc
);
3514 if(count
== -1) count
= strlen(str
);
3515 lenW
= MultiByteToWideChar(cp
, 0, str
, count
, NULL
, 0);
3516 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
*sizeof(WCHAR
));
3517 MultiByteToWideChar(cp
, 0, str
, count
, strW
, lenW
);
3518 TRACE("mapped %s -> %s\n", debugstr_an(str
, count
), debugstr_wn(strW
, lenW
));
3519 if(plenW
) *plenW
= lenW
;
3524 /***********************************************************************
3525 * CreateFontIndirectExA (GDI32.@)
3527 HFONT WINAPI
CreateFontIndirectExA( const ENUMLOGFONTEXDVA
*penumexA
)
3529 ENUMLOGFONTEXDVW enumexW
;
3531 if (!penumexA
) return 0;
3533 FONT_EnumLogFontExAToW( &penumexA
->elfEnumLogfontEx
, &enumexW
.elfEnumLogfontEx
);
3534 enumexW
.elfDesignVector
= penumexA
->elfDesignVector
;
3535 return CreateFontIndirectExW( &enumexW
);
3538 /***********************************************************************
3539 * CreateFontIndirectExW (GDI32.@)
3541 HFONT WINAPI
CreateFontIndirectExW( const ENUMLOGFONTEXDVW
*penumex
)
3545 const LOGFONTW
*plf
;
3547 if (!penumex
) return 0;
3549 if (penumex
->elfEnumLogfontEx
.elfFullName
[0] ||
3550 penumex
->elfEnumLogfontEx
.elfStyle
[0] ||
3551 penumex
->elfEnumLogfontEx
.elfScript
[0])
3553 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
3554 debugstr_w(penumex
->elfEnumLogfontEx
.elfFullName
),
3555 debugstr_w(penumex
->elfEnumLogfontEx
.elfStyle
),
3556 debugstr_w(penumex
->elfEnumLogfontEx
.elfScript
));
3559 plf
= &penumex
->elfEnumLogfontEx
.elfLogFont
;
3560 if (!(fontPtr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr
) ))) return 0;
3562 fontPtr
->logfont
= *plf
;
3564 if (!(hFont
= alloc_gdi_handle( fontPtr
, OBJ_FONT
, &fontobj_funcs
)))
3566 HeapFree( GetProcessHeap(), 0, fontPtr
);
3570 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
3571 plf
->lfHeight
, plf
->lfWidth
,
3572 plf
->lfEscapement
, plf
->lfOrientation
,
3573 plf
->lfPitchAndFamily
,
3574 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
3575 plf
->lfQuality
, plf
->lfCharSet
,
3576 debugstr_w(plf
->lfFaceName
),
3577 plf
->lfWeight
> 400 ? "Bold" : "",
3578 plf
->lfItalic
? "Italic" : "",
3579 plf
->lfUnderline
? "Underline" : "", hFont
);
3584 /***********************************************************************
3585 * CreateFontIndirectA (GDI32.@)
3587 HFONT WINAPI
CreateFontIndirectA( const LOGFONTA
*plfA
)
3591 if (!plfA
) return 0;
3593 FONT_LogFontAToW( plfA
, &lfW
);
3594 return CreateFontIndirectW( &lfW
);
3597 /***********************************************************************
3598 * CreateFontIndirectW (GDI32.@)
3600 HFONT WINAPI
CreateFontIndirectW( const LOGFONTW
*plf
)
3602 ENUMLOGFONTEXDVW exdv
;
3606 exdv
.elfEnumLogfontEx
.elfLogFont
= *plf
;
3607 exdv
.elfEnumLogfontEx
.elfFullName
[0] = 0;
3608 exdv
.elfEnumLogfontEx
.elfStyle
[0] = 0;
3609 exdv
.elfEnumLogfontEx
.elfScript
[0] = 0;
3610 return CreateFontIndirectExW( &exdv
);
3613 /*************************************************************************
3614 * CreateFontA (GDI32.@)
3616 HFONT WINAPI
CreateFontA( INT height
, INT width
, INT esc
,
3617 INT orient
, INT weight
, DWORD italic
,
3618 DWORD underline
, DWORD strikeout
, DWORD charset
,
3619 DWORD outpres
, DWORD clippres
, DWORD quality
,
3620 DWORD pitch
, LPCSTR name
)
3624 logfont
.lfHeight
= height
;
3625 logfont
.lfWidth
= width
;
3626 logfont
.lfEscapement
= esc
;
3627 logfont
.lfOrientation
= orient
;
3628 logfont
.lfWeight
= weight
;
3629 logfont
.lfItalic
= italic
;
3630 logfont
.lfUnderline
= underline
;
3631 logfont
.lfStrikeOut
= strikeout
;
3632 logfont
.lfCharSet
= charset
;
3633 logfont
.lfOutPrecision
= outpres
;
3634 logfont
.lfClipPrecision
= clippres
;
3635 logfont
.lfQuality
= quality
;
3636 logfont
.lfPitchAndFamily
= pitch
;
3639 lstrcpynA(logfont
.lfFaceName
,name
,sizeof(logfont
.lfFaceName
));
3641 logfont
.lfFaceName
[0] = '\0';
3643 return CreateFontIndirectA( &logfont
);
3646 /*************************************************************************
3647 * CreateFontW (GDI32.@)
3649 HFONT WINAPI
CreateFontW( INT height
, INT width
, INT esc
,
3650 INT orient
, INT weight
, DWORD italic
,
3651 DWORD underline
, DWORD strikeout
, DWORD charset
,
3652 DWORD outpres
, DWORD clippres
, DWORD quality
,
3653 DWORD pitch
, LPCWSTR name
)
3657 logfont
.lfHeight
= height
;
3658 logfont
.lfWidth
= width
;
3659 logfont
.lfEscapement
= esc
;
3660 logfont
.lfOrientation
= orient
;
3661 logfont
.lfWeight
= weight
;
3662 logfont
.lfItalic
= italic
;
3663 logfont
.lfUnderline
= underline
;
3664 logfont
.lfStrikeOut
= strikeout
;
3665 logfont
.lfCharSet
= charset
;
3666 logfont
.lfOutPrecision
= outpres
;
3667 logfont
.lfClipPrecision
= clippres
;
3668 logfont
.lfQuality
= quality
;
3669 logfont
.lfPitchAndFamily
= pitch
;
3672 lstrcpynW(logfont
.lfFaceName
, name
, ARRAY_SIZE(logfont
.lfFaceName
));
3674 logfont
.lfFaceName
[0] = '\0';
3676 return CreateFontIndirectW( &logfont
);
3679 #define ASSOC_CHARSET_OEM 1
3680 #define ASSOC_CHARSET_ANSI 2
3681 #define ASSOC_CHARSET_SYMBOL 4
3683 static DWORD
get_associated_charset_info(void)
3685 static DWORD associated_charset
= -1;
3687 if (associated_charset
== -1)
3689 static const WCHAR assoc_charset_reg_keyW
[] = {'S','y','s','t','e','m','\\',
3690 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
3691 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
3692 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
3693 static const WCHAR ansiW
[] = {'A','N','S','I','(','0','0',')','\0'};
3694 static const WCHAR oemW
[] = {'O','E','M','(','F','F',')','\0'};
3695 static const WCHAR symbolW
[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
3696 static const WCHAR yesW
[] = {'Y','E','S','\0'};
3699 DWORD type
, data_len
;
3701 associated_charset
= 0;
3703 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3704 assoc_charset_reg_keyW
, &hkey
) != ERROR_SUCCESS
)
3707 data_len
= sizeof(dataW
);
3708 if (!RegQueryValueExW(hkey
, ansiW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
3709 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
3710 associated_charset
|= ASSOC_CHARSET_ANSI
;
3712 data_len
= sizeof(dataW
);
3713 if (!RegQueryValueExW(hkey
, oemW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
3714 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
3715 associated_charset
|= ASSOC_CHARSET_OEM
;
3717 data_len
= sizeof(dataW
);
3718 if (!RegQueryValueExW(hkey
, symbolW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
3719 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
3720 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
3724 TRACE("associated_charset = %d\n", associated_charset
);
3727 return associated_charset
;
3730 static void update_font_code_page( DC
*dc
, HANDLE font
)
3733 int charset
= get_text_charset_info( dc
, NULL
, 0 );
3735 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
3739 GetObjectW( font
, sizeof(lf
), &lf
);
3740 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
3741 charset
= DEFAULT_CHARSET
;
3744 /* Hmm, nicely designed api this one! */
3745 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
3746 dc
->font_code_page
= csi
.ciACP
;
3750 dc
->font_code_page
= GetOEMCP();
3752 case DEFAULT_CHARSET
:
3753 dc
->font_code_page
= GetACP();
3756 case VISCII_CHARSET
:
3762 case CELTIC_CHARSET
:
3763 /* FIXME: These have no place here, but because x11drv
3764 enumerates fonts with these (made up) charsets some apps
3765 might use them and then the FIXME below would become
3766 annoying. Now we could pick the intended codepage for
3767 each of these, but since it's broken anyway we'll just
3768 use CP_ACP and hope it'll go away...
3770 dc
->font_code_page
= CP_ACP
;
3774 FIXME("Can't find codepage for charset %d\n", charset
);
3775 dc
->font_code_page
= CP_ACP
;
3780 TRACE("charset %d => cp %d\n", charset
, dc
->font_code_page
);
3783 static BOOL WINAPI
fill_font_gamma_ramp( INIT_ONCE
*once
, void *param
, void **context
)
3785 static const WCHAR desktopW
[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
3786 'D','e','s','k','t','o','p',0 };
3787 static const WCHAR smoothing_gamma
[] = { 'F','o','n','t','S','m','o','o','t','h','i','n','g',
3788 'G','a','m','m','a',0 };
3789 struct font_gamma_ramp
*ramp
= param
;
3790 const DWORD gamma_default
= 1400;
3794 gamma
= gamma_default
;
3795 if (RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
) == ERROR_SUCCESS
)
3797 if (get_key_value( key
, smoothing_gamma
, &gamma
) || gamma
== 0)
3798 gamma
= gamma_default
;
3801 gamma
= min( max( gamma
, 1000 ), 2200 );
3804 /* Calibrating the difference between the registry value and the Wine gamma value.
3805 This looks roughly similar to Windows Native with the same registry value.
3806 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
3807 gamma
= 1000 * gamma
/ 1400;
3809 for (i
= 0; i
< 256; i
++)
3811 ramp
->encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
3812 ramp
->decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
3815 ramp
->gamma
= gamma
;
3816 TRACE("gamma %d\n", ramp
->gamma
);
3821 static struct font_gamma_ramp
*get_font_gamma_ramp( void )
3823 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
3824 static struct font_gamma_ramp ramp
;
3826 InitOnceExecuteOnce( &init_once
, fill_font_gamma_ramp
, &ramp
, NULL
);
3830 /***********************************************************************
3833 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
)
3836 DC
*dc
= get_dc_ptr( hdc
);
3842 if (!GDI_inc_ref_count( handle
))
3844 release_dc_ptr( dc
);
3848 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
3849 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
3853 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
3854 update_font_code_page( dc
, handle
);
3855 if (dc
->font_gamma_ramp
== NULL
)
3856 dc
->font_gamma_ramp
= get_font_gamma_ramp();
3857 GDI_dec_ref_count( ret
);
3859 else GDI_dec_ref_count( handle
);
3861 release_dc_ptr( dc
);
3866 /***********************************************************************
3869 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
)
3871 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
3874 if (!font
) return 0;
3877 FONT_LogFontWToA( &font
->logfont
, &lfA
);
3878 if (count
> sizeof(lfA
)) count
= sizeof(lfA
);
3879 memcpy( buffer
, &lfA
, count
);
3881 else count
= sizeof(lfA
);
3882 GDI_ReleaseObj( handle
);
3886 /***********************************************************************
3889 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
3891 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
3893 if (!font
) return 0;
3896 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
3897 memcpy( buffer
, &font
->logfont
, count
);
3899 else count
= sizeof(LOGFONTW
);
3900 GDI_ReleaseObj( handle
);
3905 /***********************************************************************
3908 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
3912 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
3913 HeapFree( GetProcessHeap(), 0, obj
);
3918 /***********************************************************************
3921 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
3922 * We have to use other types because of the FONTENUMPROCW definition.
3924 static INT CALLBACK
FONT_EnumInstance( const LOGFONTW
*plf
, const TEXTMETRICW
*ptm
,
3925 DWORD fType
, LPARAM lp
)
3927 struct font_enum
*pfe
= (struct font_enum
*)lp
;
3930 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
3931 if ((!pfe
->lpLogFontParam
||
3932 pfe
->lpLogFontParam
->lfCharSet
== DEFAULT_CHARSET
||
3933 pfe
->lpLogFontParam
->lfCharSet
== plf
->lfCharSet
) &&
3934 (!(fType
& RASTER_FONTTYPE
) || GetDeviceCaps(pfe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
) )
3936 /* convert font metrics */
3937 ENUMLOGFONTEXA logfont
;
3938 NEWTEXTMETRICEXA tmA
;
3942 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW
*)plf
, &logfont
);
3943 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW
*)ptm
, &tmA
);
3944 plf
= (LOGFONTW
*)&logfont
.elfLogFont
;
3945 ptm
= (TEXTMETRICW
*)&tmA
;
3947 ret
= pfe
->lpEnumFunc( plf
, ptm
, fType
, pfe
->lpData
);
3953 /***********************************************************************
3954 * FONT_EnumFontFamiliesEx
3956 static INT
FONT_EnumFontFamiliesEx( HDC hDC
, LPLOGFONTW plf
, FONTENUMPROCW efproc
,
3957 LPARAM lParam
, BOOL unicode
)
3960 DC
*dc
= get_dc_ptr( hDC
);
3961 struct font_enum fe
;
3965 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
3967 if (plf
) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3968 fe
.lpLogFontParam
= plf
;
3969 fe
.lpEnumFunc
= efproc
;
3971 fe
.unicode
= unicode
;
3974 ret
= physdev
->funcs
->pEnumFonts( physdev
, plf
, FONT_EnumInstance
, (LPARAM
)&fe
);
3975 release_dc_ptr( dc
);
3977 return ret
? fe
.retval
: 0;
3980 /***********************************************************************
3981 * EnumFontFamiliesExW (GDI32.@)
3983 INT WINAPI
EnumFontFamiliesExW( HDC hDC
, LPLOGFONTW plf
,
3984 FONTENUMPROCW efproc
,
3985 LPARAM lParam
, DWORD dwFlags
)
3987 return FONT_EnumFontFamiliesEx( hDC
, plf
, efproc
, lParam
, TRUE
);
3990 /***********************************************************************
3991 * EnumFontFamiliesExA (GDI32.@)
3993 INT WINAPI
EnumFontFamiliesExA( HDC hDC
, LPLOGFONTA plf
,
3994 FONTENUMPROCA efproc
,
3995 LPARAM lParam
, DWORD dwFlags
)
3997 LOGFONTW lfW
, *plfW
;
4001 FONT_LogFontAToW( plf
, &lfW
);
4006 return FONT_EnumFontFamiliesEx( hDC
, plfW
, (FONTENUMPROCW
)efproc
, lParam
, FALSE
);
4009 /***********************************************************************
4010 * EnumFontFamiliesA (GDI32.@)
4012 INT WINAPI
EnumFontFamiliesA( HDC hDC
, LPCSTR lpFamily
,
4013 FONTENUMPROCA efproc
, LPARAM lpData
)
4019 if (!*lpFamily
) return 1;
4020 lstrcpynA( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
4021 lf
.lfCharSet
= DEFAULT_CHARSET
;
4022 lf
.lfPitchAndFamily
= 0;
4027 return EnumFontFamiliesExA( hDC
, plf
, efproc
, lpData
, 0 );
4030 /***********************************************************************
4031 * EnumFontFamiliesW (GDI32.@)
4033 INT WINAPI
EnumFontFamiliesW( HDC hDC
, LPCWSTR lpFamily
,
4034 FONTENUMPROCW efproc
, LPARAM lpData
)
4040 if (!*lpFamily
) return 1;
4041 lstrcpynW( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
4042 lf
.lfCharSet
= DEFAULT_CHARSET
;
4043 lf
.lfPitchAndFamily
= 0;
4048 return EnumFontFamiliesExW( hDC
, plf
, efproc
, lpData
, 0 );
4051 /***********************************************************************
4052 * EnumFontsA (GDI32.@)
4054 INT WINAPI
EnumFontsA( HDC hDC
, LPCSTR lpName
, FONTENUMPROCA efproc
,
4057 return EnumFontFamiliesA( hDC
, lpName
, efproc
, lpData
);
4060 /***********************************************************************
4061 * EnumFontsW (GDI32.@)
4063 INT WINAPI
EnumFontsW( HDC hDC
, LPCWSTR lpName
, FONTENUMPROCW efproc
,
4066 return EnumFontFamiliesW( hDC
, lpName
, efproc
, lpData
);
4070 /***********************************************************************
4071 * GetTextCharacterExtra (GDI32.@)
4073 INT WINAPI
GetTextCharacterExtra( HDC hdc
)
4076 DC
*dc
= get_dc_ptr( hdc
);
4077 if (!dc
) return 0x80000000;
4078 ret
= dc
->charExtra
;
4079 release_dc_ptr( dc
);
4084 /***********************************************************************
4085 * SetTextCharacterExtra (GDI32.@)
4087 INT WINAPI
SetTextCharacterExtra( HDC hdc
, INT extra
)
4089 INT ret
= 0x80000000;
4090 DC
* dc
= get_dc_ptr( hdc
);
4094 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetTextCharacterExtra
);
4095 extra
= physdev
->funcs
->pSetTextCharacterExtra( physdev
, extra
);
4096 if (extra
!= 0x80000000)
4098 ret
= dc
->charExtra
;
4099 dc
->charExtra
= extra
;
4101 release_dc_ptr( dc
);
4107 /***********************************************************************
4108 * SetTextJustification (GDI32.@)
4110 BOOL WINAPI
SetTextJustification( HDC hdc
, INT extra
, INT breaks
)
4114 DC
* dc
= get_dc_ptr( hdc
);
4116 if (!dc
) return FALSE
;
4118 physdev
= GET_DC_PHYSDEV( dc
, pSetTextJustification
);
4119 ret
= physdev
->funcs
->pSetTextJustification( physdev
, extra
, breaks
);
4122 extra
= abs((extra
* dc
->vport_ext
.cx
+ dc
->wnd_ext
.cx
/ 2) / dc
->wnd_ext
.cx
);
4123 if (!extra
) breaks
= 0;
4126 dc
->breakExtra
= extra
/ breaks
;
4127 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
4135 release_dc_ptr( dc
);
4140 /***********************************************************************
4141 * GetTextFaceA (GDI32.@)
4143 INT WINAPI
GetTextFaceA( HDC hdc
, INT count
, LPSTR name
)
4145 INT res
= GetTextFaceW(hdc
, 0, NULL
);
4146 LPWSTR nameW
= HeapAlloc( GetProcessHeap(), 0, res
* 2 );
4147 GetTextFaceW( hdc
, res
, nameW
);
4153 res
= WideCharToMultiByte(CP_ACP
, 0, nameW
, -1, name
, count
, NULL
, NULL
);
4157 /* GetTextFaceA does NOT include the nul byte in the return count. */
4164 res
= WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, NULL
, 0, NULL
, NULL
);
4165 HeapFree( GetProcessHeap(), 0, nameW
);
4169 /***********************************************************************
4170 * GetTextFaceW (GDI32.@)
4172 INT WINAPI
GetTextFaceW( HDC hdc
, INT count
, LPWSTR name
)
4177 DC
* dc
= get_dc_ptr( hdc
);
4180 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
4181 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
4182 release_dc_ptr( dc
);
4187 /***********************************************************************
4188 * GetTextExtentPoint32A (GDI32.@)
4190 * See GetTextExtentPoint32W.
4192 BOOL WINAPI
GetTextExtentPoint32A( HDC hdc
, LPCSTR str
, INT count
,
4199 if (count
< 0) return FALSE
;
4201 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
4205 ret
= GetTextExtentPoint32W( hdc
, p
, wlen
, size
);
4206 HeapFree( GetProcessHeap(), 0, p
);
4209 TRACE("(%p %s %d %p): returning %d x %d\n",
4210 hdc
, debugstr_an (str
, count
), count
, size
, size
->cx
, size
->cy
);
4215 /***********************************************************************
4216 * GetTextExtentPoint32W [GDI32.@]
4218 * Computes width/height for a string.
4220 * Computes width and height of the specified string.
4226 BOOL WINAPI
GetTextExtentPoint32W(
4227 HDC hdc
, /* [in] Handle of device context */
4228 LPCWSTR str
, /* [in] Address of text string */
4229 INT count
, /* [in] Number of characters in string */
4230 LPSIZE size
) /* [out] Address of structure for string size */
4232 return GetTextExtentExPointW(hdc
, str
, count
, 0, NULL
, NULL
, size
);
4235 /***********************************************************************
4236 * GetTextExtentExPointI [GDI32.@]
4238 * Computes width and height of the array of glyph indices.
4241 * hdc [I] Handle of device context.
4242 * indices [I] Glyph index array.
4243 * count [I] Number of glyphs in array.
4244 * max_ext [I] Maximum width in glyphs.
4245 * nfit [O] Maximum number of characters.
4246 * dxs [O] Partial string widths.
4247 * size [O] Returned string size.
4253 BOOL WINAPI
GetTextExtentExPointI( HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
4254 LPINT nfit
, LPINT dxs
, LPSIZE size
)
4259 INT buffer
[256], *pos
= dxs
;
4261 if (count
< 0) return FALSE
;
4263 dc
= get_dc_ptr( hdc
);
4264 if (!dc
) return FALSE
;
4269 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
4271 release_dc_ptr( dc
);
4276 ret
= get_char_positions_indices( dc
, indices
, count
, pos
, size
);
4281 for (i
= 0; i
< count
; i
++)
4283 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
4284 if (nfit
&& dx
> (unsigned int)max_ext
) break;
4285 if (dxs
) dxs
[i
] = dx
;
4287 if (nfit
) *nfit
= i
;
4290 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
4291 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
4294 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
4295 release_dc_ptr( dc
);
4297 TRACE("(%p %p %d %p): returning %d x %d\n",
4298 hdc
, indices
, count
, size
, size
->cx
, size
->cy
);
4302 /***********************************************************************
4303 * GetTextExtentPointI [GDI32.@]
4305 * Computes width and height of the array of glyph indices.
4308 * hdc [I] Handle of device context.
4309 * indices [I] Glyph index array.
4310 * count [I] Number of glyphs in array.
4311 * size [O] Returned string size.
4317 BOOL WINAPI
GetTextExtentPointI( HDC hdc
, const WORD
*indices
, INT count
, LPSIZE size
)
4319 return GetTextExtentExPointI( hdc
, indices
, count
, 0, NULL
, NULL
, size
);
4323 /***********************************************************************
4324 * GetTextExtentPointA (GDI32.@)
4326 BOOL WINAPI
GetTextExtentPointA( HDC hdc
, LPCSTR str
, INT count
,
4329 TRACE("not bug compatible.\n");
4330 return GetTextExtentPoint32A( hdc
, str
, count
, size
);
4333 /***********************************************************************
4334 * GetTextExtentPointW (GDI32.@)
4336 BOOL WINAPI
GetTextExtentPointW( HDC hdc
, LPCWSTR str
, INT count
,
4339 TRACE("not bug compatible.\n");
4340 return GetTextExtentPoint32W( hdc
, str
, count
, size
);
4344 /***********************************************************************
4345 * GetTextExtentExPointA (GDI32.@)
4347 BOOL WINAPI
GetTextExtentExPointA( HDC hdc
, LPCSTR str
, INT count
,
4348 INT maxExt
, LPINT lpnFit
,
4349 LPINT alpDx
, LPSIZE size
)
4356 if (count
< 0) return FALSE
;
4357 if (maxExt
< -1) return FALSE
;
4361 walpDx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(INT
) );
4362 if (!walpDx
) return FALSE
;
4365 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
4366 ret
= GetTextExtentExPointW( hdc
, p
, wlen
, maxExt
, lpnFit
, walpDx
, size
);
4369 INT n
= lpnFit
? *lpnFit
: wlen
;
4371 for(i
= 0, j
= 0; i
< n
; i
++, j
++)
4373 alpDx
[j
] = walpDx
[i
];
4374 if (IsDBCSLeadByte(str
[j
])) alpDx
[++j
] = walpDx
[i
];
4377 if (lpnFit
) *lpnFit
= WideCharToMultiByte(CP_ACP
,0,p
,*lpnFit
,NULL
,0,NULL
,NULL
);
4378 HeapFree( GetProcessHeap(), 0, p
);
4379 HeapFree( GetProcessHeap(), 0, walpDx
);
4384 /***********************************************************************
4385 * GetTextExtentExPointW (GDI32.@)
4387 * Return the size of the string as it would be if it was output properly by
4390 BOOL WINAPI
GetTextExtentExPointW( HDC hdc
, LPCWSTR str
, INT count
, INT max_ext
,
4391 LPINT nfit
, LPINT dxs
, LPSIZE size
)
4396 INT buffer
[256], *pos
= dxs
;
4398 if (count
< 0) return FALSE
;
4400 dc
= get_dc_ptr(hdc
);
4401 if (!dc
) return FALSE
;
4406 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
4408 release_dc_ptr( dc
);
4413 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
4418 for (i
= 0; i
< count
; i
++)
4420 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
4421 if (nfit
&& dx
> (unsigned int)max_ext
) break;
4422 if (dxs
) dxs
[i
] = dx
;
4424 if (nfit
) *nfit
= i
;
4427 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
4428 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
4431 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
4432 release_dc_ptr( dc
);
4434 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
4438 /***********************************************************************
4439 * GetTextMetricsA (GDI32.@)
4441 BOOL WINAPI
GetTextMetricsA( HDC hdc
, TEXTMETRICA
*metrics
)
4445 if (!GetTextMetricsW( hdc
, &tm32
)) return FALSE
;
4446 FONT_TextMetricWToA( &tm32
, metrics
);
4450 /***********************************************************************
4451 * GetTextMetricsW (GDI32.@)
4453 BOOL WINAPI
GetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
)
4457 DC
* dc
= get_dc_ptr( hdc
);
4458 if (!dc
) return FALSE
;
4460 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
4461 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
4465 /* device layer returns values in device units
4466 * therefore we have to convert them to logical */
4468 metrics
->tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
4469 metrics
->tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
4470 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
4471 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
4472 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
4473 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
4474 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
4475 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
4476 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
4477 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
4480 TRACE("text metrics:\n"
4481 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
4482 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
4483 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
4484 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
4485 " PitchAndFamily = %02x\n"
4486 " --------------------\n"
4487 " InternalLeading = %i\n"
4491 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
4492 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
4493 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
4494 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
4495 metrics
->tmPitchAndFamily
,
4496 metrics
->tmInternalLeading
,
4499 metrics
->tmHeight
);
4501 release_dc_ptr( dc
);
4506 /***********************************************************************
4507 * GetOutlineTextMetricsA (GDI32.@)
4508 * Gets metrics for TrueType fonts.
4511 * If the supplied buffer isn't big enough Windows partially fills it up to
4512 * its given length and returns that length.
4515 * Success: Non-zero or size of required buffer
4518 UINT WINAPI
GetOutlineTextMetricsA(
4519 HDC hdc
, /* [in] Handle of device context */
4520 UINT cbData
, /* [in] Size of metric data array */
4521 LPOUTLINETEXTMETRICA lpOTM
) /* [out] Address of metric data array */
4523 char buf
[512], *ptr
;
4525 OUTLINETEXTMETRICW
*lpOTMW
= (OUTLINETEXTMETRICW
*)buf
;
4526 OUTLINETEXTMETRICA
*output
= lpOTM
;
4529 if((ret
= GetOutlineTextMetricsW(hdc
, 0, NULL
)) == 0)
4531 if(ret
> sizeof(buf
))
4532 lpOTMW
= HeapAlloc(GetProcessHeap(), 0, ret
);
4533 GetOutlineTextMetricsW(hdc
, ret
, lpOTMW
);
4535 needed
= sizeof(OUTLINETEXTMETRICA
);
4536 if(lpOTMW
->otmpFamilyName
)
4537 needed
+= WideCharToMultiByte(CP_ACP
, 0,
4538 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
4539 NULL
, 0, NULL
, NULL
);
4540 if(lpOTMW
->otmpFaceName
)
4541 needed
+= WideCharToMultiByte(CP_ACP
, 0,
4542 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
4543 NULL
, 0, NULL
, NULL
);
4544 if(lpOTMW
->otmpStyleName
)
4545 needed
+= WideCharToMultiByte(CP_ACP
, 0,
4546 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
4547 NULL
, 0, NULL
, NULL
);
4548 if(lpOTMW
->otmpFullName
)
4549 needed
+= WideCharToMultiByte(CP_ACP
, 0,
4550 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
4551 NULL
, 0, NULL
, NULL
);
4558 TRACE("needed = %d\n", needed
);
4560 /* Since the supplied buffer isn't big enough, we'll alloc one
4561 that is and memcpy the first cbData bytes into the lpOTM at
4563 output
= HeapAlloc(GetProcessHeap(), 0, needed
);
4565 ret
= output
->otmSize
= min(needed
, cbData
);
4566 FONT_TextMetricWToA( &lpOTMW
->otmTextMetrics
, &output
->otmTextMetrics
);
4567 output
->otmFiller
= 0;
4568 output
->otmPanoseNumber
= lpOTMW
->otmPanoseNumber
;
4569 output
->otmfsSelection
= lpOTMW
->otmfsSelection
;
4570 output
->otmfsType
= lpOTMW
->otmfsType
;
4571 output
->otmsCharSlopeRise
= lpOTMW
->otmsCharSlopeRise
;
4572 output
->otmsCharSlopeRun
= lpOTMW
->otmsCharSlopeRun
;
4573 output
->otmItalicAngle
= lpOTMW
->otmItalicAngle
;
4574 output
->otmEMSquare
= lpOTMW
->otmEMSquare
;
4575 output
->otmAscent
= lpOTMW
->otmAscent
;
4576 output
->otmDescent
= lpOTMW
->otmDescent
;
4577 output
->otmLineGap
= lpOTMW
->otmLineGap
;
4578 output
->otmsCapEmHeight
= lpOTMW
->otmsCapEmHeight
;
4579 output
->otmsXHeight
= lpOTMW
->otmsXHeight
;
4580 output
->otmrcFontBox
= lpOTMW
->otmrcFontBox
;
4581 output
->otmMacAscent
= lpOTMW
->otmMacAscent
;
4582 output
->otmMacDescent
= lpOTMW
->otmMacDescent
;
4583 output
->otmMacLineGap
= lpOTMW
->otmMacLineGap
;
4584 output
->otmusMinimumPPEM
= lpOTMW
->otmusMinimumPPEM
;
4585 output
->otmptSubscriptSize
= lpOTMW
->otmptSubscriptSize
;
4586 output
->otmptSubscriptOffset
= lpOTMW
->otmptSubscriptOffset
;
4587 output
->otmptSuperscriptSize
= lpOTMW
->otmptSuperscriptSize
;
4588 output
->otmptSuperscriptOffset
= lpOTMW
->otmptSuperscriptOffset
;
4589 output
->otmsStrikeoutSize
= lpOTMW
->otmsStrikeoutSize
;
4590 output
->otmsStrikeoutPosition
= lpOTMW
->otmsStrikeoutPosition
;
4591 output
->otmsUnderscoreSize
= lpOTMW
->otmsUnderscoreSize
;
4592 output
->otmsUnderscorePosition
= lpOTMW
->otmsUnderscorePosition
;
4595 ptr
= (char*)(output
+ 1);
4596 left
= needed
- sizeof(*output
);
4598 if(lpOTMW
->otmpFamilyName
) {
4599 output
->otmpFamilyName
= (LPSTR
)(ptr
- (char*)output
);
4600 len
= WideCharToMultiByte(CP_ACP
, 0,
4601 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
4602 ptr
, left
, NULL
, NULL
);
4606 output
->otmpFamilyName
= 0;
4608 if(lpOTMW
->otmpFaceName
) {
4609 output
->otmpFaceName
= (LPSTR
)(ptr
- (char*)output
);
4610 len
= WideCharToMultiByte(CP_ACP
, 0,
4611 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
4612 ptr
, left
, NULL
, NULL
);
4616 output
->otmpFaceName
= 0;
4618 if(lpOTMW
->otmpStyleName
) {
4619 output
->otmpStyleName
= (LPSTR
)(ptr
- (char*)output
);
4620 len
= WideCharToMultiByte(CP_ACP
, 0,
4621 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
4622 ptr
, left
, NULL
, NULL
);
4626 output
->otmpStyleName
= 0;
4628 if(lpOTMW
->otmpFullName
) {
4629 output
->otmpFullName
= (LPSTR
)(ptr
- (char*)output
);
4630 len
= WideCharToMultiByte(CP_ACP
, 0,
4631 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
4632 ptr
, left
, NULL
, NULL
);
4635 output
->otmpFullName
= 0;
4639 if(output
!= lpOTM
) {
4640 memcpy(lpOTM
, output
, cbData
);
4641 HeapFree(GetProcessHeap(), 0, output
);
4643 /* check if the string offsets really fit into the provided size */
4644 /* FIXME: should we check string length as well? */
4645 /* make sure that we don't read/write beyond the provided buffer */
4646 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFamilyName
) + sizeof(LPSTR
))
4648 if ((UINT_PTR
)lpOTM
->otmpFamilyName
>= lpOTM
->otmSize
)
4649 lpOTM
->otmpFamilyName
= 0; /* doesn't fit */
4652 /* make sure that we don't read/write beyond the provided buffer */
4653 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFaceName
) + sizeof(LPSTR
))
4655 if ((UINT_PTR
)lpOTM
->otmpFaceName
>= lpOTM
->otmSize
)
4656 lpOTM
->otmpFaceName
= 0; /* doesn't fit */
4659 /* make sure that we don't read/write beyond the provided buffer */
4660 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpStyleName
) + sizeof(LPSTR
))
4662 if ((UINT_PTR
)lpOTM
->otmpStyleName
>= lpOTM
->otmSize
)
4663 lpOTM
->otmpStyleName
= 0; /* doesn't fit */
4666 /* make sure that we don't read/write beyond the provided buffer */
4667 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFullName
) + sizeof(LPSTR
))
4669 if ((UINT_PTR
)lpOTM
->otmpFullName
>= lpOTM
->otmSize
)
4670 lpOTM
->otmpFullName
= 0; /* doesn't fit */
4675 if(lpOTMW
!= (OUTLINETEXTMETRICW
*)buf
)
4676 HeapFree(GetProcessHeap(), 0, lpOTMW
);
4682 /***********************************************************************
4683 * GetOutlineTextMetricsW [GDI32.@]
4685 UINT WINAPI
GetOutlineTextMetricsW(
4686 HDC hdc
, /* [in] Handle of device context */
4687 UINT cbData
, /* [in] Size of metric data array */
4688 LPOUTLINETEXTMETRICW lpOTM
) /* [out] Address of metric data array */
4690 DC
*dc
= get_dc_ptr( hdc
);
4691 OUTLINETEXTMETRICW
*output
= lpOTM
;
4695 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
4698 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
4699 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
4701 if (lpOTM
&& ret
> cbData
)
4703 output
= HeapAlloc(GetProcessHeap(), 0, ret
);
4704 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
4709 output
->otmTextMetrics
.tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
4710 output
->otmTextMetrics
.tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
4711 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
4712 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
4713 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
4714 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
4715 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
4716 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
4717 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
4718 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
4719 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
4720 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
4721 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
4722 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
4723 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
4724 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
4725 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
4726 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
4727 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
4728 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
4729 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
4730 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
4731 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
4732 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
4733 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
4734 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
4735 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
4736 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
4737 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
4738 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
4739 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
4740 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
4741 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
4742 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
4746 memcpy(lpOTM
, output
, cbData
);
4747 HeapFree(GetProcessHeap(), 0, output
);
4755 static LPSTR
FONT_GetCharsByRangeA(HDC hdc
, UINT firstChar
, UINT lastChar
, PINT pByteLen
)
4757 INT i
, count
= lastChar
- firstChar
+ 1;
4765 mbcp
= GdiGetCodePage(hdc
);
4773 if (lastChar
> 0xffff)
4775 if ((firstChar
^ lastChar
) > 0xff)
4779 if (lastChar
> 0xff)
4785 str
= HeapAlloc(GetProcessHeap(), 0, count
* 2 + 1);
4789 for(i
= 0, c
= firstChar
; c
<= lastChar
; i
++, c
++)
4793 str
[i
++] = (BYTE
)(c
>> 8);
4794 if (c
<= 0xff && IsDBCSLeadByteEx(mbcp
, c
))
4795 str
[i
] = 0x1f; /* FIXME: use default character */
4809 /***********************************************************************
4810 * GetCharWidthW (GDI32.@)
4811 * GetCharWidth32W (GDI32.@)
4813 BOOL WINAPI
GetCharWidth32W( HDC hdc
, UINT firstChar
, UINT lastChar
,
4819 DC
* dc
= get_dc_ptr( hdc
);
4821 if (!dc
) return FALSE
;
4823 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
4824 ret
= dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
4828 /* convert device units to logical */
4829 for( i
= firstChar
; i
<= lastChar
; i
++, buffer
++ )
4830 *buffer
= width_to_LP( dc
, *buffer
);
4832 release_dc_ptr( dc
);
4837 /***********************************************************************
4838 * GetCharWidthA (GDI32.@)
4839 * GetCharWidth32A (GDI32.@)
4841 BOOL WINAPI
GetCharWidth32A( HDC hdc
, UINT firstChar
, UINT lastChar
,
4849 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
4853 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
4855 for(i
= 0; i
< wlen
; i
++)
4857 if(!GetCharWidth32W(hdc
, wstr
[i
], wstr
[i
], buffer
))
4865 HeapFree(GetProcessHeap(), 0, str
);
4866 HeapFree(GetProcessHeap(), 0, wstr
);
4872 /* helper for nulldrv_ExtTextOut */
4873 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
4874 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
4876 UINT indices
[3] = {0, 0, 0x20};
4882 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
4884 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
4887 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
);
4888 if (ret
!= GDI_ERROR
) break;
4891 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
4892 if (!image
) return ERROR_SUCCESS
;
4896 if (!ret
) /* empty glyph */
4898 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
4899 return ERROR_SUCCESS
;
4902 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
4903 size
= metrics
->gmBlackBoxY
* stride
;
4905 if (!(image
->ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
4906 image
->is_copy
= TRUE
;
4907 image
->free
= free_heap_bits
;
4909 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
, &identity
);
4910 if (ret
== GDI_ERROR
)
4912 HeapFree( GetProcessHeap(), 0, image
->ptr
);
4913 return ERROR_NOT_FOUND
;
4915 return ERROR_SUCCESS
;
4918 /* helper for nulldrv_ExtTextOut */
4919 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
4920 LPCWSTR str
, UINT count
, const INT
*dx
)
4925 reset_bounds( &bounds
);
4926 for (i
= 0; i
< count
; i
++)
4928 GLYPHMETRICS metrics
;
4930 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
4932 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
4933 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
4934 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
4935 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
4936 add_bounds_rect( &bounds
, &rect
);
4940 if (flags
& ETO_PDY
)
4943 y
+= dx
[ i
* 2 + 1];
4949 x
+= metrics
.gmCellIncX
;
4950 y
+= metrics
.gmCellIncY
;
4956 /* helper for nulldrv_ExtTextOut */
4957 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
4958 const struct gdi_image_bits
*image
, const RECT
*clip
)
4960 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4961 UINT i
, count
, max_count
;
4963 BYTE
*ptr
= image
->ptr
;
4964 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
4966 RECT rect
, clipped_rect
;
4968 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
4969 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
4970 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
4971 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
4972 if (!clip
) clipped_rect
= rect
;
4973 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
4975 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
4976 pts
= HeapAlloc( GetProcessHeap(), 0, max_count
* sizeof(*pts
) );
4980 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
4981 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
4983 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
4985 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
4986 pts
[count
].x
= rect
.left
+ x
;
4987 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
4988 pts
[count
+ 1].x
= rect
.left
+ x
;
4989 if (pts
[count
+ 1].x
> pts
[count
].x
)
4991 pts
[count
].y
= pts
[count
+ 1].y
= y
;
4996 assert( count
<= max_count
);
4997 dp_to_lp( dc
, pts
, count
);
4998 for (i
= 0; i
< count
; i
+= 2) Polyline( dc
->hSelf
, pts
+ i
, 2 );
4999 HeapFree( GetProcessHeap(), 0, pts
);
5002 /***********************************************************************
5003 * nulldrv_ExtTextOut
5005 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
5006 LPCWSTR str
, UINT count
, const INT
*dx
)
5008 DC
*dc
= get_nulldrv_dc( dev
);
5014 if (flags
& ETO_OPAQUE
)
5017 HBRUSH brush
= CreateSolidBrush( GetNearestColor( dev
->hdc
, dc
->backgroundColor
) );
5021 orig
= SelectObject( dev
->hdc
, brush
);
5022 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
5023 PatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
5024 SelectObject( dev
->hdc
, orig
);
5025 DeleteObject( brush
);
5029 if (!count
) return TRUE
;
5031 if (dc
->aa_flags
!= GGO_BITMAP
)
5033 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
5034 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
5035 struct gdi_image_bits bits
;
5036 struct bitblt_coords src
, dst
;
5038 /* FIXME Subpixel modes */
5039 UINT aa_flags
= GGO_GRAY4_BITMAP
;
5041 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
5042 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
5043 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
5044 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
5046 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5047 src
.x
= src
.visrect
.left
;
5048 src
.y
= src
.visrect
.top
;
5049 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
5050 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
5052 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
5053 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
5055 /* we can avoid the GetImage, just query the needed format */
5056 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
5057 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
5058 info
->bmiHeader
.biWidth
= src
.width
;
5059 info
->bmiHeader
.biHeight
= -src
.height
;
5060 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
5061 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
5062 if (!err
|| err
== ERROR_BAD_FORMAT
)
5064 /* make the source rectangle relative to the source bits */
5066 src
.visrect
.left
= src
.visrect
.top
= 0;
5067 src
.visrect
.right
= src
.width
;
5068 src
.visrect
.bottom
= src
.height
;
5070 bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
5071 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
5072 bits
.is_copy
= TRUE
;
5073 bits
.free
= free_heap_bits
;
5074 err
= ERROR_SUCCESS
;
5079 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
5080 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
5081 if (!err
&& !bits
.is_copy
)
5083 void *ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
5086 if (bits
.free
) bits
.free( &bits
);
5087 return ERROR_OUTOFMEMORY
;
5089 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
5090 if (bits
.free
) bits
.free( &bits
);
5092 bits
.is_copy
= TRUE
;
5093 bits
.free
= free_heap_bits
;
5098 /* make x,y relative to the image bits */
5099 x
+= src
.visrect
.left
- dst
.visrect
.left
;
5100 y
+= src
.visrect
.top
- dst
.visrect
.top
;
5101 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
5102 aa_flags
, str
, count
, dx
);
5103 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
5104 if (bits
.free
) bits
.free( &bits
);
5109 pen
= CreatePen( PS_SOLID
, 1, dc
->textColor
);
5110 orig
= SelectObject( dev
->hdc
, pen
);
5112 for (i
= 0; i
< count
; i
++)
5114 GLYPHMETRICS metrics
;
5115 struct gdi_image_bits image
;
5117 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
5120 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
5121 if (image
.free
) image
.free( &image
);
5125 if (flags
& ETO_PDY
)
5128 y
+= dx
[ i
* 2 + 1];
5134 x
+= metrics
.gmCellIncX
;
5135 y
+= metrics
.gmCellIncY
;
5139 SelectObject( dev
->hdc
, orig
);
5140 DeleteObject( pen
);
5145 /***********************************************************************
5146 * ExtTextOutA (GDI32.@)
5150 BOOL WINAPI
ExtTextOutA( HDC hdc
, INT x
, INT y
, UINT flags
,
5151 const RECT
*lprect
, LPCSTR str
, UINT count
, const INT
*lpDx
)
5159 if (flags
& ETO_GLYPH_INDEX
)
5160 return ExtTextOutW( hdc
, x
, y
, flags
, lprect
, (LPCWSTR
)str
, count
, lpDx
);
5162 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, &codepage
);
5165 unsigned int i
= 0, j
= 0;
5167 /* allocate enough for a ETO_PDY */
5168 lpDxW
= HeapAlloc( GetProcessHeap(), 0, 2*wlen
*sizeof(INT
));
5170 if(IsDBCSLeadByteEx(codepage
, str
[i
]))
5174 lpDxW
[j
++] = lpDx
[i
* 2] + lpDx
[(i
+ 1) * 2];
5175 lpDxW
[j
++] = lpDx
[i
* 2 + 1] + lpDx
[(i
+ 1) * 2 + 1];
5178 lpDxW
[j
++] = lpDx
[i
] + lpDx
[i
+ 1];
5185 lpDxW
[j
++] = lpDx
[i
* 2];
5186 lpDxW
[j
++] = lpDx
[i
* 2 + 1];
5189 lpDxW
[j
++] = lpDx
[i
];
5195 ret
= ExtTextOutW( hdc
, x
, y
, flags
, lprect
, p
, wlen
, lpDxW
);
5197 HeapFree( GetProcessHeap(), 0, p
);
5198 HeapFree( GetProcessHeap(), 0, lpDxW
);
5202 /***********************************************************************
5205 * Scale the underline / strikeout line width.
5207 static inline int get_line_width( DC
*dc
, int metric_size
)
5209 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
5210 if (width
== 0) width
= 1;
5211 if (metric_size
< 0) width
= -width
;
5215 /***********************************************************************
5216 * ExtTextOutW (GDI32.@)
5218 * Draws text using the currently selected font, background color, and text color.
5222 * x,y [I] coordinates of string
5224 * ETO_GRAYED - undocumented on MSDN
5225 * ETO_OPAQUE - use background color for fill the rectangle
5226 * ETO_CLIPPED - clipping text to the rectangle
5227 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5228 * than encoded characters. Implies ETO_IGNORELANGUAGE
5229 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5230 * Affects BiDi ordering
5231 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5232 * ETO_PDY - unimplemented
5233 * ETO_NUMERICSLATIN - unimplemented always assumed -
5234 * do not translate numbers into locale representations
5235 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5236 * lprect [I] dimensions for clipping or/and opaquing
5237 * str [I] text string
5238 * count [I] number of symbols in string
5239 * lpDx [I] optional parameter with distance between drawing characters
5245 BOOL WINAPI
ExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
,
5246 const RECT
*lprect
, LPCWSTR str
, UINT count
, const INT
*lpDx
)
5249 LPWSTR reordered_str
= (LPWSTR
)str
;
5250 WORD
*glyphs
= NULL
;
5256 double cosEsc
, sinEsc
;
5260 POINT
*deltas
= NULL
, width
= {0, 0};
5262 DC
* dc
= get_dc_ptr( hdc
);
5265 static int quietfixme
= 0;
5267 if (!dc
) return FALSE
;
5269 align
= dc
->textAlign
;
5270 breakRem
= dc
->breakRem
;
5271 layout
= dc
->layout
;
5273 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
5275 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5280 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
5281 type
= GetObjectType(hdc
);
5282 if(type
== OBJ_METADC
|| type
== OBJ_ENHMETADC
)
5284 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, flags
, lprect
, str
, count
, lpDx
);
5285 release_dc_ptr( dc
);
5289 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
5290 if (layout
& LAYOUT_RTL
)
5292 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
5293 align
^= TA_RTLREADING
;
5296 if( !(flags
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)) && count
> 0 )
5299 reordered_str
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
5301 BIDI_Reorder( hdc
, str
, count
, GCP_REORDER
,
5302 (align
& TA_RTLREADING
) ? WINE_GCPW_FORCE_RTL
: WINE_GCPW_FORCE_LTR
,
5303 reordered_str
, count
, NULL
, &glyphs
, &cGlyphs
);
5305 flags
|= ETO_IGNORELANGUAGE
;
5308 flags
|= ETO_GLYPH_INDEX
;
5309 if (cGlyphs
!= count
)
5313 else if(flags
& ETO_GLYPH_INDEX
)
5314 glyphs
= reordered_str
;
5316 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
5317 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
5318 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->backgroundMode
, dc
->MapMode
);
5320 if(align
& TA_UPDATECP
)
5327 GetTextMetricsW(hdc
, &tm
);
5328 GetObjectW(dc
->hFont
, sizeof(lf
), &lf
);
5330 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
5331 lf
.lfEscapement
= 0;
5333 if ((dc
->GraphicsMode
== GM_COMPATIBLE
) &&
5334 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
5336 lf
.lfEscapement
= -lf
.lfEscapement
;
5339 if(lf
.lfEscapement
!= 0)
5341 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
5342 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
5350 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
5353 lp_to_dp(dc
, (POINT
*)&rc
, 2);
5355 if (flags
& ETO_OPAQUE
)
5356 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
5358 else flags
&= ~ETO_CLIPPED
;
5368 lp_to_dp(dc
, &pt
, 1);
5372 char_extra
= GetTextCharacterExtra(hdc
);
5373 if (char_extra
&& lpDx
&& GetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
5374 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
5376 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
5379 POINT total
= {0, 0}, desired
[2];
5381 deltas
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*deltas
));
5384 if (flags
& ETO_PDY
)
5386 for (i
= 0; i
< count
; i
++)
5388 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
5389 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
5394 for (i
= 0; i
< count
; i
++)
5396 deltas
[i
].x
= lpDx
[i
] + char_extra
;
5403 INT
*dx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*dx
) );
5405 if (flags
& ETO_GLYPH_INDEX
)
5406 GetTextExtentExPointI( hdc
, glyphs
, count
, -1, NULL
, dx
, &sz
);
5408 GetTextExtentExPointW( hdc
, reordered_str
, count
, -1, NULL
, dx
, &sz
);
5410 deltas
[0].x
= dx
[0];
5412 for (i
= 1; i
< count
; i
++)
5414 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
5417 HeapFree( GetProcessHeap(), 0, dx
);
5420 for(i
= 0; i
< count
; i
++)
5422 total
.x
+= deltas
[i
].x
;
5423 total
.y
+= deltas
[i
].y
;
5425 desired
[0].x
= desired
[0].y
= 0;
5427 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
5428 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
5430 lp_to_dp(dc
, desired
, 2);
5431 desired
[1].x
-= desired
[0].x
;
5432 desired
[1].y
-= desired
[0].y
;
5434 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
5436 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5437 desired
[1].x
= -desired
[1].x
;
5438 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5439 desired
[1].y
= -desired
[1].y
;
5442 deltas
[i
].x
= desired
[1].x
- width
.x
;
5443 deltas
[i
].y
= desired
[1].y
- width
.y
;
5453 if(flags
& ETO_GLYPH_INDEX
)
5454 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
5456 GetTextExtentPointW(hdc
, reordered_str
, count
, &sz
);
5457 desired
[0].x
= desired
[0].y
= 0;
5458 desired
[1].x
= sz
.cx
;
5460 lp_to_dp(dc
, desired
, 2);
5461 desired
[1].x
-= desired
[0].x
;
5462 desired
[1].y
-= desired
[0].y
;
5464 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
5466 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
5467 desired
[1].x
= -desired
[1].x
;
5468 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
5469 desired
[1].y
= -desired
[1].y
;
5474 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
5475 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
5476 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
5479 if (align
& TA_UPDATECP
)
5483 dp_to_lp(dc
, &pt
, 1);
5484 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
5496 if (align
& TA_UPDATECP
)
5500 dp_to_lp(dc
, &pt
, 1);
5501 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
5506 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
5509 y
+= tm
.tmAscent
* cosEsc
;
5510 x
+= tm
.tmAscent
* sinEsc
;
5514 y
-= tm
.tmDescent
* cosEsc
;
5515 x
-= tm
.tmDescent
* sinEsc
;
5522 if (dc
->backgroundMode
!= TRANSPARENT
)
5524 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
5526 if(!(flags
& ETO_OPAQUE
) || !lprect
||
5527 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
5528 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
5532 text_box
.right
= x
+ width
.x
;
5533 text_box
.top
= y
- tm
.tmAscent
;
5534 text_box
.bottom
= y
+ tm
.tmDescent
;
5536 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
5537 if (!is_rect_empty( &text_box
))
5538 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
5543 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
5544 glyphs
? glyphs
: reordered_str
, count
, (INT
*)deltas
);
5547 HeapFree(GetProcessHeap(), 0, deltas
);
5548 if(glyphs
!= reordered_str
)
5549 HeapFree(GetProcessHeap(), 0, glyphs
);
5550 if(reordered_str
!= str
)
5551 HeapFree(GetProcessHeap(), 0, reordered_str
);
5553 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
5555 int underlinePos
, strikeoutPos
;
5556 int underlineWidth
, strikeoutWidth
;
5557 UINT size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
5558 OUTLINETEXTMETRICW
* otm
= NULL
;
5560 HPEN hpen
= SelectObject(hdc
, GetStockObject(NULL_PEN
));
5561 HBRUSH hbrush
= CreateSolidBrush(dc
->textColor
);
5563 hbrush
= SelectObject(hdc
, hbrush
);
5568 underlineWidth
= tm
.tmAscent
/ 20 + 1;
5569 strikeoutPos
= tm
.tmAscent
/ 2;
5570 strikeoutWidth
= underlineWidth
;
5574 otm
= HeapAlloc(GetProcessHeap(), 0, size
);
5575 GetOutlineTextMetricsW(hdc
, size
, otm
);
5576 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
5577 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
5578 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
5579 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
5580 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
5581 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
5582 HeapFree(GetProcessHeap(), 0, otm
);
5588 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5589 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5590 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
5591 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
5592 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
5593 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
5594 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
5595 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
5596 pts
[4].x
= pts
[0].x
;
5597 pts
[4].y
= pts
[0].y
;
5598 dp_to_lp(dc
, pts
, 5);
5599 Polygon(hdc
, pts
, 5);
5604 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5605 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5606 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
5607 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
5608 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
5609 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
5610 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
5611 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
5612 pts
[4].x
= pts
[0].x
;
5613 pts
[4].y
= pts
[0].y
;
5614 dp_to_lp(dc
, pts
, 5);
5615 Polygon(hdc
, pts
, 5);
5618 SelectObject(hdc
, hpen
);
5619 hbrush
= SelectObject(hdc
, hbrush
);
5620 DeleteObject(hbrush
);
5623 release_dc_ptr( dc
);
5629 /***********************************************************************
5630 * TextOutA (GDI32.@)
5632 BOOL WINAPI
TextOutA( HDC hdc
, INT x
, INT y
, LPCSTR str
, INT count
)
5634 return ExtTextOutA( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
5638 /***********************************************************************
5639 * TextOutW (GDI32.@)
5641 BOOL WINAPI
TextOutW(HDC hdc
, INT x
, INT y
, LPCWSTR str
, INT count
)
5643 return ExtTextOutW( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
5647 /***********************************************************************
5648 * PolyTextOutA (GDI32.@)
5652 BOOL WINAPI
PolyTextOutA( HDC hdc
, const POLYTEXTA
*pptxt
, INT cStrings
)
5654 for (; cStrings
>0; cStrings
--, pptxt
++)
5655 if (!ExtTextOutA( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
5662 /***********************************************************************
5663 * PolyTextOutW (GDI32.@)
5665 * Draw several Strings
5671 BOOL WINAPI
PolyTextOutW( HDC hdc
, const POLYTEXTW
*pptxt
, INT cStrings
)
5673 for (; cStrings
>0; cStrings
--, pptxt
++)
5674 if (!ExtTextOutW( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
5680 /***********************************************************************
5681 * SetMapperFlags (GDI32.@)
5683 DWORD WINAPI
SetMapperFlags( HDC hdc
, DWORD flags
)
5685 DC
*dc
= get_dc_ptr( hdc
);
5686 DWORD ret
= GDI_ERROR
;
5690 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetMapperFlags
);
5691 flags
= physdev
->funcs
->pSetMapperFlags( physdev
, flags
);
5692 if (flags
!= GDI_ERROR
)
5694 ret
= dc
->mapperFlags
;
5695 dc
->mapperFlags
= flags
;
5697 release_dc_ptr( dc
);
5702 /***********************************************************************
5703 * GetAspectRatioFilterEx (GDI32.@)
5705 BOOL WINAPI
GetAspectRatioFilterEx( HDC hdc
, LPSIZE pAspectRatio
)
5707 FIXME("(%p, %p): -- Empty Stub !\n", hdc
, pAspectRatio
);
5712 /***********************************************************************
5713 * GetCharABCWidthsA (GDI32.@)
5715 * See GetCharABCWidthsW.
5717 BOOL WINAPI
GetCharABCWidthsA(HDC hdc
, UINT firstChar
, UINT lastChar
,
5725 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
5729 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
5732 HeapFree(GetProcessHeap(), 0, str
);
5736 for(i
= 0; i
< wlen
; i
++)
5738 if(!GetCharABCWidthsW(hdc
, wstr
[i
], wstr
[i
], abc
))
5746 HeapFree(GetProcessHeap(), 0, str
);
5747 HeapFree(GetProcessHeap(), 0, wstr
);
5753 /******************************************************************************
5754 * GetCharABCWidthsW [GDI32.@]
5756 * Retrieves widths of characters in range.
5759 * hdc [I] Handle of device context
5760 * firstChar [I] First character in range to query
5761 * lastChar [I] Last character in range to query
5762 * abc [O] Address of character-width structure
5765 * Only works with TrueType fonts
5771 BOOL WINAPI
GetCharABCWidthsW( HDC hdc
, UINT firstChar
, UINT lastChar
,
5774 DC
*dc
= get_dc_ptr(hdc
);
5780 if (!dc
) return FALSE
;
5784 release_dc_ptr( dc
);
5788 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
5789 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
5790 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
5792 release_dc_ptr( dc
);
5796 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
5797 ret
= dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, abc
);
5800 /* convert device units to logical */
5801 for( i
= firstChar
; i
<= lastChar
; i
++, abc
++ ) {
5802 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
5803 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
5804 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
5808 release_dc_ptr( dc
);
5813 /******************************************************************************
5814 * GetCharABCWidthsI [GDI32.@]
5816 * Retrieves widths of characters in range.
5819 * hdc [I] Handle of device context
5820 * firstChar [I] First glyphs in range to query
5821 * count [I] Last glyphs in range to query
5822 * pgi [i] Array of glyphs to query
5823 * abc [O] Address of character-width structure
5826 * Only works with TrueType fonts
5832 BOOL WINAPI
GetCharABCWidthsI( HDC hdc
, UINT firstChar
, UINT count
,
5833 LPWORD pgi
, LPABC abc
)
5835 DC
*dc
= get_dc_ptr(hdc
);
5840 if (!dc
) return FALSE
;
5844 release_dc_ptr( dc
);
5848 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
5849 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, abc
);
5852 /* convert device units to logical */
5853 for( i
= 0; i
< count
; i
++, abc
++ ) {
5854 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
5855 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
5856 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
5860 release_dc_ptr( dc
);
5865 /***********************************************************************
5866 * GetGlyphOutlineA (GDI32.@)
5868 DWORD WINAPI
GetGlyphOutlineA( HDC hdc
, UINT uChar
, UINT fuFormat
,
5869 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
5870 LPVOID lpBuffer
, const MAT2
*lpmat2
)
5872 if (!lpmat2
) return GDI_ERROR
;
5874 if(!(fuFormat
& GGO_GLYPH_INDEX
)) {
5880 cp
= GdiGetCodePage(hdc
);
5881 if (IsDBCSLeadByteEx(cp
, uChar
>> 8)) {
5883 mbchs
[0] = (uChar
& 0xff00) >> 8;
5884 mbchs
[1] = (uChar
& 0xff);
5887 mbchs
[0] = (uChar
& 0xff);
5890 MultiByteToWideChar(cp
, 0, mbchs
, len
, &wChar
, 1);
5894 return GetGlyphOutlineW(hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
,
5898 /***********************************************************************
5899 * GetGlyphOutlineW (GDI32.@)
5901 DWORD WINAPI
GetGlyphOutlineW( HDC hdc
, UINT uChar
, UINT fuFormat
,
5902 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
5903 LPVOID lpBuffer
, const MAT2
*lpmat2
)
5909 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
5910 hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
5912 if (!lpmat2
) return GDI_ERROR
;
5914 dc
= get_dc_ptr(hdc
);
5915 if(!dc
) return GDI_ERROR
;
5919 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
5920 ret
= dev
->funcs
->pGetGlyphOutline( dev
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
5921 release_dc_ptr( dc
);
5926 /***********************************************************************
5927 * CreateScalableFontResourceA (GDI32.@)
5929 BOOL WINAPI
CreateScalableFontResourceA( DWORD fHidden
,
5930 LPCSTR lpszResourceFile
,
5931 LPCSTR lpszFontFile
,
5932 LPCSTR lpszCurrentPath
)
5934 LPWSTR lpszResourceFileW
= NULL
;
5935 LPWSTR lpszFontFileW
= NULL
;
5936 LPWSTR lpszCurrentPathW
= NULL
;
5940 if (lpszResourceFile
)
5942 len
= MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, NULL
, 0);
5943 lpszResourceFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5944 MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, lpszResourceFileW
, len
);
5949 len
= MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, NULL
, 0);
5950 lpszFontFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5951 MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, lpszFontFileW
, len
);
5954 if (lpszCurrentPath
)
5956 len
= MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, NULL
, 0);
5957 lpszCurrentPathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5958 MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, lpszCurrentPathW
, len
);
5961 ret
= CreateScalableFontResourceW(fHidden
, lpszResourceFileW
,
5962 lpszFontFileW
, lpszCurrentPathW
);
5964 HeapFree(GetProcessHeap(), 0, lpszResourceFileW
);
5965 HeapFree(GetProcessHeap(), 0, lpszFontFileW
);
5966 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW
);
5971 #define NE_FFLAGS_LIBMODULE 0x8000
5972 #define NE_OSFLAGS_WINDOWS 0x02
5974 static const char dos_string
[0x40] = "This is a TrueType resource file";
5975 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
5977 #include <pshpack1.h>
5980 WORD num_of_resources
;
5984 CHAR dfCopyright
[60];
5990 WORD dfInternalLeading
;
5991 WORD dfExternalLeading
;
5999 BYTE dfPitchAndFamily
;
6010 CHAR szFaceName
[LF_FACESIZE
];
6012 #include <poppack.h>
6014 #include <pshpack2.h>
6035 struct ne_typeinfo fontdir_type
;
6036 struct ne_nameinfo fontdir_name
;
6037 struct ne_typeinfo scalable_type
;
6038 struct ne_nameinfo scalable_name
;
6040 BYTE fontdir_res_name
[8];
6043 #include <poppack.h>
6045 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
6049 DWORD size
, written
;
6051 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
6052 char *font_fileA
, *last_part
, *ext
;
6053 IMAGE_DOS_HEADER dos
;
6054 IMAGE_OS2_HEADER ne
=
6056 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
6058 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
6059 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
6061 struct rsrc_tab rsrc_tab
=
6065 { 0, 0, 0x0c50, 0x2c, 0 },
6067 { 0, 0, 0x0c50, 0x8001, 0 },
6069 { 7,'F','O','N','T','D','I','R'}
6072 memset( &dos
, 0, sizeof(dos
) );
6073 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
6074 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
6076 /* import name is last part\0, resident name is last part without extension
6077 non-resident name is "FONTRES:" + lfFaceName */
6079 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
6080 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
6081 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
6083 last_part
= strrchr( font_fileA
, '\\' );
6084 if (last_part
) last_part
++;
6085 else last_part
= font_fileA
;
6086 import_name_len
= strlen( last_part
) + 1;
6088 ext
= strchr( last_part
, '.' );
6089 if (ext
) res_name_len
= ext
- last_part
;
6090 else res_name_len
= import_name_len
- 1;
6092 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
6094 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
6095 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
6096 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
6097 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
6099 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
6101 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
6102 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
6103 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
6104 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
6106 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
6107 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
6111 HeapFree( GetProcessHeap(), 0, font_fileA
);
6115 memcpy( ptr
, &dos
, sizeof(dos
) );
6116 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
6117 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
6119 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
6120 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
6122 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
6123 *ptr
++ = res_name_len
;
6124 memcpy( ptr
, last_part
, res_name_len
);
6126 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
6127 *ptr
++ = import_name_len
;
6128 memcpy( ptr
, last_part
, import_name_len
);
6130 ptr
= start
+ ne
.ne_nrestab
;
6131 *ptr
++ = non_res_name_len
;
6132 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
6133 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
6135 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
6136 memcpy( ptr
, font_fileA
, font_file_len
);
6138 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
6139 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
6141 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
6142 if (file
!= INVALID_HANDLE_VALUE
)
6144 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
6146 CloseHandle( file
);
6149 HeapFree( GetProcessHeap(), 0, start
);
6150 HeapFree( GetProcessHeap(), 0, font_fileA
);
6155 /***********************************************************************
6156 * CreateScalableFontResourceW (GDI32.@)
6158 BOOL WINAPI
CreateScalableFontResourceW( DWORD hidden
, LPCWSTR resource_file
,
6159 LPCWSTR font_file
, LPCWSTR font_path
)
6161 static const WCHAR backslashW
[] = {'\\',0};
6162 struct fontdir fontdir
= { 0 };
6163 struct gdi_font
*font
= NULL
;
6164 WCHAR path
[MAX_PATH
];
6166 TRACE("(%d, %s, %s, %s)\n", hidden
, debugstr_w(resource_file
),
6167 debugstr_w(font_file
), debugstr_w(font_path
) );
6169 if (!font_funcs
) return FALSE
;
6171 if (!font_file
) goto done
;
6172 if (font_path
&& font_path
[0])
6174 int len
= strlenW( font_path
) + strlenW( font_file
) + 2;
6175 if (len
> MAX_PATH
) goto done
;
6176 lstrcpynW( path
, font_path
, MAX_PATH
);
6177 strcatW( path
, backslashW
);
6178 strcatW( path
, font_file
);
6180 else if (!GetFullPathNameW( font_file
, MAX_PATH
, path
, NULL
)) goto done
;
6182 if (!(font
= alloc_gdi_font( path
, NULL
, 0 ))) goto done
;
6183 font
->lf
.lfHeight
= 100;
6184 if (!font_funcs
->load_font( font
)) goto done
;
6185 if (!font_funcs
->set_outline_text_metrics( font
)) goto done
;
6187 if (!(font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_TRUETYPE
)) goto done
;
6189 fontdir
.num_of_resources
= 1;
6191 fontdir
.dfVersion
= 0x200;
6192 fontdir
.dfSize
= sizeof(fontdir
);
6193 strcpy( fontdir
.dfCopyright
, "Wine fontdir" );
6194 fontdir
.dfType
= 0x4003; /* 0x0080 set if private */
6195 fontdir
.dfPoints
= font
->otm
.otmEMSquare
;
6196 fontdir
.dfVertRes
= 72;
6197 fontdir
.dfHorizRes
= 72;
6198 fontdir
.dfAscent
= font
->otm
.otmTextMetrics
.tmAscent
;
6199 fontdir
.dfInternalLeading
= font
->otm
.otmTextMetrics
.tmInternalLeading
;
6200 fontdir
.dfExternalLeading
= font
->otm
.otmTextMetrics
.tmExternalLeading
;
6201 fontdir
.dfItalic
= font
->otm
.otmTextMetrics
.tmItalic
;
6202 fontdir
.dfUnderline
= font
->otm
.otmTextMetrics
.tmUnderlined
;
6203 fontdir
.dfStrikeOut
= font
->otm
.otmTextMetrics
.tmStruckOut
;
6204 fontdir
.dfWeight
= font
->otm
.otmTextMetrics
.tmWeight
;
6205 fontdir
.dfCharSet
= font
->otm
.otmTextMetrics
.tmCharSet
;
6206 fontdir
.dfPixWidth
= 0;
6207 fontdir
.dfPixHeight
= font
->otm
.otmTextMetrics
.tmHeight
;
6208 fontdir
.dfPitchAndFamily
= font
->otm
.otmTextMetrics
.tmPitchAndFamily
;
6209 fontdir
.dfAvgWidth
= font
->otm
.otmTextMetrics
.tmAveCharWidth
;
6210 fontdir
.dfMaxWidth
= font
->otm
.otmTextMetrics
.tmMaxCharWidth
;
6211 fontdir
.dfFirstChar
= font
->otm
.otmTextMetrics
.tmFirstChar
;
6212 fontdir
.dfLastChar
= font
->otm
.otmTextMetrics
.tmLastChar
;
6213 fontdir
.dfDefaultChar
= font
->otm
.otmTextMetrics
.tmDefaultChar
;
6214 fontdir
.dfBreakChar
= font
->otm
.otmTextMetrics
.tmBreakChar
;
6215 fontdir
.dfWidthBytes
= 0;
6216 fontdir
.dfDevice
= 0;
6217 fontdir
.dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
6218 fontdir
.dfReserved
= 0;
6219 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)font
->otm
.otmpFamilyName
, -1,
6220 fontdir
.szFaceName
, LF_FACESIZE
, NULL
, NULL
);
6222 if (hidden
) fontdir
.dfType
|= 0x80;
6223 return create_fot( resource_file
, font_file
, &fontdir
);
6226 if (font
) free_gdi_font( font
);
6227 SetLastError( ERROR_INVALID_PARAMETER
);
6231 /*************************************************************************
6232 * GetKerningPairsA (GDI32.@)
6234 DWORD WINAPI
GetKerningPairsA( HDC hDC
, DWORD cPairs
,
6235 LPKERNINGPAIR kern_pairA
)
6239 DWORD i
, total_kern_pairs
, kern_pairs_copied
= 0;
6240 KERNINGPAIR
*kern_pairW
;
6242 if (!cPairs
&& kern_pairA
)
6244 SetLastError(ERROR_INVALID_PARAMETER
);
6248 cp
= GdiGetCodePage(hDC
);
6250 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
6251 * to fail on an invalid character for CP_SYMBOL.
6253 cpi
.DefaultChar
[0] = 0;
6254 if (cp
!= CP_SYMBOL
&& !GetCPInfo(cp
, &cpi
))
6256 FIXME("Can't find codepage %u info\n", cp
);
6260 total_kern_pairs
= GetKerningPairsW(hDC
, 0, NULL
);
6261 if (!total_kern_pairs
) return 0;
6263 kern_pairW
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pairW
));
6264 GetKerningPairsW(hDC
, total_kern_pairs
, kern_pairW
);
6266 for (i
= 0; i
< total_kern_pairs
; i
++)
6270 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wFirst
, 1, &first
, 1, NULL
, NULL
))
6273 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wSecond
, 1, &second
, 1, NULL
, NULL
))
6276 if (first
== cpi
.DefaultChar
[0] || second
== cpi
.DefaultChar
[0])
6281 if (kern_pairs_copied
>= cPairs
) break;
6283 kern_pairA
->wFirst
= (BYTE
)first
;
6284 kern_pairA
->wSecond
= (BYTE
)second
;
6285 kern_pairA
->iKernAmount
= kern_pairW
[i
].iKernAmount
;
6288 kern_pairs_copied
++;
6291 HeapFree(GetProcessHeap(), 0, kern_pairW
);
6293 return kern_pairs_copied
;
6296 /*************************************************************************
6297 * GetKerningPairsW (GDI32.@)
6299 DWORD WINAPI
GetKerningPairsW( HDC hDC
, DWORD cPairs
,
6300 LPKERNINGPAIR lpKerningPairs
)
6306 TRACE("(%p,%d,%p)\n", hDC
, cPairs
, lpKerningPairs
);
6308 if (!cPairs
&& lpKerningPairs
)
6310 SetLastError(ERROR_INVALID_PARAMETER
);
6314 dc
= get_dc_ptr(hDC
);
6317 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
6318 ret
= dev
->funcs
->pGetKerningPairs( dev
, cPairs
, lpKerningPairs
);
6319 release_dc_ptr( dc
);
6323 /*************************************************************************
6324 * TranslateCharsetInfo [GDI32.@]
6326 * Fills a CHARSETINFO structure for a character set, code page, or
6327 * font. This allows making the correspondence between different labels
6328 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
6329 * of the same encoding.
6331 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
6332 * only one codepage should be set in *lpSrc.
6335 * TRUE on success, FALSE on failure.
6338 BOOL WINAPI
TranslateCharsetInfo(
6339 LPDWORD lpSrc
, /* [in]
6340 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
6341 if flags == TCI_SRCCHARSET: a character set value
6342 if flags == TCI_SRCCODEPAGE: a code page value
6344 LPCHARSETINFO lpCs
, /* [out] structure to receive charset information */
6345 DWORD flags
/* [in] determines interpretation of lpSrc */)
6349 case TCI_SRCFONTSIG
:
6350 while (index
< MAXTCIINDEX
&& !(*lpSrc
>>index
& 0x0001)) index
++;
6352 case TCI_SRCCODEPAGE
:
6353 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciACP
) index
++;
6355 case TCI_SRCCHARSET
:
6356 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciCharset
) index
++;
6361 if (index
>= MAXTCIINDEX
|| FONT_tci
[index
].ciCharset
== DEFAULT_CHARSET
) return FALSE
;
6362 *lpCs
= FONT_tci
[index
];
6366 /*************************************************************************
6367 * GetFontLanguageInfo (GDI32.@)
6369 DWORD WINAPI
GetFontLanguageInfo(HDC hdc
)
6371 FONTSIGNATURE fontsig
;
6372 static const DWORD GCP_DBCS_MASK
=FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
,
6373 GCP_DIACRITIC_MASK
=0x00000000,
6374 FLI_GLYPHS_MASK
=0x00000000,
6375 GCP_GLYPHSHAPE_MASK
=FS_ARABIC
,
6376 GCP_KASHIDA_MASK
=0x00000000,
6377 GCP_LIGATE_MASK
=0x00000000,
6378 GCP_REORDER_MASK
=FS_HEBREW
|FS_ARABIC
;
6382 GetTextCharsetInfo( hdc
, &fontsig
, 0 );
6383 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
6385 if( (fontsig
.fsCsb
[0]&GCP_DBCS_MASK
)!=0 )
6388 if( (fontsig
.fsCsb
[0]&GCP_DIACRITIC_MASK
)!=0 )
6389 result
|=GCP_DIACRITIC
;
6391 if( (fontsig
.fsCsb
[0]&FLI_GLYPHS_MASK
)!=0 )
6394 if( (fontsig
.fsCsb
[0]&GCP_GLYPHSHAPE_MASK
)!=0 )
6395 result
|=GCP_GLYPHSHAPE
;
6397 if( (fontsig
.fsCsb
[0]&GCP_KASHIDA_MASK
)!=0 )
6398 result
|=GCP_KASHIDA
;
6400 if( (fontsig
.fsCsb
[0]&GCP_LIGATE_MASK
)!=0 )
6403 if( GetKerningPairsW( hdc
, 0, NULL
) )
6404 result
|=GCP_USEKERNING
;
6406 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
6407 if( GetTextAlign( hdc
) & TA_RTLREADING
)
6408 if( (fontsig
.fsCsb
[0]&GCP_REORDER_MASK
)!=0 )
6409 result
|=GCP_REORDER
;
6415 /*************************************************************************
6416 * GetFontData [GDI32.@]
6418 * Retrieve data for TrueType font.
6422 * success: Number of bytes returned
6423 * failure: GDI_ERROR
6427 * Calls SetLastError()
6430 DWORD WINAPI
GetFontData(HDC hdc
, DWORD table
, DWORD offset
,
6431 LPVOID buffer
, DWORD length
)
6433 DC
*dc
= get_dc_ptr(hdc
);
6437 if(!dc
) return GDI_ERROR
;
6439 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
6440 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
6441 release_dc_ptr( dc
);
6445 /*************************************************************************
6446 * GetGlyphIndicesA [GDI32.@]
6448 DWORD WINAPI
GetGlyphIndicesA(HDC hdc
, LPCSTR lpstr
, INT count
,
6449 LPWORD pgi
, DWORD flags
)
6455 TRACE("(%p, %s, %d, %p, 0x%x)\n",
6456 hdc
, debugstr_an(lpstr
, count
), count
, pgi
, flags
);
6458 lpstrW
= FONT_mbtowc(hdc
, lpstr
, count
, &countW
, NULL
);
6459 ret
= GetGlyphIndicesW(hdc
, lpstrW
, countW
, pgi
, flags
);
6460 HeapFree(GetProcessHeap(), 0, lpstrW
);
6465 /*************************************************************************
6466 * GetGlyphIndicesW [GDI32.@]
6468 DWORD WINAPI
GetGlyphIndicesW(HDC hdc
, LPCWSTR lpstr
, INT count
,
6469 LPWORD pgi
, DWORD flags
)
6471 DC
*dc
= get_dc_ptr(hdc
);
6475 TRACE("(%p, %s, %d, %p, 0x%x)\n",
6476 hdc
, debugstr_wn(lpstr
, count
), count
, pgi
, flags
);
6478 if(!dc
) return GDI_ERROR
;
6480 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
6481 ret
= dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6482 release_dc_ptr( dc
);
6486 /*************************************************************************
6487 * GetCharacterPlacementA [GDI32.@]
6489 * See GetCharacterPlacementW.
6492 * the web browser control of ie4 calls this with dwFlags=0
6495 GetCharacterPlacementA(HDC hdc
, LPCSTR lpString
, INT uCount
,
6496 INT nMaxExtent
, GCP_RESULTSA
*lpResults
,
6501 GCP_RESULTSW resultsW
;
6505 TRACE("%s, %d, %d, 0x%08x\n",
6506 debugstr_an(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
6508 lpStringW
= FONT_mbtowc(hdc
, lpString
, uCount
, &uCountW
, &font_cp
);
6512 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, NULL
, dwFlags
);
6513 HeapFree(GetProcessHeap(), 0, lpStringW
);
6517 /* both structs are equal in size */
6518 memcpy(&resultsW
, lpResults
, sizeof(resultsW
));
6520 if(lpResults
->lpOutString
)
6521 resultsW
.lpOutString
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*uCountW
);
6523 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, &resultsW
, dwFlags
);
6525 lpResults
->nGlyphs
= resultsW
.nGlyphs
;
6526 lpResults
->nMaxFit
= resultsW
.nMaxFit
;
6528 if(lpResults
->lpOutString
) {
6529 WideCharToMultiByte(font_cp
, 0, resultsW
.lpOutString
, uCountW
,
6530 lpResults
->lpOutString
, uCount
, NULL
, NULL
);
6533 HeapFree(GetProcessHeap(), 0, lpStringW
);
6534 HeapFree(GetProcessHeap(), 0, resultsW
.lpOutString
);
6539 static int kern_pair(const KERNINGPAIR
*kern
, int count
, WCHAR c1
, WCHAR c2
)
6543 for (i
= 0; i
< count
; i
++)
6545 if (kern
[i
].wFirst
== c1
&& kern
[i
].wSecond
== c2
)
6546 return kern
[i
].iKernAmount
;
6552 static int *kern_string(HDC hdc
, const WCHAR
*str
, int len
, int *kern_total
)
6555 KERNINGPAIR
*kern
= NULL
;
6560 ret
= heap_alloc(len
* sizeof(*ret
));
6561 if (!ret
) return NULL
;
6563 count
= GetKerningPairsW(hdc
, 0, NULL
);
6566 kern
= heap_alloc(count
* sizeof(*kern
));
6573 GetKerningPairsW(hdc
, count
, kern
);
6576 for (i
= 0; i
< len
- 1; i
++)
6578 ret
[i
] = kern_pair(kern
, count
, str
[i
], str
[i
+ 1]);
6579 *kern_total
+= ret
[i
];
6582 ret
[len
- 1] = 0; /* no kerning for last element */
6588 /*************************************************************************
6589 * GetCharacterPlacementW [GDI32.@]
6591 * Retrieve information about a string. This includes the width, reordering,
6592 * Glyphing and so on.
6596 * The width and height of the string if successful, 0 if failed.
6600 * All flags except GCP_REORDER are not yet implemented.
6601 * Reordering is not 100% compliant to the Windows BiDi method.
6602 * Caret positioning is not yet implemented for BiDi.
6603 * Classes are not yet implemented.
6607 GetCharacterPlacementW(
6608 HDC hdc
, /* [in] Device context for which the rendering is to be done */
6609 LPCWSTR lpString
, /* [in] The string for which information is to be returned */
6610 INT uCount
, /* [in] Number of WORDS in string. */
6611 INT nMaxExtent
, /* [in] Maximum extent the string is to take (in HDC logical units) */
6612 GCP_RESULTSW
*lpResults
, /* [in/out] A pointer to a GCP_RESULTSW struct */
6613 DWORD dwFlags
/* [in] Flags specifying how to process the string */
6619 int *kern
= NULL
, kern_total
= 0;
6621 TRACE("%s, %d, %d, 0x%08x\n",
6622 debugstr_wn(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
6628 return GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
) ? MAKELONG(size
.cx
, size
.cy
) : 0;
6630 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
6631 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
6632 lpResults
->lStructSize
, lpResults
->lpOutString
, lpResults
->lpOrder
,
6633 lpResults
->lpDx
, lpResults
->lpCaretPos
, lpResults
->lpClass
,
6634 lpResults
->lpGlyphs
, lpResults
->nGlyphs
, lpResults
->nMaxFit
);
6636 if (dwFlags
& ~(GCP_REORDER
| GCP_USEKERNING
))
6637 FIXME("flags 0x%08x ignored\n", dwFlags
);
6638 if (lpResults
->lpClass
)
6639 FIXME("classes not implemented\n");
6640 if (lpResults
->lpCaretPos
&& (dwFlags
& GCP_REORDER
))
6641 FIXME("Caret positions for complex scripts not implemented\n");
6643 nSet
= (UINT
)uCount
;
6644 if (nSet
> lpResults
->nGlyphs
)
6645 nSet
= lpResults
->nGlyphs
;
6647 /* return number of initialized fields */
6648 lpResults
->nGlyphs
= nSet
;
6650 if (!(dwFlags
& GCP_REORDER
))
6652 /* Treat the case where no special handling was requested in a fastpath way */
6653 /* copy will do if the GCP_REORDER flag is not set */
6654 if (lpResults
->lpOutString
)
6655 memcpy( lpResults
->lpOutString
, lpString
, nSet
* sizeof(WCHAR
));
6657 if (lpResults
->lpOrder
)
6659 for (i
= 0; i
< nSet
; i
++)
6660 lpResults
->lpOrder
[i
] = i
;
6665 BIDI_Reorder(NULL
, lpString
, uCount
, dwFlags
, WINE_GCPW_FORCE_LTR
, lpResults
->lpOutString
,
6666 nSet
, lpResults
->lpOrder
, NULL
, NULL
);
6669 if (dwFlags
& GCP_USEKERNING
)
6671 kern
= kern_string(hdc
, lpString
, nSet
, &kern_total
);
6674 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
6679 /* FIXME: Will use the placement chars */
6680 if (lpResults
->lpDx
)
6683 for (i
= 0; i
< nSet
; i
++)
6685 if (GetCharWidth32W(hdc
, lpString
[i
], lpString
[i
], &c
))
6687 lpResults
->lpDx
[i
] = c
;
6688 if (dwFlags
& GCP_USEKERNING
)
6689 lpResults
->lpDx
[i
] += kern
[i
];
6694 if (lpResults
->lpCaretPos
&& !(dwFlags
& GCP_REORDER
))
6698 lpResults
->lpCaretPos
[0] = 0;
6699 for (i
= 0; i
< nSet
- 1; i
++)
6701 if (dwFlags
& GCP_USEKERNING
)
6704 if (GetTextExtentPoint32W(hdc
, &lpString
[i
], 1, &size
))
6705 lpResults
->lpCaretPos
[i
+ 1] = (pos
+= size
.cx
);
6709 if (lpResults
->lpGlyphs
)
6710 GetGlyphIndicesW(hdc
, lpString
, nSet
, lpResults
->lpGlyphs
, 0);
6712 if (GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
))
6713 ret
= MAKELONG(size
.cx
+ kern_total
, size
.cy
);
6720 /*************************************************************************
6721 * GetCharABCWidthsFloatA [GDI32.@]
6723 * See GetCharABCWidthsFloatW.
6725 BOOL WINAPI
GetCharABCWidthsFloatA( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
6732 str
= FONT_GetCharsByRangeA(hdc
, first
, last
, &i
);
6736 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
6738 for (i
= 0; i
< wlen
; i
++)
6740 if (!GetCharABCWidthsFloatW( hdc
, wstr
[i
], wstr
[i
], abcf
))
6748 HeapFree( GetProcessHeap(), 0, str
);
6749 HeapFree( GetProcessHeap(), 0, wstr
);
6754 /*************************************************************************
6755 * GetCharABCWidthsFloatW [GDI32.@]
6757 * Retrieves widths of a range of characters.
6760 * hdc [I] Handle to device context.
6761 * first [I] First character in range to query.
6762 * last [I] Last character in range to query.
6763 * abcf [O] Array of LPABCFLOAT structures.
6769 BOOL WINAPI
GetCharABCWidthsFloatW( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
6775 DC
*dc
= get_dc_ptr( hdc
);
6777 TRACE("%p, %d, %d, %p\n", hdc
, first
, last
, abcf
);
6779 if (!dc
) return FALSE
;
6781 if (!abcf
) goto done
;
6782 if (!(abc
= HeapAlloc( GetProcessHeap(), 0, (last
- first
+ 1) * sizeof(*abc
) ))) goto done
;
6784 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
6785 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, abc
);
6788 /* convert device units to logical */
6789 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
6790 for (i
= first
; i
<= last
; i
++, abcf
++)
6792 abcf
->abcfA
= abc
[i
- first
].abcA
* scale
;
6793 abcf
->abcfB
= abc
[i
- first
].abcB
* scale
;
6794 abcf
->abcfC
= abc
[i
- first
].abcC
* scale
;
6797 HeapFree( GetProcessHeap(), 0, abc
);
6800 release_dc_ptr( dc
);
6804 /*************************************************************************
6805 * GetCharWidthFloatA [GDI32.@]
6807 BOOL WINAPI
GetCharWidthFloatA( HDC hdc
, UINT first
, UINT last
, float *buffer
)
6813 if (!(str
= FONT_GetCharsByRangeA( hdc
, first
, last
, &i
)))
6815 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
6818 for (i
= 0; i
< wlen
; ++i
)
6820 if (!GetCharWidthFloatW( hdc
, wstr
[i
], wstr
[i
], &buffer
[i
] ))
6830 /*************************************************************************
6831 * GetCharWidthFloatW [GDI32.@]
6833 BOOL WINAPI
GetCharWidthFloatW( HDC hdc
, UINT first
, UINT last
, float *buffer
)
6835 DC
*dc
= get_dc_ptr( hdc
);
6841 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc
, first
, last
, buffer
);
6843 if (!dc
) return FALSE
;
6845 if (!(ibuffer
= heap_alloc( (last
- first
+ 1) * sizeof(int) )))
6847 release_dc_ptr( dc
);
6851 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
6852 if ((ret
= dev
->funcs
->pGetCharWidth( dev
, first
, last
, ibuffer
)))
6854 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
6855 for (i
= first
; i
<= last
; ++i
)
6856 buffer
[i
- first
] = ibuffer
[i
- first
] * scale
;
6863 /***********************************************************************
6865 * Font Resource API *
6867 ***********************************************************************/
6869 /***********************************************************************
6870 * AddFontResourceA (GDI32.@)
6872 INT WINAPI
AddFontResourceA( LPCSTR str
)
6874 return AddFontResourceExA( str
, 0, NULL
);
6877 /***********************************************************************
6878 * AddFontResourceW (GDI32.@)
6880 INT WINAPI
AddFontResourceW( LPCWSTR str
)
6882 return AddFontResourceExW(str
, 0, NULL
);
6886 /***********************************************************************
6887 * AddFontResourceExA (GDI32.@)
6889 INT WINAPI
AddFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
6891 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
6892 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6895 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
6896 ret
= AddFontResourceExW(strW
, fl
, pdv
);
6897 HeapFree(GetProcessHeap(), 0, strW
);
6901 static BOOL CALLBACK
load_enumed_resource(HMODULE hModule
, LPCWSTR type
, LPWSTR name
, LONG_PTR lParam
)
6903 HRSRC rsrc
= FindResourceW(hModule
, name
, type
);
6904 HGLOBAL hMem
= LoadResource(hModule
, rsrc
);
6905 LPVOID
*pMem
= LockResource(hMem
);
6906 int *num_total
= (int *)lParam
;
6909 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type
));
6910 if (!AddFontMemResourceEx(pMem
, SizeofResource(hModule
, rsrc
), NULL
, &num_in_res
))
6912 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule
, hMem
);
6916 *num_total
+= num_in_res
;
6920 static void *map_file( const WCHAR
*filename
, LARGE_INTEGER
*size
)
6922 HANDLE file
, mapping
;
6925 file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
6926 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
6928 if (!GetFileSizeEx( file
, size
) || size
->u
.HighPart
)
6930 CloseHandle( file
);
6934 mapping
= CreateFileMappingW( file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
6935 CloseHandle( file
);
6936 if (!mapping
) return NULL
;
6938 ptr
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
6939 CloseHandle( mapping
);
6944 static void *find_resource( BYTE
*ptr
, WORD type
, DWORD rsrc_off
, DWORD size
, DWORD
*len
)
6946 WORD align
, type_id
, count
;
6949 if (size
< rsrc_off
+ 10) return NULL
;
6950 align
= *(WORD
*)(ptr
+ rsrc_off
);
6952 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
6953 while (type_id
&& type_id
!= type
)
6955 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
6956 rsrc_off
+= 8 + count
* 12;
6957 if (size
< rsrc_off
+ 8) return NULL
;
6958 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
6960 if (!type_id
) return NULL
;
6961 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
6962 if (size
< rsrc_off
+ 8 + count
* 12) return NULL
;
6963 res_off
= *(WORD
*)(ptr
+ rsrc_off
+ 8) << align
;
6964 *len
= *(WORD
*)(ptr
+ rsrc_off
+ 10) << align
;
6965 if (size
< res_off
+ *len
) return NULL
;
6966 return ptr
+ res_off
;
6969 static WCHAR
*get_scalable_filename( const WCHAR
*res
, BOOL
*hidden
)
6972 BYTE
*ptr
= map_file( res
, &size
);
6973 const IMAGE_DOS_HEADER
*dos
;
6974 const IMAGE_OS2_HEADER
*ne
;
6980 if (!ptr
) return NULL
;
6982 if (size
.u
.LowPart
< sizeof( *dos
)) goto fail
;
6983 dos
= (const IMAGE_DOS_HEADER
*)ptr
;
6984 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto fail
;
6985 if (size
.u
.LowPart
< dos
->e_lfanew
+ sizeof( *ne
)) goto fail
;
6986 ne
= (const IMAGE_OS2_HEADER
*)(ptr
+ dos
->e_lfanew
);
6988 fontdir
= find_resource( ptr
, 0x8007, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
6989 if (!fontdir
) goto fail
;
6990 *hidden
= (fontdir
[35] & 0x80) != 0; /* fontdir->dfType */
6992 data
= find_resource( ptr
, 0x80cc, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
6993 if (!data
) goto fail
;
6994 if (!memchr( data
, 0, len
)) goto fail
;
6996 len
= MultiByteToWideChar( CP_ACP
, 0, data
, -1, NULL
, 0 );
6997 name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
6998 if (name
) MultiByteToWideChar( CP_ACP
, 0, data
, -1, name
, len
);
7001 UnmapViewOfFile( ptr
);
7005 static int add_system_font_resource( const WCHAR
*file
, DWORD flags
)
7007 WCHAR path
[MAX_PATH
];
7010 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
7011 get_fonts_win_dir_path( file
, path
);
7012 EnterCriticalSection( &font_cs
);
7013 ret
= font_funcs
->add_font( path
, flags
);
7014 LeaveCriticalSection( &font_cs
);
7015 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
7018 get_fonts_data_dir_path( file
, path
);
7019 EnterCriticalSection( &font_cs
);
7020 ret
= font_funcs
->add_font( path
, flags
);
7021 LeaveCriticalSection( &font_cs
);
7026 static BOOL
remove_system_font_resource( LPCWSTR file
, DWORD flags
)
7028 WCHAR path
[MAX_PATH
];
7031 get_fonts_win_dir_path( file
, path
);
7032 EnterCriticalSection( &font_cs
);
7033 ret
= font_funcs
->remove_font( path
, flags
);
7034 LeaveCriticalSection( &font_cs
);
7037 get_fonts_data_dir_path( file
, path
);
7038 EnterCriticalSection( &font_cs
);
7039 ret
= font_funcs
->remove_font( path
, flags
);
7040 LeaveCriticalSection( &font_cs
);
7045 static int add_font_resource( LPCWSTR file
, DWORD flags
)
7047 WCHAR path
[MAX_PATH
];
7050 if (GetFullPathNameW( file
, MAX_PATH
, path
, NULL
))
7052 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
7054 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
7055 EnterCriticalSection( &font_cs
);
7056 ret
= font_funcs
->add_font( path
, addfont_flags
);
7057 LeaveCriticalSection( &font_cs
);
7060 if (!ret
&& !strchrW( file
, '\\' ))
7061 ret
= add_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
7066 static BOOL
remove_font_resource( LPCWSTR file
, DWORD flags
)
7068 WCHAR path
[MAX_PATH
];
7071 if (GetFullPathNameW( file
, MAX_PATH
, path
, NULL
))
7073 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
7075 if (!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
7076 EnterCriticalSection( &font_cs
);
7077 ret
= font_funcs
->remove_font( path
, addfont_flags
);
7078 LeaveCriticalSection( &font_cs
);
7081 if (!ret
&& !strchrW( file
, '\\' ))
7082 ret
= remove_system_font_resource( file
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
7087 void load_system_bitmap_fonts(void)
7089 static const WCHAR keyW
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s',0};
7090 static const WCHAR fontsW
[] = {'F','O','N','T','S','.','F','O','N',0};
7091 static const WCHAR oemfontW
[] = {'O','E','M','F','O','N','T','.','F','O','N',0};
7092 static const WCHAR fixedfonW
[] = {'F','I','X','E','D','F','O','N','.','F','O','N',0};
7093 static const WCHAR
* const fonts
[] = { fontsW
, oemfontW
, fixedfonW
};
7096 WCHAR data
[MAX_PATH
];
7097 DWORD i
, dlen
, type
;
7099 if (RegOpenKeyW( HKEY_CURRENT_CONFIG
, keyW
, &hkey
)) return;
7100 for (i
= 0; i
< ARRAY_SIZE(fonts
); i
++)
7102 dlen
= sizeof(data
);
7103 if (!RegQueryValueExW( hkey
, fonts
[i
], 0, &type
, (BYTE
*)data
, &dlen
) && type
== REG_SZ
)
7104 add_system_font_resource( data
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
7106 RegCloseKey( hkey
);
7109 static void load_directory_fonts( WCHAR
*path
, UINT flags
)
7112 WIN32_FIND_DATAW data
;
7115 p
= path
+ strlenW(path
) - 1;
7116 TRACE( "loading fonts from %s\n", debugstr_w(path
) );
7117 handle
= FindFirstFileW( path
, &data
);
7118 if (handle
== INVALID_HANDLE_VALUE
) return;
7121 if (data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) continue;
7122 strcpyW( p
, data
.cFileName
);
7123 font_funcs
->add_font( path
, flags
);
7124 } while (FindNextFileW( handle
, &data
));
7125 FindClose( handle
);
7128 void load_file_system_fonts(void)
7130 static const WCHAR pathW
[] = {'P','a','t','h',0};
7131 static const WCHAR slashstarW
[] = {'\\','*',0};
7132 static const WCHAR starW
[] = {'*',0};
7133 WCHAR
*ptr
, *next
, path
[MAX_PATH
], value
[1024];
7134 DWORD len
= ARRAY_SIZE(value
);
7136 /* Windows directory */
7137 get_fonts_win_dir_path( starW
, path
);
7138 load_directory_fonts( path
, ADDFONT_ADD_TO_CACHE
);
7140 /* Wine data directory */
7141 get_fonts_data_dir_path( starW
, path
);
7142 load_directory_fonts( path
, ADDFONT_ADD_TO_CACHE
| ADDFONT_EXTERNAL_FONT
);
7145 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
7146 if (!RegQueryValueExW( wine_fonts_key
, pathW
, NULL
, NULL
, (BYTE
*)value
, &len
))
7148 for (ptr
= value
; ptr
; ptr
= next
)
7150 if ((next
= strchrW( ptr
, ';' ))) *next
++ = 0;
7151 if (next
&& next
- ptr
< 2) continue;
7152 lstrcpynW( path
, ptr
, MAX_PATH
- 2 );
7153 strcatW( path
, slashstarW
);
7154 load_directory_fonts( path
, ADDFONT_ADD_TO_CACHE
| ADDFONT_EXTERNAL_FONT
);
7159 void load_registry_fonts(void)
7161 static const WCHAR dot_fonW
[] = {'.','f','o','n',0};
7162 static const WCHAR win9x_key
[] = {'S','o','f','t','w','a','r','e','\\',
7163 'M','i','c','r','o','s','o','f','t','\\',
7164 'W','i','n','d','o','w','s','\\',
7165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7166 'F','o','n','t','s',0};
7167 static const WCHAR winnt_key
[] = {'S','o','f','t','w','a','r','e','\\',
7168 'M','i','c','r','o','s','o','f','t','\\',
7169 'W','i','n','d','o','w','s',' ','N','T','\\',
7170 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7171 'F','o','n','t','s',0};
7172 WCHAR value
[MAX_PATH
], data
[MAX_PATH
];
7173 DWORD i
= 0, type
, dlen
, vlen
;
7176 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
7177 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
7178 full path as the entry. Also look for any .fon fonts, since ReadFontDir
7180 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_key
: winnt_key
, &hkey
))
7183 vlen
= ARRAY_SIZE(value
);
7184 dlen
= sizeof(data
);
7185 while (!RegEnumValueW( hkey
, i
++, value
, &vlen
, NULL
, &type
, (LPBYTE
)data
, &dlen
))
7187 dlen
/= sizeof(WCHAR
);
7188 if (data
[0] && data
[1] == ':')
7189 add_font_resource( data
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
7190 else if (dlen
>= 6 && !strcmpiW( data
+ dlen
- 5, dot_fonW
))
7191 add_system_font_resource( data
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
7193 vlen
= ARRAY_SIZE(value
);
7194 dlen
= sizeof(data
);
7196 RegCloseKey( hkey
);
7199 /***********************************************************************
7200 * AddFontResourceExW (GDI32.@)
7202 INT WINAPI
AddFontResourceExW( LPCWSTR str
, DWORD flags
, PVOID pdv
)
7208 if (!font_funcs
) return 1;
7209 if (!(ret
= add_font_resource( str
, flags
)))
7211 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
7212 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
7213 if (hModule
!= NULL
)
7215 int num_resources
= 0;
7216 LPWSTR rt_font
= (LPWSTR
)((ULONG_PTR
)8); /* we don't want to include winuser.h */
7218 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
7219 wine_dbgstr_w(str
));
7220 if (EnumResourceNamesW(hModule
, rt_font
, load_enumed_resource
, (LONG_PTR
)&num_resources
))
7221 ret
= num_resources
;
7222 FreeLibrary(hModule
);
7224 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
7226 if (hidden
) flags
|= FR_PRIVATE
| FR_NOT_ENUM
;
7227 ret
= add_font_resource( filename
, flags
);
7228 HeapFree( GetProcessHeap(), 0, filename
);
7234 /***********************************************************************
7235 * RemoveFontResourceA (GDI32.@)
7237 BOOL WINAPI
RemoveFontResourceA( LPCSTR str
)
7239 return RemoveFontResourceExA(str
, 0, 0);
7242 /***********************************************************************
7243 * RemoveFontResourceW (GDI32.@)
7245 BOOL WINAPI
RemoveFontResourceW( LPCWSTR str
)
7247 return RemoveFontResourceExW(str
, 0, 0);
7250 /***********************************************************************
7251 * AddFontMemResourceEx (GDI32.@)
7253 HANDLE WINAPI
AddFontMemResourceEx( PVOID ptr
, DWORD size
, PVOID pdv
, DWORD
*pcFonts
)
7259 if (!ptr
|| !size
|| !pcFonts
)
7261 SetLastError(ERROR_INVALID_PARAMETER
);
7264 if (!font_funcs
) return NULL
;
7265 if (!(copy
= HeapAlloc( GetProcessHeap(), 0, size
))) return NULL
;
7266 memcpy( copy
, ptr
, size
);
7268 EnterCriticalSection( &font_cs
);
7269 num_fonts
= font_funcs
->add_mem_font( copy
, size
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
7270 LeaveCriticalSection( &font_cs
);
7274 HeapFree( GetProcessHeap(), 0, copy
);
7278 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
7279 * For now return something unique but quite random
7281 ret
= (HANDLE
)((INT_PTR
)copy
^ 0x87654321);
7285 *pcFonts
= num_fonts
;
7289 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts
);
7290 RemoveFontMemResourceEx( ret
);
7294 TRACE( "Returning handle %p\n", ret
);
7298 /***********************************************************************
7299 * RemoveFontMemResourceEx (GDI32.@)
7301 BOOL WINAPI
RemoveFontMemResourceEx( HANDLE fh
)
7303 FIXME("(%p) stub\n", fh
);
7307 /***********************************************************************
7308 * RemoveFontResourceExA (GDI32.@)
7310 BOOL WINAPI
RemoveFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
7312 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
7313 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7316 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
7317 ret
= RemoveFontResourceExW(strW
, fl
, pdv
);
7318 HeapFree(GetProcessHeap(), 0, strW
);
7322 /***********************************************************************
7323 * RemoveFontResourceExW (GDI32.@)
7325 BOOL WINAPI
RemoveFontResourceExW( LPCWSTR str
, DWORD flags
, PVOID pdv
)
7331 if (!font_funcs
) return TRUE
;
7333 if (!(ret
= remove_font_resource( str
, flags
)))
7335 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
7336 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
7337 if (hModule
!= NULL
)
7339 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str
));
7340 FreeLibrary(hModule
);
7342 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
7344 if (hidden
) flags
|= FR_PRIVATE
| FR_NOT_ENUM
;
7345 ret
= remove_font_resource( filename
, flags
);
7346 HeapFree( GetProcessHeap(), 0, filename
);
7352 /***********************************************************************
7353 * GetFontResourceInfoW (GDI32.@)
7355 BOOL WINAPI
GetFontResourceInfoW( LPCWSTR str
, LPDWORD size
, PVOID buffer
, DWORD type
)
7357 FIXME("%s %p(%d) %p %d\n", debugstr_w(str
), size
, size
? *size
: 0, buffer
, type
);
7361 /***********************************************************************
7362 * GetTextCharset (GDI32.@)
7364 UINT WINAPI
GetTextCharset(HDC hdc
)
7366 /* MSDN docs say this is equivalent */
7367 return GetTextCharsetInfo(hdc
, NULL
, 0);
7370 /***********************************************************************
7371 * GdiGetCharDimensions (GDI32.@)
7373 * Gets the average width of the characters in the English alphabet.
7376 * hdc [I] Handle to the device context to measure on.
7377 * lptm [O] Pointer to memory to store the text metrics into.
7378 * height [O] On exit, the maximum height of characters in the English alphabet.
7381 * The average width of characters in the English alphabet.
7384 * This function is used by the dialog manager to get the size of a dialog
7385 * unit. It should also be used by other pieces of code that need to know
7386 * the size of a dialog unit in logical units without having access to the
7387 * window handle of the dialog.
7388 * Windows caches the font metrics from this function, but we don't and
7389 * there doesn't appear to be an immediate advantage to do so.
7392 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
7394 LONG WINAPI
GdiGetCharDimensions(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
)
7397 static const WCHAR alphabet
[] = {
7398 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
7399 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
7400 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
7402 if(lptm
&& !GetTextMetricsW(hdc
, lptm
)) return 0;
7404 if(!GetTextExtentPointW(hdc
, alphabet
, 52, &sz
)) return 0;
7406 if (height
) *height
= sz
.cy
;
7407 return (sz
.cx
/ 26 + 1) / 2;
7410 BOOL WINAPI
EnableEUDC(BOOL fEnableEUDC
)
7412 FIXME("(%d): stub\n", fEnableEUDC
);
7416 /***********************************************************************
7417 * GetCharWidthI (GDI32.@)
7419 * Retrieve widths of characters.
7422 * hdc [I] Handle to a device context.
7423 * first [I] First glyph in range to query.
7424 * count [I] Number of glyph indices to query.
7425 * glyphs [I] Array of glyphs to query.
7426 * buffer [O] Buffer to receive character widths.
7429 * Only works with TrueType fonts.
7435 BOOL WINAPI
GetCharWidthI(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPINT buffer
)
7440 TRACE("(%p, %d, %d, %p, %p)\n", hdc
, first
, count
, glyphs
, buffer
);
7442 if (!(abc
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(ABC
))))
7445 if (!GetCharABCWidthsI(hdc
, first
, count
, glyphs
, abc
))
7447 HeapFree(GetProcessHeap(), 0, abc
);
7451 for (i
= 0; i
< count
; i
++)
7452 buffer
[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
7454 HeapFree(GetProcessHeap(), 0, abc
);
7458 /***********************************************************************
7459 * GetFontUnicodeRanges (GDI32.@)
7461 * Retrieve a list of supported Unicode characters in a font.
7464 * hdc [I] Handle to a device context.
7465 * lpgs [O] GLYPHSET structure specifying supported character ranges.
7468 * Success: Number of bytes written to the buffer pointed to by lpgs.
7472 DWORD WINAPI
GetFontUnicodeRanges(HDC hdc
, LPGLYPHSET lpgs
)
7476 DC
*dc
= get_dc_ptr(hdc
);
7478 TRACE("(%p, %p)\n", hdc
, lpgs
);
7482 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
7483 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
7489 /*************************************************************
7490 * FontIsLinked (GDI32.@)
7492 BOOL WINAPI
FontIsLinked(HDC hdc
)
7494 DC
*dc
= get_dc_ptr(hdc
);
7498 if (!dc
) return FALSE
;
7499 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
7500 ret
= dev
->funcs
->pFontIsLinked( dev
);
7502 TRACE("returning %d\n", ret
);
7506 /*************************************************************
7507 * GetFontRealizationInfo (GDI32.@)
7509 BOOL WINAPI
GetFontRealizationInfo(HDC hdc
, struct font_realization_info
*info
)
7511 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, unk
);
7516 if (info
->size
!= sizeof(*info
) && !is_v0
)
7519 dc
= get_dc_ptr(hdc
);
7520 if (!dc
) return FALSE
;
7521 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
7522 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
7527 /*************************************************************************
7528 * GetRasterizerCaps (GDI32.@)
7530 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7532 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7533 lprs
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
7534 lprs
->nLanguageID
= 0;
7538 /*************************************************************************
7539 * GetFontFileData (GDI32.@)
7541 BOOL WINAPI
GetFontFileData( DWORD instance_id
, DWORD unknown
, UINT64 offset
, void *buff
, DWORD buff_size
)
7543 struct gdi_font
*font
;
7544 DWORD tag
= 0, size
;
7547 if (!font_funcs
) return FALSE
;
7548 EnterCriticalSection( &font_cs
);
7549 if ((font
= get_font_from_handle( instance_id
)))
7551 if (font
->ttc_item_offset
) tag
= MS_TTCF_TAG
;
7552 size
= font_funcs
->get_font_data( font
, tag
, 0, NULL
, 0 );
7553 if (size
!= GDI_ERROR
&& size
>= buff_size
&& offset
<= size
- buff_size
)
7554 ret
= font_funcs
->get_font_data( font
, tag
, offset
, buff
, buff_size
) != GDI_ERROR
;
7556 SetLastError( ERROR_INVALID_PARAMETER
);
7558 LeaveCriticalSection( &font_cs
);
7562 /* Undocumented structure filled in by GetFontFileInfo */
7563 struct font_fileinfo
7570 /*************************************************************************
7571 * GetFontFileInfo (GDI32.@)
7573 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
,
7574 SIZE_T size
, SIZE_T
*needed
)
7576 SIZE_T required_size
= 0;
7577 struct gdi_font
*font
;
7580 EnterCriticalSection( &font_cs
);
7582 if ((font
= get_font_from_handle( instance_id
)))
7584 required_size
= sizeof(*info
) + strlenW( font
->file
) * sizeof(WCHAR
);
7585 if (required_size
<= size
)
7587 info
->writetime
= font
->writetime
;
7588 info
->size
.QuadPart
= font
->data_size
;
7589 strcpyW( info
->path
, font
->file
);
7592 else SetLastError( ERROR_INSUFFICIENT_BUFFER
);
7595 LeaveCriticalSection( &font_cs
);
7596 if (needed
) *needed
= required_size
;
7600 struct realization_info
7602 DWORD flags
; /* 1 for bitmap fonts, 3 for scalable fonts */
7603 DWORD cache_num
; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
7604 DWORD instance_id
; /* identifies a realized font instance */
7607 /*************************************************************
7608 * GdiRealizationInfo (GDI32.@)
7610 * Returns a structure that contains some font information.
7612 BOOL WINAPI
GdiRealizationInfo(HDC hdc
, struct realization_info
*info
)
7614 struct font_realization_info ri
;
7617 ri
.size
= sizeof(ri
);
7618 ret
= GetFontRealizationInfo( hdc
, &ri
);
7621 info
->flags
= ri
.flags
;
7622 info
->cache_num
= ri
.cache_num
;
7623 info
->instance_id
= ri
.instance_id
;
7629 /*************************************************************
7630 * GetCharWidthInfo (GDI32.@)
7633 BOOL WINAPI
GetCharWidthInfo(HDC hdc
, struct char_width_info
*info
)
7639 dc
= get_dc_ptr(hdc
);
7640 if (!dc
) return FALSE
;
7641 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
7642 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
7646 info
->lsb
= width_to_LP( dc
, info
->lsb
);
7647 info
->rsb
= width_to_LP( dc
, info
->rsb
);