gdi32: Directly use ntgdi interface to select objects.
[wine.git] / dlls / gdi32 / font.c
blob2a51e3f7411e737fa9f75459419a3af9b7910cc8
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include "winerror.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32 #include "winternl.h"
33 #include "winreg.h"
34 #include "gdi_private.h"
35 #include "resource.h"
36 #include "wine/exception.h"
37 #include "wine/heap.h"
38 #include "wine/rbtree.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(font);
43 static HKEY wine_fonts_key;
44 static HKEY wine_fonts_cache_key;
46 struct font_physdev
48 struct gdi_physdev dev;
49 struct gdi_font *font;
52 static inline struct font_physdev *get_font_dev( PHYSDEV dev )
54 return (struct font_physdev *)dev;
57 struct gdi_font_family
59 struct wine_rb_entry name_entry;
60 struct wine_rb_entry second_name_entry;
61 unsigned int refcount;
62 WCHAR family_name[LF_FACESIZE];
63 WCHAR second_name[LF_FACESIZE];
64 struct list faces;
65 struct gdi_font_family *replacement;
68 struct gdi_font_face
70 struct list entry;
71 unsigned int refcount;
72 WCHAR *style_name;
73 WCHAR *full_name;
74 WCHAR *file;
75 void *data_ptr;
76 SIZE_T data_size;
77 UINT face_index;
78 FONTSIGNATURE fs;
79 DWORD ntmFlags;
80 DWORD version;
81 DWORD flags; /* ADDFONT flags */
82 BOOL scalable;
83 struct bitmap_font_size size; /* set if face is a bitmap */
84 struct gdi_font_family *family;
85 struct gdi_font_enum_data *cached_enum_data;
86 struct wine_rb_entry full_name_entry;
89 static const struct font_backend_funcs *font_funcs;
91 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
93 static UINT font_smoothing = GGO_BITMAP;
94 static UINT subpixel_orientation = GGO_GRAY4_BITMAP;
95 static BOOL antialias_fakes = TRUE;
96 static struct font_gamma_ramp font_gamma_ramp;
98 static void add_face_to_cache( struct gdi_font_face *face );
99 static void remove_face_from_cache( struct gdi_font_face *face );
101 static inline WCHAR facename_tolower( WCHAR c )
103 if (c >= 'A' && c <= 'Z') return c - 'A' + 'a';
104 else if (c > 127) return RtlDowncaseUnicodeChar( c );
105 else return c;
108 static inline int facename_compare( const WCHAR *str1, const WCHAR *str2, SIZE_T len )
110 while (len--)
112 WCHAR c1 = facename_tolower( *str1++ ), c2 = facename_tolower( *str2++ );
113 if (c1 != c2) return c1 - c2;
114 else if (!c1) return 0;
116 return 0;
119 /* Device -> World size conversion */
121 /* Performs a device to world transformation on the specified width (which
122 * is in integer format).
124 static inline INT INTERNAL_XDSTOWS(DC *dc, INT width)
126 double floatWidth;
128 /* Perform operation with floating point */
129 floatWidth = (double)width * dc->xformVport2World.eM11;
130 /* Round to integers */
131 return GDI_ROUND(floatWidth);
134 /* Performs a device to world transformation on the specified size (which
135 * is in integer format).
137 static inline INT INTERNAL_YDSTOWS(DC *dc, INT height)
139 double floatHeight;
141 /* Perform operation with floating point */
142 floatHeight = (double)height * dc->xformVport2World.eM22;
143 /* Round to integers */
144 return GDI_ROUND(floatHeight);
147 /* scale width and height but don't mirror them */
149 static inline INT width_to_LP( DC *dc, INT width )
151 return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
154 static inline INT height_to_LP( DC *dc, INT height )
156 return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
159 static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
161 POINT pt[2];
162 pt[0].x = pt[0].y = 0;
163 pt[1].x = 0;
164 pt[1].y = height;
165 lp_to_dp(dc, pt, 2);
166 return pt[1].y - pt[0].y;
169 static inline BOOL is_win9x(void)
171 return GetVersion() & 0x80000000;
174 static inline WCHAR *strdupW( const WCHAR *p )
176 WCHAR *ret;
177 DWORD len = (lstrlenW(p) + 1) * sizeof(WCHAR);
178 ret = HeapAlloc(GetProcessHeap(), 0, len);
179 memcpy(ret, p, len);
180 return ret;
183 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
184 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
185 static BOOL FONT_DeleteObject( HGDIOBJ handle );
187 static const struct gdi_obj_funcs fontobj_funcs =
189 FONT_GetObjectA, /* pGetObjectA */
190 FONT_GetObjectW, /* pGetObjectW */
191 NULL, /* pUnrealizeObject */
192 FONT_DeleteObject /* pDeleteObject */
195 typedef struct
197 struct gdi_obj_header obj;
198 LOGFONTW logfont;
199 } FONTOBJ;
201 struct font_enum
203 LPLOGFONTW lpLogFontParam;
204 FONTENUMPROCW lpEnumFunc;
205 LPARAM lpData;
206 BOOL unicode;
207 HDC hdc;
208 INT retval;
212 * For TranslateCharsetInfo
214 #define MAXTCIINDEX 32
215 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
216 /* ANSI */
217 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
218 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
219 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
220 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
221 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
222 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
223 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
224 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
225 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
226 /* reserved by ANSI */
227 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
228 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
229 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
230 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
231 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
232 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
233 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
234 /* ANSI and OEM */
235 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
236 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
237 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
238 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
239 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
240 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
241 /* reserved for alternate ANSI and OEM */
242 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
243 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
244 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
245 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
246 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
247 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
248 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
249 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
250 /* reserved for system */
251 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
252 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
255 static const WCHAR * const default_serif_list[3] =
257 L"Times New Roman",
258 L"Liberation Serif",
259 L"Bitstream Vera Serif"
261 static const WCHAR * const default_fixed_list[3] =
263 L"Courier New",
264 L"Liberation Mono",
265 L"Bitstream Vera Sans Mono"
267 static const WCHAR * const default_sans_list[3] =
269 L"Arial",
270 L"Liberation Sans",
271 L"Bitstream Vera Sans"
273 static WCHAR ff_roman_default[LF_FACESIZE];
274 static WCHAR ff_modern_default[LF_FACESIZE];
275 static WCHAR ff_swiss_default[LF_FACESIZE];
277 static const struct nls_update_font_list
279 UINT ansi_cp, oem_cp;
280 const char *oem, *fixed, *system;
281 const char *courier, *serif, *small, *sserif_96, *sserif_120;
282 /* these are for font substitutes */
283 const char *shelldlg, *tmsrmn;
284 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0, *helv_0, *tmsrmn_0;
285 struct subst { const char *from, *to; } arial_0, courier_new_0, times_new_roman_0;
286 } nls_update_font_list[] =
288 /* Latin 1 (United States) */
289 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
291 "Tahoma","Times New Roman"
293 /* Latin 1 (Multilingual) */
294 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
295 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
296 "Tahoma","Times New Roman" /* FIXME unverified */
298 /* Eastern Europe */
299 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
300 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
301 "Tahoma","Times New Roman", /* FIXME unverified */
302 "Fixedsys,238", "System,238",
303 "Courier New,238", "MS Serif,238", "Small Fonts,238",
304 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
305 { "Arial CE,0", "Arial,238" },
306 { "Courier New CE,0", "Courier New,238" },
307 { "Times New Roman CE,0", "Times New Roman,238" }
309 /* Cyrillic */
310 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
311 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
312 "Tahoma","Times New Roman", /* FIXME unverified */
313 "Fixedsys,204", "System,204",
314 "Courier New,204", "MS Serif,204", "Small Fonts,204",
315 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
316 { "Arial Cyr,0", "Arial,204" },
317 { "Courier New Cyr,0", "Courier New,204" },
318 { "Times New Roman Cyr,0", "Times New Roman,204" }
320 /* Greek */
321 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
322 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
323 "Tahoma","Times New Roman", /* FIXME unverified */
324 "Fixedsys,161", "System,161",
325 "Courier New,161", "MS Serif,161", "Small Fonts,161",
326 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
327 { "Arial Greek,0", "Arial,161" },
328 { "Courier New Greek,0", "Courier New,161" },
329 { "Times New Roman Greek,0", "Times New Roman,161" }
331 /* Turkish */
332 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
333 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
334 "Tahoma","Times New Roman", /* FIXME unverified */
335 "Fixedsys,162", "System,162",
336 "Courier New,162", "MS Serif,162", "Small Fonts,162",
337 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
338 { "Arial Tur,0", "Arial,162" },
339 { "Courier New Tur,0", "Courier New,162" },
340 { "Times New Roman Tur,0", "Times New Roman,162" }
342 /* Hebrew */
343 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
344 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
345 "Tahoma","Times New Roman", /* FIXME unverified */
346 "Fixedsys,177", "System,177",
347 "Courier New,177", "MS Serif,177", "Small Fonts,177",
348 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
350 /* Arabic */
351 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
352 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
353 "Microsoft Sans Serif","Times New Roman",
354 "Fixedsys,178", "System,178",
355 "Courier New,178", "MS Serif,178", "Small Fonts,178",
356 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
358 /* Baltic */
359 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
360 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
361 "Tahoma","Times New Roman", /* FIXME unverified */
362 "Fixedsys,186", "System,186",
363 "Courier New,186", "MS Serif,186", "Small Fonts,186",
364 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
365 { "Arial Baltic,0", "Arial,186" },
366 { "Courier New Baltic,0", "Courier New,186" },
367 { "Times New Roman Baltic,0", "Times New Roman,186" }
369 /* Vietnamese */
370 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
371 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
372 "Tahoma","Times New Roman" /* FIXME unverified */
374 /* Thai */
375 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
376 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
377 "Tahoma","Times New Roman" /* FIXME unverified */
379 /* Japanese */
380 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
381 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
382 "MS UI Gothic","MS Serif"
384 /* Chinese Simplified */
385 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
386 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
387 "SimSun", "NSimSun"
389 /* Korean */
390 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
391 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
392 "Gulim", "Batang"
394 /* Chinese Traditional */
395 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
396 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
397 "PMingLiU", "MingLiU"
401 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
403 return ( ansi_cp == 932 /* CP932 for Japanese */
404 || ansi_cp == 936 /* CP936 for Chinese Simplified */
405 || ansi_cp == 949 /* CP949 for Korean */
406 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
409 static CRITICAL_SECTION font_cs;
410 static CRITICAL_SECTION_DEBUG critsect_debug =
412 0, 0, &font_cs,
413 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
414 0, 0, { (DWORD_PTR)(__FILE__ ": font_cs") }
416 static CRITICAL_SECTION font_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
418 #ifndef WINE_FONT_DIR
419 #define WINE_FONT_DIR "fonts"
420 #endif
422 #ifdef WORDS_BIGENDIAN
423 #define GET_BE_WORD(x) (x)
424 #define GET_BE_DWORD(x) (x)
425 #else
426 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
427 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
428 #endif
430 static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
432 if (GetEnvironmentVariableW( L"WINEDATADIR", path, MAX_PATH ))
433 lstrcatW( path, L"\\" WINE_FONT_DIR "\\" );
434 else if (GetEnvironmentVariableW( L"WINEBUILDDIR", path, MAX_PATH ))
435 lstrcatW( path, L"\\fonts\\" );
437 lstrcatW( path, file );
438 if (path[5] == ':') memmove( path, path + 4, (lstrlenW(path) - 3) * sizeof(WCHAR) );
439 else path[1] = '\\'; /* change \??\ to \\?\ */
442 static void get_fonts_win_dir_path( const WCHAR *file, WCHAR *path )
444 GetWindowsDirectoryW( path, MAX_PATH );
445 lstrcatW( path, L"\\fonts\\" );
446 lstrcatW( path, file );
449 /* font substitutions */
451 struct gdi_font_subst
453 struct list entry;
454 int from_charset;
455 int to_charset;
456 WCHAR names[1];
459 static struct list font_subst_list = LIST_INIT(font_subst_list);
461 static inline WCHAR *get_subst_to_name( struct gdi_font_subst *subst )
463 return subst->names + lstrlenW( subst->names ) + 1;
466 static void dump_gdi_font_subst(void)
468 struct gdi_font_subst *subst;
470 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
472 if (subst->from_charset != -1 || subst->to_charset != -1)
473 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst->names),
474 subst->from_charset, debugstr_w(get_subst_to_name(subst)), subst->to_charset);
475 else
476 TRACE("%s -> %s\n", debugstr_w(subst->names), debugstr_w(get_subst_to_name(subst)));
480 static const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset )
482 struct gdi_font_subst *subst;
484 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
486 if (!facename_compare( subst->names, from_name, -1 ) &&
487 (subst->from_charset == from_charset || subst->from_charset == -1))
489 if (to_charset) *to_charset = subst->to_charset;
490 return get_subst_to_name( subst );
493 return NULL;
496 static BOOL add_gdi_font_subst( const WCHAR *from_name, int from_charset, const WCHAR *to_name, int to_charset )
498 struct gdi_font_subst *subst;
499 int len = lstrlenW( from_name ) + lstrlenW( to_name ) + 2;
501 if (get_gdi_font_subst( from_name, from_charset, NULL )) return FALSE; /* already exists */
503 if (!(subst = HeapAlloc( GetProcessHeap(), 0,
504 offsetof( struct gdi_font_subst, names[len] ))))
505 return FALSE;
506 lstrcpyW( subst->names, from_name );
507 lstrcpyW( get_subst_to_name(subst), to_name );
508 subst->from_charset = from_charset;
509 subst->to_charset = to_charset;
510 list_add_tail( &font_subst_list, &subst->entry );
511 return TRUE;
514 static void load_gdi_font_subst(void)
516 HKEY hkey;
517 DWORD i = 0, type, dlen, vlen;
518 WCHAR value[64], data[64], *p;
520 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
521 &hkey)) return;
523 dlen = sizeof(data);
524 vlen = ARRAY_SIZE(value);
525 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)data, &dlen ))
527 int from_charset = -1, to_charset = -1;
529 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
530 if ((p = wcsrchr( value, ',' )) && p[1])
532 *p++ = 0;
533 from_charset = wcstol( p, NULL, 10 );
535 if ((p = wcsrchr( data, ',' )) && p[1])
537 *p++ = 0;
538 to_charset = wcstol( p, NULL, 10 );
541 /* Win 2000 doesn't allow mapping between different charsets
542 or mapping of DEFAULT_CHARSET */
543 if ((!from_charset || to_charset == from_charset) && to_charset != DEFAULT_CHARSET)
544 add_gdi_font_subst( value, from_charset, data, to_charset );
546 /* reset dlen and vlen */
547 dlen = sizeof(data);
548 vlen = ARRAY_SIZE(value);
550 RegCloseKey( hkey );
553 /* font families */
555 static int family_namecmp( const WCHAR *str1, const WCHAR *str2 )
557 int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0);
559 if (!facename_compare( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0;
560 else if (!facename_compare( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1;
561 else if (!facename_compare( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2;
562 else prio1 = 3;
564 if (!facename_compare( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0;
565 else if (!facename_compare( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1;
566 else if (!facename_compare( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2;
567 else prio2 = 3;
569 if (prio1 != prio2) return prio1 - prio2;
570 if (vert1 != vert2) return vert1 - vert2;
571 return facename_compare( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 );
574 static int family_name_compare( const void *key, const struct wine_rb_entry *entry )
576 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, name_entry );
577 return family_namecmp( (const WCHAR *)key, family->family_name );
580 static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry )
582 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, second_name_entry );
583 return family_namecmp( (const WCHAR *)key, family->second_name );
586 static int face_full_name_compare( const void *key, const struct wine_rb_entry *entry )
588 const struct gdi_font_face *face = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_face, full_name_entry );
589 return facename_compare( (const WCHAR *)key, face->full_name, LF_FULLFACESIZE - 1 );
592 static struct wine_rb_tree family_name_tree = { family_name_compare };
593 static struct wine_rb_tree family_second_name_tree = { family_second_name_compare };
594 static struct wine_rb_tree face_full_name_tree = { face_full_name_compare };
596 static int face_is_in_full_name_tree( const struct gdi_font_face *face )
598 return face->full_name_entry.parent || face_full_name_tree.root == &face->full_name_entry;
601 static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name )
603 struct gdi_font_family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
605 family->refcount = 1;
606 lstrcpynW( family->family_name, name, LF_FACESIZE );
607 if (second_name && second_name[0] && wcsicmp( name, second_name ))
609 lstrcpynW( family->second_name, second_name, LF_FACESIZE );
610 add_gdi_font_subst( second_name, -1, name, -1 );
612 else family->second_name[0] = 0;
613 list_init( &family->faces );
614 family->replacement = NULL;
615 wine_rb_put( &family_name_tree, family->family_name, &family->name_entry );
616 if (family->second_name[0]) wine_rb_put( &family_second_name_tree, family->second_name, &family->second_name_entry );
617 return family;
620 static void release_family( struct gdi_font_family *family )
622 if (--family->refcount) return;
623 assert( list_empty( &family->faces ));
624 wine_rb_remove( &family_name_tree, &family->name_entry );
625 if (family->second_name[0]) wine_rb_remove( &family_second_name_tree, &family->second_name_entry );
626 if (family->replacement) release_family( family->replacement );
627 HeapFree( GetProcessHeap(), 0, family );
630 static struct gdi_font_family *find_family_from_name( const WCHAR *name )
632 struct wine_rb_entry *entry;
633 if (!(entry = wine_rb_get( &family_name_tree, name ))) return NULL;
634 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, name_entry );
637 static struct gdi_font_family *find_family_from_any_name( const WCHAR *name )
639 struct wine_rb_entry *entry;
640 struct gdi_font_family *family;
641 if ((family = find_family_from_name( name ))) return family;
642 if (!(entry = wine_rb_get( &family_second_name_tree, name ))) return NULL;
643 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, second_name_entry );
646 static struct gdi_font_face *find_face_from_full_name( const WCHAR *full_name )
648 struct wine_rb_entry *entry;
649 if (!(entry = wine_rb_get( &face_full_name_tree, full_name ))) return NULL;
650 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_face, full_name_entry );
653 static const struct list *get_family_face_list( const struct gdi_font_family *family )
655 return family->replacement ? &family->replacement->faces : &family->faces;
658 static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name )
660 struct gdi_font_face *face;
661 const WCHAR *file;
662 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
664 if (!face->file) continue;
665 file = wcsrchr(face->file, '\\');
666 if (!file) file = face->file;
667 else file++;
668 if (wcsicmp( file, file_name )) continue;
669 face->refcount++;
670 return face;
672 return NULL;
675 static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name )
677 struct gdi_font_family *family;
678 struct gdi_font_face *face;
680 TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
682 if (!family_name)
684 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
685 if ((face = family_find_face_from_filename( family, file_name ))) return face;
686 return NULL;
689 if (!(family = find_family_from_name( family_name ))) return NULL;
690 return family_find_face_from_filename( family, file_name );
693 static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
695 struct gdi_font_family *new_family, *family;
696 struct gdi_font_face *face;
697 WCHAR new_name_vert[LF_FACESIZE], replace_vert[LF_FACESIZE];
699 if (!(family = find_family_from_any_name( replace )))
701 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace) );
702 return FALSE;
705 if (!(new_family = create_family( new_name, NULL ))) return FALSE;
706 new_family->replacement = family;
707 family->refcount++;
708 TRACE( "mapping %s to %s\n", debugstr_w(replace), debugstr_w(new_name) );
710 /* also add replacement for vertical font if necessary */
711 if (replace[0] == '@') return TRUE;
712 if (list_empty( &family->faces )) return TRUE;
713 face = LIST_ENTRY( list_head(&family->faces), struct gdi_font_face, entry );
714 if (!(face->fs.fsCsb[0] & FS_DBCS_MASK)) return TRUE;
716 new_name_vert[0] = '@';
717 lstrcpynW( new_name_vert + 1, new_name, LF_FACESIZE - 1 );
718 if (find_family_from_any_name( new_name_vert )) return TRUE; /* already exists */
720 replace_vert[0] = '@';
721 lstrcpynW( replace_vert + 1, replace, LF_FACESIZE - 1 );
722 add_family_replacement( new_name_vert, replace_vert );
723 return TRUE;
727 * The replacement list is a way to map an entire font
728 * family onto another family. For example adding
730 * [HKCU\Software\Wine\Fonts\Replacements]
731 * "Wingdings"="Winedings"
733 * would enumerate the Winedings font both as Winedings and
734 * Wingdings. However if a real Wingdings font is present the
735 * replacement does not take place.
737 static void load_gdi_font_replacements(void)
739 HKEY hkey;
740 DWORD i = 0, type, dlen, vlen;
741 WCHAR value[LF_FACESIZE], data[1024];
743 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
744 if (RegOpenKeyW( wine_fonts_key, L"Replacements", &hkey )) return;
746 dlen = sizeof(data);
747 vlen = ARRAY_SIZE(value);
748 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)data, &dlen ))
750 /* "NewName"="Oldname" */
751 if (!find_family_from_any_name( value ))
753 if (type == REG_MULTI_SZ)
755 WCHAR *replace = data;
756 while (*replace)
758 if (add_family_replacement( value, replace )) break;
759 replace += lstrlenW(replace) + 1;
762 else if (type == REG_SZ) add_family_replacement( value, data );
764 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
766 /* reset dlen and vlen */
767 dlen = sizeof(data);
768 vlen = ARRAY_SIZE(value);
770 RegCloseKey( hkey );
773 static void dump_gdi_font_list(void)
775 struct gdi_font_family *family;
776 struct gdi_font_face *face;
778 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
780 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
781 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
783 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
784 face->fs.fsCsb[0] );
785 if (!face->scalable) TRACE(" %d", face->size.height );
786 TRACE("\n");
791 static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
793 if (index < 3)
795 const WCHAR * const *defaults;
797 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
798 defaults = default_fixed_list;
799 else if ((pitch_and_family & 0xf0) == FF_ROMAN)
800 defaults = default_serif_list;
801 else
802 defaults = default_sans_list;
803 lstrcpynW( buffer, defaults[index], LF_FACESIZE );
804 return TRUE;
806 return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
809 static void set_default_family( DWORD pitch_and_family, WCHAR *default_name )
811 struct wine_rb_entry *entry;
812 WCHAR name[LF_FACESIZE];
813 int i = 0;
815 while (enum_fallbacks( pitch_and_family, i++, name ))
817 if (!(entry = wine_rb_get( &family_name_tree, name ))) continue;
818 wine_rb_remove( &family_name_tree, entry );
819 lstrcpynW( default_name, name, LF_FACESIZE - 1 );
820 wine_rb_put( &family_name_tree, name, entry );
821 return;
825 static void reorder_font_list(void)
827 set_default_family( FF_ROMAN, ff_roman_default );
828 set_default_family( FF_MODERN, ff_modern_default );
829 set_default_family( FF_SWISS, ff_swiss_default );
832 static void release_face( struct gdi_font_face *face )
834 if (--face->refcount) return;
835 if (face->family)
837 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
838 list_remove( &face->entry );
839 release_family( face->family );
841 if (face_is_in_full_name_tree( face )) wine_rb_remove( &face_full_name_tree, &face->full_name_entry );
842 HeapFree( GetProcessHeap(), 0, face->file );
843 HeapFree( GetProcessHeap(), 0, face->style_name );
844 HeapFree( GetProcessHeap(), 0, face->full_name );
845 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
846 HeapFree( GetProcessHeap(), 0, face );
849 static int remove_font( const WCHAR *file, DWORD flags )
851 struct gdi_font_family *family, *family_next;
852 struct gdi_font_face *face, *face_next;
853 int count = 0;
855 EnterCriticalSection( &font_cs );
856 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_name_tree, struct gdi_font_family, name_entry )
858 family->refcount++;
859 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry )
861 if (!face->file) continue;
862 if (LOWORD(face->flags) != LOWORD(flags)) continue;
863 if (!wcsicmp( face->file, file ))
865 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
866 release_face( face );
867 count++;
870 release_family( family );
872 LeaveCriticalSection( &font_cs );
873 return count;
876 static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
878 if (facename_compare( f1->full_name, f2->full_name, -1 )) return FALSE;
879 if (f1->scalable) return TRUE;
880 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
881 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
884 static inline int style_order( const struct gdi_font_face *face )
886 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
888 case NTM_REGULAR:
889 return 0;
890 case NTM_BOLD:
891 return 1;
892 case NTM_ITALIC:
893 return 2;
894 case NTM_BOLD | NTM_ITALIC:
895 return 3;
896 default:
897 WARN( "Don't know how to order face %s with flags 0x%08x\n",
898 debugstr_w(face->full_name), face->ntmFlags );
899 return 9999;
903 static BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
905 struct gdi_font_face *cursor;
907 LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
909 if (faces_equal( face, cursor ))
911 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
912 debugstr_w(face->full_name), debugstr_w(family->family_name),
913 cursor->version, face->version );
915 if (face->file && cursor->file && !wcsicmp( face->file, cursor->file ))
917 cursor->refcount++;
918 TRACE("Font %s already in list, refcount now %d\n",
919 debugstr_w(face->file), cursor->refcount);
920 return FALSE;
922 if (face->version <= cursor->version)
924 TRACE("Original font %s is newer so skipping %s\n",
925 debugstr_w(cursor->file), debugstr_w(face->file));
926 return FALSE;
928 else
930 TRACE("Replacing original %s with %s\n",
931 debugstr_w(cursor->file), debugstr_w(face->file));
932 list_add_before( &cursor->entry, &face->entry );
933 face->family = family;
934 family->refcount++;
935 face->refcount++;
936 if (face_is_in_full_name_tree( cursor ))
938 wine_rb_replace( &face_full_name_tree, &cursor->full_name_entry, &face->full_name_entry );
939 memset( &cursor->full_name_entry, 0, sizeof(cursor->full_name_entry) );
941 release_face( cursor );
942 return TRUE;
945 if (style_order( face ) < style_order( cursor )) break;
948 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
949 debugstr_w(family->family_name), debugstr_w(face->file) );
950 list_add_before( &cursor->entry, &face->entry );
951 if (face->scalable) wine_rb_put( &face_full_name_tree, face->full_name, &face->full_name_entry );
952 face->family = family;
953 family->refcount++;
954 face->refcount++;
955 return TRUE;
958 static struct gdi_font_face *create_face( struct gdi_font_family *family, const WCHAR *style,
959 const WCHAR *fullname, const WCHAR *file,
960 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
961 DWORD ntmflags, DWORD version, DWORD flags,
962 const struct bitmap_font_size *size )
964 struct gdi_font_face *face = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*face) );
966 face->refcount = 1;
967 face->style_name = strdupW( style );
968 face->full_name = strdupW( fullname );
969 face->face_index = index;
970 face->fs = fs;
971 face->ntmFlags = ntmflags;
972 face->version = version;
973 face->flags = flags;
974 face->data_ptr = data_ptr;
975 face->data_size = data_size;
976 if (file) face->file = strdupW( file );
977 if (size) face->size = *size;
978 else face->scalable = TRUE;
979 if (insert_face_in_family_list( face, family )) return face;
980 release_face( face );
981 return NULL;
984 static int CDECL add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
985 const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
986 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
987 DWORD ntmflags, DWORD version, DWORD flags,
988 const struct bitmap_font_size *size )
990 struct gdi_font_face *face;
991 struct gdi_font_family *family;
992 int ret = 0;
994 if ((family = find_family_from_name( family_name ))) family->refcount++;
995 else if (!(family = create_family( family_name, second_name ))) return ret;
997 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
998 index, fs, ntmflags, version, flags, size )))
1000 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1001 release_face( face );
1003 release_family( family );
1004 ret++;
1006 if (fs.fsCsb[0] & FS_DBCS_MASK)
1008 WCHAR vert_family[LF_FACESIZE], vert_second[LF_FACESIZE], vert_full[LF_FULLFACESIZE];
1010 vert_family[0] = '@';
1011 lstrcpynW( vert_family + 1, family_name, LF_FACESIZE - 1 );
1013 if (second_name && second_name[0])
1015 vert_second[0] = '@';
1016 lstrcpynW( vert_second + 1, second_name, LF_FACESIZE - 1 );
1018 else vert_second[0] = 0;
1020 if (fullname)
1022 vert_full[0] = '@';
1023 lstrcpynW( vert_full + 1, fullname, LF_FULLFACESIZE - 1 );
1024 fullname = vert_full;
1027 if ((family = find_family_from_name( vert_family ))) family->refcount++;
1028 else if (!(family = create_family( vert_family, vert_second ))) return ret;
1030 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1031 index, fs, ntmflags, version, flags | ADDFONT_VERTICAL_FONT, size )))
1033 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1034 release_face( face );
1036 release_family( family );
1037 ret++;
1039 return ret;
1042 /* font cache */
1044 struct cached_face
1046 DWORD index;
1047 DWORD flags;
1048 DWORD ntmflags;
1049 DWORD version;
1050 struct bitmap_font_size size;
1051 FONTSIGNATURE fs;
1052 WCHAR full_name[1];
1053 /* WCHAR file_name[]; */
1056 static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
1057 void *buffer, DWORD buffer_size, BOOL scalable )
1059 DWORD type, size, needed, index = 0;
1060 struct gdi_font_face *face;
1061 HKEY hkey_strike;
1062 WCHAR name[256];
1063 struct cached_face *cached = (struct cached_face *)buffer;
1065 size = sizeof(name);
1066 needed = buffer_size - sizeof(DWORD);
1067 while (!RegEnumValueW( hkey_family, index++, name, &size, NULL, &type, buffer, &needed ))
1069 if (type == REG_BINARY && needed > sizeof(*cached))
1071 ((DWORD *)buffer)[needed / sizeof(DWORD)] = 0;
1072 if ((face = create_face( family, name, cached->full_name,
1073 cached->full_name + lstrlenW(cached->full_name) + 1,
1074 NULL, 0, cached->index, cached->fs, cached->ntmflags, cached->version,
1075 cached->flags, scalable ? NULL : &cached->size )))
1077 if (!scalable)
1078 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1079 face->size.height, face->size.width, face->size.size >> 6,
1080 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1082 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1083 face->fs.fsCsb[0], face->fs.fsCsb[1],
1084 face->fs.fsUsb[0], face->fs.fsUsb[1],
1085 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1087 release_face( face );
1090 size = sizeof(name);
1091 needed = buffer_size - sizeof(DWORD);
1094 /* load bitmap strikes */
1096 index = 0;
1097 needed = buffer_size;
1098 while (!RegEnumKeyExW( hkey_family, index++, buffer, &needed, NULL, NULL, NULL, NULL ))
1100 if (!RegOpenKeyExW( hkey_family, buffer, 0, KEY_ALL_ACCESS, &hkey_strike ))
1102 load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
1103 RegCloseKey( hkey_strike );
1105 needed = buffer_size;
1109 static void load_font_list_from_cache(void)
1111 DWORD size, family_index = 0;
1112 struct gdi_font_family *family;
1113 HKEY hkey_family;
1114 WCHAR buffer[4096], second_name[LF_FACESIZE];
1116 size = sizeof(buffer);
1117 while (!RegEnumKeyExW( wine_fonts_cache_key, family_index++, buffer, &size, NULL, NULL, NULL, NULL ))
1119 RegOpenKeyExW( wine_fonts_cache_key, buffer, 0, KEY_ALL_ACCESS, &hkey_family );
1120 TRACE("opened family key %s\n", debugstr_w(buffer));
1121 size = sizeof(second_name);
1122 if (RegQueryValueExW( hkey_family, NULL, NULL, NULL, (BYTE *)second_name, &size ))
1123 second_name[0] = 0;
1125 family = create_family( buffer, second_name );
1127 load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
1129 RegCloseKey( hkey_family );
1130 release_family( family );
1131 size = sizeof(buffer);
1135 static void add_face_to_cache( struct gdi_font_face *face )
1137 HKEY hkey_family, hkey_face;
1138 DWORD len, buffer[1024];
1139 struct cached_face *cached = (struct cached_face *)buffer;
1141 if (RegCreateKeyExW( wine_fonts_cache_key, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE,
1142 KEY_ALL_ACCESS, NULL, &hkey_family, NULL ))
1143 return;
1145 if (face->family->second_name[0])
1146 RegSetValueExW( hkey_family, NULL, 0, REG_SZ, (BYTE *)face->family->second_name,
1147 (lstrlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1149 if (!face->scalable)
1151 WCHAR name[10];
1153 swprintf( name, ARRAY_SIZE(name), L"%d", face->size.y_ppem );
1154 RegCreateKeyExW( hkey_family, name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
1155 NULL, &hkey_face, NULL);
1157 else hkey_face = hkey_family;
1159 memset( cached, 0, sizeof(*cached) );
1160 cached->index = face->face_index;
1161 cached->flags = face->flags;
1162 cached->ntmflags = face->ntmFlags;
1163 cached->version = face->version;
1164 cached->fs = face->fs;
1165 if (!face->scalable) cached->size = face->size;
1166 lstrcpyW( cached->full_name, face->full_name );
1167 len = lstrlenW( face->full_name ) + 1;
1168 lstrcpyW( cached->full_name + len, face->file );
1169 len += lstrlenW( face->file ) + 1;
1171 RegSetValueExW( hkey_face, face->style_name, 0, REG_BINARY, (BYTE *)cached,
1172 offsetof( struct cached_face, full_name[len] ));
1174 if (hkey_face != hkey_family) RegCloseKey( hkey_face );
1175 RegCloseKey( hkey_family );
1178 static void remove_face_from_cache( struct gdi_font_face *face )
1180 HKEY hkey_family;
1182 if (RegOpenKeyExW( wine_fonts_cache_key, face->family->family_name, 0, KEY_ALL_ACCESS, &hkey_family ))
1183 return;
1185 if (!face->scalable)
1187 WCHAR name[10];
1188 swprintf( name, ARRAY_SIZE(name), L"%d", face->size.y_ppem );
1189 RegDeleteKeyW( hkey_family, name );
1191 else RegDeleteValueW( hkey_family, face->style_name );
1193 RegCloseKey( hkey_family );
1196 /* font links */
1198 struct gdi_font_link
1200 struct list entry;
1201 struct list links;
1202 WCHAR name[LF_FACESIZE];
1203 FONTSIGNATURE fs;
1206 struct gdi_font_link_entry
1208 struct list entry;
1209 FONTSIGNATURE fs;
1210 WCHAR family_name[LF_FACESIZE];
1213 static struct list font_links = LIST_INIT(font_links);
1215 static struct gdi_font_link *find_gdi_font_link( const WCHAR *name )
1217 struct gdi_font_link *link;
1219 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1220 if (!facename_compare( link->name, name, LF_FACESIZE - 1 )) return link;
1221 return NULL;
1224 static struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
1225 FONTSIGNATURE fs )
1227 struct gdi_font_link *link;
1228 struct gdi_font_link_entry *entry;
1229 struct gdi_font_family *family;
1231 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1233 if (!facename_compare( link->name, name, LF_FACESIZE - 1 ) ||
1234 (subst && !facename_compare( link->name, subst, LF_FACESIZE - 1 )))
1236 TRACE("found entry in system list\n");
1237 LIST_FOR_EACH_ENTRY( entry, &link->links, struct gdi_font_link_entry, entry )
1239 const struct gdi_font_link *links;
1241 family = find_family_from_name( entry->family_name );
1242 if (!fs.fsCsb[0]) return family;
1243 if (fs.fsCsb[0] & entry->fs.fsCsb[0]) return family;
1244 if ((links = find_gdi_font_link( family->family_name )) && fs.fsCsb[0] & links->fs.fsCsb[0])
1245 return family;
1249 return NULL;
1252 static struct gdi_font_link *add_gdi_font_link( const WCHAR *name )
1254 struct gdi_font_link *link = find_gdi_font_link( name );
1256 if (link) return link;
1257 if ((link = HeapAlloc( GetProcessHeap(), 0, sizeof(*link) )))
1259 lstrcpynW( link->name, name, LF_FACESIZE );
1260 memset( &link->fs, 0, sizeof(link->fs) );
1261 list_init( &link->links );
1262 list_add_tail( &font_links, &link->entry );
1264 return link;
1267 static void add_gdi_font_link_entry( struct gdi_font_link *link, const WCHAR *family_name, FONTSIGNATURE fs )
1269 struct gdi_font_link_entry *entry;
1271 entry = HeapAlloc( GetProcessHeap(), 0, sizeof(*entry) );
1272 lstrcpynW( entry->family_name, family_name, LF_FACESIZE );
1273 entry->fs = fs;
1274 link->fs.fsCsb[0] |= fs.fsCsb[0];
1275 link->fs.fsCsb[1] |= fs.fsCsb[1];
1276 list_add_tail( &link->links, &entry->entry );
1279 static const WCHAR * const font_links_list[] =
1281 L"Lucida Sans Unicode",
1282 L"Microsoft Sans Serif",
1283 L"Tahoma"
1286 static const struct font_links_defaults_list
1288 /* Keyed off substitution for "MS Shell Dlg" */
1289 const WCHAR *shelldlg;
1290 /* Maximum of four substitutes, plus terminating NULL pointer */
1291 const WCHAR *substitutes[5];
1292 } font_links_defaults_list[] =
1294 /* Non East-Asian */
1295 { L"Tahoma", /* FIXME unverified ordering */
1296 { L"MS UI Gothic", L"SimSun", L"Gulim", L"PMingLiU", NULL }
1298 /* Below lists are courtesy of
1299 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1301 /* Japanese */
1302 { L"MS UI Gothic",
1303 { L"MS UI Gothic", L"PMingLiU", L"SimSun", L"Gulim", NULL }
1305 /* Chinese Simplified */
1306 { L"SimSun",
1307 { L"SimSun", L"PMingLiU", L"MS UI Gothic", L"Batang", NULL }
1309 /* Korean */
1310 { L"Gulim",
1311 { L"Gulim", L"PMingLiU", L"MS UI Gothic", L"SimSun", NULL }
1313 /* Chinese Traditional */
1314 { L"PMingLiU",
1315 { L"PMingLiU", L"SimSun", L"MS UI Gothic", L"Batang", NULL }
1319 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1321 struct gdi_font_family *family;
1322 struct gdi_font_face *face;
1323 struct gdi_font_link *font_link;
1324 const WCHAR *file, *value;
1326 /* Don't store fonts that are only substitutes for other fonts */
1327 if (get_gdi_font_subst( name, -1, NULL ))
1329 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1330 return;
1332 font_link = add_gdi_font_link( name );
1333 for ( ; *values; values++)
1335 if (!facename_compare( name, *values, -1 )) continue;
1336 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1337 if (!(family = find_family_from_name( value ))) continue;
1338 /* use first extant filename for this Family */
1339 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1341 if (!face->file) continue;
1342 file = wcsrchr(face->file, '\\');
1343 if (!file) file = face->file;
1344 else file++;
1345 if ((face = find_face_from_filename( file, value )))
1347 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1348 TRACE( "added internal SystemLink for %s to %s in %s\n",
1349 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1351 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1352 break;
1357 static void load_system_links(void)
1359 HKEY hkey;
1360 DWORD i, j;
1361 const WCHAR *shelldlg_name;
1362 struct gdi_font_link *font_link, *system_font_link;
1363 struct gdi_font_face *face;
1365 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE,
1366 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey ))
1368 WCHAR value[MAX_PATH], data[1024];
1369 DWORD type, val_len, data_len;
1370 WCHAR *entry, *next;
1372 val_len = ARRAY_SIZE(value);
1373 data_len = sizeof(data);
1374 i = 0;
1375 while (!RegEnumValueW( hkey, i++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len))
1377 /* Don't store fonts that are only substitutes for other fonts */
1378 if (!get_gdi_font_subst( value, -1, NULL ))
1380 font_link = add_gdi_font_link( value );
1381 for (entry = data; (char *)entry < (char *)data + data_len && *entry; entry = next)
1383 const WCHAR *family_name = NULL;
1384 WCHAR *p;
1386 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1388 next = entry + lstrlenW(entry) + 1;
1389 if ((p = wcschr( entry, ',' )))
1391 *p++ = 0;
1392 while (iswspace(*p)) p++;
1393 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
1395 if ((face = find_face_from_filename( entry, family_name )))
1397 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1398 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
1400 else TRACE( "Unable to find file %s family %s\n",
1401 debugstr_w(entry), debugstr_w(family_name) );
1404 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1406 val_len = ARRAY_SIZE(value);
1407 data_len = sizeof(data);
1409 RegCloseKey( hkey );
1412 if ((shelldlg_name = get_gdi_font_subst( L"MS Shell Dlg", -1, NULL )))
1414 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
1416 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
1418 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
1419 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
1421 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
1422 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
1423 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
1424 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
1428 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1430 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1431 that Tahoma has */
1433 system_font_link = add_gdi_font_link( L"System" );
1434 if ((face = find_face_from_filename( L"tahoma.ttf", L"Tahoma" )))
1436 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
1437 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
1439 if ((font_link = find_gdi_font_link( L"Tahoma" )))
1441 struct gdi_font_link_entry *entry;
1442 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
1443 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
1447 /* font matching */
1449 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
1451 struct gdi_font_link *font_link;
1453 if (!face->scalable && !can_use_bitmap) return FALSE;
1454 if (!fs.fsCsb[0]) return TRUE;
1455 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
1456 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
1457 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
1458 return FALSE;
1461 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
1462 const LOGFONTW *lf, FONTSIGNATURE fs,
1463 BOOL can_use_bitmap )
1465 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
1466 unsigned int best_score = 4;
1467 int best_diff = 0;
1468 int it = !!lf->lfItalic;
1469 int bd = lf->lfWeight > 550;
1470 int height = lf->lfHeight;
1472 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1474 int italic = !!(face->ntmFlags & NTM_ITALIC);
1475 int bold = !!(face->ntmFlags & NTM_BOLD);
1476 int score = (italic ^ it) + (bold ^ bd);
1478 if (!can_select_face( face, fs, can_use_bitmap )) continue;
1479 if (score > best_score) continue;
1480 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
1481 best_score = score;
1482 best = face;
1483 if (best->scalable && best_score == 0) break;
1484 if (!best->scalable)
1486 int diff;
1487 if (height > 0)
1488 diff = height - (signed int)best->size.height;
1489 else
1490 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
1491 if (!best_bitmap ||
1492 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
1493 (best_diff < 0 && diff > best_diff))
1495 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
1496 best_diff = diff;
1497 best_bitmap = best;
1498 if (best_score == 0 && best_diff == 0) break;
1502 if (!best) return NULL;
1503 return best->scalable ? best : best_bitmap;
1506 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
1507 const LOGFONTW *lf, FONTSIGNATURE fs,
1508 BOOL can_use_bitmap )
1510 struct gdi_font_family *family;
1511 struct gdi_font_face *face;
1513 family = find_family_from_any_name( name );
1514 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1515 if (subst)
1517 family = find_family_from_any_name( subst );
1518 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1521 /* search by full face name */
1522 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1523 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1524 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
1525 can_select_face( face, fs, can_use_bitmap ))
1526 return face;
1528 if ((family = find_family_from_font_links( name, subst, fs )))
1530 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1532 return NULL;
1535 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
1536 BOOL can_use_bitmap, BOOL want_vertical )
1538 struct gdi_font_family *family;
1539 struct gdi_font_face *face;
1540 WCHAR name[LF_FACESIZE + 1];
1541 int i = 0;
1543 /* first try the family fallbacks */
1544 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
1546 if (want_vertical)
1548 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
1549 name[0] = '@';
1552 if (!(family = find_family_from_any_name(name))) continue;
1553 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1555 /* otherwise try only scalable */
1556 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1558 if ((family->family_name[0] == '@') == !want_vertical) continue;
1559 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1561 if (!can_use_bitmap) return NULL;
1562 /* then also bitmap fonts */
1563 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1565 if ((family->family_name[0] == '@') == !want_vertical) continue;
1566 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1568 return NULL;
1571 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
1572 const WCHAR **orig_name )
1574 BOOL want_vertical = (lf->lfFaceName[0] == '@');
1575 struct gdi_font_face *face;
1577 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
1579 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
1580 csi->fs.fsCsb[0] = 0;
1583 if (lf->lfFaceName[0])
1585 int subst_charset;
1586 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
1588 if (subst)
1590 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
1591 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
1592 if (subst_charset != -1)
1593 TranslateCharsetInfo( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
1594 *orig_name = lf->lfFaceName;
1597 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap )))
1598 return face;
1600 *orig_name = NULL; /* substitution is no longer relevant */
1602 /* If requested charset was DEFAULT_CHARSET then try using charset
1603 corresponding to the current ansi codepage */
1604 if (!csi->fs.fsCsb[0])
1606 INT acp = GetACP();
1607 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)acp, csi, TCI_SRCCODEPAGE ))
1609 FIXME( "TCI failed on codepage %d\n", acp );
1610 csi->fs.fsCsb[0] = 0;
1614 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1615 if (csi->fs.fsCsb[0])
1617 csi->fs.fsCsb[0] = 0;
1618 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1620 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
1621 return NULL;
1624 /* realized font objects */
1626 #define FIRST_FONT_HANDLE 1
1627 #define MAX_FONT_HANDLES 256
1629 struct font_handle_entry
1631 struct gdi_font *font;
1632 WORD generation; /* generation count for reusing handle values */
1635 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
1636 static struct font_handle_entry *next_free;
1637 static struct font_handle_entry *next_unused = font_handles;
1639 static struct font_handle_entry *handle_entry( DWORD handle )
1641 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
1643 if (idx < MAX_FONT_HANDLES)
1645 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
1646 return &font_handles[idx];
1648 if (handle) WARN( "invalid handle 0x%08x\n", handle );
1649 return NULL;
1652 static struct gdi_font *get_font_from_handle( DWORD handle )
1654 struct font_handle_entry *entry = handle_entry( handle );
1656 if (entry) return entry->font;
1657 SetLastError( ERROR_INVALID_PARAMETER );
1658 return NULL;
1661 static DWORD alloc_font_handle( struct gdi_font *font )
1663 struct font_handle_entry *entry;
1665 entry = next_free;
1666 if (entry)
1667 next_free = (struct font_handle_entry *)entry->font;
1668 else if (next_unused < font_handles + MAX_FONT_HANDLES)
1669 entry = next_unused++;
1670 else
1672 ERR( "out of realized font handles\n" );
1673 return 0;
1675 entry->font = font;
1676 if (++entry->generation == 0xffff) entry->generation = 1;
1677 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
1680 static void free_font_handle( DWORD handle )
1682 struct font_handle_entry *entry;
1684 if ((entry = handle_entry( handle )))
1686 entry->font = (struct gdi_font *)next_free;
1687 next_free = entry;
1691 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
1693 UINT len = file ? lstrlenW(file) : 0;
1694 struct gdi_font *font = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1695 offsetof( struct gdi_font, file[len + 1] ));
1697 font->refcount = 1;
1698 font->matrix.eM11 = font->matrix.eM22 = 1.0;
1699 font->scale_y = 1;
1700 font->kern_count = -1;
1701 list_init( &font->child_fonts );
1703 if (file)
1705 WIN32_FILE_ATTRIBUTE_DATA info;
1706 if (GetFileAttributesExW( file, GetFileExInfoStandard, &info ))
1708 font->writetime = info.ftLastWriteTime;
1709 font->data_size = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
1710 memcpy( font->file, file, len * sizeof(WCHAR) );
1713 else
1715 font->data_ptr = data_ptr;
1716 font->data_size = data_size;
1719 font->handle = alloc_font_handle( font );
1720 return font;
1723 static void free_gdi_font( struct gdi_font *font )
1725 DWORD i;
1726 struct gdi_font *child, *child_next;
1728 if (font->private) font_funcs->destroy_font( font );
1729 free_font_handle( font->handle );
1730 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
1732 list_remove( &child->entry );
1733 free_gdi_font( child );
1735 for (i = 0; i < font->gm_size; i++) HeapFree( GetProcessHeap(), 0, font->gm[i] );
1736 HeapFree( GetProcessHeap(), 0, font->otm.otmpFamilyName );
1737 HeapFree( GetProcessHeap(), 0, font->otm.otmpStyleName );
1738 HeapFree( GetProcessHeap(), 0, font->otm.otmpFaceName );
1739 HeapFree( GetProcessHeap(), 0, font->otm.otmpFullName );
1740 HeapFree( GetProcessHeap(), 0, font->gm );
1741 HeapFree( GetProcessHeap(), 0, font->kern_pairs );
1742 HeapFree( GetProcessHeap(), 0, font->gsub_table );
1743 HeapFree( GetProcessHeap(), 0, font );
1746 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
1748 return (WCHAR *)font->otm.otmpFamilyName;
1751 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
1752 const LOGFONTW *lf )
1754 struct gdi_font *font;
1756 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
1757 font->fs = face->fs;
1758 font->lf = *lf;
1759 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
1760 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
1761 font->scalable = face->scalable;
1762 font->face_index = face->face_index;
1763 font->ntmFlags = face->ntmFlags;
1764 font->aa_flags = HIWORD( face->flags );
1765 if (!family_name) family_name = face->family->family_name;
1766 font->otm.otmpFamilyName = (char *)strdupW( family_name );
1767 font->otm.otmpStyleName = (char *)strdupW( face->style_name );
1768 font->otm.otmpFaceName = (char *)strdupW( face->full_name );
1769 return font;
1772 struct glyph_metrics
1774 GLYPHMETRICS gm;
1775 ABC abc; /* metrics of the unrotated char */
1776 BOOL init;
1779 #define GM_BLOCK_SIZE 128
1781 /* TODO: GGO format support */
1782 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
1784 UINT block = index / GM_BLOCK_SIZE;
1785 UINT entry = index % GM_BLOCK_SIZE;
1787 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
1789 *gm = font->gm[block][entry].gm;
1790 *abc = font->gm[block][entry].abc;
1792 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
1793 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
1794 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
1795 return TRUE;
1798 return FALSE;
1801 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
1802 const GLYPHMETRICS *gm, const ABC *abc )
1804 UINT block = index / GM_BLOCK_SIZE;
1805 UINT entry = index % GM_BLOCK_SIZE;
1807 if (block >= font->gm_size)
1809 struct glyph_metrics **ptr;
1811 if (font->gm)
1812 ptr = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm, (block + 1) * sizeof(*ptr) );
1813 else
1814 ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, (block + 1) * sizeof(*ptr) );
1815 if (!ptr) return;
1816 font->gm_size = block + 1;
1817 font->gm = ptr;
1819 if (!font->gm[block])
1821 font->gm[block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**font->gm) * GM_BLOCK_SIZE );
1822 if (!font->gm[block]) return;
1824 font->gm[block][entry].gm = *gm;
1825 font->gm[block][entry].abc = *abc;
1826 font->gm[block][entry].init = TRUE;
1830 /* GSUB table support */
1832 typedef struct
1834 DWORD version;
1835 WORD ScriptList;
1836 WORD FeatureList;
1837 WORD LookupList;
1838 } GSUB_Header;
1840 typedef struct
1842 CHAR ScriptTag[4];
1843 WORD Script;
1844 } GSUB_ScriptRecord;
1846 typedef struct
1848 WORD ScriptCount;
1849 GSUB_ScriptRecord ScriptRecord[1];
1850 } GSUB_ScriptList;
1852 typedef struct
1854 CHAR LangSysTag[4];
1855 WORD LangSys;
1856 } GSUB_LangSysRecord;
1858 typedef struct
1860 WORD DefaultLangSys;
1861 WORD LangSysCount;
1862 GSUB_LangSysRecord LangSysRecord[1];
1863 } GSUB_Script;
1865 typedef struct
1867 WORD LookupOrder; /* Reserved */
1868 WORD ReqFeatureIndex;
1869 WORD FeatureCount;
1870 WORD FeatureIndex[1];
1871 } GSUB_LangSys;
1873 typedef struct
1875 CHAR FeatureTag[4];
1876 WORD Feature;
1877 } GSUB_FeatureRecord;
1879 typedef struct
1881 WORD FeatureCount;
1882 GSUB_FeatureRecord FeatureRecord[1];
1883 } GSUB_FeatureList;
1885 typedef struct
1887 WORD FeatureParams; /* Reserved */
1888 WORD LookupCount;
1889 WORD LookupListIndex[1];
1890 } GSUB_Feature;
1892 typedef struct
1894 WORD LookupCount;
1895 WORD Lookup[1];
1896 } GSUB_LookupList;
1898 typedef struct
1900 WORD LookupType;
1901 WORD LookupFlag;
1902 WORD SubTableCount;
1903 WORD SubTable[1];
1904 } GSUB_LookupTable;
1906 typedef struct
1908 WORD CoverageFormat;
1909 WORD GlyphCount;
1910 WORD GlyphArray[1];
1911 } GSUB_CoverageFormat1;
1913 typedef struct
1915 WORD Start;
1916 WORD End;
1917 WORD StartCoverageIndex;
1918 } GSUB_RangeRecord;
1920 typedef struct
1922 WORD CoverageFormat;
1923 WORD RangeCount;
1924 GSUB_RangeRecord RangeRecord[1];
1925 } GSUB_CoverageFormat2;
1927 typedef struct
1929 WORD SubstFormat; /* = 1 */
1930 WORD Coverage;
1931 WORD DeltaGlyphID;
1932 } GSUB_SingleSubstFormat1;
1934 typedef struct
1936 WORD SubstFormat; /* = 2 */
1937 WORD Coverage;
1938 WORD GlyphCount;
1939 WORD Substitute[1];
1940 } GSUB_SingleSubstFormat2;
1942 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
1944 GSUB_ScriptList *script;
1945 GSUB_Script *deflt = NULL;
1946 int i;
1948 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
1949 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
1950 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
1952 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
1953 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
1954 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
1955 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
1957 return deflt;
1960 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
1962 int i, offset;
1963 GSUB_LangSys *lang;
1965 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
1967 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
1969 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
1970 lang = (GSUB_LangSys *)((BYTE *)script + offset);
1971 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
1973 offset = GET_BE_WORD(script->DefaultLangSys);
1974 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
1975 return NULL;
1978 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
1980 int i;
1981 const GSUB_FeatureList *feature;
1983 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
1984 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
1985 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
1987 int index = GET_BE_WORD(lang->FeatureIndex[i]);
1988 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
1989 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
1991 return NULL;
1994 static const char *get_opentype_script( const struct gdi_font *font )
1997 * I am not sure if this is the correct way to generate our script tag
1999 switch (font->charset)
2001 case ANSI_CHARSET: return "latn";
2002 case BALTIC_CHARSET: return "latn"; /* ?? */
2003 case CHINESEBIG5_CHARSET: return "hani";
2004 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
2005 case GB2312_CHARSET: return "hani";
2006 case GREEK_CHARSET: return "grek";
2007 case HANGUL_CHARSET: return "hang";
2008 case RUSSIAN_CHARSET: return "cyrl";
2009 case SHIFTJIS_CHARSET: return "kana";
2010 case TURKISH_CHARSET: return "latn"; /* ?? */
2011 case VIETNAMESE_CHARSET: return "latn";
2012 case JOHAB_CHARSET: return "latn"; /* ?? */
2013 case ARABIC_CHARSET: return "arab";
2014 case HEBREW_CHARSET: return "hebr";
2015 case THAI_CHARSET: return "thai";
2016 default: return "latn";
2020 static void *get_GSUB_vert_feature( struct gdi_font *font )
2022 GSUB_Header *header;
2023 GSUB_Script *script;
2024 GSUB_LangSys *language;
2025 GSUB_Feature *feature;
2026 DWORD length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2028 if (length == GDI_ERROR) return NULL;
2030 header = HeapAlloc( GetProcessHeap(), 0, length );
2031 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2032 TRACE( "Loaded GSUB table of %i bytes\n", length );
2034 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2036 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2038 feature = GSUB_get_feature( header, language, "vrt2" );
2039 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2040 if (feature)
2042 font->gsub_table = header;
2043 return feature;
2045 TRACE("vrt2/vert feature not found\n");
2047 else TRACE("Language not found\n");
2049 else TRACE("Script not found\n");
2051 HeapFree( GetProcessHeap(), 0, header );
2052 return NULL;
2055 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2057 GSUB_CoverageFormat1 *cf1 = table;
2059 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2061 int i, count = GET_BE_WORD(cf1->GlyphCount);
2063 TRACE("Coverage Format 1, %i glyphs\n",count);
2064 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2065 return -1;
2067 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2069 int i, count;
2070 GSUB_CoverageFormat2 *cf2 = table;
2072 count = GET_BE_WORD(cf2->RangeCount);
2073 TRACE("Coverage Format 2, %i ranges\n",count);
2074 for (i = 0; i < count; i++)
2076 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2077 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2078 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2080 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2081 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2084 return -1;
2086 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2088 return -1;
2091 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2093 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2094 int i, j, offset;
2096 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2097 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2099 GSUB_LookupTable *look;
2100 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2101 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2102 TRACE("type %i, flag %x, subtables %i\n",
2103 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2104 if (GET_BE_WORD(look->LookupType) == 1)
2106 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2108 GSUB_SingleSubstFormat1 *ssf1;
2109 offset = GET_BE_WORD(look->SubTable[j]);
2110 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2111 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2113 int offset = GET_BE_WORD(ssf1->Coverage);
2114 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2115 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2117 TRACE(" Glyph 0x%x ->",glyph);
2118 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2119 TRACE(" 0x%x\n",glyph);
2122 else
2124 GSUB_SingleSubstFormat2 *ssf2;
2125 int index, offset;
2127 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2128 offset = GET_BE_WORD(ssf1->Coverage);
2129 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2130 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2131 TRACE(" Coverage index %i\n",index);
2132 if (index != -1)
2134 TRACE(" Glyph is 0x%x ->",glyph);
2135 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2136 TRACE("0x%x\n",glyph);
2141 else FIXME("We only handle SubType 1\n");
2143 return glyph;
2146 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2148 if (!glyph) return glyph;
2149 if (!font->gsub_table) return glyph;
2150 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2153 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2155 FONTSIGNATURE fs = {{0}};
2156 struct gdi_font *child;
2157 struct gdi_font_face *face;
2159 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE ))) return;
2161 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2162 child->matrix = font->matrix;
2163 child->can_use_bitmap = font->can_use_bitmap;
2164 child->scale_y = font->scale_y;
2165 child->aveWidth = font->aveWidth;
2166 child->charset = font->charset;
2167 child->codepage = font->codepage;
2168 child->base_font = font;
2169 list_add_tail( &font->child_fonts, &child->entry );
2170 TRACE( "created child font %p for base %p\n", child, font );
2173 static void create_child_font_list( struct gdi_font *font )
2175 struct gdi_font_link *font_link;
2176 struct gdi_font_link_entry *entry;
2177 const WCHAR* font_name;
2179 if (!(font_name = get_gdi_font_subst( get_gdi_font_name(font), -1, NULL )))
2180 font_name = get_gdi_font_name( font );
2182 if ((font_link = find_gdi_font_link( font_name )))
2184 TRACE("found entry in system list\n");
2185 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2186 add_child_font( font, entry->family_name );
2189 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2190 * Sans Serif. This is how asian windows get default fallbacks for fonts
2192 if (is_dbcs_ansi_cp(GetACP()) && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2193 facename_compare( font_name, L"Microsoft Sans Serif", -1 ) != 0)
2195 if ((font_link = find_gdi_font_link( L"Microsoft Sans Serif" )))
2197 TRACE("found entry in default fallback list\n");
2198 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2199 add_child_font( font, entry->family_name );
2204 /* font cache */
2206 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2207 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2208 static unsigned int unused_font_count;
2209 #define UNUSED_CACHE_SIZE 10
2211 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2212 const FMAT2 *matrix, BOOL can_use_bitmap )
2214 if (font->hash != hash) return TRUE;
2215 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2216 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2217 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2218 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2221 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2223 DWORD hash = 0, *ptr, two_chars;
2224 WORD *pwc;
2225 unsigned int i;
2227 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2228 hash ^= *ptr;
2229 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2230 hash ^= *ptr;
2231 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2233 two_chars = *ptr;
2234 pwc = (WCHAR *)&two_chars;
2235 if(!*pwc) break;
2236 *pwc = towupper(*pwc);
2237 pwc++;
2238 *pwc = towupper(*pwc);
2239 hash ^= two_chars;
2240 if(!*pwc) break;
2242 hash ^= !can_use_bitmap;
2243 return hash;
2246 static void cache_gdi_font( struct gdi_font *font )
2248 static DWORD cache_num = 1;
2250 font->cache_num = cache_num++;
2251 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2252 list_add_head( &gdi_font_list, &font->entry );
2253 TRACE( "font %p\n", font );
2256 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2258 struct gdi_font *font;
2259 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2261 /* try the in-use list */
2262 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2264 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2265 list_remove( &font->entry );
2266 list_add_head( &gdi_font_list, &font->entry );
2267 if (!font->refcount++)
2269 list_remove( &font->unused_entry );
2270 unused_font_count--;
2272 return font;
2274 return NULL;
2277 static void release_gdi_font( struct gdi_font *font )
2279 if (!font) return;
2280 if (--font->refcount) return;
2282 TRACE( "font %p\n", font );
2284 /* add it to the unused list */
2285 EnterCriticalSection( &font_cs );
2286 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2287 if (unused_font_count > UNUSED_CACHE_SIZE)
2289 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2290 TRACE( "freeing %p\n", font );
2291 list_remove( &font->entry );
2292 list_remove( &font->unused_entry );
2293 free_gdi_font( font );
2295 else unused_font_count++;
2296 LeaveCriticalSection( &font_cs );
2299 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2301 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2303 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2304 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2305 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
2306 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2309 static void set_value_key(HKEY hkey, const char *name, const char *value)
2311 if (value)
2312 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2313 else if (name)
2314 RegDeleteValueA(hkey, name);
2317 static void update_font_association_info(UINT current_ansi_codepage)
2319 if (is_dbcs_ansi_cp(current_ansi_codepage))
2321 HKEY hkey;
2322 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\FontAssoc", &hkey) == ERROR_SUCCESS)
2324 HKEY hsubkey;
2325 if (RegCreateKeyW(hkey, L"Associated Charset", &hsubkey) == ERROR_SUCCESS)
2327 switch (current_ansi_codepage)
2329 case 932:
2330 set_value_key(hsubkey, "ANSI(00)", "NO");
2331 set_value_key(hsubkey, "OEM(FF)", "NO");
2332 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2333 break;
2334 case 936:
2335 case 949:
2336 case 950:
2337 set_value_key(hsubkey, "ANSI(00)", "YES");
2338 set_value_key(hsubkey, "OEM(FF)", "YES");
2339 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2340 break;
2342 RegCloseKey(hsubkey);
2345 /* TODO: Associated DefaultFonts */
2347 RegCloseKey(hkey);
2350 else
2351 RegDeleteTreeW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\FontAssoc");
2354 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
2356 if (value)
2357 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
2358 else if (name)
2359 RegDeleteValueW(hkey, name);
2362 static void update_font_system_link_info(UINT current_ansi_codepage)
2364 static const WCHAR system_link_simplified_chinese[] =
2365 L"SIMSUN.TTC,SimSun\0"
2366 L"MINGLIU.TTC,PMingLiu\0"
2367 L"MSGOTHIC.TTC,MS UI Gothic\0"
2368 L"BATANG.TTC,Batang\0";
2369 static const WCHAR system_link_traditional_chinese[] =
2370 L"MINGLIU.TTC,PMingLiu\0"
2371 L"SIMSUN.TTC,SimSun\0"
2372 L"MSGOTHIC.TTC,MS UI Gothic\0"
2373 L"BATANG.TTC,Batang\0";
2374 static const WCHAR system_link_japanese[] =
2375 L"MSGOTHIC.TTC,MS UI Gothic\0"
2376 L"MINGLIU.TTC,PMingLiU\0"
2377 L"SIMSUN.TTC,SimSun\0"
2378 L"GULIM.TTC,Gulim\0";
2379 static const WCHAR system_link_korean[] =
2380 L"GULIM.TTC,Gulim\0"
2381 L"MSGOTHIC.TTC,MS UI Gothic\0"
2382 L"MINGLIU.TTC,PMingLiU\0"
2383 L"SIMSUN.TTC,SimSun\0";
2384 static const WCHAR system_link_non_cjk[] =
2385 L"MSGOTHIC.TTC,MS UI Gothic\0"
2386 L"MINGLIU.TTC,PMingLiU\0"
2387 L"SIMSUN.TTC,SimSun\0"
2388 L"GULIM.TTC,Gulim\0";
2389 HKEY hkey;
2391 if (!RegCreateKeyW(HKEY_LOCAL_MACHINE,
2392 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey))
2394 const WCHAR *link;
2395 DWORD len;
2397 switch (current_ansi_codepage)
2399 case 932:
2400 link = system_link_japanese;
2401 len = sizeof(system_link_japanese);
2402 break;
2403 case 936:
2404 link = system_link_simplified_chinese;
2405 len = sizeof(system_link_simplified_chinese);
2406 break;
2407 case 949:
2408 link = system_link_korean;
2409 len = sizeof(system_link_korean);
2410 break;
2411 case 950:
2412 link = system_link_traditional_chinese;
2413 len = sizeof(system_link_traditional_chinese);
2414 break;
2415 default:
2416 link = system_link_non_cjk;
2417 len = sizeof(system_link_non_cjk);
2419 set_multi_value_key(hkey, L"Lucida Sans Unicode", link, len);
2420 set_multi_value_key(hkey, L"Microsoft Sans Serif", link, len);
2421 set_multi_value_key(hkey, L"Tahoma", link, len);
2422 RegCloseKey(hkey);
2426 static void update_codepage(void)
2428 char buf[40], cpbuf[40];
2429 HKEY hkey;
2430 DWORD len, type, size;
2431 UINT i, ansi_cp, oem_cp;
2432 DWORD screen_dpi, font_dpi = 0;
2433 BOOL done = FALSE;
2435 screen_dpi = get_dpi();
2436 if (!screen_dpi) screen_dpi = 96;
2438 size = sizeof(DWORD);
2439 if (RegQueryValueExW(wine_fonts_key, L"LogPixels", NULL, &type, (BYTE *)&font_dpi, &size) ||
2440 type != REG_DWORD || size != sizeof(DWORD))
2441 font_dpi = 0;
2443 ansi_cp = GetACP();
2444 oem_cp = GetOEMCP();
2445 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2447 buf[0] = 0;
2448 len = sizeof(buf);
2449 if (!RegQueryValueExA(wine_fonts_key, "Codepages", 0, &type, (BYTE *)buf, &len) && type == REG_SZ)
2451 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) return; /* already set correctly */
2452 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2453 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
2455 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2456 ansi_cp, oem_cp, screen_dpi);
2458 RegSetValueExA(wine_fonts_key, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2459 RegSetValueExW(wine_fonts_key, L"LogPixels", 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
2461 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
2463 if (nls_update_font_list[i].ansi_cp == ansi_cp && nls_update_font_list[i].oem_cp == oem_cp)
2465 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &hkey ))
2467 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem,
2468 strlen(nls_update_font_list[i].oem)+1);
2469 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed,
2470 strlen(nls_update_font_list[i].fixed)+1);
2471 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system,
2472 strlen(nls_update_font_list[i].system)+1);
2473 RegCloseKey(hkey);
2475 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE,
2476 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey ))
2478 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2479 RegCloseKey(hkey);
2481 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE,
2482 L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey ))
2484 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2485 RegCloseKey(hkey);
2487 /* Only update these if the Codepage changed. */
2488 if (strcmp( buf, cpbuf ) && !RegCreateKeyW( HKEY_LOCAL_MACHINE,
2489 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2491 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2492 strlen(nls_update_font_list[i].shelldlg)+1);
2493 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2494 strlen(nls_update_font_list[i].tmsrmn)+1);
2496 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2497 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2498 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2499 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2500 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2501 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2502 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2503 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2505 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2506 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2507 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2509 RegCloseKey(hkey);
2511 done = TRUE;
2513 else
2515 /* Delete the FontSubstitutes from other locales */
2516 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2518 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2519 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2520 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2521 RegCloseKey(hkey);
2525 if (!done)
2526 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2528 /* update locale dependent font association info and font system link info in registry.
2529 update only when codepages changed, not logpixels. */
2530 if (strcmp(buf, cpbuf) != 0)
2532 update_font_association_info(ansi_cp);
2533 update_font_system_link_info(ansi_cp);
2538 /*************************************************************
2539 * font_CreateDC
2541 static BOOL CDECL font_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
2542 LPCWSTR output, const DEVMODEW *devmode )
2544 struct font_physdev *physdev;
2546 if (!font_funcs) return TRUE;
2547 if (!(physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) ))) return FALSE;
2548 push_dc_driver( dev, &physdev->dev, &font_driver );
2549 return TRUE;
2553 /*************************************************************
2554 * font_DeleteDC
2556 static BOOL CDECL font_DeleteDC( PHYSDEV dev )
2558 struct font_physdev *physdev = get_font_dev( dev );
2560 release_gdi_font( physdev->font );
2561 HeapFree( GetProcessHeap(), 0, physdev );
2562 return TRUE;
2566 struct gdi_font_enum_data
2568 ENUMLOGFONTEXW elf;
2569 NEWTEXTMETRICEXW ntm;
2572 struct enum_charset
2574 DWORD mask;
2575 DWORD charset;
2576 DWORD script;
2579 static int load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
2581 HRSRC rsrc;
2582 HGLOBAL hMem;
2583 WCHAR *p;
2584 int i;
2586 id += IDS_FIRST_SCRIPT;
2587 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
2588 if (!rsrc) return 0;
2589 hMem = LoadResource( gdi32_module, rsrc );
2590 if (!hMem) return 0;
2592 p = LockResource( hMem );
2593 id &= 0x000f;
2594 while (id--) p += *p + 1;
2596 i = min(LF_FACESIZE - 1, *p);
2597 memcpy(buffer, p + 1, i * sizeof(WCHAR));
2598 buffer[i] = 0;
2599 return i;
2602 static BOOL is_complex_script_ansi_cp( UINT ansi_cp )
2604 return (ansi_cp == 874 /* Thai */
2605 || ansi_cp == 1255 /* Hebrew */
2606 || ansi_cp == 1256 /* Arabic */
2610 /***************************************************
2611 * create_enum_charset_list
2613 * This function creates charset enumeration list because in DEFAULT_CHARSET
2614 * case, the ANSI codepage's charset takes precedence over other charsets.
2615 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2616 * This function works as a filter other than DEFAULT_CHARSET case.
2618 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
2620 struct enum_charset *start = list;
2621 CHARSETINFO csi;
2622 int i;
2624 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && csi.fs.fsCsb[0] != 0)
2626 list->mask = csi.fs.fsCsb[0];
2627 list->charset = csi.ciCharset;
2628 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2629 list++;
2631 else /* charset is DEFAULT_CHARSET or invalid. */
2633 int acp = GetACP();
2634 DWORD mask = 0;
2636 /* Set the current codepage's charset as the first element. */
2637 if (!is_complex_script_ansi_cp(acp) &&
2638 TranslateCharsetInfo( (DWORD *)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE ) &&
2639 csi.fs.fsCsb[0] != 0)
2641 list->mask = csi.fs.fsCsb[0];
2642 list->charset = csi.ciCharset;
2643 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2644 mask |= csi.fs.fsCsb[0];
2645 list++;
2648 /* Fill out left elements. */
2649 for (i = 0; i < 32; i++)
2651 FONTSIGNATURE fs;
2652 fs.fsCsb[0] = 1u << i;
2653 fs.fsCsb[1] = 0;
2654 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
2655 if (!TranslateCharsetInfo( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
2656 continue; /* skip, this is an invalid fsCsb bit. */
2657 list->mask = fs.fsCsb[0];
2658 list->charset = csi.ciCharset;
2659 list->script = i;
2660 mask |= fs.fsCsb[0];
2661 list++;
2663 /* add catch all mask for remaining bits */
2664 if (~mask)
2666 list->mask = ~mask;
2667 list->charset = DEFAULT_CHARSET;
2668 list->script = IDS_OTHER - IDS_FIRST_SCRIPT;
2669 list++;
2672 return list - start;
2675 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
2677 UINT ret = 0;
2679 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
2680 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
2681 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
2682 return ret;
2685 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
2687 struct gdi_font *font;
2688 LOGFONTW lf = { .lfHeight = -4096 /* preferable EM Square size */ };
2690 if (!face->scalable) lf.lfHeight = 0;
2692 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2694 if (!font_funcs->load_font( font ))
2696 free_gdi_font( font );
2697 return FALSE;
2700 if (font->scalable && -lf.lfHeight % font->otm.otmEMSquare != 0)
2702 /* reload with the original EM Square size */
2703 lf.lfHeight = -font->otm.otmEMSquare;
2704 free_gdi_font( font );
2706 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2707 if (!font_funcs->load_font( font ))
2709 free_gdi_font( font );
2710 return FALSE;
2714 if (font_funcs->set_outline_text_metrics( font ))
2716 static const DWORD ntm_ppem = 32;
2717 UINT cell_height;
2719 #define TM font->otm.otmTextMetrics
2720 #define SCALE_NTM(value) (MulDiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
2721 cell_height = TM.tmHeight / ( -lf.lfHeight / font->otm.otmEMSquare );
2722 ntm->ntmTm.tmHeight = MulDiv( ntm_ppem, cell_height, font->otm.otmEMSquare );
2723 ntm->ntmTm.tmAscent = SCALE_NTM( TM.tmAscent );
2724 ntm->ntmTm.tmDescent = ntm->ntmTm.tmHeight - ntm->ntmTm.tmAscent;
2725 ntm->ntmTm.tmInternalLeading = SCALE_NTM( TM.tmInternalLeading );
2726 ntm->ntmTm.tmExternalLeading = SCALE_NTM( TM.tmExternalLeading );
2727 ntm->ntmTm.tmAveCharWidth = SCALE_NTM( TM.tmAveCharWidth );
2728 ntm->ntmTm.tmMaxCharWidth = SCALE_NTM( TM.tmMaxCharWidth );
2730 memcpy((char *)&ntm->ntmTm + offsetof( TEXTMETRICW, tmWeight ),
2731 (const char *)&TM + offsetof( TEXTMETRICW, tmWeight ),
2732 sizeof(TEXTMETRICW) - offsetof( TEXTMETRICW, tmWeight ));
2733 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
2734 ntm->ntmTm.ntmCellHeight = cell_height;
2735 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
2736 #undef SCALE_NTM
2737 #undef TM
2739 else if (font_funcs->set_bitmap_text_metrics( font ))
2741 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
2742 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
2743 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
2744 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
2746 ntm->ntmTm.ntmFlags = font->ntmFlags;
2747 ntm->ntmFontSig = font->fs;
2749 elf->elfLogFont.lfEscapement = 0;
2750 elf->elfLogFont.lfOrientation = 0;
2751 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
2752 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
2753 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
2754 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
2755 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
2756 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
2757 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
2758 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2759 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2760 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
2761 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
2762 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
2763 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
2764 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
2766 free_gdi_font( font );
2767 return TRUE;
2770 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
2772 struct gdi_font_face *face;
2774 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
2775 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2776 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
2777 return FALSE;
2780 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
2782 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
2783 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
2786 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
2787 struct enum_charset *list, DWORD count, FONTENUMPROCW proc, LPARAM lparam,
2788 const WCHAR *subst )
2790 ENUMLOGFONTEXW elf;
2791 NEWTEXTMETRICEXW ntm;
2792 DWORD type, i;
2794 if (!face->cached_enum_data)
2796 struct gdi_font_enum_data *data;
2798 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )) ||
2799 !get_face_enum_data( face, &data->elf, &data->ntm ))
2801 HeapFree( GetProcessHeap(), 0, data );
2802 return TRUE;
2804 face->cached_enum_data = data;
2807 elf = face->cached_enum_data->elf;
2808 ntm = face->cached_enum_data->ntm;
2809 type = get_font_type( &ntm );
2811 /* font replacement */
2812 if (family != face->family)
2814 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
2815 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
2817 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
2819 for (i = 0; i < count; i++)
2821 if (face->fs.fsCsb[0] == 0) /* OEM */
2823 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2824 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
2825 i = count; /* break out of loop after enumeration */
2827 else
2829 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
2830 /* use the DEFAULT_CHARSET case only if no other charset is present */
2831 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
2832 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
2833 load_script_name( list[i].script, elf.elfScript );
2834 if (!elf.elfScript[0]) FIXME("Unknown elfscript for id %u\n", list[i].script);
2836 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2837 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2838 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
2839 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, ntm.ntmTm.ntmFlags );
2840 /* release section before callback (FIXME) */
2841 LeaveCriticalSection( &font_cs );
2842 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
2843 EnterCriticalSection( &font_cs );
2845 return TRUE;
2848 /*************************************************************
2849 * font_EnumFonts
2851 static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
2853 struct gdi_font_family *family;
2854 struct gdi_font_face *face;
2855 struct enum_charset enum_charsets[32];
2856 DWORD count, charset;
2858 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
2860 count = create_enum_charset_list( charset, enum_charsets );
2862 EnterCriticalSection( &font_cs );
2864 if (lf && lf->lfFaceName[0])
2866 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
2867 const WCHAR *orig_name = NULL;
2869 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
2870 if (face_name)
2872 orig_name = lf->lfFaceName;
2873 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
2875 else face_name = lf->lfFaceName;
2877 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2879 if (!family_matches(family, face_name)) continue;
2880 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2882 if (!face_matches( family->family_name, face, face_name )) continue;
2883 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
2884 return FALSE;
2888 else
2890 TRACE( "charset %d\n", charset );
2891 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2893 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
2894 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
2895 return FALSE;
2898 LeaveCriticalSection( &font_cs );
2899 return TRUE;
2903 static BOOL check_unicode_tategaki( WCHAR ch )
2905 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
2906 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
2908 /* We only reach this code if typographical substitution did not occur */
2909 /* Type: U or Type: Tu */
2910 return (orientation == 1 || orientation == 3);
2913 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2915 UINT index;
2917 if (glyph < 0x100) glyph += 0xf000;
2918 /* there are a number of old pre-Unicode "broken" TTFs, which
2919 do have symbols at U+00XX instead of U+f0XX */
2920 index = glyph;
2921 font_funcs->get_glyph_index( font, &index, FALSE );
2922 if (!index)
2924 index = glyph - 0xf000;
2925 font_funcs->get_glyph_index( font, &index, FALSE );
2927 return index;
2930 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
2932 WCHAR wc = glyph;
2933 char ch;
2934 BOOL used;
2936 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
2938 if (font->codepage == CP_SYMBOL)
2940 glyph = get_glyph_index_symbol( font, wc );
2941 if (!glyph)
2943 if (WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, &wc, 1, &ch, 1, NULL, NULL ))
2944 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2947 else if (WideCharToMultiByte( font->codepage, WC_NO_BEST_FIT_CHARS, &wc, 1, &ch, 1, NULL, &used ) && !used)
2949 glyph = (unsigned char)ch;
2950 font_funcs->get_glyph_index( font, &glyph, FALSE );
2952 else return 0;
2954 return glyph;
2957 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
2959 struct gdi_font *child;
2960 UINT res;
2962 if ((res = get_glyph_index( *font, glyph ))) return res;
2963 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
2965 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
2967 if (!child->private && !font_funcs->load_font( child )) continue;
2968 if ((res = get_glyph_index( child, glyph )))
2970 *font = child;
2971 return res;
2974 return 0;
2977 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
2978 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
2979 const MAT2 *mat )
2981 GLYPHMETRICS gm;
2982 ABC abc;
2983 DWORD ret = 1;
2984 UINT index = glyph;
2985 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
2987 if (format & GGO_GLYPH_INDEX)
2989 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
2990 as glyph index. "Treasure Adventure Game" depends on this. */
2991 font_funcs->get_glyph_index( font, &index, FALSE );
2992 format &= ~GGO_GLYPH_INDEX;
2993 /* TODO: Window also turns off tategaki for glyphs passed in by index
2994 if their unicode code points fall outside of the range that is
2995 rotated. */
2997 else
2999 index = get_glyph_index_linked( &font, glyph );
3000 if (tategaki)
3002 UINT orig = index;
3003 index = get_GSUB_vert_glyph( font, index );
3004 if (index == orig) tategaki = check_unicode_tategaki( glyph );
3008 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
3010 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
3011 goto done;
3013 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
3014 if (ret == GDI_ERROR) return ret;
3016 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && !mat)
3017 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
3019 done:
3020 if (gm_ret) *gm_ret = gm;
3021 if (abc_ret) *abc_ret = abc;
3022 return ret;
3026 /*************************************************************
3027 * font_FontIsLinked
3029 static BOOL CDECL font_FontIsLinked( PHYSDEV dev )
3031 struct font_physdev *physdev = get_font_dev( dev );
3033 if (!physdev->font)
3035 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
3036 return dev->funcs->pFontIsLinked( dev );
3038 return !list_empty( &physdev->font->child_fonts );
3042 /*************************************************************
3043 * font_GetCharABCWidths
3045 static BOOL CDECL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT last, ABC *buffer )
3047 struct font_physdev *physdev = get_font_dev( dev );
3048 UINT c;
3050 if (!physdev->font)
3052 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3053 return dev->funcs->pGetCharABCWidths( dev, first, last, buffer );
3056 TRACE( "%p, %u, %u, %p\n", physdev->font, first, last, buffer );
3058 EnterCriticalSection( &font_cs );
3059 for (c = first; c <= last; c++, buffer++)
3060 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, buffer, 0, NULL, NULL );
3061 LeaveCriticalSection( &font_cs );
3062 return TRUE;
3066 /*************************************************************
3067 * font_GetCharABCWidthsI
3069 static BOOL CDECL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3071 struct font_physdev *physdev = get_font_dev( dev );
3072 UINT c;
3074 if (!physdev->font)
3076 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3077 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3080 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3082 EnterCriticalSection( &font_cs );
3083 for (c = 0; c < count; c++, buffer++)
3084 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3085 NULL, buffer, 0, NULL, NULL );
3086 LeaveCriticalSection( &font_cs );
3087 return TRUE;
3091 /*************************************************************
3092 * font_GetCharWidth
3094 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT last, INT *buffer )
3096 struct font_physdev *physdev = get_font_dev( dev );
3097 ABC abc;
3098 UINT c;
3100 if (!physdev->font)
3102 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3103 return dev->funcs->pGetCharWidth( dev, first, last, buffer );
3106 TRACE( "%p, %d, %d, %p\n", physdev->font, first, last, buffer );
3108 EnterCriticalSection( &font_cs );
3109 for (c = first; c <= last; c++)
3111 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3112 buffer[c - first] = 0;
3113 else
3114 buffer[c - first] = abc.abcA + abc.abcB + abc.abcC;
3116 LeaveCriticalSection( &font_cs );
3117 return TRUE;
3121 /*************************************************************
3122 * font_GetCharWidthInfo
3124 static BOOL CDECL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3126 struct font_physdev *physdev = get_font_dev( dev );
3127 struct char_width_info *info = ptr;
3129 if (!physdev->font)
3131 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3132 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3135 info->unk = 0;
3136 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3137 info->lsb = info->rsb = 0;
3139 return TRUE;
3143 /*************************************************************
3144 * font_GetFontData
3146 static DWORD CDECL font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
3148 struct font_physdev *physdev = get_font_dev( dev );
3150 if (!physdev->font)
3152 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
3153 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
3155 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
3159 /*************************************************************
3160 * font_GetFontRealizationInfo
3162 static BOOL CDECL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
3164 struct font_physdev *physdev = get_font_dev( dev );
3165 struct font_realization_info *info = ptr;
3167 if (!physdev->font)
3169 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
3170 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
3173 TRACE( "(%p, %p)\n", physdev->font, info);
3175 info->flags = 1;
3176 if (physdev->font->scalable) info->flags |= 2;
3178 info->cache_num = physdev->font->cache_num;
3179 info->instance_id = physdev->font->handle;
3180 if (info->size == sizeof(*info))
3182 info->unk = 0;
3183 info->face_index = physdev->font->face_index;
3184 info->simulations = 0;
3185 if (physdev->font->fake_bold) info->simulations |= 0x1;
3186 if (physdev->font->fake_italic) info->simulations |= 0x2;
3188 return TRUE;
3192 /*************************************************************
3193 * font_GetFontUnicodeRanges
3195 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
3197 struct font_physdev *physdev = get_font_dev( dev );
3198 DWORD size, num_ranges;
3200 if (!physdev->font)
3202 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
3203 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
3206 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
3207 size = offsetof( GLYPHSET, ranges[num_ranges] );
3208 if (glyphset)
3210 glyphset->cbThis = size;
3211 glyphset->cRanges = num_ranges;
3212 glyphset->flAccel = 0;
3214 return size;
3218 /*************************************************************
3219 * font_GetGlyphIndices
3221 static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
3223 struct font_physdev *physdev = get_font_dev( dev );
3224 UINT default_char;
3225 char ch;
3226 BOOL used, got_default = FALSE;
3227 int i;
3229 if (!physdev->font)
3231 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
3232 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
3235 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3237 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
3238 got_default = TRUE;
3241 EnterCriticalSection( &font_cs );
3243 for (i = 0; i < count; i++)
3245 UINT glyph = str[i];
3247 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
3249 glyph = 0;
3250 if (physdev->font->codepage == CP_SYMBOL)
3252 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
3253 else if (str[i] < 0x100) glyph = str[i];
3255 else if (WideCharToMultiByte( physdev->font->codepage, WC_NO_BEST_FIT_CHARS, &str[i], 1,
3256 &ch, 1, NULL, &used ) && !used)
3257 glyph = (unsigned char)ch;
3259 if (!glyph)
3261 if (!got_default)
3263 default_char = font_funcs->get_default_glyph( physdev->font );
3264 got_default = TRUE;
3266 gi[i] = default_char;
3268 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
3271 LeaveCriticalSection( &font_cs );
3272 return count;
3276 /*************************************************************
3277 * font_GetGlyphOutline
3279 static DWORD CDECL font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
3280 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
3282 struct font_physdev *physdev = get_font_dev( dev );
3283 DWORD ret;
3285 if (!physdev->font)
3287 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
3288 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
3290 EnterCriticalSection( &font_cs );
3291 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
3292 LeaveCriticalSection( &font_cs );
3293 return ret;
3297 /*************************************************************
3298 * font_GetKerningPairs
3300 static DWORD CDECL font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
3302 struct font_physdev *physdev = get_font_dev( dev );
3304 if (!physdev->font)
3306 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
3307 return dev->funcs->pGetKerningPairs( dev, count, pairs );
3310 EnterCriticalSection( &font_cs );
3311 if (physdev->font->kern_count == -1)
3312 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
3313 &physdev->font->kern_pairs );
3314 LeaveCriticalSection( &font_cs );
3316 if (count && pairs)
3318 count = min( count, physdev->font->kern_count );
3319 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
3321 else count = physdev->font->kern_count;
3323 return count;
3327 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
3329 double scale_x, scale_y;
3331 if (font->aveWidth)
3333 scale_x = (double)font->aveWidth;
3334 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3336 else
3337 scale_x = font->scale_y;
3339 scale_x *= fabs(font->matrix.eM11);
3340 scale_y = font->scale_y * fabs(font->matrix.eM22);
3342 /* Windows scales these values as signed integers even if they are unsigned */
3343 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3344 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3346 SCALE_Y(otm->otmTextMetrics.tmHeight);
3347 SCALE_Y(otm->otmTextMetrics.tmAscent);
3348 SCALE_Y(otm->otmTextMetrics.tmDescent);
3349 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
3350 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
3352 SCALE_X(otm->otmTextMetrics.tmOverhang);
3353 if (font->fake_bold)
3355 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
3356 otm->otmTextMetrics.tmAveCharWidth++;
3357 otm->otmTextMetrics.tmMaxCharWidth++;
3359 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
3360 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
3362 SCALE_Y(otm->otmAscent);
3363 SCALE_Y(otm->otmDescent);
3364 SCALE_Y(otm->otmLineGap);
3365 SCALE_Y(otm->otmsCapEmHeight);
3366 SCALE_Y(otm->otmsXHeight);
3367 SCALE_Y(otm->otmrcFontBox.top);
3368 SCALE_Y(otm->otmrcFontBox.bottom);
3369 SCALE_X(otm->otmrcFontBox.left);
3370 SCALE_X(otm->otmrcFontBox.right);
3371 SCALE_Y(otm->otmMacAscent);
3372 SCALE_Y(otm->otmMacDescent);
3373 SCALE_Y(otm->otmMacLineGap);
3374 SCALE_X(otm->otmptSubscriptSize.x);
3375 SCALE_Y(otm->otmptSubscriptSize.y);
3376 SCALE_X(otm->otmptSubscriptOffset.x);
3377 SCALE_Y(otm->otmptSubscriptOffset.y);
3378 SCALE_X(otm->otmptSuperscriptSize.x);
3379 SCALE_Y(otm->otmptSuperscriptSize.y);
3380 SCALE_X(otm->otmptSuperscriptOffset.x);
3381 SCALE_Y(otm->otmptSuperscriptOffset.y);
3382 SCALE_Y(otm->otmsStrikeoutSize);
3383 SCALE_Y(otm->otmsStrikeoutPosition);
3384 SCALE_Y(otm->otmsUnderscoreSize);
3385 SCALE_Y(otm->otmsUnderscorePosition);
3387 #undef SCALE_X
3388 #undef SCALE_Y
3391 /*************************************************************
3392 * font_GetOutlineTextMetrics
3394 static UINT CDECL font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
3396 struct font_physdev *physdev = get_font_dev( dev );
3397 UINT ret = 0;
3399 if (!physdev->font)
3401 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
3402 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
3405 if (!physdev->font->scalable) return 0;
3407 EnterCriticalSection( &font_cs );
3408 if (font_funcs->set_outline_text_metrics( physdev->font ))
3410 ret = physdev->font->otm.otmSize;
3411 if (metrics && size >= physdev->font->otm.otmSize)
3413 WCHAR *ptr = (WCHAR *)(metrics + 1);
3414 *metrics = physdev->font->otm;
3415 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
3416 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
3417 ptr += lstrlenW(ptr) + 1;
3418 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
3419 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
3420 ptr += lstrlenW(ptr) + 1;
3421 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
3422 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
3423 ptr += lstrlenW(ptr) + 1;
3424 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
3425 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
3426 scale_outline_font_metrics( physdev->font, metrics );
3429 LeaveCriticalSection( &font_cs );
3430 return ret;
3434 /*************************************************************
3435 * font_GetTextCharsetInfo
3437 static UINT CDECL font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
3439 struct font_physdev *physdev = get_font_dev( dev );
3441 if (!physdev->font)
3443 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
3444 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3446 if (fs) *fs = physdev->font->fs;
3447 return physdev->font->charset;
3451 /*************************************************************
3452 * font_GetTextExtentExPoint
3454 static BOOL CDECL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
3456 struct font_physdev *physdev = get_font_dev( dev );
3457 INT i, pos;
3458 ABC abc;
3460 if (!physdev->font)
3462 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
3463 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
3466 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
3468 EnterCriticalSection( &font_cs );
3469 for (i = pos = 0; i < count; i++)
3471 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
3472 pos += abc.abcA + abc.abcB + abc.abcC;
3473 dxs[i] = pos;
3475 LeaveCriticalSection( &font_cs );
3476 return TRUE;
3480 /*************************************************************
3481 * font_GetTextExtentExPointI
3483 static BOOL CDECL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
3485 struct font_physdev *physdev = get_font_dev( dev );
3486 INT i, pos;
3487 ABC abc;
3489 if (!physdev->font)
3491 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
3492 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
3495 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
3497 EnterCriticalSection( &font_cs );
3498 for (i = pos = 0; i < count; i++)
3500 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
3501 NULL, &abc, 0, NULL, NULL );
3502 pos += abc.abcA + abc.abcB + abc.abcC;
3503 dxs[i] = pos;
3505 LeaveCriticalSection( &font_cs );
3506 return TRUE;
3510 /*************************************************************
3511 * font_GetTextFace
3513 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
3515 struct font_physdev *physdev = get_font_dev( dev );
3516 INT len;
3518 if (!physdev->font)
3520 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
3521 return dev->funcs->pGetTextFace( dev, count, str );
3523 len = lstrlenW( get_gdi_font_name(physdev->font) ) + 1;
3524 if (str)
3526 lstrcpynW( str, get_gdi_font_name(physdev->font), count );
3527 len = min( count, len );
3529 return len;
3533 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
3535 double scale_x, scale_y;
3537 /* Make sure that the font has sane width/height ratio */
3538 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
3540 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
3541 font->aveWidth = 0;
3544 if (font->aveWidth)
3546 scale_x = (double)font->aveWidth;
3547 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3549 else
3550 scale_x = font->scale_y;
3552 scale_x *= fabs(font->matrix.eM11);
3553 scale_y = font->scale_y * fabs(font->matrix.eM22);
3555 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3556 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3558 SCALE_Y(tm->tmHeight);
3559 SCALE_Y(tm->tmAscent);
3560 SCALE_Y(tm->tmDescent);
3561 SCALE_Y(tm->tmInternalLeading);
3562 SCALE_Y(tm->tmExternalLeading);
3564 SCALE_X(tm->tmOverhang);
3565 if (font->fake_bold)
3567 if (!font->scalable) tm->tmOverhang++;
3568 tm->tmAveCharWidth++;
3569 tm->tmMaxCharWidth++;
3571 SCALE_X(tm->tmAveCharWidth);
3572 SCALE_X(tm->tmMaxCharWidth);
3574 #undef SCALE_X
3575 #undef SCALE_Y
3578 /*************************************************************
3579 * font_GetTextMetrics
3581 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
3583 struct font_physdev *physdev = get_font_dev( dev );
3584 BOOL ret = FALSE;
3586 if (!physdev->font)
3588 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
3589 return dev->funcs->pGetTextMetrics( dev, metrics );
3592 EnterCriticalSection( &font_cs );
3593 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
3594 font_funcs->set_bitmap_text_metrics( physdev->font ))
3596 *metrics = physdev->font->otm.otmTextMetrics;
3597 scale_font_metrics( physdev->font, metrics );
3598 ret = TRUE;
3600 LeaveCriticalSection( &font_cs );
3601 return ret;
3605 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
3607 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3608 a single face with the requested charset. The idea is to check if
3609 the selected font supports the current ANSI codepage, if it does
3610 return the corresponding charset, else return the first charset */
3612 int i;
3614 if (TranslateCharsetInfo( (DWORD*)(INT_PTR)GetACP(), csi, TCI_SRCCODEPAGE ))
3616 const struct gdi_font_link *font_link;
3618 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
3619 font_link = find_gdi_font_link(family_name);
3620 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
3622 for (i = 0; i < 32; i++)
3624 DWORD fs0 = 1u << i;
3625 if (face->fs.fsCsb[0] & fs0)
3627 if (TranslateCharsetInfo(&fs0, csi, TCI_SRCFONTSIG)) return;
3628 FIXME("TCI failing on %x\n", fs0);
3632 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3633 face->fs.fsCsb[0], debugstr_w(face->file));
3634 csi->ciACP = GetACP();
3635 csi->ciCharset = DEFAULT_CHARSET;
3638 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
3640 struct gdi_font *font;
3641 struct gdi_font_face *face;
3642 INT height;
3643 CHARSETINFO csi;
3644 const WCHAR *orig_name = NULL;
3646 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3647 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3648 original value lfCharSet. Note this is a special case for
3649 Symbol and doesn't happen at least for "Wingdings*" */
3650 if (!facename_compare( lf->lfFaceName, L"Symbol", -1 )) lf->lfCharSet = SYMBOL_CHARSET;
3652 /* check the cache first */
3653 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
3655 TRACE( "returning cached gdiFont(%p)\n", font );
3656 return font;
3658 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &orig_name )))
3660 FIXME( "can't find a single appropriate font - bailing\n" );
3661 return NULL;
3663 height = lf->lfHeight;
3665 font = create_gdi_font( face, orig_name, lf );
3666 font->matrix = dcmat;
3667 font->can_use_bitmap = can_use_bitmap;
3668 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
3669 font->charset = csi.ciCharset;
3670 font->codepage = csi.ciACP;
3672 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
3673 face->data_ptr, face->face_index );
3675 font->aveWidth = height ? lf->lfWidth : 0;
3676 if (!face->scalable)
3678 /* Windows uses integer scaling factors for bitmap fonts */
3679 INT scale, scaled_height, diff;
3680 struct gdi_font *cachedfont;
3682 if (height > 0)
3683 diff = height - (signed int)face->size.height;
3684 else
3685 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
3687 /* FIXME: rotation of bitmap fonts is ignored */
3688 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
3689 if (font->aveWidth)
3690 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
3691 font->matrix.eM11 = font->matrix.eM22 = 1.0;
3692 dcmat.eM11 = dcmat.eM22 = 1.0;
3693 /* As we changed the matrix, we need to search the cache for the font again,
3694 * otherwise we might explode the cache. */
3695 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
3697 TRACE("Found cached font after non-scalable matrix rescale!\n");
3698 free_gdi_font( font );
3699 return cachedfont;
3702 if (height != 0) height = diff;
3703 height += face->size.height;
3705 scale = (height + face->size.height - 1) / face->size.height;
3706 scaled_height = scale * face->size.height;
3707 /* Only jump to the next height if the difference <= 25% original height */
3708 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3709 /* The jump between unscaled and doubled is delayed by 1 */
3710 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3711 font->scale_y = scale;
3712 TRACE("font scale y: %d\n", font->scale_y);
3715 if (!font_funcs->load_font( font ))
3717 free_gdi_font( font );
3718 return NULL;
3721 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
3722 font->vert_feature = get_GSUB_vert_feature( font );
3724 create_child_font_list( font );
3726 TRACE( "caching: gdiFont=%p\n", font );
3727 cache_gdi_font( font );
3728 return font;
3731 /*************************************************************
3732 * font_SelectFont
3734 static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
3736 struct font_physdev *physdev = get_font_dev( dev );
3737 struct gdi_font *font = NULL, *prev = physdev->font;
3738 DC *dc = get_physdev_dc( dev );
3740 if (hfont)
3742 LOGFONTW lf;
3743 FMAT2 dcmat;
3744 BOOL can_use_bitmap = !!(GetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
3746 GetObjectW( hfont, sizeof(lf), &lf );
3747 switch (lf.lfQuality)
3749 case NONANTIALIASED_QUALITY:
3750 if (!*aa_flags) *aa_flags = GGO_BITMAP;
3751 break;
3752 case ANTIALIASED_QUALITY:
3753 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
3754 break;
3757 lf.lfWidth = abs(lf.lfWidth);
3759 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3760 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3761 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3762 lf.lfEscapement );
3764 if (dc->GraphicsMode == GM_ADVANCED)
3766 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
3767 /* try to avoid not necessary glyph transformations */
3768 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3770 lf.lfHeight *= fabs(dcmat.eM11);
3771 lf.lfWidth *= fabs(dcmat.eM11);
3772 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
3775 else
3777 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
3778 dcmat.eM11 = dcmat.eM22 = 1.0;
3779 dcmat.eM21 = dcmat.eM12 = 0;
3780 lf.lfOrientation = lf.lfEscapement;
3781 if (dc->vport2WorldValid)
3783 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3784 lf.lfOrientation = -lf.lfOrientation;
3785 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3786 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3789 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
3791 EnterCriticalSection( &font_cs );
3793 font = select_font( &lf, dcmat, can_use_bitmap );
3795 if (font)
3797 if (!*aa_flags) *aa_flags = font->aa_flags;
3798 if (!*aa_flags)
3800 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
3801 *aa_flags = subpixel_orientation;
3802 else
3803 *aa_flags = font_smoothing;
3805 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
3807 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
3808 LeaveCriticalSection( &font_cs );
3810 physdev->font = font;
3811 if (prev) release_gdi_font( prev );
3812 return font ? hfont : 0;
3816 const struct gdi_dc_funcs font_driver =
3818 NULL, /* pAbortDoc */
3819 NULL, /* pAbortPath */
3820 NULL, /* pAlphaBlend */
3821 NULL, /* pAngleArc */
3822 NULL, /* pArc */
3823 NULL, /* pArcTo */
3824 NULL, /* pBeginPath */
3825 NULL, /* pBlendImage */
3826 NULL, /* pChord */
3827 NULL, /* pCloseFigure */
3828 NULL, /* pCreateCompatibleDC */
3829 font_CreateDC, /* pCreateDC */
3830 font_DeleteDC, /* pDeleteDC */
3831 NULL, /* pDeleteObject */
3832 NULL, /* pDeviceCapabilities */
3833 NULL, /* pEllipse */
3834 NULL, /* pEndDoc */
3835 NULL, /* pEndPage */
3836 NULL, /* pEndPath */
3837 font_EnumFonts, /* pEnumFonts */
3838 NULL, /* pEnumICMProfiles */
3839 NULL, /* pExcludeClipRect */
3840 NULL, /* pExtDeviceMode */
3841 NULL, /* pExtEscape */
3842 NULL, /* pExtFloodFill */
3843 NULL, /* pExtSelectClipRgn */
3844 NULL, /* pExtTextOut */
3845 NULL, /* pFillPath */
3846 NULL, /* pFillRgn */
3847 NULL, /* pFlattenPath */
3848 font_FontIsLinked, /* pFontIsLinked */
3849 NULL, /* pFrameRgn */
3850 NULL, /* pGdiComment */
3851 NULL, /* pGetBoundsRect */
3852 font_GetCharABCWidths, /* pGetCharABCWidths */
3853 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
3854 font_GetCharWidth, /* pGetCharWidth */
3855 font_GetCharWidthInfo, /* pGetCharWidthInfo */
3856 NULL, /* pGetDeviceCaps */
3857 NULL, /* pGetDeviceGammaRamp */
3858 font_GetFontData, /* pGetFontData */
3859 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
3860 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
3861 font_GetGlyphIndices, /* pGetGlyphIndices */
3862 font_GetGlyphOutline, /* pGetGlyphOutline */
3863 NULL, /* pGetICMProfile */
3864 NULL, /* pGetImage */
3865 font_GetKerningPairs, /* pGetKerningPairs */
3866 NULL, /* pGetNearestColor */
3867 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
3868 NULL, /* pGetPixel */
3869 NULL, /* pGetSystemPaletteEntries */
3870 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
3871 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
3872 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
3873 font_GetTextFace, /* pGetTextFace */
3874 font_GetTextMetrics, /* pGetTextMetrics */
3875 NULL, /* pGradientFill */
3876 NULL, /* pIntersectClipRect */
3877 NULL, /* pInvertRgn */
3878 NULL, /* pLineTo */
3879 NULL, /* pModifyWorldTransform */
3880 NULL, /* pMoveTo */
3881 NULL, /* pOffsetClipRgn */
3882 NULL, /* pOffsetViewportOrg */
3883 NULL, /* pOffsetWindowOrg */
3884 NULL, /* pPaintRgn */
3885 NULL, /* pPatBlt */
3886 NULL, /* pPie */
3887 NULL, /* pPolyBezier */
3888 NULL, /* pPolyBezierTo */
3889 NULL, /* pPolyDraw */
3890 NULL, /* pPolyPolygon */
3891 NULL, /* pPolyPolyline */
3892 NULL, /* pPolygon */
3893 NULL, /* pPolyline */
3894 NULL, /* pPolylineTo */
3895 NULL, /* pPutImage */
3896 NULL, /* pRealizeDefaultPalette */
3897 NULL, /* pRealizePalette */
3898 NULL, /* pRectangle */
3899 NULL, /* pResetDC */
3900 NULL, /* pRestoreDC */
3901 NULL, /* pRoundRect */
3902 NULL, /* pSaveDC */
3903 NULL, /* pScaleViewportExt */
3904 NULL, /* pScaleWindowExt */
3905 NULL, /* pSelectBitmap */
3906 NULL, /* pSelectBrush */
3907 NULL, /* pSelectClipPath */
3908 font_SelectFont, /* pSelectFont */
3909 NULL, /* pSelectPalette */
3910 NULL, /* pSelectPen */
3911 NULL, /* pSetArcDirection */
3912 NULL, /* pSetBkColor */
3913 NULL, /* pSetBkMode */
3914 NULL, /* pSetBoundsRect */
3915 NULL, /* pSetDCBrushColor */
3916 NULL, /* pSetDCPenColor */
3917 NULL, /* pSetDIBitsToDevice */
3918 NULL, /* pSetDeviceClipping */
3919 NULL, /* pSetDeviceGammaRamp */
3920 NULL, /* pSetLayout */
3921 NULL, /* pSetMapMode */
3922 NULL, /* pSetMapperFlags */
3923 NULL, /* pSetPixel */
3924 NULL, /* pSetPolyFillMode */
3925 NULL, /* pSetROP2 */
3926 NULL, /* pSetRelAbs */
3927 NULL, /* pSetStretchBltMode */
3928 NULL, /* pSetTextAlign */
3929 NULL, /* pSetTextCharacterExtra */
3930 NULL, /* pSetTextColor */
3931 NULL, /* pSetTextJustification */
3932 NULL, /* pSetViewportExt */
3933 NULL, /* pSetViewportOrg */
3934 NULL, /* pSetWindowExt */
3935 NULL, /* pSetWindowOrg */
3936 NULL, /* pSetWorldTransform */
3937 NULL, /* pStartDoc */
3938 NULL, /* pStartPage */
3939 NULL, /* pStretchBlt */
3940 NULL, /* pStretchDIBits */
3941 NULL, /* pStrokeAndFillPath */
3942 NULL, /* pStrokePath */
3943 NULL, /* pUnrealizePalette */
3944 NULL, /* pWidenPath */
3945 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
3946 NULL, /* pD3DKMTSetVidPnSourceOwner */
3947 NULL, /* wine_get_wgl_driver */
3948 NULL, /* wine_get_vulkan_driver */
3949 GDI_PRIORITY_FONT_DRV /* priority */
3952 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
3954 WCHAR buf[12];
3955 DWORD count = sizeof(buf), type, err;
3957 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
3958 if (!err)
3960 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
3961 else *value = wcstol( buf, NULL, 10 );
3963 return err;
3966 static void init_font_options(void)
3968 HKEY key;
3969 DWORD i, type, size, val, gamma = 1400;
3970 WCHAR buffer[20];
3972 size = sizeof(buffer);
3973 if (!RegQueryValueExW( wine_fonts_key, L"AntialiasFakeBoldOrItalic", NULL,
3974 &type, (BYTE *)buffer, &size) && type == REG_SZ && size >= 1)
3976 antialias_fakes = (wcschr(L"yYtT1", buffer[0]) != NULL);
3979 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Control Panel\\Desktop", &key ))
3981 /* FIXME: handle vertical orientations even though Windows doesn't */
3982 if (!get_key_value( key, L"FontSmoothingOrientation", &val ))
3984 switch (val)
3986 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
3987 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
3988 break;
3989 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
3990 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
3991 break;
3994 if (!get_key_value( key, L"FontSmoothing", &val ) && val /* enabled */)
3996 if (!get_key_value( key, L"FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
3997 font_smoothing = subpixel_orientation;
3998 else
3999 font_smoothing = GGO_GRAY4_BITMAP;
4001 if (!get_key_value( key, L"FontSmoothingGamma", &val ) && val)
4003 gamma = min( max( val, 1000 ), 2200 );
4005 RegCloseKey( key );
4008 /* Calibrating the difference between the registry value and the Wine gamma value.
4009 This looks roughly similar to Windows Native with the same registry value.
4010 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
4011 gamma = 1000 * gamma / 1400;
4012 if (gamma != 1000)
4014 for (i = 0; i < 256; i++)
4016 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
4017 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
4020 font_gamma_ramp.gamma = gamma;
4021 TRACE("gamma %d\n", font_gamma_ramp.gamma);
4025 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
4027 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
4028 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
4029 LF_FACESIZE);
4030 fontW->lfFaceName[LF_FACESIZE-1] = 0;
4033 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
4035 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
4036 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
4037 LF_FACESIZE, NULL, NULL);
4038 fontA->lfFaceName[LF_FACESIZE-1] = 0;
4041 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
4043 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
4045 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
4046 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
4047 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
4048 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
4049 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
4050 fontA->elfStyle[LF_FACESIZE-1] = '\0';
4051 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
4052 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
4053 fontA->elfScript[LF_FACESIZE-1] = '\0';
4056 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
4058 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
4060 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
4061 fontW->elfFullName, LF_FULLFACESIZE );
4062 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
4063 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
4064 fontW->elfStyle, LF_FACESIZE );
4065 fontW->elfStyle[LF_FACESIZE-1] = '\0';
4066 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
4067 fontW->elfScript, LF_FACESIZE );
4068 fontW->elfScript[LF_FACESIZE-1] = '\0';
4071 /***********************************************************************
4072 * TEXTMETRIC conversion functions.
4074 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
4076 ptmA->tmHeight = ptmW->tmHeight;
4077 ptmA->tmAscent = ptmW->tmAscent;
4078 ptmA->tmDescent = ptmW->tmDescent;
4079 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
4080 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
4081 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
4082 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
4083 ptmA->tmWeight = ptmW->tmWeight;
4084 ptmA->tmOverhang = ptmW->tmOverhang;
4085 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
4086 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
4087 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
4088 if (ptmW->tmCharSet == SYMBOL_CHARSET)
4090 ptmA->tmFirstChar = 0x1e;
4091 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
4093 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
4095 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
4096 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
4098 else
4100 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
4101 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
4103 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
4104 ptmA->tmBreakChar = ptmW->tmBreakChar;
4105 ptmA->tmItalic = ptmW->tmItalic;
4106 ptmA->tmUnderlined = ptmW->tmUnderlined;
4107 ptmA->tmStruckOut = ptmW->tmStruckOut;
4108 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
4109 ptmA->tmCharSet = ptmW->tmCharSet;
4113 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
4115 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
4116 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
4117 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
4118 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
4119 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
4120 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
4123 /* compute positions for text rendering, in device coords */
4124 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4126 TEXTMETRICW tm;
4127 PHYSDEV dev;
4129 size->cx = size->cy = 0;
4130 if (!count) return TRUE;
4132 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4133 dev->funcs->pGetTextMetrics( dev, &tm );
4135 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4136 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4138 if (dc->breakExtra || dc->breakRem)
4140 int i, space = 0, rem = dc->breakRem;
4142 for (i = 0; i < count; i++)
4144 if (str[i] == tm.tmBreakChar)
4146 space += dc->breakExtra;
4147 if (rem > 0)
4149 space++;
4150 rem--;
4153 dx[i] += space;
4156 size->cx = dx[count - 1];
4157 size->cy = tm.tmHeight;
4158 return TRUE;
4161 /* compute positions for text rendering, in device coords */
4162 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4164 TEXTMETRICW tm;
4165 PHYSDEV dev;
4167 size->cx = size->cy = 0;
4168 if (!count) return TRUE;
4170 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4171 dev->funcs->pGetTextMetrics( dev, &tm );
4173 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4174 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4176 if (dc->breakExtra || dc->breakRem)
4178 WORD space_index;
4179 int i, space = 0, rem = dc->breakRem;
4181 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4182 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4184 for (i = 0; i < count; i++)
4186 if (indices[i] == space_index)
4188 space += dc->breakExtra;
4189 if (rem > 0)
4191 space++;
4192 rem--;
4195 dx[i] += space;
4198 size->cx = dx[count - 1];
4199 size->cy = tm.tmHeight;
4200 return TRUE;
4203 /***********************************************************************
4204 * GdiGetCodePage (GDI32.@)
4206 DWORD WINAPI GdiGetCodePage( HDC hdc )
4208 UINT cp = CP_ACP;
4209 DC *dc = get_dc_ptr( hdc );
4211 if (dc)
4213 cp = dc->font_code_page;
4214 release_dc_ptr( dc );
4216 return cp;
4219 /***********************************************************************
4220 * get_text_charset_info
4222 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4224 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4226 UINT ret = DEFAULT_CHARSET;
4227 PHYSDEV dev;
4229 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4230 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4232 if (ret == DEFAULT_CHARSET && fs)
4233 memset(fs, 0, sizeof(FONTSIGNATURE));
4234 return ret;
4237 /***********************************************************************
4238 * GetTextCharsetInfo (GDI32.@)
4240 UINT WINAPI GetTextCharsetInfo(HDC hdc, FONTSIGNATURE *fs, DWORD flags)
4242 UINT ret = DEFAULT_CHARSET;
4243 DC *dc = get_dc_ptr(hdc);
4245 if (dc)
4247 ret = get_text_charset_info( dc, fs, flags );
4248 release_dc_ptr( dc );
4250 return ret;
4253 /***********************************************************************
4254 * FONT_mbtowc
4256 * Returns a Unicode translation of str using the charset of the
4257 * currently selected font in hdc. If count is -1 then str is assumed
4258 * to be '\0' terminated, otherwise it contains the number of bytes to
4259 * convert. If plenW is non-NULL, on return it will point to the
4260 * number of WCHARs that have been written. If pCP is non-NULL, on
4261 * return it will point to the codepage used in the conversion. The
4262 * caller should free the returned LPWSTR from the process heap
4263 * itself.
4265 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
4267 UINT cp;
4268 INT lenW;
4269 LPWSTR strW;
4271 cp = GdiGetCodePage( hdc );
4273 if(count == -1) count = strlen(str);
4274 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
4275 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
4276 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
4277 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
4278 if(plenW) *plenW = lenW;
4279 if(pCP) *pCP = cp;
4280 return strW;
4283 /***********************************************************************
4284 * CreateFontIndirectExA (GDI32.@)
4286 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
4288 ENUMLOGFONTEXDVW enumexW;
4290 if (!penumexA) return 0;
4292 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
4293 enumexW.elfDesignVector = penumexA->elfDesignVector;
4294 return CreateFontIndirectExW( &enumexW );
4297 /***********************************************************************
4298 * CreateFontIndirectExW (GDI32.@)
4300 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
4302 HFONT hFont;
4303 FONTOBJ *fontPtr;
4304 const LOGFONTW *plf;
4306 if (!penumex) return 0;
4308 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
4309 penumex->elfEnumLogfontEx.elfStyle[0] ||
4310 penumex->elfEnumLogfontEx.elfScript[0])
4312 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4313 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
4314 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
4315 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
4318 plf = &penumex->elfEnumLogfontEx.elfLogFont;
4319 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
4321 fontPtr->logfont = *plf;
4323 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, OBJ_FONT, &fontobj_funcs )))
4325 HeapFree( GetProcessHeap(), 0, fontPtr );
4326 return 0;
4329 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4330 plf->lfHeight, plf->lfWidth,
4331 plf->lfEscapement, plf->lfOrientation,
4332 plf->lfPitchAndFamily,
4333 plf->lfOutPrecision, plf->lfClipPrecision,
4334 plf->lfQuality, plf->lfCharSet,
4335 debugstr_w(plf->lfFaceName),
4336 plf->lfWeight > 400 ? "Bold" : "",
4337 plf->lfItalic ? "Italic" : "",
4338 plf->lfUnderline ? "Underline" : "", hFont);
4340 return hFont;
4343 /***********************************************************************
4344 * CreateFontIndirectA (GDI32.@)
4346 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
4348 LOGFONTW lfW;
4350 if (!plfA) return 0;
4352 FONT_LogFontAToW( plfA, &lfW );
4353 return CreateFontIndirectW( &lfW );
4356 /***********************************************************************
4357 * CreateFontIndirectW (GDI32.@)
4359 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
4361 ENUMLOGFONTEXDVW exdv;
4363 if (!plf) return 0;
4365 exdv.elfEnumLogfontEx.elfLogFont = *plf;
4366 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
4367 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
4368 exdv.elfEnumLogfontEx.elfScript[0] = 0;
4369 return CreateFontIndirectExW( &exdv );
4372 /*************************************************************************
4373 * CreateFontA (GDI32.@)
4375 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
4376 INT orient, INT weight, DWORD italic,
4377 DWORD underline, DWORD strikeout, DWORD charset,
4378 DWORD outpres, DWORD clippres, DWORD quality,
4379 DWORD pitch, LPCSTR name )
4381 LOGFONTA logfont;
4383 logfont.lfHeight = height;
4384 logfont.lfWidth = width;
4385 logfont.lfEscapement = esc;
4386 logfont.lfOrientation = orient;
4387 logfont.lfWeight = weight;
4388 logfont.lfItalic = italic;
4389 logfont.lfUnderline = underline;
4390 logfont.lfStrikeOut = strikeout;
4391 logfont.lfCharSet = charset;
4392 logfont.lfOutPrecision = outpres;
4393 logfont.lfClipPrecision = clippres;
4394 logfont.lfQuality = quality;
4395 logfont.lfPitchAndFamily = pitch;
4397 if (name)
4398 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
4399 else
4400 logfont.lfFaceName[0] = '\0';
4402 return CreateFontIndirectA( &logfont );
4405 /*************************************************************************
4406 * CreateFontW (GDI32.@)
4408 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
4409 INT orient, INT weight, DWORD italic,
4410 DWORD underline, DWORD strikeout, DWORD charset,
4411 DWORD outpres, DWORD clippres, DWORD quality,
4412 DWORD pitch, LPCWSTR name )
4414 LOGFONTW logfont;
4416 logfont.lfHeight = height;
4417 logfont.lfWidth = width;
4418 logfont.lfEscapement = esc;
4419 logfont.lfOrientation = orient;
4420 logfont.lfWeight = weight;
4421 logfont.lfItalic = italic;
4422 logfont.lfUnderline = underline;
4423 logfont.lfStrikeOut = strikeout;
4424 logfont.lfCharSet = charset;
4425 logfont.lfOutPrecision = outpres;
4426 logfont.lfClipPrecision = clippres;
4427 logfont.lfQuality = quality;
4428 logfont.lfPitchAndFamily = pitch;
4430 if (name)
4431 lstrcpynW(logfont.lfFaceName, name, ARRAY_SIZE(logfont.lfFaceName));
4432 else
4433 logfont.lfFaceName[0] = '\0';
4435 return CreateFontIndirectW( &logfont );
4438 #define ASSOC_CHARSET_OEM 1
4439 #define ASSOC_CHARSET_ANSI 2
4440 #define ASSOC_CHARSET_SYMBOL 4
4442 static DWORD get_associated_charset_info(void)
4444 static DWORD associated_charset = -1;
4446 if (associated_charset == -1)
4448 HKEY hkey;
4449 WCHAR dataW[32];
4450 DWORD type, data_len;
4452 associated_charset = 0;
4454 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
4455 L"System\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset", &hkey))
4456 return 0;
4458 data_len = sizeof(dataW);
4459 if (!RegQueryValueExW(hkey, L"ANSI(00)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4460 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4461 associated_charset |= ASSOC_CHARSET_ANSI;
4463 data_len = sizeof(dataW);
4464 if (!RegQueryValueExW(hkey, L"OEM(FF)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4465 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4466 associated_charset |= ASSOC_CHARSET_OEM;
4468 data_len = sizeof(dataW);
4469 if (!RegQueryValueExW(hkey, L"SYMBOL(02)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4470 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4471 associated_charset |= ASSOC_CHARSET_SYMBOL;
4473 RegCloseKey(hkey);
4475 TRACE("associated_charset = %d\n", associated_charset);
4478 return associated_charset;
4481 static void update_font_code_page( DC *dc, HANDLE font )
4483 CHARSETINFO csi;
4484 int charset = get_text_charset_info( dc, NULL, 0 );
4486 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
4488 LOGFONTW lf;
4490 GetObjectW( font, sizeof(lf), &lf );
4491 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
4492 charset = DEFAULT_CHARSET;
4495 /* Hmm, nicely designed api this one! */
4496 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
4497 dc->font_code_page = csi.ciACP;
4498 else {
4499 switch(charset) {
4500 case OEM_CHARSET:
4501 dc->font_code_page = GetOEMCP();
4502 break;
4503 case DEFAULT_CHARSET:
4504 dc->font_code_page = GetACP();
4505 break;
4507 case VISCII_CHARSET:
4508 case TCVN_CHARSET:
4509 case KOI8_CHARSET:
4510 case ISO3_CHARSET:
4511 case ISO4_CHARSET:
4512 case ISO10_CHARSET:
4513 case CELTIC_CHARSET:
4514 /* FIXME: These have no place here, but because x11drv
4515 enumerates fonts with these (made up) charsets some apps
4516 might use them and then the FIXME below would become
4517 annoying. Now we could pick the intended codepage for
4518 each of these, but since it's broken anyway we'll just
4519 use CP_ACP and hope it'll go away...
4521 dc->font_code_page = CP_ACP;
4522 break;
4524 default:
4525 FIXME("Can't find codepage for charset %d\n", charset);
4526 dc->font_code_page = CP_ACP;
4527 break;
4531 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
4534 /***********************************************************************
4535 * NtGdiSelectFont (win32u.@)
4537 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
4539 HGDIOBJ ret = 0;
4540 DC *dc = get_dc_ptr( hdc );
4541 PHYSDEV physdev;
4542 UINT aa_flags = 0;
4544 if (!dc) return 0;
4546 if (!GDI_inc_ref_count( handle ))
4548 release_dc_ptr( dc );
4549 return 0;
4552 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
4553 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
4555 ret = dc->hFont;
4556 dc->hFont = handle;
4557 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
4558 update_font_code_page( dc, handle );
4559 if (dc->font_gamma_ramp == NULL)
4560 dc->font_gamma_ramp = &font_gamma_ramp;
4561 GDI_dec_ref_count( ret );
4563 else GDI_dec_ref_count( handle );
4565 release_dc_ptr( dc );
4566 return ret;
4570 /***********************************************************************
4571 * FONT_GetObjectA
4573 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
4575 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
4576 LOGFONTA lfA;
4578 if (!font) return 0;
4579 if (buffer)
4581 FONT_LogFontWToA( &font->logfont, &lfA );
4582 if (count > sizeof(lfA)) count = sizeof(lfA);
4583 memcpy( buffer, &lfA, count );
4585 else count = sizeof(lfA);
4586 GDI_ReleaseObj( handle );
4587 return count;
4590 /***********************************************************************
4591 * FONT_GetObjectW
4593 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
4595 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
4597 if (!font) return 0;
4598 if (buffer)
4600 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
4601 memcpy( buffer, &font->logfont, count );
4603 else count = sizeof(LOGFONTW);
4604 GDI_ReleaseObj( handle );
4605 return count;
4609 /***********************************************************************
4610 * FONT_DeleteObject
4612 static BOOL FONT_DeleteObject( HGDIOBJ handle )
4614 FONTOBJ *obj;
4616 if (!(obj = free_gdi_handle( handle ))) return FALSE;
4617 HeapFree( GetProcessHeap(), 0, obj );
4618 return TRUE;
4622 /***********************************************************************
4623 * FONT_EnumInstance
4625 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
4626 * We have to use other types because of the FONTENUMPROCW definition.
4628 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
4629 DWORD fType, LPARAM lp )
4631 struct font_enum *pfe = (struct font_enum *)lp;
4632 INT ret = 1;
4634 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
4635 if ((!pfe->lpLogFontParam ||
4636 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
4637 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
4638 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
4640 /* convert font metrics */
4641 ENUMLOGFONTEXA logfont;
4642 NEWTEXTMETRICEXA tmA;
4644 if (!pfe->unicode)
4646 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
4647 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
4648 plf = (LOGFONTW *)&logfont.elfLogFont;
4649 ptm = (TEXTMETRICW *)&tmA;
4651 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
4652 pfe->retval = ret;
4654 return ret;
4657 /***********************************************************************
4658 * FONT_EnumFontFamiliesEx
4660 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
4661 LPARAM lParam, BOOL unicode )
4663 INT ret = 0;
4664 DC *dc = get_dc_ptr( hDC );
4665 struct font_enum fe;
4667 if (dc)
4669 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
4671 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4672 fe.lpLogFontParam = plf;
4673 fe.lpEnumFunc = efproc;
4674 fe.lpData = lParam;
4675 fe.unicode = unicode;
4676 fe.hdc = hDC;
4677 fe.retval = 1;
4678 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
4679 release_dc_ptr( dc );
4681 return ret ? fe.retval : 0;
4684 /***********************************************************************
4685 * EnumFontFamiliesExW (GDI32.@)
4687 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
4688 FONTENUMPROCW efproc,
4689 LPARAM lParam, DWORD dwFlags )
4691 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
4694 /***********************************************************************
4695 * EnumFontFamiliesExA (GDI32.@)
4697 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
4698 FONTENUMPROCA efproc,
4699 LPARAM lParam, DWORD dwFlags)
4701 LOGFONTW lfW, *plfW;
4703 if (plf)
4705 FONT_LogFontAToW( plf, &lfW );
4706 plfW = &lfW;
4708 else plfW = NULL;
4710 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
4713 /***********************************************************************
4714 * EnumFontFamiliesA (GDI32.@)
4716 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
4717 FONTENUMPROCA efproc, LPARAM lpData )
4719 LOGFONTA lf, *plf;
4721 if (lpFamily)
4723 if (!*lpFamily) return 1;
4724 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
4725 lf.lfCharSet = DEFAULT_CHARSET;
4726 lf.lfPitchAndFamily = 0;
4727 plf = &lf;
4729 else plf = NULL;
4731 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
4734 /***********************************************************************
4735 * EnumFontFamiliesW (GDI32.@)
4737 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
4738 FONTENUMPROCW efproc, LPARAM lpData )
4740 LOGFONTW lf, *plf;
4742 if (lpFamily)
4744 if (!*lpFamily) return 1;
4745 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
4746 lf.lfCharSet = DEFAULT_CHARSET;
4747 lf.lfPitchAndFamily = 0;
4748 plf = &lf;
4750 else plf = NULL;
4752 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
4755 /***********************************************************************
4756 * EnumFontsA (GDI32.@)
4758 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
4759 LPARAM lpData )
4761 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
4764 /***********************************************************************
4765 * EnumFontsW (GDI32.@)
4767 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
4768 LPARAM lpData )
4770 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
4774 /***********************************************************************
4775 * GetTextCharacterExtra (GDI32.@)
4777 INT WINAPI GetTextCharacterExtra( HDC hdc )
4779 INT ret;
4780 DC *dc = get_dc_ptr( hdc );
4781 if (!dc) return 0x80000000;
4782 ret = dc->charExtra;
4783 release_dc_ptr( dc );
4784 return ret;
4788 /***********************************************************************
4789 * SetTextCharacterExtra (GDI32.@)
4791 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
4793 INT ret = 0x80000000;
4794 DC * dc = get_dc_ptr( hdc );
4796 if (dc)
4798 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
4799 extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
4800 if (extra != 0x80000000)
4802 ret = dc->charExtra;
4803 dc->charExtra = extra;
4805 release_dc_ptr( dc );
4807 return ret;
4811 /***********************************************************************
4812 * SetTextJustification (GDI32.@)
4814 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
4816 BOOL ret;
4817 PHYSDEV physdev;
4818 DC * dc = get_dc_ptr( hdc );
4820 if (!dc) return FALSE;
4822 physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
4823 ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
4824 if (ret)
4826 extra = abs((extra * dc->vport_ext.cx + dc->wnd_ext.cx / 2) / dc->wnd_ext.cx);
4827 if (!extra) breaks = 0;
4828 if (breaks)
4830 dc->breakExtra = extra / breaks;
4831 dc->breakRem = extra - (breaks * dc->breakExtra);
4833 else
4835 dc->breakExtra = 0;
4836 dc->breakRem = 0;
4839 release_dc_ptr( dc );
4840 return ret;
4844 /***********************************************************************
4845 * GetTextFaceA (GDI32.@)
4847 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
4849 INT res = GetTextFaceW(hdc, 0, NULL);
4850 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
4851 GetTextFaceW( hdc, res, nameW );
4853 if (name)
4855 if (count)
4857 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
4858 if (res == 0)
4859 res = count;
4860 name[count-1] = 0;
4861 /* GetTextFaceA does NOT include the nul byte in the return count. */
4862 res--;
4864 else
4865 res = 0;
4867 else
4868 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
4869 HeapFree( GetProcessHeap(), 0, nameW );
4870 return res;
4873 /***********************************************************************
4874 * GetTextFaceW (GDI32.@)
4876 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
4878 PHYSDEV dev;
4879 INT ret;
4881 DC * dc = get_dc_ptr( hdc );
4882 if (!dc) return 0;
4884 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
4885 ret = dev->funcs->pGetTextFace( dev, count, name );
4886 release_dc_ptr( dc );
4887 return ret;
4891 /***********************************************************************
4892 * GetTextExtentPoint32A (GDI32.@)
4894 * See GetTextExtentPoint32W.
4896 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
4897 LPSIZE size )
4899 BOOL ret = FALSE;
4900 INT wlen;
4901 LPWSTR p;
4903 if (count < 0) return FALSE;
4905 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
4907 if (p)
4909 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
4910 HeapFree( GetProcessHeap(), 0, p );
4913 TRACE("(%p %s %d %p): returning %d x %d\n",
4914 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
4915 return ret;
4919 /***********************************************************************
4920 * GetTextExtentPoint32W [GDI32.@]
4922 * Computes width/height for a string.
4924 * Computes width and height of the specified string.
4926 * RETURNS
4927 * Success: TRUE
4928 * Failure: FALSE
4930 BOOL WINAPI GetTextExtentPoint32W(
4931 HDC hdc, /* [in] Handle of device context */
4932 LPCWSTR str, /* [in] Address of text string */
4933 INT count, /* [in] Number of characters in string */
4934 LPSIZE size) /* [out] Address of structure for string size */
4936 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
4939 /***********************************************************************
4940 * GetTextExtentExPointI [GDI32.@]
4942 * Computes width and height of the array of glyph indices.
4944 * PARAMS
4945 * hdc [I] Handle of device context.
4946 * indices [I] Glyph index array.
4947 * count [I] Number of glyphs in array.
4948 * max_ext [I] Maximum width in glyphs.
4949 * nfit [O] Maximum number of characters.
4950 * dxs [O] Partial string widths.
4951 * size [O] Returned string size.
4953 * RETURNS
4954 * Success: TRUE
4955 * Failure: FALSE
4957 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
4958 LPINT nfit, LPINT dxs, LPSIZE size )
4960 DC *dc;
4961 int i;
4962 BOOL ret;
4963 INT buffer[256], *pos = dxs;
4965 if (count < 0) return FALSE;
4967 dc = get_dc_ptr( hdc );
4968 if (!dc) return FALSE;
4970 if (!dxs)
4972 pos = buffer;
4973 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
4975 release_dc_ptr( dc );
4976 return FALSE;
4980 ret = get_char_positions_indices( dc, indices, count, pos, size );
4981 if (ret)
4983 if (dxs || nfit)
4985 for (i = 0; i < count; i++)
4987 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
4988 if (nfit && dx > (unsigned int)max_ext) break;
4989 if (dxs) dxs[i] = dx;
4991 if (nfit) *nfit = i;
4994 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
4995 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
4998 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
4999 release_dc_ptr( dc );
5001 TRACE("(%p %p %d %p): returning %d x %d\n",
5002 hdc, indices, count, size, size->cx, size->cy );
5003 return ret;
5006 /***********************************************************************
5007 * GetTextExtentPointI [GDI32.@]
5009 * Computes width and height of the array of glyph indices.
5011 * PARAMS
5012 * hdc [I] Handle of device context.
5013 * indices [I] Glyph index array.
5014 * count [I] Number of glyphs in array.
5015 * size [O] Returned string size.
5017 * RETURNS
5018 * Success: TRUE
5019 * Failure: FALSE
5021 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
5023 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
5027 /***********************************************************************
5028 * GetTextExtentPointA (GDI32.@)
5030 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
5031 LPSIZE size )
5033 TRACE("not bug compatible.\n");
5034 return GetTextExtentPoint32A( hdc, str, count, size );
5037 /***********************************************************************
5038 * GetTextExtentPointW (GDI32.@)
5040 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
5041 LPSIZE size )
5043 TRACE("not bug compatible.\n");
5044 return GetTextExtentPoint32W( hdc, str, count, size );
5048 /***********************************************************************
5049 * GetTextExtentExPointA (GDI32.@)
5051 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
5052 INT maxExt, LPINT lpnFit,
5053 LPINT alpDx, LPSIZE size )
5055 BOOL ret;
5056 INT wlen;
5057 INT *walpDx = NULL;
5058 LPWSTR p = NULL;
5060 if (count < 0) return FALSE;
5061 if (maxExt < -1) return FALSE;
5063 if (alpDx)
5065 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
5066 if (!walpDx) return FALSE;
5069 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
5070 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
5071 if (walpDx)
5073 INT n = lpnFit ? *lpnFit : wlen;
5074 INT i, j;
5075 for(i = 0, j = 0; i < n; i++, j++)
5077 alpDx[j] = walpDx[i];
5078 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
5081 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
5082 HeapFree( GetProcessHeap(), 0, p );
5083 HeapFree( GetProcessHeap(), 0, walpDx );
5084 return ret;
5088 /***********************************************************************
5089 * GetTextExtentExPointW (GDI32.@)
5091 * Return the size of the string as it would be if it was output properly by
5092 * e.g. TextOut.
5094 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
5095 LPINT nfit, LPINT dxs, LPSIZE size )
5097 DC *dc;
5098 int i;
5099 BOOL ret;
5100 INT buffer[256], *pos = dxs;
5102 if (count < 0) return FALSE;
5104 dc = get_dc_ptr(hdc);
5105 if (!dc) return FALSE;
5107 if (!dxs)
5109 pos = buffer;
5110 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
5112 release_dc_ptr( dc );
5113 return FALSE;
5117 ret = get_char_positions( dc, str, count, pos, size );
5118 if (ret)
5120 if (dxs || nfit)
5122 for (i = 0; i < count; i++)
5124 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra;
5125 if (nfit && dx > (unsigned int)max_ext) break;
5126 if (dxs) dxs[i] = dx;
5128 if (nfit) *nfit = i;
5131 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra;
5132 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5135 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
5136 release_dc_ptr( dc );
5138 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
5139 return ret;
5142 /***********************************************************************
5143 * GetTextMetricsA (GDI32.@)
5145 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
5147 TEXTMETRICW tm32;
5149 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
5150 FONT_TextMetricWToA( &tm32, metrics );
5151 return TRUE;
5154 /***********************************************************************
5155 * GetTextMetricsW (GDI32.@)
5157 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
5159 PHYSDEV physdev;
5160 BOOL ret = FALSE;
5161 DC * dc = get_dc_ptr( hdc );
5162 if (!dc) return FALSE;
5164 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5165 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5167 if (ret)
5169 /* device layer returns values in device units
5170 * therefore we have to convert them to logical */
5172 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
5173 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
5174 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5175 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5176 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5177 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5178 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5179 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5180 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5181 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5182 ret = TRUE;
5184 TRACE("text metrics:\n"
5185 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5186 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5187 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5188 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5189 " PitchAndFamily = %02x\n"
5190 " --------------------\n"
5191 " InternalLeading = %i\n"
5192 " Ascent = %i\n"
5193 " Descent = %i\n"
5194 " Height = %i\n",
5195 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
5196 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
5197 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
5198 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5199 metrics->tmPitchAndFamily,
5200 metrics->tmInternalLeading,
5201 metrics->tmAscent,
5202 metrics->tmDescent,
5203 metrics->tmHeight );
5205 release_dc_ptr( dc );
5206 return ret;
5210 /***********************************************************************
5211 * GetOutlineTextMetricsA (GDI32.@)
5212 * Gets metrics for TrueType fonts.
5214 * NOTES
5215 * If the supplied buffer isn't big enough Windows partially fills it up to
5216 * its given length and returns that length.
5218 * RETURNS
5219 * Success: Non-zero or size of required buffer
5220 * Failure: 0
5222 UINT WINAPI GetOutlineTextMetricsA(
5223 HDC hdc, /* [in] Handle of device context */
5224 UINT cbData, /* [in] Size of metric data array */
5225 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
5227 char buf[512], *ptr;
5228 UINT ret, needed;
5229 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
5230 OUTLINETEXTMETRICA *output = lpOTM;
5231 INT left, len;
5233 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
5234 return 0;
5235 if(ret > sizeof(buf))
5236 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
5237 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
5239 needed = sizeof(OUTLINETEXTMETRICA);
5240 if(lpOTMW->otmpFamilyName)
5241 needed += WideCharToMultiByte(CP_ACP, 0,
5242 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
5243 NULL, 0, NULL, NULL);
5244 if(lpOTMW->otmpFaceName)
5245 needed += WideCharToMultiByte(CP_ACP, 0,
5246 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
5247 NULL, 0, NULL, NULL);
5248 if(lpOTMW->otmpStyleName)
5249 needed += WideCharToMultiByte(CP_ACP, 0,
5250 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
5251 NULL, 0, NULL, NULL);
5252 if(lpOTMW->otmpFullName)
5253 needed += WideCharToMultiByte(CP_ACP, 0,
5254 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
5255 NULL, 0, NULL, NULL);
5257 if(!lpOTM) {
5258 ret = needed;
5259 goto end;
5262 TRACE("needed = %d\n", needed);
5263 if(needed > cbData)
5264 /* Since the supplied buffer isn't big enough, we'll alloc one
5265 that is and memcpy the first cbData bytes into the lpOTM at
5266 the end. */
5267 output = HeapAlloc(GetProcessHeap(), 0, needed);
5269 ret = output->otmSize = min(needed, cbData);
5270 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
5271 output->otmFiller = 0;
5272 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
5273 output->otmfsSelection = lpOTMW->otmfsSelection;
5274 output->otmfsType = lpOTMW->otmfsType;
5275 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
5276 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
5277 output->otmItalicAngle = lpOTMW->otmItalicAngle;
5278 output->otmEMSquare = lpOTMW->otmEMSquare;
5279 output->otmAscent = lpOTMW->otmAscent;
5280 output->otmDescent = lpOTMW->otmDescent;
5281 output->otmLineGap = lpOTMW->otmLineGap;
5282 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
5283 output->otmsXHeight = lpOTMW->otmsXHeight;
5284 output->otmrcFontBox = lpOTMW->otmrcFontBox;
5285 output->otmMacAscent = lpOTMW->otmMacAscent;
5286 output->otmMacDescent = lpOTMW->otmMacDescent;
5287 output->otmMacLineGap = lpOTMW->otmMacLineGap;
5288 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
5289 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
5290 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
5291 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
5292 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
5293 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
5294 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
5295 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
5296 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
5299 ptr = (char*)(output + 1);
5300 left = needed - sizeof(*output);
5302 if(lpOTMW->otmpFamilyName) {
5303 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
5304 len = WideCharToMultiByte(CP_ACP, 0,
5305 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
5306 ptr, left, NULL, NULL);
5307 left -= len;
5308 ptr += len;
5309 } else
5310 output->otmpFamilyName = 0;
5312 if(lpOTMW->otmpFaceName) {
5313 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
5314 len = WideCharToMultiByte(CP_ACP, 0,
5315 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
5316 ptr, left, NULL, NULL);
5317 left -= len;
5318 ptr += len;
5319 } else
5320 output->otmpFaceName = 0;
5322 if(lpOTMW->otmpStyleName) {
5323 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
5324 len = WideCharToMultiByte(CP_ACP, 0,
5325 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
5326 ptr, left, NULL, NULL);
5327 left -= len;
5328 ptr += len;
5329 } else
5330 output->otmpStyleName = 0;
5332 if(lpOTMW->otmpFullName) {
5333 output->otmpFullName = (LPSTR)(ptr - (char*)output);
5334 len = WideCharToMultiByte(CP_ACP, 0,
5335 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
5336 ptr, left, NULL, NULL);
5337 left -= len;
5338 } else
5339 output->otmpFullName = 0;
5341 assert(left == 0);
5343 if(output != lpOTM) {
5344 memcpy(lpOTM, output, cbData);
5345 HeapFree(GetProcessHeap(), 0, output);
5347 /* check if the string offsets really fit into the provided size */
5348 /* FIXME: should we check string length as well? */
5349 /* make sure that we don't read/write beyond the provided buffer */
5350 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
5352 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
5353 lpOTM->otmpFamilyName = 0; /* doesn't fit */
5356 /* make sure that we don't read/write beyond the provided buffer */
5357 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
5359 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
5360 lpOTM->otmpFaceName = 0; /* doesn't fit */
5363 /* make sure that we don't read/write beyond the provided buffer */
5364 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
5366 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
5367 lpOTM->otmpStyleName = 0; /* doesn't fit */
5370 /* make sure that we don't read/write beyond the provided buffer */
5371 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
5373 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
5374 lpOTM->otmpFullName = 0; /* doesn't fit */
5378 end:
5379 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
5380 HeapFree(GetProcessHeap(), 0, lpOTMW);
5382 return ret;
5386 /***********************************************************************
5387 * GetOutlineTextMetricsW [GDI32.@]
5389 UINT WINAPI GetOutlineTextMetricsW(
5390 HDC hdc, /* [in] Handle of device context */
5391 UINT cbData, /* [in] Size of metric data array */
5392 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
5394 DC *dc = get_dc_ptr( hdc );
5395 OUTLINETEXTMETRICW *output = lpOTM;
5396 PHYSDEV dev;
5397 UINT ret;
5399 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5400 if(!dc) return 0;
5402 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5403 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5405 if (lpOTM && ret > cbData)
5407 output = HeapAlloc(GetProcessHeap(), 0, ret);
5408 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5411 if (lpOTM && ret)
5413 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
5414 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
5415 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5416 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5417 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5418 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5419 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5420 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5421 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5422 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5423 output->otmAscent = height_to_LP( dc, output->otmAscent);
5424 output->otmDescent = height_to_LP( dc, output->otmDescent);
5425 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5426 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5427 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5428 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5429 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5430 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5431 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5432 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5433 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5434 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5435 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5436 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5437 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5438 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5439 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5440 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5441 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5442 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5443 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5444 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5445 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5446 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5448 if(output != lpOTM)
5450 memcpy(lpOTM, output, cbData);
5451 HeapFree(GetProcessHeap(), 0, output);
5452 ret = cbData;
5455 release_dc_ptr(dc);
5456 return ret;
5459 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
5461 INT i, count = lastChar - firstChar + 1;
5462 UINT mbcp;
5463 UINT c;
5464 LPSTR str;
5466 if (count <= 0)
5467 return NULL;
5469 mbcp = GdiGetCodePage(hdc);
5470 switch (mbcp)
5472 case 932:
5473 case 936:
5474 case 949:
5475 case 950:
5476 case 1361:
5477 if (lastChar > 0xffff)
5478 return NULL;
5479 if ((firstChar ^ lastChar) > 0xff)
5480 return NULL;
5481 break;
5482 default:
5483 if (lastChar > 0xff)
5484 return NULL;
5485 mbcp = 0;
5486 break;
5489 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
5490 if (str == NULL)
5491 return NULL;
5493 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
5495 if (mbcp) {
5496 if (c > 0xff)
5497 str[i++] = (BYTE)(c >> 8);
5498 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
5499 str[i] = 0x1f; /* FIXME: use default character */
5500 else
5501 str[i] = (BYTE)c;
5503 else
5504 str[i] = (BYTE)c;
5506 str[i] = '\0';
5508 *pByteLen = i;
5510 return str;
5513 /***********************************************************************
5514 * GetCharWidthW (GDI32.@)
5515 * GetCharWidth32W (GDI32.@)
5517 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
5518 LPINT buffer )
5520 UINT i;
5521 BOOL ret;
5522 PHYSDEV dev;
5523 DC * dc = get_dc_ptr( hdc );
5525 if (!dc) return FALSE;
5527 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5528 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
5530 if (ret)
5532 /* convert device units to logical */
5533 for( i = firstChar; i <= lastChar; i++, buffer++ )
5534 *buffer = width_to_LP( dc, *buffer );
5536 release_dc_ptr( dc );
5537 return ret;
5541 /***********************************************************************
5542 * GetCharWidthA (GDI32.@)
5543 * GetCharWidth32A (GDI32.@)
5545 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
5546 LPINT buffer )
5548 INT i, wlen;
5549 LPSTR str;
5550 LPWSTR wstr;
5551 BOOL ret = TRUE;
5553 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
5554 if(str == NULL)
5555 return FALSE;
5557 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
5559 for(i = 0; i < wlen; i++)
5561 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
5563 ret = FALSE;
5564 break;
5566 buffer++;
5569 HeapFree(GetProcessHeap(), 0, str);
5570 HeapFree(GetProcessHeap(), 0, wstr);
5572 return ret;
5576 /* helper for nulldrv_ExtTextOut */
5577 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5578 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5580 UINT indices[3] = {0, 0, 0x20};
5581 unsigned int i;
5582 DWORD ret, size;
5583 int stride;
5585 indices[0] = index;
5586 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5588 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5590 index = indices[i];
5591 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
5592 if (ret != GDI_ERROR) break;
5595 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5596 if (!image) return ERROR_SUCCESS;
5598 image->ptr = NULL;
5599 image->free = NULL;
5600 if (!ret) /* empty glyph */
5602 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5603 return ERROR_SUCCESS;
5606 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5607 size = metrics->gmBlackBoxY * stride;
5609 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
5610 image->is_copy = TRUE;
5611 image->free = free_heap_bits;
5613 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
5614 if (ret == GDI_ERROR)
5616 HeapFree( GetProcessHeap(), 0, image->ptr );
5617 return ERROR_NOT_FOUND;
5619 return ERROR_SUCCESS;
5622 /* helper for nulldrv_ExtTextOut */
5623 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5624 LPCWSTR str, UINT count, const INT *dx )
5626 UINT i;
5627 RECT rect, bounds;
5629 reset_bounds( &bounds );
5630 for (i = 0; i < count; i++)
5632 GLYPHMETRICS metrics;
5634 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5636 rect.left = x + metrics.gmptGlyphOrigin.x;
5637 rect.top = y - metrics.gmptGlyphOrigin.y;
5638 rect.right = rect.left + metrics.gmBlackBoxX;
5639 rect.bottom = rect.top + metrics.gmBlackBoxY;
5640 add_bounds_rect( &bounds, &rect );
5642 if (dx)
5644 if (flags & ETO_PDY)
5646 x += dx[ i * 2 ];
5647 y += dx[ i * 2 + 1];
5649 else x += dx[ i ];
5651 else
5653 x += metrics.gmCellIncX;
5654 y += metrics.gmCellIncY;
5657 return bounds;
5660 /* helper for nulldrv_ExtTextOut */
5661 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5662 const struct gdi_image_bits *image, const RECT *clip )
5664 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5665 UINT i, count, max_count;
5666 LONG x, y;
5667 BYTE *ptr = image->ptr;
5668 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5669 POINT *pts;
5670 RECT rect, clipped_rect;
5672 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5673 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5674 rect.right = rect.left + metrics->gmBlackBoxX;
5675 rect.bottom = rect.top + metrics->gmBlackBoxY;
5676 if (!clip) clipped_rect = rect;
5677 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5679 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5680 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
5681 if (!pts) return;
5683 count = 0;
5684 ptr += (clipped_rect.top - rect.top) * stride;
5685 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5687 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5689 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5690 pts[count].x = rect.left + x;
5691 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5692 pts[count + 1].x = rect.left + x;
5693 if (pts[count + 1].x > pts[count].x)
5695 pts[count].y = pts[count + 1].y = y;
5696 count += 2;
5700 assert( count <= max_count );
5701 dp_to_lp( dc, pts, count );
5702 for (i = 0; i < count; i += 2) Polyline( dc->hSelf, pts + i, 2 );
5703 HeapFree( GetProcessHeap(), 0, pts );
5706 /***********************************************************************
5707 * nulldrv_ExtTextOut
5709 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5710 LPCWSTR str, UINT count, const INT *dx )
5712 DC *dc = get_nulldrv_dc( dev );
5713 UINT i;
5714 DWORD err;
5715 HGDIOBJ orig;
5716 HPEN pen;
5718 if (flags & ETO_OPAQUE)
5720 RECT rc = *rect;
5721 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, dc->backgroundColor ) );
5723 if (brush)
5725 orig = NtGdiSelectBrush( dev->hdc, brush );
5726 dp_to_lp( dc, (POINT *)&rc, 2 );
5727 PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5728 NtGdiSelectBrush( dev->hdc, orig );
5729 DeleteObject( brush );
5733 if (!count) return TRUE;
5735 if (dc->aa_flags != GGO_BITMAP)
5737 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5738 BITMAPINFO *info = (BITMAPINFO *)buffer;
5739 struct gdi_image_bits bits;
5740 struct bitblt_coords src, dst;
5741 PHYSDEV dst_dev;
5742 /* FIXME Subpixel modes */
5743 UINT aa_flags = GGO_GRAY4_BITMAP;
5745 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5746 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5747 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5748 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5750 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5751 src.x = src.visrect.left;
5752 src.y = src.visrect.top;
5753 src.width = src.visrect.right - src.visrect.left;
5754 src.height = src.visrect.bottom - src.visrect.top;
5755 dst = src;
5756 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5757 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5759 /* we can avoid the GetImage, just query the needed format */
5760 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5761 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5762 info->bmiHeader.biWidth = src.width;
5763 info->bmiHeader.biHeight = -src.height;
5764 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5765 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5766 if (!err || err == ERROR_BAD_FORMAT)
5768 /* make the source rectangle relative to the source bits */
5769 src.x = src.y = 0;
5770 src.visrect.left = src.visrect.top = 0;
5771 src.visrect.right = src.width;
5772 src.visrect.bottom = src.height;
5774 bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
5775 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5776 bits.is_copy = TRUE;
5777 bits.free = free_heap_bits;
5778 err = ERROR_SUCCESS;
5781 else
5783 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5784 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5785 if (!err && !bits.is_copy)
5787 void *ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
5788 if (!ptr)
5790 if (bits.free) bits.free( &bits );
5791 return ERROR_OUTOFMEMORY;
5793 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5794 if (bits.free) bits.free( &bits );
5795 bits.ptr = ptr;
5796 bits.is_copy = TRUE;
5797 bits.free = free_heap_bits;
5800 if (!err)
5802 /* make x,y relative to the image bits */
5803 x += src.visrect.left - dst.visrect.left;
5804 y += src.visrect.top - dst.visrect.top;
5805 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5806 aa_flags, str, count, dx );
5807 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5808 if (bits.free) bits.free( &bits );
5809 return !err;
5813 pen = CreatePen( PS_SOLID, 1, dc->textColor );
5814 orig = NtGdiSelectPen( dev->hdc, pen );
5816 for (i = 0; i < count; i++)
5818 GLYPHMETRICS metrics;
5819 struct gdi_image_bits image;
5821 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5822 if (err) continue;
5824 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5825 if (image.free) image.free( &image );
5827 if (dx)
5829 if (flags & ETO_PDY)
5831 x += dx[ i * 2 ];
5832 y += dx[ i * 2 + 1];
5834 else x += dx[ i ];
5836 else
5838 x += metrics.gmCellIncX;
5839 y += metrics.gmCellIncY;
5843 NtGdiSelectPen( dev->hdc, orig );
5844 DeleteObject( pen );
5845 return TRUE;
5849 /***********************************************************************
5850 * ExtTextOutA (GDI32.@)
5852 * See ExtTextOutW.
5854 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
5855 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
5857 INT wlen;
5858 UINT codepage;
5859 LPWSTR p;
5860 BOOL ret;
5861 LPINT lpDxW = NULL;
5863 if (count > INT_MAX) return FALSE;
5865 if (flags & ETO_GLYPH_INDEX)
5866 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
5868 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
5870 if (lpDx) {
5871 unsigned int i = 0, j = 0;
5873 /* allocate enough for a ETO_PDY */
5874 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
5875 while(i < count) {
5876 if(IsDBCSLeadByteEx(codepage, str[i]))
5878 if(flags & ETO_PDY)
5880 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
5881 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
5883 else
5884 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
5885 i = i + 2;
5887 else
5889 if(flags & ETO_PDY)
5891 lpDxW[j++] = lpDx[i * 2];
5892 lpDxW[j++] = lpDx[i * 2 + 1];
5894 else
5895 lpDxW[j++] = lpDx[i];
5896 i = i + 1;
5901 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
5903 HeapFree( GetProcessHeap(), 0, p );
5904 HeapFree( GetProcessHeap(), 0, lpDxW );
5905 return ret;
5908 /***********************************************************************
5909 * get_line_width
5911 * Scale the underline / strikeout line width.
5913 static inline int get_line_width( DC *dc, int metric_size )
5915 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5916 if (width == 0) width = 1;
5917 if (metric_size < 0) width = -width;
5918 return width;
5921 /***********************************************************************
5922 * ExtTextOutW (GDI32.@)
5924 * Draws text using the currently selected font, background color, and text color.
5927 * PARAMS
5928 * x,y [I] coordinates of string
5929 * flags [I]
5930 * ETO_GRAYED - undocumented on MSDN
5931 * ETO_OPAQUE - use background color for fill the rectangle
5932 * ETO_CLIPPED - clipping text to the rectangle
5933 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5934 * than encoded characters. Implies ETO_IGNORELANGUAGE
5935 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5936 * Affects BiDi ordering
5937 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5938 * ETO_PDY - unimplemented
5939 * ETO_NUMERICSLATIN - unimplemented always assumed -
5940 * do not translate numbers into locale representations
5941 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5942 * lprect [I] dimensions for clipping or/and opaquing
5943 * str [I] text string
5944 * count [I] number of symbols in string
5945 * lpDx [I] optional parameter with distance between drawing characters
5947 * RETURNS
5948 * Success: TRUE
5949 * Failure: FALSE
5951 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
5952 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
5954 BOOL ret = FALSE;
5955 LPWSTR reordered_str = (LPWSTR)str;
5956 WORD *glyphs = NULL;
5957 UINT align;
5958 DWORD layout;
5959 POINT pt;
5960 TEXTMETRICW tm;
5961 LOGFONTW lf;
5962 double cosEsc, sinEsc;
5963 INT char_extra;
5964 SIZE sz;
5965 RECT rc;
5966 POINT *deltas = NULL, width = {0, 0};
5967 DWORD type;
5968 DC * dc = get_dc_ptr( hdc );
5969 PHYSDEV physdev;
5970 INT breakRem;
5971 static int quietfixme = 0;
5973 if (!dc) return FALSE;
5974 if (count > INT_MAX) return FALSE;
5976 align = dc->textAlign;
5977 breakRem = dc->breakRem;
5978 layout = dc->layout;
5980 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5982 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5983 quietfixme = 1;
5986 update_dc( dc );
5987 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5988 type = GetObjectType(hdc);
5989 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
5991 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
5992 release_dc_ptr( dc );
5993 return ret;
5996 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5997 if (layout & LAYOUT_RTL)
5999 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
6000 align ^= TA_RTLREADING;
6003 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
6005 INT cGlyphs;
6006 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
6008 BIDI_Reorder( hdc, str, count, GCP_REORDER,
6009 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
6010 reordered_str, count, NULL, &glyphs, &cGlyphs);
6012 flags |= ETO_IGNORELANGUAGE;
6013 if (glyphs)
6015 flags |= ETO_GLYPH_INDEX;
6016 if (cGlyphs != count)
6017 count = cGlyphs;
6020 else if(flags & ETO_GLYPH_INDEX)
6021 glyphs = reordered_str;
6023 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
6024 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
6025 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->backgroundMode, dc->MapMode);
6027 if(align & TA_UPDATECP)
6029 pt = dc->cur_pos;
6030 x = pt.x;
6031 y = pt.y;
6034 GetTextMetricsW(hdc, &tm);
6035 GetObjectW(dc->hFont, sizeof(lf), &lf);
6037 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
6038 lf.lfEscapement = 0;
6040 if ((dc->GraphicsMode == GM_COMPATIBLE) &&
6041 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
6043 lf.lfEscapement = -lf.lfEscapement;
6046 if(lf.lfEscapement != 0)
6048 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
6049 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
6051 else
6053 cosEsc = 1;
6054 sinEsc = 0;
6057 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
6059 rc = *lprect;
6060 lp_to_dp(dc, (POINT*)&rc, 2);
6061 order_rect( &rc );
6062 if (flags & ETO_OPAQUE)
6063 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
6065 else flags &= ~ETO_CLIPPED;
6067 if(count == 0)
6069 ret = TRUE;
6070 goto done;
6073 pt.x = x;
6074 pt.y = y;
6075 lp_to_dp(dc, &pt, 1);
6076 x = pt.x;
6077 y = pt.y;
6079 char_extra = GetTextCharacterExtra(hdc);
6080 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
6081 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
6083 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
6085 UINT i;
6086 POINT total = {0, 0}, desired[2];
6088 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
6089 if (lpDx)
6091 if (flags & ETO_PDY)
6093 for (i = 0; i < count; i++)
6095 deltas[i].x = lpDx[i * 2] + char_extra;
6096 deltas[i].y = -lpDx[i * 2 + 1];
6099 else
6101 for (i = 0; i < count; i++)
6103 deltas[i].x = lpDx[i] + char_extra;
6104 deltas[i].y = 0;
6108 else
6110 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
6112 if (flags & ETO_GLYPH_INDEX)
6113 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
6114 else
6115 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
6117 deltas[0].x = dx[0];
6118 deltas[0].y = 0;
6119 for (i = 1; i < count; i++)
6121 deltas[i].x = dx[i] - dx[i - 1];
6122 deltas[i].y = 0;
6124 HeapFree( GetProcessHeap(), 0, dx );
6127 for(i = 0; i < count; i++)
6129 total.x += deltas[i].x;
6130 total.y += deltas[i].y;
6132 desired[0].x = desired[0].y = 0;
6134 desired[1].x = cosEsc * total.x + sinEsc * total.y;
6135 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
6137 lp_to_dp(dc, desired, 2);
6138 desired[1].x -= desired[0].x;
6139 desired[1].y -= desired[0].y;
6141 if (dc->GraphicsMode == GM_COMPATIBLE)
6143 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6144 desired[1].x = -desired[1].x;
6145 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6146 desired[1].y = -desired[1].y;
6149 deltas[i].x = desired[1].x - width.x;
6150 deltas[i].y = desired[1].y - width.y;
6152 width = desired[1];
6154 flags |= ETO_PDY;
6156 else
6158 POINT desired[2];
6160 if(flags & ETO_GLYPH_INDEX)
6161 GetTextExtentPointI(hdc, glyphs, count, &sz);
6162 else
6163 GetTextExtentPointW(hdc, reordered_str, count, &sz);
6164 desired[0].x = desired[0].y = 0;
6165 desired[1].x = sz.cx;
6166 desired[1].y = 0;
6167 lp_to_dp(dc, desired, 2);
6168 desired[1].x -= desired[0].x;
6169 desired[1].y -= desired[0].y;
6171 if (dc->GraphicsMode == GM_COMPATIBLE)
6173 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6174 desired[1].x = -desired[1].x;
6175 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6176 desired[1].y = -desired[1].y;
6178 width = desired[1];
6181 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
6182 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
6183 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
6185 case TA_LEFT:
6186 if (align & TA_UPDATECP)
6188 pt.x = x + width.x;
6189 pt.y = y + width.y;
6190 dp_to_lp(dc, &pt, 1);
6191 MoveToEx(hdc, pt.x, pt.y, NULL);
6193 break;
6195 case TA_CENTER:
6196 x -= width.x / 2;
6197 y -= width.y / 2;
6198 break;
6200 case TA_RIGHT:
6201 x -= width.x;
6202 y -= width.y;
6203 if (align & TA_UPDATECP)
6205 pt.x = x;
6206 pt.y = y;
6207 dp_to_lp(dc, &pt, 1);
6208 MoveToEx(hdc, pt.x, pt.y, NULL);
6210 break;
6213 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
6215 case TA_TOP:
6216 y += tm.tmAscent * cosEsc;
6217 x += tm.tmAscent * sinEsc;
6218 break;
6220 case TA_BOTTOM:
6221 y -= tm.tmDescent * cosEsc;
6222 x -= tm.tmDescent * sinEsc;
6223 break;
6225 case TA_BASELINE:
6226 break;
6229 if (dc->backgroundMode != TRANSPARENT)
6231 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
6233 if(!(flags & ETO_OPAQUE) || !lprect ||
6234 x < rc.left || x + width.x >= rc.right ||
6235 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
6237 RECT text_box;
6238 text_box.left = x;
6239 text_box.right = x + width.x;
6240 text_box.top = y - tm.tmAscent;
6241 text_box.bottom = y + tm.tmDescent;
6243 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
6244 if (!is_rect_empty( &text_box ))
6245 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
6250 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
6251 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
6253 done:
6254 HeapFree(GetProcessHeap(), 0, deltas);
6255 if(glyphs != reordered_str)
6256 HeapFree(GetProcessHeap(), 0, glyphs);
6257 if(reordered_str != str)
6258 HeapFree(GetProcessHeap(), 0, reordered_str);
6260 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
6262 int underlinePos, strikeoutPos;
6263 int underlineWidth, strikeoutWidth;
6264 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
6265 OUTLINETEXTMETRICW* otm = NULL;
6266 POINT pts[5];
6267 HPEN hpen = NtGdiSelectPen(hdc, GetStockObject(NULL_PEN));
6268 HBRUSH hbrush = CreateSolidBrush(dc->textColor);
6270 hbrush = NtGdiSelectBrush(hdc, hbrush);
6272 if(!size)
6274 underlinePos = 0;
6275 underlineWidth = tm.tmAscent / 20 + 1;
6276 strikeoutPos = tm.tmAscent / 2;
6277 strikeoutWidth = underlineWidth;
6279 else
6281 otm = HeapAlloc(GetProcessHeap(), 0, size);
6282 GetOutlineTextMetricsW(hdc, size, otm);
6283 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
6284 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
6285 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
6286 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
6287 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
6288 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
6289 HeapFree(GetProcessHeap(), 0, otm);
6293 if (lf.lfUnderline)
6295 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
6296 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
6297 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
6298 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
6299 pts[2].x = pts[1].x + underlineWidth * sinEsc;
6300 pts[2].y = pts[1].y + underlineWidth * cosEsc;
6301 pts[3].x = pts[0].x + underlineWidth * sinEsc;
6302 pts[3].y = pts[0].y + underlineWidth * cosEsc;
6303 pts[4].x = pts[0].x;
6304 pts[4].y = pts[0].y;
6305 dp_to_lp(dc, pts, 5);
6306 Polygon(hdc, pts, 5);
6309 if (lf.lfStrikeOut)
6311 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6312 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6313 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6314 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6315 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
6316 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
6317 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
6318 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
6319 pts[4].x = pts[0].x;
6320 pts[4].y = pts[0].y;
6321 dp_to_lp(dc, pts, 5);
6322 Polygon(hdc, pts, 5);
6325 NtGdiSelectPen(hdc, hpen);
6326 hbrush = NtGdiSelectBrush(hdc, hbrush);
6327 DeleteObject(hbrush);
6330 release_dc_ptr( dc );
6332 return ret;
6336 /***********************************************************************
6337 * TextOutA (GDI32.@)
6339 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
6341 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
6345 /***********************************************************************
6346 * TextOutW (GDI32.@)
6348 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
6350 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
6354 /***********************************************************************
6355 * PolyTextOutA (GDI32.@)
6357 * See PolyTextOutW.
6359 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
6361 for (; cStrings>0; cStrings--, pptxt++)
6362 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
6363 return FALSE;
6364 return TRUE;
6369 /***********************************************************************
6370 * PolyTextOutW (GDI32.@)
6372 * Draw several Strings
6374 * RETURNS
6375 * TRUE: Success.
6376 * FALSE: Failure.
6378 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
6380 for (; cStrings>0; cStrings--, pptxt++)
6381 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
6382 return FALSE;
6383 return TRUE;
6387 /***********************************************************************
6388 * SetMapperFlags (GDI32.@)
6390 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
6392 DC *dc = get_dc_ptr( hdc );
6393 DWORD ret = GDI_ERROR;
6395 if (dc)
6397 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
6398 flags = physdev->funcs->pSetMapperFlags( physdev, flags );
6399 if (flags != GDI_ERROR)
6401 ret = dc->mapperFlags;
6402 dc->mapperFlags = flags;
6404 release_dc_ptr( dc );
6406 return ret;
6409 /***********************************************************************
6410 * GetAspectRatioFilterEx (GDI32.@)
6412 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
6414 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
6415 return FALSE;
6419 /***********************************************************************
6420 * GetCharABCWidthsA (GDI32.@)
6422 * See GetCharABCWidthsW.
6424 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
6425 LPABC abc )
6427 INT i, wlen;
6428 LPSTR str;
6429 LPWSTR wstr;
6430 BOOL ret = TRUE;
6432 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
6433 if (str == NULL)
6434 return FALSE;
6436 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
6437 if (wstr == NULL)
6439 HeapFree(GetProcessHeap(), 0, str);
6440 return FALSE;
6443 for(i = 0; i < wlen; i++)
6445 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
6447 ret = FALSE;
6448 break;
6450 abc++;
6453 HeapFree(GetProcessHeap(), 0, str);
6454 HeapFree(GetProcessHeap(), 0, wstr);
6456 return ret;
6460 /******************************************************************************
6461 * GetCharABCWidthsW [GDI32.@]
6463 * Retrieves widths of characters in range.
6465 * PARAMS
6466 * hdc [I] Handle of device context
6467 * firstChar [I] First character in range to query
6468 * lastChar [I] Last character in range to query
6469 * abc [O] Address of character-width structure
6471 * NOTES
6472 * Only works with TrueType fonts
6474 * RETURNS
6475 * Success: TRUE
6476 * Failure: FALSE
6478 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
6479 LPABC abc )
6481 DC *dc = get_dc_ptr(hdc);
6482 PHYSDEV dev;
6483 unsigned int i;
6484 BOOL ret;
6485 TEXTMETRICW tm;
6487 if (!dc) return FALSE;
6489 if (!abc)
6491 release_dc_ptr( dc );
6492 return FALSE;
6495 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
6496 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
6497 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
6499 release_dc_ptr( dc );
6500 return FALSE;
6503 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6504 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
6505 if (ret)
6507 /* convert device units to logical */
6508 for( i = firstChar; i <= lastChar; i++, abc++ ) {
6509 abc->abcA = width_to_LP(dc, abc->abcA);
6510 abc->abcB = width_to_LP(dc, abc->abcB);
6511 abc->abcC = width_to_LP(dc, abc->abcC);
6515 release_dc_ptr( dc );
6516 return ret;
6520 /******************************************************************************
6521 * GetCharABCWidthsI [GDI32.@]
6523 * Retrieves widths of characters in range.
6525 * PARAMS
6526 * hdc [I] Handle of device context
6527 * firstChar [I] First glyphs in range to query
6528 * count [I] Last glyphs in range to query
6529 * pgi [i] Array of glyphs to query
6530 * abc [O] Address of character-width structure
6532 * NOTES
6533 * Only works with TrueType fonts
6535 * RETURNS
6536 * Success: TRUE
6537 * Failure: FALSE
6539 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
6540 LPWORD pgi, LPABC abc)
6542 DC *dc = get_dc_ptr(hdc);
6543 PHYSDEV dev;
6544 unsigned int i;
6545 BOOL ret;
6547 if (!dc) return FALSE;
6549 if (!abc)
6551 release_dc_ptr( dc );
6552 return FALSE;
6555 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6556 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
6557 if (ret)
6559 /* convert device units to logical */
6560 for( i = 0; i < count; i++, abc++ ) {
6561 abc->abcA = width_to_LP(dc, abc->abcA);
6562 abc->abcB = width_to_LP(dc, abc->abcB);
6563 abc->abcC = width_to_LP(dc, abc->abcC);
6567 release_dc_ptr( dc );
6568 return ret;
6572 /***********************************************************************
6573 * GetGlyphOutlineA (GDI32.@)
6575 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
6576 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
6577 LPVOID lpBuffer, const MAT2 *lpmat2 )
6579 if (!lpmat2) return GDI_ERROR;
6581 if(!(fuFormat & GGO_GLYPH_INDEX)) {
6582 UINT cp;
6583 int len;
6584 char mbchs[2];
6585 WCHAR wChar;
6587 cp = GdiGetCodePage(hdc);
6588 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
6589 len = 2;
6590 mbchs[0] = (uChar & 0xff00) >> 8;
6591 mbchs[1] = (uChar & 0xff);
6592 } else {
6593 len = 1;
6594 mbchs[0] = (uChar & 0xff);
6596 wChar = 0;
6597 MultiByteToWideChar(cp, 0, mbchs, len, &wChar, 1);
6598 uChar = wChar;
6601 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
6602 lpmat2);
6605 /***********************************************************************
6606 * GetGlyphOutlineW (GDI32.@)
6608 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
6609 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
6610 LPVOID lpBuffer, const MAT2 *lpmat2 )
6612 DC *dc;
6613 DWORD ret;
6614 PHYSDEV dev;
6616 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
6617 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
6619 if (!lpmat2) return GDI_ERROR;
6621 dc = get_dc_ptr(hdc);
6622 if(!dc) return GDI_ERROR;
6624 uChar &= 0xffff;
6626 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6627 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
6628 release_dc_ptr( dc );
6629 return ret;
6633 /***********************************************************************
6634 * CreateScalableFontResourceA (GDI32.@)
6636 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
6637 LPCSTR lpszResourceFile,
6638 LPCSTR lpszFontFile,
6639 LPCSTR lpszCurrentPath )
6641 LPWSTR lpszResourceFileW = NULL;
6642 LPWSTR lpszFontFileW = NULL;
6643 LPWSTR lpszCurrentPathW = NULL;
6644 int len;
6645 BOOL ret;
6647 if (lpszResourceFile)
6649 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
6650 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6651 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
6654 if (lpszFontFile)
6656 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
6657 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6658 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
6661 if (lpszCurrentPath)
6663 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
6664 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6665 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
6668 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
6669 lpszFontFileW, lpszCurrentPathW);
6671 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
6672 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
6673 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
6675 return ret;
6678 #define NE_FFLAGS_LIBMODULE 0x8000
6679 #define NE_OSFLAGS_WINDOWS 0x02
6681 static const char dos_string[0x40] = "This is a TrueType resource file";
6682 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
6684 #include <pshpack1.h>
6685 struct fontdir
6687 WORD num_of_resources;
6688 WORD res_id;
6689 WORD dfVersion;
6690 DWORD dfSize;
6691 CHAR dfCopyright[60];
6692 WORD dfType;
6693 WORD dfPoints;
6694 WORD dfVertRes;
6695 WORD dfHorizRes;
6696 WORD dfAscent;
6697 WORD dfInternalLeading;
6698 WORD dfExternalLeading;
6699 BYTE dfItalic;
6700 BYTE dfUnderline;
6701 BYTE dfStrikeOut;
6702 WORD dfWeight;
6703 BYTE dfCharSet;
6704 WORD dfPixWidth;
6705 WORD dfPixHeight;
6706 BYTE dfPitchAndFamily;
6707 WORD dfAvgWidth;
6708 WORD dfMaxWidth;
6709 BYTE dfFirstChar;
6710 BYTE dfLastChar;
6711 BYTE dfDefaultChar;
6712 BYTE dfBreakChar;
6713 WORD dfWidthBytes;
6714 DWORD dfDevice;
6715 DWORD dfFace;
6716 DWORD dfReserved;
6717 CHAR szFaceName[LF_FACESIZE];
6719 #include <poppack.h>
6721 #include <pshpack2.h>
6723 struct ne_typeinfo
6725 WORD type_id;
6726 WORD count;
6727 DWORD res;
6730 struct ne_nameinfo
6732 WORD off;
6733 WORD len;
6734 WORD flags;
6735 WORD id;
6736 DWORD res;
6739 struct rsrc_tab
6741 WORD align;
6742 struct ne_typeinfo fontdir_type;
6743 struct ne_nameinfo fontdir_name;
6744 struct ne_typeinfo scalable_type;
6745 struct ne_nameinfo scalable_name;
6746 WORD end_of_rsrc;
6747 BYTE fontdir_res_name[8];
6750 #include <poppack.h>
6752 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
6754 BOOL ret = FALSE;
6755 HANDLE file;
6756 DWORD size, written;
6757 BYTE *ptr, *start;
6758 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
6759 char *font_fileA, *last_part, *ext;
6760 IMAGE_DOS_HEADER dos;
6761 IMAGE_OS2_HEADER ne =
6763 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
6764 0, 0, 0, 0, 0, 0,
6765 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
6766 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
6768 struct rsrc_tab rsrc_tab =
6771 { 0x8007, 1, 0 },
6772 { 0, 0, 0x0c50, 0x2c, 0 },
6773 { 0x80cc, 1, 0 },
6774 { 0, 0, 0x0c50, 0x8001, 0 },
6776 { 7,'F','O','N','T','D','I','R'}
6779 memset( &dos, 0, sizeof(dos) );
6780 dos.e_magic = IMAGE_DOS_SIGNATURE;
6781 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
6783 /* import name is last part\0, resident name is last part without extension
6784 non-resident name is "FONTRES:" + lfFaceName */
6786 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
6787 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
6788 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
6790 last_part = strrchr( font_fileA, '\\' );
6791 if (last_part) last_part++;
6792 else last_part = font_fileA;
6793 import_name_len = strlen( last_part ) + 1;
6795 ext = strchr( last_part, '.' );
6796 if (ext) res_name_len = ext - last_part;
6797 else res_name_len = import_name_len - 1;
6799 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
6801 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
6802 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
6803 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
6804 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
6805 ne.ne_cbenttab = 2;
6806 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
6808 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
6809 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
6810 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
6811 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
6813 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
6814 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
6816 if (!ptr)
6818 HeapFree( GetProcessHeap(), 0, font_fileA );
6819 return FALSE;
6822 memcpy( ptr, &dos, sizeof(dos) );
6823 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
6824 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
6826 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
6827 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
6829 ptr = start + dos.e_lfanew + ne.ne_restab;
6830 *ptr++ = res_name_len;
6831 memcpy( ptr, last_part, res_name_len );
6833 ptr = start + dos.e_lfanew + ne.ne_imptab;
6834 *ptr++ = import_name_len;
6835 memcpy( ptr, last_part, import_name_len );
6837 ptr = start + ne.ne_nrestab;
6838 *ptr++ = non_res_name_len;
6839 memcpy( ptr, FONTRES, sizeof(FONTRES) );
6840 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
6842 ptr = start + (rsrc_tab.scalable_name.off << 4);
6843 memcpy( ptr, font_fileA, font_file_len );
6845 ptr = start + (rsrc_tab.fontdir_name.off << 4);
6846 memcpy( ptr, fontdir, fontdir->dfSize );
6848 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
6849 if (file != INVALID_HANDLE_VALUE)
6851 if (WriteFile( file, start, size, &written, NULL ) && written == size)
6852 ret = TRUE;
6853 CloseHandle( file );
6856 HeapFree( GetProcessHeap(), 0, start );
6857 HeapFree( GetProcessHeap(), 0, font_fileA );
6859 return ret;
6862 /***********************************************************************
6863 * CreateScalableFontResourceW (GDI32.@)
6865 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
6866 LPCWSTR font_file, LPCWSTR font_path )
6868 struct fontdir fontdir = { 0 };
6869 struct gdi_font *font = NULL;
6870 WCHAR path[MAX_PATH];
6872 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
6873 debugstr_w(font_file), debugstr_w(font_path) );
6875 if (!font_funcs) return FALSE;
6877 if (!font_file) goto done;
6878 if (font_path && font_path[0])
6880 int len = lstrlenW( font_path ) + lstrlenW( font_file ) + 2;
6881 if (len > MAX_PATH) goto done;
6882 lstrcpynW( path, font_path, MAX_PATH );
6883 lstrcatW( path, L"\\" );
6884 lstrcatW( path, font_file );
6886 else if (!GetFullPathNameW( font_file, MAX_PATH, path, NULL )) goto done;
6888 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6889 font->lf.lfHeight = 100;
6890 if (!font_funcs->load_font( font )) goto done;
6891 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6893 if (!(font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) goto done;
6895 fontdir.num_of_resources = 1;
6896 fontdir.res_id = 0;
6897 fontdir.dfVersion = 0x200;
6898 fontdir.dfSize = sizeof(fontdir);
6899 strcpy( fontdir.dfCopyright, "Wine fontdir" );
6900 fontdir.dfType = 0x4003; /* 0x0080 set if private */
6901 fontdir.dfPoints = font->otm.otmEMSquare;
6902 fontdir.dfVertRes = 72;
6903 fontdir.dfHorizRes = 72;
6904 fontdir.dfAscent = font->otm.otmTextMetrics.tmAscent;
6905 fontdir.dfInternalLeading = font->otm.otmTextMetrics.tmInternalLeading;
6906 fontdir.dfExternalLeading = font->otm.otmTextMetrics.tmExternalLeading;
6907 fontdir.dfItalic = font->otm.otmTextMetrics.tmItalic;
6908 fontdir.dfUnderline = font->otm.otmTextMetrics.tmUnderlined;
6909 fontdir.dfStrikeOut = font->otm.otmTextMetrics.tmStruckOut;
6910 fontdir.dfWeight = font->otm.otmTextMetrics.tmWeight;
6911 fontdir.dfCharSet = font->otm.otmTextMetrics.tmCharSet;
6912 fontdir.dfPixWidth = 0;
6913 fontdir.dfPixHeight = font->otm.otmTextMetrics.tmHeight;
6914 fontdir.dfPitchAndFamily = font->otm.otmTextMetrics.tmPitchAndFamily;
6915 fontdir.dfAvgWidth = font->otm.otmTextMetrics.tmAveCharWidth;
6916 fontdir.dfMaxWidth = font->otm.otmTextMetrics.tmMaxCharWidth;
6917 fontdir.dfFirstChar = font->otm.otmTextMetrics.tmFirstChar;
6918 fontdir.dfLastChar = font->otm.otmTextMetrics.tmLastChar;
6919 fontdir.dfDefaultChar = font->otm.otmTextMetrics.tmDefaultChar;
6920 fontdir.dfBreakChar = font->otm.otmTextMetrics.tmBreakChar;
6921 fontdir.dfWidthBytes = 0;
6922 fontdir.dfDevice = 0;
6923 fontdir.dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
6924 fontdir.dfReserved = 0;
6925 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)font->otm.otmpFamilyName, -1,
6926 fontdir.szFaceName, LF_FACESIZE, NULL, NULL );
6927 free_gdi_font( font );
6929 if (hidden) fontdir.dfType |= 0x80;
6930 return create_fot( resource_file, font_file, &fontdir );
6932 done:
6933 if (font) free_gdi_font( font );
6934 SetLastError( ERROR_INVALID_PARAMETER );
6935 return FALSE;
6938 /*************************************************************************
6939 * GetKerningPairsA (GDI32.@)
6941 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
6942 LPKERNINGPAIR kern_pairA )
6944 UINT cp;
6945 CPINFO cpi;
6946 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
6947 KERNINGPAIR *kern_pairW;
6949 if (!cPairs && kern_pairA)
6951 SetLastError(ERROR_INVALID_PARAMETER);
6952 return 0;
6955 cp = GdiGetCodePage(hDC);
6957 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
6958 * to fail on an invalid character for CP_SYMBOL.
6960 cpi.DefaultChar[0] = 0;
6961 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
6963 FIXME("Can't find codepage %u info\n", cp);
6964 return 0;
6967 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
6968 if (!total_kern_pairs) return 0;
6970 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
6971 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
6973 for (i = 0; i < total_kern_pairs; i++)
6975 char first, second;
6977 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
6978 continue;
6980 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
6981 continue;
6983 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
6984 continue;
6986 if (kern_pairA)
6988 if (kern_pairs_copied >= cPairs) break;
6990 kern_pairA->wFirst = (BYTE)first;
6991 kern_pairA->wSecond = (BYTE)second;
6992 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
6993 kern_pairA++;
6995 kern_pairs_copied++;
6998 HeapFree(GetProcessHeap(), 0, kern_pairW);
7000 return kern_pairs_copied;
7003 /*************************************************************************
7004 * GetKerningPairsW (GDI32.@)
7006 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
7007 LPKERNINGPAIR lpKerningPairs )
7009 DC *dc;
7010 DWORD ret;
7011 PHYSDEV dev;
7013 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
7015 if (!cPairs && lpKerningPairs)
7017 SetLastError(ERROR_INVALID_PARAMETER);
7018 return 0;
7021 dc = get_dc_ptr(hDC);
7022 if (!dc) return 0;
7024 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
7025 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
7026 release_dc_ptr( dc );
7027 return ret;
7030 /*************************************************************************
7031 * TranslateCharsetInfo [GDI32.@]
7033 * Fills a CHARSETINFO structure for a character set, code page, or
7034 * font. This allows making the correspondence between different labels
7035 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
7036 * of the same encoding.
7038 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
7039 * only one codepage should be set in *lpSrc.
7041 * RETURNS
7042 * TRUE on success, FALSE on failure.
7045 BOOL WINAPI TranslateCharsetInfo(
7046 LPDWORD lpSrc, /* [in]
7047 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
7048 if flags == TCI_SRCCHARSET: a character set value
7049 if flags == TCI_SRCCODEPAGE: a code page value
7051 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
7052 DWORD flags /* [in] determines interpretation of lpSrc */)
7054 int index = 0;
7055 switch (flags) {
7056 case TCI_SRCFONTSIG:
7057 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
7058 break;
7059 case TCI_SRCCODEPAGE:
7060 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
7061 break;
7062 case TCI_SRCCHARSET:
7063 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
7064 break;
7065 default:
7066 return FALSE;
7068 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
7069 *lpCs = FONT_tci[index];
7070 return TRUE;
7073 /*************************************************************************
7074 * GetFontLanguageInfo (GDI32.@)
7076 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
7078 FONTSIGNATURE fontsig;
7079 static const DWORD GCP_DBCS_MASK=FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB,
7080 GCP_DIACRITIC_MASK=0x00000000,
7081 FLI_GLYPHS_MASK=0x00000000,
7082 GCP_GLYPHSHAPE_MASK=FS_ARABIC,
7083 GCP_KASHIDA_MASK=0x00000000,
7084 GCP_LIGATE_MASK=0x00000000,
7085 GCP_REORDER_MASK=FS_HEBREW|FS_ARABIC;
7087 DWORD result=0;
7089 GetTextCharsetInfo( hdc, &fontsig, 0 );
7090 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
7092 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
7093 result|=GCP_DBCS;
7095 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
7096 result|=GCP_DIACRITIC;
7098 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
7099 result|=FLI_GLYPHS;
7101 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
7102 result|=GCP_GLYPHSHAPE;
7104 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
7105 result|=GCP_KASHIDA;
7107 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
7108 result|=GCP_LIGATE;
7110 if( GetKerningPairsW( hdc, 0, NULL ) )
7111 result|=GCP_USEKERNING;
7113 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
7114 if( GetTextAlign( hdc) & TA_RTLREADING )
7115 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
7116 result|=GCP_REORDER;
7118 return result;
7122 /*************************************************************************
7123 * GetFontData [GDI32.@]
7125 * Retrieve data for TrueType font.
7127 * RETURNS
7129 * success: Number of bytes returned
7130 * failure: GDI_ERROR
7132 * NOTES
7134 * Calls SetLastError()
7137 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
7138 LPVOID buffer, DWORD length)
7140 DC *dc = get_dc_ptr(hdc);
7141 PHYSDEV dev;
7142 DWORD ret;
7144 if(!dc) return GDI_ERROR;
7146 dev = GET_DC_PHYSDEV( dc, pGetFontData );
7147 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
7148 release_dc_ptr( dc );
7149 return ret;
7152 /*************************************************************************
7153 * GetGlyphIndicesA [GDI32.@]
7155 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
7156 LPWORD pgi, DWORD flags)
7158 DWORD ret;
7159 WCHAR *lpstrW;
7160 INT countW;
7162 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7163 hdc, debugstr_an(lpstr, count), count, pgi, flags);
7165 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
7166 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
7167 HeapFree(GetProcessHeap(), 0, lpstrW);
7169 return ret;
7172 /*************************************************************************
7173 * GetGlyphIndicesW [GDI32.@]
7175 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
7176 LPWORD pgi, DWORD flags)
7178 DC *dc = get_dc_ptr(hdc);
7179 PHYSDEV dev;
7180 DWORD ret;
7182 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7183 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
7185 if(!dc) return GDI_ERROR;
7187 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
7188 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
7189 release_dc_ptr( dc );
7190 return ret;
7193 /*************************************************************************
7194 * GetCharacterPlacementA [GDI32.@]
7196 * See GetCharacterPlacementW.
7198 * NOTES:
7199 * the web browser control of ie4 calls this with dwFlags=0
7201 DWORD WINAPI
7202 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
7203 INT nMaxExtent, GCP_RESULTSA *lpResults,
7204 DWORD dwFlags)
7206 WCHAR *lpStringW;
7207 INT uCountW;
7208 GCP_RESULTSW resultsW;
7209 DWORD ret;
7210 UINT font_cp;
7212 TRACE("%s, %d, %d, 0x%08x\n",
7213 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
7215 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
7217 if (!lpResults)
7219 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, NULL, dwFlags);
7220 HeapFree(GetProcessHeap(), 0, lpStringW);
7221 return ret;
7224 /* both structs are equal in size */
7225 memcpy(&resultsW, lpResults, sizeof(resultsW));
7227 if(lpResults->lpOutString)
7228 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
7230 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
7232 lpResults->nGlyphs = resultsW.nGlyphs;
7233 lpResults->nMaxFit = resultsW.nMaxFit;
7235 if(lpResults->lpOutString) {
7236 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
7237 lpResults->lpOutString, uCount, NULL, NULL );
7240 HeapFree(GetProcessHeap(), 0, lpStringW);
7241 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
7243 return ret;
7246 static int kern_pair(const KERNINGPAIR *kern, int count, WCHAR c1, WCHAR c2)
7248 int i;
7250 for (i = 0; i < count; i++)
7252 if (kern[i].wFirst == c1 && kern[i].wSecond == c2)
7253 return kern[i].iKernAmount;
7256 return 0;
7259 static int *kern_string(HDC hdc, const WCHAR *str, int len, int *kern_total)
7261 int i, count;
7262 KERNINGPAIR *kern = NULL;
7263 int *ret;
7265 *kern_total = 0;
7267 ret = heap_alloc(len * sizeof(*ret));
7268 if (!ret) return NULL;
7270 count = GetKerningPairsW(hdc, 0, NULL);
7271 if (count)
7273 kern = heap_alloc(count * sizeof(*kern));
7274 if (!kern)
7276 heap_free(ret);
7277 return NULL;
7280 GetKerningPairsW(hdc, count, kern);
7283 for (i = 0; i < len - 1; i++)
7285 ret[i] = kern_pair(kern, count, str[i], str[i + 1]);
7286 *kern_total += ret[i];
7289 ret[len - 1] = 0; /* no kerning for last element */
7291 heap_free(kern);
7292 return ret;
7295 /*************************************************************************
7296 * GetCharacterPlacementW [GDI32.@]
7298 * Retrieve information about a string. This includes the width, reordering,
7299 * Glyphing and so on.
7301 * RETURNS
7303 * The width and height of the string if successful, 0 if failed.
7305 * BUGS
7307 * All flags except GCP_REORDER are not yet implemented.
7308 * Reordering is not 100% compliant to the Windows BiDi method.
7309 * Caret positioning is not yet implemented for BiDi.
7310 * Classes are not yet implemented.
7313 DWORD WINAPI
7314 GetCharacterPlacementW(
7315 HDC hdc, /* [in] Device context for which the rendering is to be done */
7316 LPCWSTR lpString, /* [in] The string for which information is to be returned */
7317 INT uCount, /* [in] Number of WORDS in string. */
7318 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
7319 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
7320 DWORD dwFlags /* [in] Flags specifying how to process the string */
7323 DWORD ret=0;
7324 SIZE size;
7325 UINT i, nSet;
7326 int *kern = NULL, kern_total = 0;
7328 TRACE("%s, %d, %d, 0x%08x\n",
7329 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
7331 if (!uCount)
7332 return 0;
7334 if (!lpResults)
7335 return GetTextExtentPoint32W(hdc, lpString, uCount, &size) ? MAKELONG(size.cx, size.cy) : 0;
7337 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
7338 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
7339 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
7340 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
7341 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
7343 if (dwFlags & ~(GCP_REORDER | GCP_USEKERNING))
7344 FIXME("flags 0x%08x ignored\n", dwFlags);
7345 if (lpResults->lpClass)
7346 FIXME("classes not implemented\n");
7347 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
7348 FIXME("Caret positions for complex scripts not implemented\n");
7350 nSet = (UINT)uCount;
7351 if (nSet > lpResults->nGlyphs)
7352 nSet = lpResults->nGlyphs;
7354 /* return number of initialized fields */
7355 lpResults->nGlyphs = nSet;
7357 if (!(dwFlags & GCP_REORDER))
7359 /* Treat the case where no special handling was requested in a fastpath way */
7360 /* copy will do if the GCP_REORDER flag is not set */
7361 if (lpResults->lpOutString)
7362 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
7364 if (lpResults->lpOrder)
7366 for (i = 0; i < nSet; i++)
7367 lpResults->lpOrder[i] = i;
7370 else
7372 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
7373 nSet, lpResults->lpOrder, NULL, NULL );
7376 if (dwFlags & GCP_USEKERNING)
7378 kern = kern_string(hdc, lpString, nSet, &kern_total);
7379 if (!kern)
7381 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
7382 return 0;
7386 /* FIXME: Will use the placement chars */
7387 if (lpResults->lpDx)
7389 int c;
7390 for (i = 0; i < nSet; i++)
7392 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
7394 lpResults->lpDx[i] = c;
7395 if (dwFlags & GCP_USEKERNING)
7396 lpResults->lpDx[i] += kern[i];
7401 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
7403 int pos = 0;
7405 lpResults->lpCaretPos[0] = 0;
7406 for (i = 0; i < nSet - 1; i++)
7408 if (dwFlags & GCP_USEKERNING)
7409 pos += kern[i];
7411 if (GetTextExtentPoint32W(hdc, &lpString[i], 1, &size))
7412 lpResults->lpCaretPos[i + 1] = (pos += size.cx);
7416 if (lpResults->lpGlyphs)
7417 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
7419 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
7420 ret = MAKELONG(size.cx + kern_total, size.cy);
7422 heap_free(kern);
7424 return ret;
7427 /*************************************************************************
7428 * GetCharABCWidthsFloatA [GDI32.@]
7430 * See GetCharABCWidthsFloatW.
7432 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
7434 INT i, wlen;
7435 LPSTR str;
7436 LPWSTR wstr;
7437 BOOL ret = TRUE;
7439 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
7440 if (str == NULL)
7441 return FALSE;
7443 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
7445 for (i = 0; i < wlen; i++)
7447 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
7449 ret = FALSE;
7450 break;
7452 abcf++;
7455 HeapFree( GetProcessHeap(), 0, str );
7456 HeapFree( GetProcessHeap(), 0, wstr );
7458 return ret;
7461 /*************************************************************************
7462 * GetCharABCWidthsFloatW [GDI32.@]
7464 * Retrieves widths of a range of characters.
7466 * PARAMS
7467 * hdc [I] Handle to device context.
7468 * first [I] First character in range to query.
7469 * last [I] Last character in range to query.
7470 * abcf [O] Array of LPABCFLOAT structures.
7472 * RETURNS
7473 * Success: TRUE
7474 * Failure: FALSE
7476 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
7478 UINT i;
7479 ABC *abc;
7480 PHYSDEV dev;
7481 BOOL ret = FALSE;
7482 DC *dc = get_dc_ptr( hdc );
7484 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
7486 if (!dc) return FALSE;
7488 if (!abcf) goto done;
7489 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
7491 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
7492 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
7493 if (ret)
7495 /* convert device units to logical */
7496 FLOAT scale = fabs( dc->xformVport2World.eM11 );
7497 for (i = first; i <= last; i++, abcf++)
7499 abcf->abcfA = abc[i - first].abcA * scale;
7500 abcf->abcfB = abc[i - first].abcB * scale;
7501 abcf->abcfC = abc[i - first].abcC * scale;
7504 HeapFree( GetProcessHeap(), 0, abc );
7506 done:
7507 release_dc_ptr( dc );
7508 return ret;
7511 /*************************************************************************
7512 * GetCharWidthFloatA [GDI32.@]
7514 BOOL WINAPI GetCharWidthFloatA( HDC hdc, UINT first, UINT last, float *buffer )
7516 WCHAR *wstr;
7517 int i, wlen;
7518 char *str;
7520 if (!(str = FONT_GetCharsByRangeA( hdc, first, last, &i )))
7521 return FALSE;
7522 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
7523 heap_free(str);
7525 for (i = 0; i < wlen; ++i)
7527 if (!GetCharWidthFloatW( hdc, wstr[i], wstr[i], &buffer[i] ))
7529 heap_free(wstr);
7530 return FALSE;
7533 heap_free(wstr);
7534 return TRUE;
7537 /*************************************************************************
7538 * GetCharWidthFloatW [GDI32.@]
7540 BOOL WINAPI GetCharWidthFloatW( HDC hdc, UINT first, UINT last, float *buffer )
7542 DC *dc = get_dc_ptr( hdc );
7543 int *ibuffer;
7544 PHYSDEV dev;
7545 BOOL ret;
7546 UINT i;
7548 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc, first, last, buffer);
7550 if (!dc) return FALSE;
7552 if (!(ibuffer = heap_alloc( (last - first + 1) * sizeof(int) )))
7554 release_dc_ptr( dc );
7555 return FALSE;
7558 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
7559 if ((ret = dev->funcs->pGetCharWidth( dev, first, last, ibuffer )))
7561 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
7562 for (i = first; i <= last; ++i)
7563 buffer[i - first] = ibuffer[i - first] * scale;
7566 heap_free(ibuffer);
7567 return ret;
7570 /***********************************************************************
7572 * Font Resource API *
7574 ***********************************************************************/
7576 /***********************************************************************
7577 * AddFontResourceA (GDI32.@)
7579 INT WINAPI AddFontResourceA( LPCSTR str )
7581 return AddFontResourceExA( str, 0, NULL);
7584 /***********************************************************************
7585 * AddFontResourceW (GDI32.@)
7587 INT WINAPI AddFontResourceW( LPCWSTR str )
7589 return AddFontResourceExW(str, 0, NULL);
7593 /***********************************************************************
7594 * AddFontResourceExA (GDI32.@)
7596 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
7598 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
7599 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7600 INT ret;
7602 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
7603 ret = AddFontResourceExW(strW, fl, pdv);
7604 HeapFree(GetProcessHeap(), 0, strW);
7605 return ret;
7608 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
7610 HRSRC rsrc = FindResourceW(hModule, name, type);
7611 HGLOBAL hMem = LoadResource(hModule, rsrc);
7612 LPVOID *pMem = LockResource(hMem);
7613 int *num_total = (int *)lParam;
7614 DWORD num_in_res;
7616 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
7617 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
7619 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
7620 return FALSE;
7623 *num_total += num_in_res;
7624 return TRUE;
7627 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
7629 HANDLE file, mapping;
7630 void *ptr;
7632 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
7633 if (file == INVALID_HANDLE_VALUE) return NULL;
7635 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
7637 CloseHandle( file );
7638 return NULL;
7641 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
7642 CloseHandle( file );
7643 if (!mapping) return NULL;
7645 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
7646 CloseHandle( mapping );
7648 return ptr;
7651 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
7653 WORD align, type_id, count;
7654 DWORD res_off;
7656 if (size < rsrc_off + 10) return NULL;
7657 align = *(WORD *)(ptr + rsrc_off);
7658 rsrc_off += 2;
7659 type_id = *(WORD *)(ptr + rsrc_off);
7660 while (type_id && type_id != type)
7662 count = *(WORD *)(ptr + rsrc_off + 2);
7663 rsrc_off += 8 + count * 12;
7664 if (size < rsrc_off + 8) return NULL;
7665 type_id = *(WORD *)(ptr + rsrc_off);
7667 if (!type_id) return NULL;
7668 count = *(WORD *)(ptr + rsrc_off + 2);
7669 if (size < rsrc_off + 8 + count * 12) return NULL;
7670 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
7671 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
7672 if (size < res_off + *len) return NULL;
7673 return ptr + res_off;
7676 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
7678 LARGE_INTEGER size;
7679 BYTE *ptr = map_file( res, &size );
7680 const IMAGE_DOS_HEADER *dos;
7681 const IMAGE_OS2_HEADER *ne;
7682 WORD *fontdir;
7683 char *data;
7684 WCHAR *name = NULL;
7685 DWORD len;
7687 if (!ptr) return NULL;
7689 if (size.u.LowPart < sizeof( *dos )) goto fail;
7690 dos = (const IMAGE_DOS_HEADER *)ptr;
7691 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
7692 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
7693 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
7695 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
7696 if (!fontdir) goto fail;
7697 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
7699 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
7700 if (!data) goto fail;
7701 if (!memchr( data, 0, len )) goto fail;
7703 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
7704 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
7705 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
7707 fail:
7708 UnmapViewOfFile( ptr );
7709 return name;
7712 static int add_system_font_resource( const WCHAR *file, DWORD flags )
7714 WCHAR path[MAX_PATH];
7715 int ret;
7717 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
7718 get_fonts_win_dir_path( file, path );
7719 EnterCriticalSection( &font_cs );
7720 ret = font_funcs->add_font( path, flags );
7721 LeaveCriticalSection( &font_cs );
7722 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
7723 if (!ret)
7725 get_fonts_data_dir_path( file, path );
7726 EnterCriticalSection( &font_cs );
7727 ret = font_funcs->add_font( path, flags );
7728 LeaveCriticalSection( &font_cs );
7730 return ret;
7733 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
7735 WCHAR path[MAX_PATH];
7736 int ret;
7738 get_fonts_win_dir_path( file, path );
7739 if (!(ret = remove_font( path, flags )))
7741 get_fonts_data_dir_path( file, path );
7742 ret = remove_font( path, flags );
7744 return ret;
7747 static int add_font_resource( LPCWSTR file, DWORD flags )
7749 WCHAR path[MAX_PATH];
7750 int ret = 0;
7752 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
7754 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
7756 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
7757 EnterCriticalSection( &font_cs );
7758 ret = font_funcs->add_font( path, addfont_flags );
7759 LeaveCriticalSection( &font_cs );
7762 if (!ret && !wcschr( file, '\\' ))
7763 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
7765 return ret;
7768 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
7770 WCHAR path[MAX_PATH];
7771 BOOL ret = FALSE;
7773 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
7775 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
7777 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
7778 ret = remove_font( path, addfont_flags );
7781 if (!ret && !wcschr( file, '\\' ))
7782 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
7784 return ret;
7787 static void load_system_bitmap_fonts(void)
7789 static const WCHAR * const fonts[] = { L"FONTS.FON", L"OEMFONT.FON", L"FIXEDFON.FON" };
7790 HKEY hkey;
7791 WCHAR data[MAX_PATH];
7792 DWORD i, dlen, type;
7794 if (RegOpenKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &hkey )) return;
7795 for (i = 0; i < ARRAY_SIZE(fonts); i++)
7797 dlen = sizeof(data);
7798 if (!RegQueryValueExW( hkey, fonts[i], 0, &type, (BYTE *)data, &dlen ) && type == REG_SZ)
7799 add_system_font_resource( data, ADDFONT_ALLOW_BITMAP );
7801 RegCloseKey( hkey );
7804 static void load_directory_fonts( WCHAR *path, UINT flags )
7806 HANDLE handle;
7807 WIN32_FIND_DATAW data;
7808 WCHAR *p;
7810 p = path + lstrlenW(path) - 1;
7811 TRACE( "loading fonts from %s\n", debugstr_w(path) );
7812 handle = FindFirstFileW( path, &data );
7813 if (handle == INVALID_HANDLE_VALUE) return;
7816 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
7817 lstrcpyW( p, data.cFileName );
7818 font_funcs->add_font( path, flags );
7819 } while (FindNextFileW( handle, &data ));
7820 FindClose( handle );
7823 static void load_file_system_fonts(void)
7825 WCHAR *ptr, *next, path[MAX_PATH], value[1024];
7826 DWORD len = ARRAY_SIZE(value);
7828 /* Windows directory */
7829 get_fonts_win_dir_path( L"*", path );
7830 load_directory_fonts( path, 0 );
7832 /* Wine data directory */
7833 get_fonts_data_dir_path( L"*", path );
7834 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
7836 /* custom paths */
7837 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
7838 if (!RegQueryValueExW( wine_fonts_key, L"Path", NULL, NULL, (BYTE *)value, &len ))
7840 for (ptr = value; ptr; ptr = next)
7842 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
7843 if (next && next - ptr < 2) continue;
7844 lstrcpynW( path, ptr, MAX_PATH - 2 );
7845 lstrcatW( path, L"\\*" );
7846 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
7851 struct external_key
7853 struct list entry;
7854 WCHAR value[LF_FULLFACESIZE + 12];
7857 static void update_external_font_keys(void)
7859 struct list external_keys = LIST_INIT(external_keys);
7860 HKEY winnt_key = 0, win9x_key = 0;
7861 struct gdi_font_family *family;
7862 struct external_key *key, *next;
7863 struct gdi_font_face *face;
7864 DWORD len, i = 0, type, dlen, vlen;
7865 WCHAR value[LF_FULLFACESIZE + 12], path[MAX_PATH], *tmp;
7866 WCHAR *file;
7867 HKEY hkey;
7869 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
7870 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL );
7871 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
7872 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL );
7874 /* enumerate the fonts and add external ones to the two keys */
7876 if (RegCreateKeyW( wine_fonts_key, L"External Fonts", &hkey )) return;
7878 vlen = ARRAY_SIZE(value);
7879 dlen = sizeof(path);
7880 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)path, &dlen ))
7882 if (type != REG_SZ) goto next;
7883 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, L" (TrueType)", -1 )) *tmp = 0;
7884 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
7886 face->flags |= ADDFONT_EXTERNAL_FOUND;
7887 goto next;
7889 if (tmp && !*tmp) *tmp = ' ';
7890 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) ))) break;
7891 lstrcpyW( key->value, value );
7892 list_add_tail( &external_keys, &key->entry );
7893 next:
7894 vlen = ARRAY_SIZE(value);
7895 dlen = sizeof(path);
7898 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
7900 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
7902 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
7903 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
7905 lstrcpyW( value, face->full_name );
7906 if (face->scalable) lstrcatW( value, L" (TrueType)" );
7908 if (GetFullPathNameW( face->file, MAX_PATH, path, NULL ))
7909 file = path;
7910 else if ((file = wcsrchr( face->file, '\\' )))
7911 file++;
7912 else
7913 file = face->file;
7915 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
7916 RegSetValueExW( winnt_key, value, 0, REG_SZ, (BYTE *)file, len );
7917 RegSetValueExW( win9x_key, value, 0, REG_SZ, (BYTE *)file, len );
7918 RegSetValueExW( hkey, value, 0, REG_SZ, (BYTE *)file, len );
7921 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
7923 RegDeleteValueW( win9x_key, key->value );
7924 RegDeleteValueW( winnt_key, key->value );
7925 RegDeleteValueW( hkey, key->value );
7926 list_remove( &key->entry );
7927 HeapFree( GetProcessHeap(), 0, key );
7929 RegCloseKey( win9x_key );
7930 RegCloseKey( winnt_key );
7931 RegCloseKey( hkey );
7934 static void load_registry_fonts(void)
7936 WCHAR value[LF_FULLFACESIZE + 12], data[MAX_PATH], *tmp;
7937 DWORD i = 0, type, dlen, vlen;
7938 HKEY hkey;
7940 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
7941 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
7942 full path as the entry. Also look for any .fon fonts, since ReadFontDir
7943 will skip these. */
7944 if (RegOpenKeyW( HKEY_LOCAL_MACHINE,
7945 is_win9x() ? L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts" :
7946 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey ))
7947 return;
7949 vlen = ARRAY_SIZE(value);
7950 dlen = sizeof(data);
7951 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, NULL, NULL ))
7953 if (type != REG_SZ) goto next;
7954 dlen /= sizeof(WCHAR);
7955 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, L" (TrueType)", -1 )) *tmp = 0;
7956 if (find_face_from_full_name( value )) goto next;
7957 if (tmp && !*tmp) *tmp = ' ';
7959 if (RegQueryValueExW( hkey, value, NULL, NULL, (LPBYTE)data, &dlen ))
7961 WARN( "Unable to get face path %s\n", debugstr_w(value) );
7962 goto next;
7965 dlen /= sizeof(WCHAR);
7966 if (data[0] && data[1] == ':')
7967 add_font_resource( data, ADDFONT_ALLOW_BITMAP );
7968 else if (dlen >= 6 && !wcsicmp( data + dlen - 5, L".fon" ))
7969 add_system_font_resource( data, ADDFONT_ALLOW_BITMAP );
7970 next:
7971 vlen = ARRAY_SIZE(value);
7972 dlen = sizeof(data);
7974 RegCloseKey( hkey );
7977 static const struct font_callback_funcs callback_funcs = { add_gdi_face };
7979 /***********************************************************************
7980 * font_init
7982 void font_init(void)
7984 HANDLE mutex;
7985 DWORD disposition;
7987 if (RegCreateKeyExW( HKEY_CURRENT_USER, L"Software\\Wine\\Fonts", 0, NULL, 0,
7988 KEY_ALL_ACCESS, NULL, &wine_fonts_key, NULL ))
7989 return;
7991 init_font_options();
7992 update_codepage();
7993 if (__wine_init_unix_lib( gdi32_module, DLL_PROCESS_ATTACH, &callback_funcs, &font_funcs )) return;
7995 load_system_bitmap_fonts();
7996 load_file_system_fonts();
7997 font_funcs->load_fonts();
7999 if (!(mutex = CreateMutexW( NULL, FALSE, L"__WINE_FONT_MUTEX__" ))) return;
8000 WaitForSingleObject( mutex, INFINITE );
8002 RegCreateKeyExW( wine_fonts_key, L"Cache", 0, NULL, REG_OPTION_VOLATILE,
8003 KEY_ALL_ACCESS, NULL, &wine_fonts_cache_key, &disposition );
8005 if (disposition == REG_CREATED_NEW_KEY)
8007 load_registry_fonts();
8008 update_external_font_keys();
8011 ReleaseMutex( mutex );
8013 if (disposition != REG_CREATED_NEW_KEY)
8015 load_registry_fonts();
8016 load_font_list_from_cache();
8019 reorder_font_list();
8020 load_gdi_font_subst();
8021 load_gdi_font_replacements();
8022 load_system_links();
8023 dump_gdi_font_list();
8024 dump_gdi_font_subst();
8027 /***********************************************************************
8028 * AddFontResourceExW (GDI32.@)
8030 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD flags, PVOID pdv )
8032 int ret;
8033 WCHAR *filename;
8034 BOOL hidden;
8036 if (!font_funcs) return 1;
8037 if (!(ret = add_font_resource( str, flags )))
8039 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8040 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
8041 if (hModule != NULL)
8043 int num_resources = 0;
8044 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
8046 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
8047 wine_dbgstr_w(str));
8048 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
8049 ret = num_resources;
8050 FreeLibrary(hModule);
8052 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
8054 if (hidden) flags |= FR_PRIVATE | FR_NOT_ENUM;
8055 ret = add_font_resource( filename, flags );
8056 HeapFree( GetProcessHeap(), 0, filename );
8059 return ret;
8062 /***********************************************************************
8063 * RemoveFontResourceA (GDI32.@)
8065 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
8067 return RemoveFontResourceExA(str, 0, 0);
8070 /***********************************************************************
8071 * RemoveFontResourceW (GDI32.@)
8073 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
8075 return RemoveFontResourceExW(str, 0, 0);
8078 /***********************************************************************
8079 * AddFontMemResourceEx (GDI32.@)
8081 HANDLE WINAPI AddFontMemResourceEx( PVOID ptr, DWORD size, PVOID pdv, DWORD *pcFonts )
8083 HANDLE ret;
8084 DWORD num_fonts;
8085 void *copy;
8087 if (!ptr || !size || !pcFonts)
8089 SetLastError(ERROR_INVALID_PARAMETER);
8090 return NULL;
8092 if (!font_funcs) return NULL;
8093 if (!(copy = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
8094 memcpy( copy, ptr, size );
8096 EnterCriticalSection( &font_cs );
8097 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
8098 LeaveCriticalSection( &font_cs );
8100 if (!num_fonts)
8102 HeapFree( GetProcessHeap(), 0, copy );
8103 return NULL;
8106 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
8107 * For now return something unique but quite random
8109 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
8111 __TRY
8113 *pcFonts = num_fonts;
8115 __EXCEPT_PAGE_FAULT
8117 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
8118 RemoveFontMemResourceEx( ret );
8119 ret = 0;
8121 __ENDTRY
8122 TRACE( "Returning handle %p\n", ret );
8123 return ret;
8126 /***********************************************************************
8127 * RemoveFontMemResourceEx (GDI32.@)
8129 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
8131 FIXME("(%p) stub\n", fh);
8132 return TRUE;
8135 /***********************************************************************
8136 * RemoveFontResourceExA (GDI32.@)
8138 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
8140 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
8141 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8142 INT ret;
8144 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
8145 ret = RemoveFontResourceExW(strW, fl, pdv);
8146 HeapFree(GetProcessHeap(), 0, strW);
8147 return ret;
8150 /***********************************************************************
8151 * RemoveFontResourceExW (GDI32.@)
8153 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD flags, PVOID pdv )
8155 int ret;
8156 WCHAR *filename;
8157 BOOL hidden;
8159 if (!font_funcs) return TRUE;
8161 if (!(ret = remove_font_resource( str, flags )))
8163 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8164 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
8165 if (hModule != NULL)
8167 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
8168 FreeLibrary(hModule);
8170 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
8172 if (hidden) flags |= FR_PRIVATE | FR_NOT_ENUM;
8173 ret = remove_font_resource( filename, flags );
8174 HeapFree( GetProcessHeap(), 0, filename );
8177 return ret;
8180 /***********************************************************************
8181 * GetFontResourceInfoW (GDI32.@)
8183 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
8185 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
8186 return FALSE;
8189 /***********************************************************************
8190 * GetTextCharset (GDI32.@)
8192 UINT WINAPI GetTextCharset(HDC hdc)
8194 /* MSDN docs say this is equivalent */
8195 return GetTextCharsetInfo(hdc, NULL, 0);
8198 /***********************************************************************
8199 * GdiGetCharDimensions (GDI32.@)
8201 * Gets the average width of the characters in the English alphabet.
8203 * PARAMS
8204 * hdc [I] Handle to the device context to measure on.
8205 * lptm [O] Pointer to memory to store the text metrics into.
8206 * height [O] On exit, the maximum height of characters in the English alphabet.
8208 * RETURNS
8209 * The average width of characters in the English alphabet.
8211 * NOTES
8212 * This function is used by the dialog manager to get the size of a dialog
8213 * unit. It should also be used by other pieces of code that need to know
8214 * the size of a dialog unit in logical units without having access to the
8215 * window handle of the dialog.
8216 * Windows caches the font metrics from this function, but we don't and
8217 * there doesn't appear to be an immediate advantage to do so.
8219 * SEE ALSO
8220 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
8222 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
8224 SIZE sz;
8226 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
8228 if(!GetTextExtentPointW(hdc, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52, &sz))
8229 return 0;
8231 if (height) *height = sz.cy;
8232 return (sz.cx / 26 + 1) / 2;
8235 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
8237 FIXME("(%d): stub\n", fEnableEUDC);
8238 return FALSE;
8241 /***********************************************************************
8242 * GetCharWidthI (GDI32.@)
8244 * Retrieve widths of characters.
8246 * PARAMS
8247 * hdc [I] Handle to a device context.
8248 * first [I] First glyph in range to query.
8249 * count [I] Number of glyph indices to query.
8250 * glyphs [I] Array of glyphs to query.
8251 * buffer [O] Buffer to receive character widths.
8253 * NOTES
8254 * Only works with TrueType fonts.
8256 * RETURNS
8257 * Success: TRUE
8258 * Failure: FALSE
8260 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
8262 ABC *abc;
8263 unsigned int i;
8265 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
8267 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
8268 return FALSE;
8270 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
8272 HeapFree(GetProcessHeap(), 0, abc);
8273 return FALSE;
8276 for (i = 0; i < count; i++)
8277 buffer[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
8279 HeapFree(GetProcessHeap(), 0, abc);
8280 return TRUE;
8283 /***********************************************************************
8284 * GetFontUnicodeRanges (GDI32.@)
8286 * Retrieve a list of supported Unicode characters in a font.
8288 * PARAMS
8289 * hdc [I] Handle to a device context.
8290 * lpgs [O] GLYPHSET structure specifying supported character ranges.
8292 * RETURNS
8293 * Success: Number of bytes written to the buffer pointed to by lpgs.
8294 * Failure: 0
8297 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
8299 DWORD ret;
8300 PHYSDEV dev;
8301 DC *dc = get_dc_ptr(hdc);
8303 TRACE("(%p, %p)\n", hdc, lpgs);
8305 if (!dc) return 0;
8307 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
8308 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
8309 release_dc_ptr(dc);
8310 return ret;
8314 /*************************************************************
8315 * FontIsLinked (GDI32.@)
8317 BOOL WINAPI FontIsLinked(HDC hdc)
8319 DC *dc = get_dc_ptr(hdc);
8320 PHYSDEV dev;
8321 BOOL ret;
8323 if (!dc) return FALSE;
8324 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
8325 ret = dev->funcs->pFontIsLinked( dev );
8326 release_dc_ptr(dc);
8327 TRACE("returning %d\n", ret);
8328 return ret;
8331 /*************************************************************
8332 * GetFontRealizationInfo (GDI32.@)
8334 BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info)
8336 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, unk);
8337 PHYSDEV dev;
8338 BOOL ret;
8339 DC *dc;
8341 if (info->size != sizeof(*info) && !is_v0)
8342 return FALSE;
8344 dc = get_dc_ptr(hdc);
8345 if (!dc) return FALSE;
8346 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
8347 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
8348 release_dc_ptr(dc);
8349 return ret;
8352 /*************************************************************************
8353 * GetRasterizerCaps (GDI32.@)
8355 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8357 lprs->nSize = sizeof(RASTERIZER_STATUS);
8358 lprs->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
8359 lprs->nLanguageID = 0;
8360 return TRUE;
8363 /*************************************************************************
8364 * GetFontFileData (GDI32.@)
8366 BOOL WINAPI GetFontFileData( DWORD instance_id, DWORD unknown, UINT64 offset, void *buff, DWORD buff_size )
8368 struct gdi_font *font;
8369 DWORD tag = 0, size;
8370 BOOL ret = FALSE;
8372 if (!font_funcs) return FALSE;
8373 EnterCriticalSection( &font_cs );
8374 if ((font = get_font_from_handle( instance_id )))
8376 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
8377 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
8378 if (size != GDI_ERROR && size >= buff_size && offset <= size - buff_size)
8379 ret = font_funcs->get_font_data( font, tag, offset, buff, buff_size ) != GDI_ERROR;
8380 else
8381 SetLastError( ERROR_INVALID_PARAMETER );
8383 LeaveCriticalSection( &font_cs );
8384 return ret;
8387 /* Undocumented structure filled in by GetFontFileInfo */
8388 struct font_fileinfo
8390 FILETIME writetime;
8391 LARGE_INTEGER size;
8392 WCHAR path[1];
8395 /*************************************************************************
8396 * GetFontFileInfo (GDI32.@)
8398 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info,
8399 SIZE_T size, SIZE_T *needed )
8401 SIZE_T required_size = 0;
8402 struct gdi_font *font;
8403 BOOL ret = FALSE;
8405 EnterCriticalSection( &font_cs );
8407 if ((font = get_font_from_handle( instance_id )))
8409 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
8410 if (required_size <= size)
8412 info->writetime = font->writetime;
8413 info->size.QuadPart = font->data_size;
8414 lstrcpyW( info->path, font->file );
8415 ret = TRUE;
8417 else SetLastError( ERROR_INSUFFICIENT_BUFFER );
8420 LeaveCriticalSection( &font_cs );
8421 if (needed) *needed = required_size;
8422 return ret;
8425 struct realization_info
8427 DWORD flags; /* 1 for bitmap fonts, 3 for scalable fonts */
8428 DWORD cache_num; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
8429 DWORD instance_id; /* identifies a realized font instance */
8432 /*************************************************************
8433 * GdiRealizationInfo (GDI32.@)
8435 * Returns a structure that contains some font information.
8437 BOOL WINAPI GdiRealizationInfo(HDC hdc, struct realization_info *info)
8439 struct font_realization_info ri;
8440 BOOL ret;
8442 ri.size = sizeof(ri);
8443 ret = GetFontRealizationInfo( hdc, &ri );
8444 if (ret)
8446 info->flags = ri.flags;
8447 info->cache_num = ri.cache_num;
8448 info->instance_id = ri.instance_id;
8451 return ret;
8454 /*************************************************************
8455 * GetCharWidthInfo (GDI32.@)
8458 BOOL WINAPI GetCharWidthInfo(HDC hdc, struct char_width_info *info)
8460 PHYSDEV dev;
8461 BOOL ret;
8462 DC *dc;
8464 dc = get_dc_ptr(hdc);
8465 if (!dc) return FALSE;
8466 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
8467 ret = dev->funcs->pGetCharWidthInfo( dev, info );
8469 if (ret)
8471 info->lsb = width_to_LP( dc, info->lsb );
8472 info->rsb = width_to_LP( dc, info->rsb );
8474 release_dc_ptr(dc);
8475 return ret;