hidclass.sys: Pass sizeof(packet) as input for IOCTL_HID_SET_OUTPUT_REPORT.
[wine.git] / dlls / gdi32 / font.c
blobb8dc2cc4b1f1b17635f946ed529830f2514a200e
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 "ntgdi_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_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
184 static BOOL FONT_DeleteObject( HGDIOBJ handle );
186 static const struct gdi_obj_funcs fontobj_funcs =
188 FONT_GetObjectW, /* pGetObjectW */
189 NULL, /* pUnrealizeObject */
190 FONT_DeleteObject /* pDeleteObject */
193 typedef struct
195 struct gdi_obj_header obj;
196 LOGFONTW logfont;
197 } FONTOBJ;
199 struct font_enum
201 LPLOGFONTW lpLogFontParam;
202 FONTENUMPROCW lpEnumFunc;
203 LPARAM lpData;
204 BOOL unicode;
205 HDC hdc;
206 INT retval;
210 * For TranslateCharsetInfo
212 #define MAXTCIINDEX 32
213 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
214 /* ANSI */
215 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
216 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
217 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
218 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
219 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
220 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
221 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
222 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
223 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
224 /* reserved by ANSI */
225 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
226 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
227 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
228 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
229 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
230 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
231 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
232 /* ANSI and OEM */
233 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
234 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
235 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
236 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
237 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
238 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
239 /* reserved for alternate ANSI and OEM */
240 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
241 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
242 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
243 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
244 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
245 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
246 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
247 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
248 /* reserved for system */
249 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
250 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
253 static const WCHAR * const default_serif_list[3] =
255 L"Times New Roman",
256 L"Liberation Serif",
257 L"Bitstream Vera Serif"
259 static const WCHAR * const default_fixed_list[3] =
261 L"Courier New",
262 L"Liberation Mono",
263 L"Bitstream Vera Sans Mono"
265 static const WCHAR * const default_sans_list[3] =
267 L"Arial",
268 L"Liberation Sans",
269 L"Bitstream Vera Sans"
271 static WCHAR ff_roman_default[LF_FACESIZE];
272 static WCHAR ff_modern_default[LF_FACESIZE];
273 static WCHAR ff_swiss_default[LF_FACESIZE];
275 static const struct nls_update_font_list
277 UINT ansi_cp, oem_cp;
278 const char *oem, *fixed, *system;
279 const char *courier, *serif, *small, *sserif_96, *sserif_120;
280 /* these are for font substitutes */
281 const char *shelldlg, *tmsrmn;
282 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0, *helv_0, *tmsrmn_0;
283 struct subst { const char *from, *to; } arial_0, courier_new_0, times_new_roman_0;
284 } nls_update_font_list[] =
286 /* Latin 1 (United States) */
287 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
288 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
289 "Tahoma","Times New Roman"
291 /* Latin 1 (Multilingual) */
292 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
293 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
294 "Tahoma","Times New Roman" /* FIXME unverified */
296 /* Eastern Europe */
297 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
298 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
299 "Tahoma","Times New Roman", /* FIXME unverified */
300 "Fixedsys,238", "System,238",
301 "Courier New,238", "MS Serif,238", "Small Fonts,238",
302 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
303 { "Arial CE,0", "Arial,238" },
304 { "Courier New CE,0", "Courier New,238" },
305 { "Times New Roman CE,0", "Times New Roman,238" }
307 /* Cyrillic */
308 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
309 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
310 "Tahoma","Times New Roman", /* FIXME unverified */
311 "Fixedsys,204", "System,204",
312 "Courier New,204", "MS Serif,204", "Small Fonts,204",
313 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
314 { "Arial Cyr,0", "Arial,204" },
315 { "Courier New Cyr,0", "Courier New,204" },
316 { "Times New Roman Cyr,0", "Times New Roman,204" }
318 /* Greek */
319 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
320 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
321 "Tahoma","Times New Roman", /* FIXME unverified */
322 "Fixedsys,161", "System,161",
323 "Courier New,161", "MS Serif,161", "Small Fonts,161",
324 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
325 { "Arial Greek,0", "Arial,161" },
326 { "Courier New Greek,0", "Courier New,161" },
327 { "Times New Roman Greek,0", "Times New Roman,161" }
329 /* Turkish */
330 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
331 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
332 "Tahoma","Times New Roman", /* FIXME unverified */
333 "Fixedsys,162", "System,162",
334 "Courier New,162", "MS Serif,162", "Small Fonts,162",
335 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
336 { "Arial Tur,0", "Arial,162" },
337 { "Courier New Tur,0", "Courier New,162" },
338 { "Times New Roman Tur,0", "Times New Roman,162" }
340 /* Hebrew */
341 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
342 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
343 "Tahoma","Times New Roman", /* FIXME unverified */
344 "Fixedsys,177", "System,177",
345 "Courier New,177", "MS Serif,177", "Small Fonts,177",
346 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
348 /* Arabic */
349 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
350 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
351 "Microsoft Sans Serif","Times New Roman",
352 "Fixedsys,178", "System,178",
353 "Courier New,178", "MS Serif,178", "Small Fonts,178",
354 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
356 /* Baltic */
357 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
358 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
359 "Tahoma","Times New Roman", /* FIXME unverified */
360 "Fixedsys,186", "System,186",
361 "Courier New,186", "MS Serif,186", "Small Fonts,186",
362 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
363 { "Arial Baltic,0", "Arial,186" },
364 { "Courier New Baltic,0", "Courier New,186" },
365 { "Times New Roman Baltic,0", "Times New Roman,186" }
367 /* Vietnamese */
368 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
369 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
370 "Tahoma","Times New Roman" /* FIXME unverified */
372 /* Thai */
373 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
374 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
375 "Tahoma","Times New Roman" /* FIXME unverified */
377 /* Japanese */
378 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
379 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
380 "MS UI Gothic","MS Serif"
382 /* Chinese Simplified */
383 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
384 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
385 "SimSun", "NSimSun"
387 /* Korean */
388 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
389 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
390 "Gulim", "Batang"
392 /* Chinese Traditional */
393 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
394 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
395 "PMingLiU", "MingLiU"
399 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
401 return ( ansi_cp == 932 /* CP932 for Japanese */
402 || ansi_cp == 936 /* CP936 for Chinese Simplified */
403 || ansi_cp == 949 /* CP949 for Korean */
404 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
407 static CRITICAL_SECTION font_cs;
408 static CRITICAL_SECTION_DEBUG critsect_debug =
410 0, 0, &font_cs,
411 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
412 0, 0, { (DWORD_PTR)(__FILE__ ": font_cs") }
414 static CRITICAL_SECTION font_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
416 #ifndef WINE_FONT_DIR
417 #define WINE_FONT_DIR "fonts"
418 #endif
420 #ifdef WORDS_BIGENDIAN
421 #define GET_BE_WORD(x) (x)
422 #define GET_BE_DWORD(x) (x)
423 #else
424 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
425 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
426 #endif
428 static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
430 if (GetEnvironmentVariableW( L"WINEDATADIR", path, MAX_PATH ))
431 lstrcatW( path, L"\\" WINE_FONT_DIR "\\" );
432 else if (GetEnvironmentVariableW( L"WINEBUILDDIR", path, MAX_PATH ))
433 lstrcatW( path, L"\\fonts\\" );
435 lstrcatW( path, file );
436 if (path[5] == ':') memmove( path, path + 4, (lstrlenW(path) - 3) * sizeof(WCHAR) );
437 else path[1] = '\\'; /* change \??\ to \\?\ */
440 static void get_fonts_win_dir_path( const WCHAR *file, WCHAR *path )
442 GetWindowsDirectoryW( path, MAX_PATH );
443 lstrcatW( path, L"\\fonts\\" );
444 lstrcatW( path, file );
447 /* font substitutions */
449 struct gdi_font_subst
451 struct list entry;
452 int from_charset;
453 int to_charset;
454 WCHAR names[1];
457 static struct list font_subst_list = LIST_INIT(font_subst_list);
459 static inline WCHAR *get_subst_to_name( struct gdi_font_subst *subst )
461 return subst->names + lstrlenW( subst->names ) + 1;
464 static void dump_gdi_font_subst(void)
466 struct gdi_font_subst *subst;
468 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
470 if (subst->from_charset != -1 || subst->to_charset != -1)
471 TRACE("%s,%d -> %s,%d\n", debugstr_w(subst->names),
472 subst->from_charset, debugstr_w(get_subst_to_name(subst)), subst->to_charset);
473 else
474 TRACE("%s -> %s\n", debugstr_w(subst->names), debugstr_w(get_subst_to_name(subst)));
478 static const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset )
480 struct gdi_font_subst *subst;
482 LIST_FOR_EACH_ENTRY( subst, &font_subst_list, struct gdi_font_subst, entry )
484 if (!facename_compare( subst->names, from_name, -1 ) &&
485 (subst->from_charset == from_charset || subst->from_charset == -1))
487 if (to_charset) *to_charset = subst->to_charset;
488 return get_subst_to_name( subst );
491 return NULL;
494 static BOOL add_gdi_font_subst( const WCHAR *from_name, int from_charset, const WCHAR *to_name, int to_charset )
496 struct gdi_font_subst *subst;
497 int len = lstrlenW( from_name ) + lstrlenW( to_name ) + 2;
499 if (get_gdi_font_subst( from_name, from_charset, NULL )) return FALSE; /* already exists */
501 if (!(subst = HeapAlloc( GetProcessHeap(), 0,
502 offsetof( struct gdi_font_subst, names[len] ))))
503 return FALSE;
504 lstrcpyW( subst->names, from_name );
505 lstrcpyW( get_subst_to_name(subst), to_name );
506 subst->from_charset = from_charset;
507 subst->to_charset = to_charset;
508 list_add_tail( &font_subst_list, &subst->entry );
509 return TRUE;
512 static void load_gdi_font_subst(void)
514 HKEY hkey;
515 DWORD i = 0, type, dlen, vlen;
516 WCHAR value[64], data[64], *p;
518 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
519 &hkey)) return;
521 dlen = sizeof(data);
522 vlen = ARRAY_SIZE(value);
523 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)data, &dlen ))
525 int from_charset = -1, to_charset = -1;
527 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
528 if ((p = wcsrchr( value, ',' )) && p[1])
530 *p++ = 0;
531 from_charset = wcstol( p, NULL, 10 );
533 if ((p = wcsrchr( data, ',' )) && p[1])
535 *p++ = 0;
536 to_charset = wcstol( p, NULL, 10 );
539 /* Win 2000 doesn't allow mapping between different charsets
540 or mapping of DEFAULT_CHARSET */
541 if ((!from_charset || to_charset == from_charset) && to_charset != DEFAULT_CHARSET)
542 add_gdi_font_subst( value, from_charset, data, to_charset );
544 /* reset dlen and vlen */
545 dlen = sizeof(data);
546 vlen = ARRAY_SIZE(value);
548 RegCloseKey( hkey );
551 /* font families */
553 static int family_namecmp( const WCHAR *str1, const WCHAR *str2 )
555 int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0);
557 if (!facename_compare( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0;
558 else if (!facename_compare( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1;
559 else if (!facename_compare( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2;
560 else prio1 = 3;
562 if (!facename_compare( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0;
563 else if (!facename_compare( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1;
564 else if (!facename_compare( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2;
565 else prio2 = 3;
567 if (prio1 != prio2) return prio1 - prio2;
568 if (vert1 != vert2) return vert1 - vert2;
569 return facename_compare( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 );
572 static int family_name_compare( const void *key, const struct wine_rb_entry *entry )
574 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, name_entry );
575 return family_namecmp( (const WCHAR *)key, family->family_name );
578 static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry )
580 const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, second_name_entry );
581 return family_namecmp( (const WCHAR *)key, family->second_name );
584 static int face_full_name_compare( const void *key, const struct wine_rb_entry *entry )
586 const struct gdi_font_face *face = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_face, full_name_entry );
587 return facename_compare( (const WCHAR *)key, face->full_name, LF_FULLFACESIZE - 1 );
590 static struct wine_rb_tree family_name_tree = { family_name_compare };
591 static struct wine_rb_tree family_second_name_tree = { family_second_name_compare };
592 static struct wine_rb_tree face_full_name_tree = { face_full_name_compare };
594 static int face_is_in_full_name_tree( const struct gdi_font_face *face )
596 return face->full_name_entry.parent || face_full_name_tree.root == &face->full_name_entry;
599 static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name )
601 struct gdi_font_family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
603 family->refcount = 1;
604 lstrcpynW( family->family_name, name, LF_FACESIZE );
605 if (second_name && second_name[0] && wcsicmp( name, second_name ))
607 lstrcpynW( family->second_name, second_name, LF_FACESIZE );
608 add_gdi_font_subst( second_name, -1, name, -1 );
610 else family->second_name[0] = 0;
611 list_init( &family->faces );
612 family->replacement = NULL;
613 wine_rb_put( &family_name_tree, family->family_name, &family->name_entry );
614 if (family->second_name[0]) wine_rb_put( &family_second_name_tree, family->second_name, &family->second_name_entry );
615 return family;
618 static void release_family( struct gdi_font_family *family )
620 if (--family->refcount) return;
621 assert( list_empty( &family->faces ));
622 wine_rb_remove( &family_name_tree, &family->name_entry );
623 if (family->second_name[0]) wine_rb_remove( &family_second_name_tree, &family->second_name_entry );
624 if (family->replacement) release_family( family->replacement );
625 HeapFree( GetProcessHeap(), 0, family );
628 static struct gdi_font_family *find_family_from_name( const WCHAR *name )
630 struct wine_rb_entry *entry;
631 if (!(entry = wine_rb_get( &family_name_tree, name ))) return NULL;
632 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, name_entry );
635 static struct gdi_font_family *find_family_from_any_name( const WCHAR *name )
637 struct wine_rb_entry *entry;
638 struct gdi_font_family *family;
639 if ((family = find_family_from_name( name ))) return family;
640 if (!(entry = wine_rb_get( &family_second_name_tree, name ))) return NULL;
641 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, second_name_entry );
644 static struct gdi_font_face *find_face_from_full_name( const WCHAR *full_name )
646 struct wine_rb_entry *entry;
647 if (!(entry = wine_rb_get( &face_full_name_tree, full_name ))) return NULL;
648 return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_face, full_name_entry );
651 static const struct list *get_family_face_list( const struct gdi_font_family *family )
653 return family->replacement ? &family->replacement->faces : &family->faces;
656 static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name )
658 struct gdi_font_face *face;
659 const WCHAR *file;
660 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
662 if (!face->file) continue;
663 file = wcsrchr(face->file, '\\');
664 if (!file) file = face->file;
665 else file++;
666 if (wcsicmp( file, file_name )) continue;
667 face->refcount++;
668 return face;
670 return NULL;
673 static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name )
675 struct gdi_font_family *family;
676 struct gdi_font_face *face;
678 TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
680 if (!family_name)
682 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
683 if ((face = family_find_face_from_filename( family, file_name ))) return face;
684 return NULL;
687 if (!(family = find_family_from_name( family_name ))) return NULL;
688 return family_find_face_from_filename( family, file_name );
691 static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
693 struct gdi_font_family *new_family, *family;
694 struct gdi_font_face *face;
695 WCHAR new_name_vert[LF_FACESIZE], replace_vert[LF_FACESIZE];
697 if (!(family = find_family_from_any_name( replace )))
699 TRACE( "%s is not available. Skip this replacement.\n", debugstr_w(replace) );
700 return FALSE;
703 if (!(new_family = create_family( new_name, NULL ))) return FALSE;
704 new_family->replacement = family;
705 family->refcount++;
706 TRACE( "mapping %s to %s\n", debugstr_w(replace), debugstr_w(new_name) );
708 /* also add replacement for vertical font if necessary */
709 if (replace[0] == '@') return TRUE;
710 if (list_empty( &family->faces )) return TRUE;
711 face = LIST_ENTRY( list_head(&family->faces), struct gdi_font_face, entry );
712 if (!(face->fs.fsCsb[0] & FS_DBCS_MASK)) return TRUE;
714 new_name_vert[0] = '@';
715 lstrcpynW( new_name_vert + 1, new_name, LF_FACESIZE - 1 );
716 if (find_family_from_any_name( new_name_vert )) return TRUE; /* already exists */
718 replace_vert[0] = '@';
719 lstrcpynW( replace_vert + 1, replace, LF_FACESIZE - 1 );
720 add_family_replacement( new_name_vert, replace_vert );
721 return TRUE;
725 * The replacement list is a way to map an entire font
726 * family onto another family. For example adding
728 * [HKCU\Software\Wine\Fonts\Replacements]
729 * "Wingdings"="Winedings"
731 * would enumerate the Winedings font both as Winedings and
732 * Wingdings. However if a real Wingdings font is present the
733 * replacement does not take place.
735 static void load_gdi_font_replacements(void)
737 HKEY hkey;
738 DWORD i = 0, type, dlen, vlen;
739 WCHAR value[LF_FACESIZE], data[1024];
741 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
742 if (RegOpenKeyW( wine_fonts_key, L"Replacements", &hkey )) return;
744 dlen = sizeof(data);
745 vlen = ARRAY_SIZE(value);
746 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)data, &dlen ))
748 /* "NewName"="Oldname" */
749 if (!find_family_from_any_name( value ))
751 if (type == REG_MULTI_SZ)
753 WCHAR *replace = data;
754 while (*replace)
756 if (add_family_replacement( value, replace )) break;
757 replace += lstrlenW(replace) + 1;
760 else if (type == REG_SZ) add_family_replacement( value, data );
762 else TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
764 /* reset dlen and vlen */
765 dlen = sizeof(data);
766 vlen = ARRAY_SIZE(value);
768 RegCloseKey( hkey );
771 static void dump_gdi_font_list(void)
773 struct gdi_font_family *family;
774 struct gdi_font_face *face;
776 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
778 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
779 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
781 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
782 face->fs.fsCsb[0] );
783 if (!face->scalable) TRACE(" %d", face->size.height );
784 TRACE("\n");
789 static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
791 if (index < 3)
793 const WCHAR * const *defaults;
795 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
796 defaults = default_fixed_list;
797 else if ((pitch_and_family & 0xf0) == FF_ROMAN)
798 defaults = default_serif_list;
799 else
800 defaults = default_sans_list;
801 lstrcpynW( buffer, defaults[index], LF_FACESIZE );
802 return TRUE;
804 return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
807 static void set_default_family( DWORD pitch_and_family, WCHAR *default_name )
809 struct wine_rb_entry *entry;
810 WCHAR name[LF_FACESIZE];
811 int i = 0;
813 while (enum_fallbacks( pitch_and_family, i++, name ))
815 if (!(entry = wine_rb_get( &family_name_tree, name ))) continue;
816 wine_rb_remove( &family_name_tree, entry );
817 lstrcpynW( default_name, name, LF_FACESIZE - 1 );
818 wine_rb_put( &family_name_tree, name, entry );
819 return;
823 static void reorder_font_list(void)
825 set_default_family( FF_ROMAN, ff_roman_default );
826 set_default_family( FF_MODERN, ff_modern_default );
827 set_default_family( FF_SWISS, ff_swiss_default );
830 static void release_face( struct gdi_font_face *face )
832 if (--face->refcount) return;
833 if (face->family)
835 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
836 list_remove( &face->entry );
837 release_family( face->family );
839 if (face_is_in_full_name_tree( face )) wine_rb_remove( &face_full_name_tree, &face->full_name_entry );
840 HeapFree( GetProcessHeap(), 0, face->file );
841 HeapFree( GetProcessHeap(), 0, face->style_name );
842 HeapFree( GetProcessHeap(), 0, face->full_name );
843 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
844 HeapFree( GetProcessHeap(), 0, face );
847 static int remove_font( const WCHAR *file, DWORD flags )
849 struct gdi_font_family *family, *family_next;
850 struct gdi_font_face *face, *face_next;
851 int count = 0;
853 EnterCriticalSection( &font_cs );
854 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_name_tree, struct gdi_font_family, name_entry )
856 family->refcount++;
857 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry )
859 if (!face->file) continue;
860 if (LOWORD(face->flags) != LOWORD(flags)) continue;
861 if (!wcsicmp( face->file, file ))
863 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
864 release_face( face );
865 count++;
868 release_family( family );
870 LeaveCriticalSection( &font_cs );
871 return count;
874 static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
876 if (facename_compare( f1->full_name, f2->full_name, -1 )) return FALSE;
877 if (f1->scalable) return TRUE;
878 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
879 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
882 static inline int style_order( const struct gdi_font_face *face )
884 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
886 case NTM_REGULAR:
887 return 0;
888 case NTM_BOLD:
889 return 1;
890 case NTM_ITALIC:
891 return 2;
892 case NTM_BOLD | NTM_ITALIC:
893 return 3;
894 default:
895 WARN( "Don't know how to order face %s with flags 0x%08x\n",
896 debugstr_w(face->full_name), face->ntmFlags );
897 return 9999;
901 static BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
903 struct gdi_font_face *cursor;
905 LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
907 if (faces_equal( face, cursor ))
909 TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
910 debugstr_w(face->full_name), debugstr_w(family->family_name),
911 cursor->version, face->version );
913 if (face->file && cursor->file && !wcsicmp( face->file, cursor->file ))
915 cursor->refcount++;
916 TRACE("Font %s already in list, refcount now %d\n",
917 debugstr_w(face->file), cursor->refcount);
918 return FALSE;
920 if (face->version <= cursor->version)
922 TRACE("Original font %s is newer so skipping %s\n",
923 debugstr_w(cursor->file), debugstr_w(face->file));
924 return FALSE;
926 else
928 TRACE("Replacing original %s with %s\n",
929 debugstr_w(cursor->file), debugstr_w(face->file));
930 list_add_before( &cursor->entry, &face->entry );
931 face->family = family;
932 family->refcount++;
933 face->refcount++;
934 if (face_is_in_full_name_tree( cursor ))
936 wine_rb_replace( &face_full_name_tree, &cursor->full_name_entry, &face->full_name_entry );
937 memset( &cursor->full_name_entry, 0, sizeof(cursor->full_name_entry) );
939 release_face( cursor );
940 return TRUE;
943 if (style_order( face ) < style_order( cursor )) break;
946 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
947 debugstr_w(family->family_name), debugstr_w(face->file) );
948 list_add_before( &cursor->entry, &face->entry );
949 if (face->scalable) wine_rb_put( &face_full_name_tree, face->full_name, &face->full_name_entry );
950 face->family = family;
951 family->refcount++;
952 face->refcount++;
953 return TRUE;
956 static struct gdi_font_face *create_face( struct gdi_font_family *family, const WCHAR *style,
957 const WCHAR *fullname, const WCHAR *file,
958 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
959 DWORD ntmflags, DWORD version, DWORD flags,
960 const struct bitmap_font_size *size )
962 struct gdi_font_face *face = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*face) );
964 face->refcount = 1;
965 face->style_name = strdupW( style );
966 face->full_name = strdupW( fullname );
967 face->face_index = index;
968 face->fs = fs;
969 face->ntmFlags = ntmflags;
970 face->version = version;
971 face->flags = flags;
972 face->data_ptr = data_ptr;
973 face->data_size = data_size;
974 if (file) face->file = strdupW( file );
975 if (size) face->size = *size;
976 else face->scalable = TRUE;
977 if (insert_face_in_family_list( face, family )) return face;
978 release_face( face );
979 return NULL;
982 static int CDECL add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
983 const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
984 void *data_ptr, SIZE_T data_size, UINT index, FONTSIGNATURE fs,
985 DWORD ntmflags, DWORD version, DWORD flags,
986 const struct bitmap_font_size *size )
988 struct gdi_font_face *face;
989 struct gdi_font_family *family;
990 int ret = 0;
992 if ((family = find_family_from_name( family_name ))) family->refcount++;
993 else if (!(family = create_family( family_name, second_name ))) return ret;
995 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
996 index, fs, ntmflags, version, flags, size )))
998 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
999 release_face( face );
1001 release_family( family );
1002 ret++;
1004 if (fs.fsCsb[0] & FS_DBCS_MASK)
1006 WCHAR vert_family[LF_FACESIZE], vert_second[LF_FACESIZE], vert_full[LF_FULLFACESIZE];
1008 vert_family[0] = '@';
1009 lstrcpynW( vert_family + 1, family_name, LF_FACESIZE - 1 );
1011 if (second_name && second_name[0])
1013 vert_second[0] = '@';
1014 lstrcpynW( vert_second + 1, second_name, LF_FACESIZE - 1 );
1016 else vert_second[0] = 0;
1018 if (fullname)
1020 vert_full[0] = '@';
1021 lstrcpynW( vert_full + 1, fullname, LF_FULLFACESIZE - 1 );
1022 fullname = vert_full;
1025 if ((family = find_family_from_name( vert_family ))) family->refcount++;
1026 else if (!(family = create_family( vert_family, vert_second ))) return ret;
1028 if ((face = create_face( family, style, fullname, file, data_ptr, data_size,
1029 index, fs, ntmflags, version, flags | ADDFONT_VERTICAL_FONT, size )))
1031 if (flags & ADDFONT_ADD_TO_CACHE) add_face_to_cache( face );
1032 release_face( face );
1034 release_family( family );
1035 ret++;
1037 return ret;
1040 /* font cache */
1042 struct cached_face
1044 DWORD index;
1045 DWORD flags;
1046 DWORD ntmflags;
1047 DWORD version;
1048 struct bitmap_font_size size;
1049 FONTSIGNATURE fs;
1050 WCHAR full_name[1];
1051 /* WCHAR file_name[]; */
1054 static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
1055 void *buffer, DWORD buffer_size, BOOL scalable )
1057 DWORD type, size, needed, index = 0;
1058 struct gdi_font_face *face;
1059 HKEY hkey_strike;
1060 WCHAR name[256];
1061 struct cached_face *cached = (struct cached_face *)buffer;
1063 size = sizeof(name);
1064 needed = buffer_size - sizeof(DWORD);
1065 while (!RegEnumValueW( hkey_family, index++, name, &size, NULL, &type, buffer, &needed ))
1067 if (type == REG_BINARY && needed > sizeof(*cached))
1069 ((DWORD *)buffer)[needed / sizeof(DWORD)] = 0;
1070 if ((face = create_face( family, name, cached->full_name,
1071 cached->full_name + lstrlenW(cached->full_name) + 1,
1072 NULL, 0, cached->index, cached->fs, cached->ntmflags, cached->version,
1073 cached->flags, scalable ? NULL : &cached->size )))
1075 if (!scalable)
1076 TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
1077 face->size.height, face->size.width, face->size.size >> 6,
1078 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1080 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1081 face->fs.fsCsb[0], face->fs.fsCsb[1],
1082 face->fs.fsUsb[0], face->fs.fsUsb[1],
1083 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1085 release_face( face );
1088 size = sizeof(name);
1089 needed = buffer_size - sizeof(DWORD);
1092 /* load bitmap strikes */
1094 index = 0;
1095 needed = buffer_size;
1096 while (!RegEnumKeyExW( hkey_family, index++, buffer, &needed, NULL, NULL, NULL, NULL ))
1098 if (!RegOpenKeyExW( hkey_family, buffer, 0, KEY_ALL_ACCESS, &hkey_strike ))
1100 load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
1101 RegCloseKey( hkey_strike );
1103 needed = buffer_size;
1107 static void load_font_list_from_cache(void)
1109 DWORD size, family_index = 0;
1110 struct gdi_font_family *family;
1111 HKEY hkey_family;
1112 WCHAR buffer[4096], second_name[LF_FACESIZE];
1114 size = sizeof(buffer);
1115 while (!RegEnumKeyExW( wine_fonts_cache_key, family_index++, buffer, &size, NULL, NULL, NULL, NULL ))
1117 RegOpenKeyExW( wine_fonts_cache_key, buffer, 0, KEY_ALL_ACCESS, &hkey_family );
1118 TRACE("opened family key %s\n", debugstr_w(buffer));
1119 size = sizeof(second_name);
1120 if (RegQueryValueExW( hkey_family, NULL, NULL, NULL, (BYTE *)second_name, &size ))
1121 second_name[0] = 0;
1123 family = create_family( buffer, second_name );
1125 load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
1127 RegCloseKey( hkey_family );
1128 release_family( family );
1129 size = sizeof(buffer);
1133 static void add_face_to_cache( struct gdi_font_face *face )
1135 HKEY hkey_family, hkey_face;
1136 DWORD len, buffer[1024];
1137 struct cached_face *cached = (struct cached_face *)buffer;
1139 if (RegCreateKeyExW( wine_fonts_cache_key, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE,
1140 KEY_ALL_ACCESS, NULL, &hkey_family, NULL ))
1141 return;
1143 if (face->family->second_name[0])
1144 RegSetValueExW( hkey_family, NULL, 0, REG_SZ, (BYTE *)face->family->second_name,
1145 (lstrlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1147 if (!face->scalable)
1149 WCHAR name[10];
1151 swprintf( name, ARRAY_SIZE(name), L"%d", face->size.y_ppem );
1152 RegCreateKeyExW( hkey_family, name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
1153 NULL, &hkey_face, NULL);
1155 else hkey_face = hkey_family;
1157 memset( cached, 0, sizeof(*cached) );
1158 cached->index = face->face_index;
1159 cached->flags = face->flags;
1160 cached->ntmflags = face->ntmFlags;
1161 cached->version = face->version;
1162 cached->fs = face->fs;
1163 if (!face->scalable) cached->size = face->size;
1164 lstrcpyW( cached->full_name, face->full_name );
1165 len = lstrlenW( face->full_name ) + 1;
1166 lstrcpyW( cached->full_name + len, face->file );
1167 len += lstrlenW( face->file ) + 1;
1169 RegSetValueExW( hkey_face, face->style_name, 0, REG_BINARY, (BYTE *)cached,
1170 offsetof( struct cached_face, full_name[len] ));
1172 if (hkey_face != hkey_family) RegCloseKey( hkey_face );
1173 RegCloseKey( hkey_family );
1176 static void remove_face_from_cache( struct gdi_font_face *face )
1178 HKEY hkey_family;
1180 if (RegOpenKeyExW( wine_fonts_cache_key, face->family->family_name, 0, KEY_ALL_ACCESS, &hkey_family ))
1181 return;
1183 if (!face->scalable)
1185 WCHAR name[10];
1186 swprintf( name, ARRAY_SIZE(name), L"%d", face->size.y_ppem );
1187 RegDeleteKeyW( hkey_family, name );
1189 else RegDeleteValueW( hkey_family, face->style_name );
1191 RegCloseKey( hkey_family );
1194 /* font links */
1196 struct gdi_font_link
1198 struct list entry;
1199 struct list links;
1200 WCHAR name[LF_FACESIZE];
1201 FONTSIGNATURE fs;
1204 struct gdi_font_link_entry
1206 struct list entry;
1207 FONTSIGNATURE fs;
1208 WCHAR family_name[LF_FACESIZE];
1211 static struct list font_links = LIST_INIT(font_links);
1213 static struct gdi_font_link *find_gdi_font_link( const WCHAR *name )
1215 struct gdi_font_link *link;
1217 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1218 if (!facename_compare( link->name, name, LF_FACESIZE - 1 )) return link;
1219 return NULL;
1222 static struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
1223 FONTSIGNATURE fs )
1225 struct gdi_font_link *link;
1226 struct gdi_font_link_entry *entry;
1227 struct gdi_font_family *family;
1229 LIST_FOR_EACH_ENTRY( link, &font_links, struct gdi_font_link, entry )
1231 if (!facename_compare( link->name, name, LF_FACESIZE - 1 ) ||
1232 (subst && !facename_compare( link->name, subst, LF_FACESIZE - 1 )))
1234 TRACE("found entry in system list\n");
1235 LIST_FOR_EACH_ENTRY( entry, &link->links, struct gdi_font_link_entry, entry )
1237 const struct gdi_font_link *links;
1239 family = find_family_from_name( entry->family_name );
1240 if (!fs.fsCsb[0]) return family;
1241 if (fs.fsCsb[0] & entry->fs.fsCsb[0]) return family;
1242 if ((links = find_gdi_font_link( family->family_name )) && fs.fsCsb[0] & links->fs.fsCsb[0])
1243 return family;
1247 return NULL;
1250 static struct gdi_font_link *add_gdi_font_link( const WCHAR *name )
1252 struct gdi_font_link *link = find_gdi_font_link( name );
1254 if (link) return link;
1255 if ((link = HeapAlloc( GetProcessHeap(), 0, sizeof(*link) )))
1257 lstrcpynW( link->name, name, LF_FACESIZE );
1258 memset( &link->fs, 0, sizeof(link->fs) );
1259 list_init( &link->links );
1260 list_add_tail( &font_links, &link->entry );
1262 return link;
1265 static void add_gdi_font_link_entry( struct gdi_font_link *link, const WCHAR *family_name, FONTSIGNATURE fs )
1267 struct gdi_font_link_entry *entry;
1269 entry = HeapAlloc( GetProcessHeap(), 0, sizeof(*entry) );
1270 lstrcpynW( entry->family_name, family_name, LF_FACESIZE );
1271 entry->fs = fs;
1272 link->fs.fsCsb[0] |= fs.fsCsb[0];
1273 link->fs.fsCsb[1] |= fs.fsCsb[1];
1274 list_add_tail( &link->links, &entry->entry );
1277 static const WCHAR * const font_links_list[] =
1279 L"Lucida Sans Unicode",
1280 L"Microsoft Sans Serif",
1281 L"Tahoma"
1284 static const struct font_links_defaults_list
1286 /* Keyed off substitution for "MS Shell Dlg" */
1287 const WCHAR *shelldlg;
1288 /* Maximum of four substitutes, plus terminating NULL pointer */
1289 const WCHAR *substitutes[5];
1290 } font_links_defaults_list[] =
1292 /* Non East-Asian */
1293 { L"Tahoma", /* FIXME unverified ordering */
1294 { L"MS UI Gothic", L"SimSun", L"Gulim", L"PMingLiU", NULL }
1296 /* Below lists are courtesy of
1297 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1299 /* Japanese */
1300 { L"MS UI Gothic",
1301 { L"MS UI Gothic", L"PMingLiU", L"SimSun", L"Gulim", NULL }
1303 /* Chinese Simplified */
1304 { L"SimSun",
1305 { L"SimSun", L"PMingLiU", L"MS UI Gothic", L"Batang", NULL }
1307 /* Korean */
1308 { L"Gulim",
1309 { L"Gulim", L"PMingLiU", L"MS UI Gothic", L"SimSun", NULL }
1311 /* Chinese Traditional */
1312 { L"PMingLiU",
1313 { L"PMingLiU", L"SimSun", L"MS UI Gothic", L"Batang", NULL }
1317 static void populate_system_links( const WCHAR *name, const WCHAR * const *values )
1319 struct gdi_font_family *family;
1320 struct gdi_font_face *face;
1321 struct gdi_font_link *font_link;
1322 const WCHAR *file, *value;
1324 /* Don't store fonts that are only substitutes for other fonts */
1325 if (get_gdi_font_subst( name, -1, NULL ))
1327 TRACE( "%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name) );
1328 return;
1330 font_link = add_gdi_font_link( name );
1331 for ( ; *values; values++)
1333 if (!facename_compare( name, *values, -1 )) continue;
1334 if (!(value = get_gdi_font_subst( *values, -1, NULL ))) value = *values;
1335 if (!(family = find_family_from_name( value ))) continue;
1336 /* use first extant filename for this Family */
1337 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1339 if (!face->file) continue;
1340 file = wcsrchr(face->file, '\\');
1341 if (!file) file = face->file;
1342 else file++;
1343 if ((face = find_face_from_filename( file, value )))
1345 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1346 TRACE( "added internal SystemLink for %s to %s in %s\n",
1347 debugstr_w(name), debugstr_w(value), debugstr_w(file) );
1349 else TRACE( "Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value) );
1350 break;
1355 static void load_system_links(void)
1357 HKEY hkey;
1358 DWORD i, j;
1359 const WCHAR *shelldlg_name;
1360 struct gdi_font_link *font_link, *system_font_link;
1361 struct gdi_font_face *face;
1363 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE,
1364 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey ))
1366 WCHAR value[MAX_PATH], data[1024];
1367 DWORD type, val_len, data_len;
1368 WCHAR *entry, *next;
1370 val_len = ARRAY_SIZE(value);
1371 data_len = sizeof(data);
1372 i = 0;
1373 while (!RegEnumValueW( hkey, i++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len))
1375 /* Don't store fonts that are only substitutes for other fonts */
1376 if (!get_gdi_font_subst( value, -1, NULL ))
1378 font_link = add_gdi_font_link( value );
1379 for (entry = data; (char *)entry < (char *)data + data_len && *entry; entry = next)
1381 const WCHAR *family_name = NULL;
1382 WCHAR *p;
1384 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1386 next = entry + lstrlenW(entry) + 1;
1387 if ((p = wcschr( entry, ',' )))
1389 *p++ = 0;
1390 while (iswspace(*p)) p++;
1391 if (!(family_name = get_gdi_font_subst( p, -1, NULL ))) family_name = p;
1393 if ((face = find_face_from_filename( entry, family_name )))
1395 add_gdi_font_link_entry( font_link, face->family->family_name, face->fs );
1396 TRACE("Adding file %s index %u\n", debugstr_w(face->file), face->face_index);
1398 else TRACE( "Unable to find file %s family %s\n",
1399 debugstr_w(entry), debugstr_w(family_name) );
1402 else TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1404 val_len = ARRAY_SIZE(value);
1405 data_len = sizeof(data);
1407 RegCloseKey( hkey );
1410 if ((shelldlg_name = get_gdi_font_subst( L"MS Shell Dlg", -1, NULL )))
1412 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
1414 const WCHAR *subst = get_gdi_font_subst( font_links_defaults_list[i].shelldlg, -1, NULL );
1416 if ((!facename_compare( font_links_defaults_list[i].shelldlg, shelldlg_name, -1 ) ||
1417 (subst && !facename_compare( subst, shelldlg_name, -1 ))))
1419 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
1420 populate_system_links( font_links_list[j], font_links_defaults_list[i].substitutes );
1421 if (!facename_compare(shelldlg_name, font_links_defaults_list[i].substitutes[0], -1))
1422 populate_system_links( shelldlg_name, font_links_defaults_list[i].substitutes );
1426 else WARN( "could not find FontSubstitute for MS Shell Dlg\n" );
1428 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1429 that Tahoma has */
1431 system_font_link = add_gdi_font_link( L"System" );
1432 if ((face = find_face_from_filename( L"tahoma.ttf", L"Tahoma" )))
1434 add_gdi_font_link_entry( system_font_link, face->family->family_name, face->fs );
1435 TRACE("Found Tahoma in %s index %u\n", debugstr_w(face->file), face->face_index);
1437 if ((font_link = find_gdi_font_link( L"Tahoma" )))
1439 struct gdi_font_link_entry *entry;
1440 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
1441 add_gdi_font_link_entry( system_font_link, entry->family_name, entry->fs );
1445 /* font matching */
1447 static BOOL can_select_face( const struct gdi_font_face *face, FONTSIGNATURE fs, BOOL can_use_bitmap )
1449 struct gdi_font_link *font_link;
1451 if (!face->scalable && !can_use_bitmap) return FALSE;
1452 if (!fs.fsCsb[0]) return TRUE;
1453 if (fs.fsCsb[0] & face->fs.fsCsb[0]) return TRUE;
1454 if (!(font_link = find_gdi_font_link( face->family->family_name ))) return FALSE;
1455 if (fs.fsCsb[0] & font_link->fs.fsCsb[0]) return TRUE;
1456 return FALSE;
1459 static struct gdi_font_face *find_best_matching_face( const struct gdi_font_family *family,
1460 const LOGFONTW *lf, FONTSIGNATURE fs,
1461 BOOL can_use_bitmap )
1463 struct gdi_font_face *face = NULL, *best = NULL, *best_bitmap = NULL;
1464 unsigned int best_score = 4;
1465 int best_diff = 0;
1466 int it = !!lf->lfItalic;
1467 int bd = lf->lfWeight > 550;
1468 int height = lf->lfHeight;
1470 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1472 int italic = !!(face->ntmFlags & NTM_ITALIC);
1473 int bold = !!(face->ntmFlags & NTM_BOLD);
1474 int score = (italic ^ it) + (bold ^ bd);
1476 if (!can_select_face( face, fs, can_use_bitmap )) continue;
1477 if (score > best_score) continue;
1478 TRACE( "(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n", italic, bold, it, bd );
1479 best_score = score;
1480 best = face;
1481 if (best->scalable && best_score == 0) break;
1482 if (!best->scalable)
1484 int diff;
1485 if (height > 0)
1486 diff = height - (signed int)best->size.height;
1487 else
1488 diff = -height - ((signed int)best->size.height - best->size.internal_leading);
1489 if (!best_bitmap ||
1490 (best_diff > 0 && diff >= 0 && diff < best_diff) ||
1491 (best_diff < 0 && diff > best_diff))
1493 TRACE( "%d is better for %d diff was %d\n", best->size.height, height, best_diff );
1494 best_diff = diff;
1495 best_bitmap = best;
1496 if (best_score == 0 && best_diff == 0) break;
1500 if (!best) return NULL;
1501 return best->scalable ? best : best_bitmap;
1504 static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, const WCHAR *subst,
1505 const LOGFONTW *lf, FONTSIGNATURE fs,
1506 BOOL can_use_bitmap )
1508 struct gdi_font_family *family;
1509 struct gdi_font_face *face;
1511 family = find_family_from_any_name( name );
1512 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1513 if (subst)
1515 family = find_family_from_any_name( subst );
1516 if (family && (face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1519 /* search by full face name */
1520 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1521 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
1522 if (!facename_compare( face->full_name, name, LF_FACESIZE - 1 ) &&
1523 can_select_face( face, fs, can_use_bitmap ))
1524 return face;
1526 if ((family = find_family_from_font_links( name, subst, fs )))
1528 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1530 return NULL;
1533 static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
1534 BOOL can_use_bitmap, BOOL want_vertical )
1536 struct gdi_font_family *family;
1537 struct gdi_font_face *face;
1538 WCHAR name[LF_FACESIZE + 1];
1539 int i = 0;
1541 /* first try the family fallbacks */
1542 while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
1544 if (want_vertical)
1546 memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE));
1547 name[0] = '@';
1550 if (!(family = find_family_from_any_name(name))) continue;
1551 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1553 /* otherwise try only scalable */
1554 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1556 if ((family->family_name[0] == '@') == !want_vertical) continue;
1557 if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
1559 if (!can_use_bitmap) return NULL;
1560 /* then also bitmap fonts */
1561 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
1563 if ((family->family_name[0] == '@') == !want_vertical) continue;
1564 if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face;
1566 return NULL;
1569 static struct gdi_font_face *find_matching_face( const LOGFONTW *lf, CHARSETINFO *csi, BOOL can_use_bitmap,
1570 const WCHAR **orig_name )
1572 BOOL want_vertical = (lf->lfFaceName[0] == '@');
1573 struct gdi_font_face *face;
1575 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)lf->lfCharSet, csi, TCI_SRCCHARSET ))
1577 if (lf->lfCharSet != DEFAULT_CHARSET) FIXME( "Untranslated charset %d\n", lf->lfCharSet );
1578 csi->fs.fsCsb[0] = 0;
1581 if (lf->lfFaceName[0])
1583 int subst_charset;
1584 const WCHAR *subst = get_gdi_font_subst( lf->lfFaceName, lf->lfCharSet, &subst_charset );
1586 if (subst)
1588 TRACE( "substituting %s,%d -> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfCharSet,
1589 debugstr_w(subst), (subst_charset != -1) ? subst_charset : lf->lfCharSet );
1590 if (subst_charset != -1)
1591 TranslateCharsetInfo( (DWORD *)(INT_PTR)subst_charset, csi, TCI_SRCCHARSET );
1592 *orig_name = lf->lfFaceName;
1595 if ((face = find_matching_face_by_name( lf->lfFaceName, subst, lf, csi->fs, can_use_bitmap )))
1596 return face;
1598 *orig_name = NULL; /* substitution is no longer relevant */
1600 /* If requested charset was DEFAULT_CHARSET then try using charset
1601 corresponding to the current ansi codepage */
1602 if (!csi->fs.fsCsb[0])
1604 INT acp = GetACP();
1605 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)acp, csi, TCI_SRCCODEPAGE ))
1607 FIXME( "TCI failed on codepage %d\n", acp );
1608 csi->fs.fsCsb[0] = 0;
1612 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1613 if (csi->fs.fsCsb[0])
1615 csi->fs.fsCsb[0] = 0;
1616 if ((face = find_any_face( lf, csi->fs, can_use_bitmap, want_vertical ))) return face;
1618 if (want_vertical && (face = find_any_face( lf, csi->fs, can_use_bitmap, FALSE ))) return face;
1619 return NULL;
1622 /* realized font objects */
1624 #define FIRST_FONT_HANDLE 1
1625 #define MAX_FONT_HANDLES 256
1627 struct font_handle_entry
1629 struct gdi_font *font;
1630 WORD generation; /* generation count for reusing handle values */
1633 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
1634 static struct font_handle_entry *next_free;
1635 static struct font_handle_entry *next_unused = font_handles;
1637 static struct font_handle_entry *handle_entry( DWORD handle )
1639 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
1641 if (idx < MAX_FONT_HANDLES)
1643 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
1644 return &font_handles[idx];
1646 if (handle) WARN( "invalid handle 0x%08x\n", handle );
1647 return NULL;
1650 static struct gdi_font *get_font_from_handle( DWORD handle )
1652 struct font_handle_entry *entry = handle_entry( handle );
1654 if (entry) return entry->font;
1655 SetLastError( ERROR_INVALID_PARAMETER );
1656 return NULL;
1659 static DWORD alloc_font_handle( struct gdi_font *font )
1661 struct font_handle_entry *entry;
1663 entry = next_free;
1664 if (entry)
1665 next_free = (struct font_handle_entry *)entry->font;
1666 else if (next_unused < font_handles + MAX_FONT_HANDLES)
1667 entry = next_unused++;
1668 else
1670 ERR( "out of realized font handles\n" );
1671 return 0;
1673 entry->font = font;
1674 if (++entry->generation == 0xffff) entry->generation = 1;
1675 return MAKELONG( entry - font_handles + FIRST_FONT_HANDLE, entry->generation );
1678 static void free_font_handle( DWORD handle )
1680 struct font_handle_entry *entry;
1682 if ((entry = handle_entry( handle )))
1684 entry->font = (struct gdi_font *)next_free;
1685 next_free = entry;
1689 static struct gdi_font *alloc_gdi_font( const WCHAR *file, void *data_ptr, SIZE_T data_size )
1691 UINT len = file ? lstrlenW(file) : 0;
1692 struct gdi_font *font = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1693 offsetof( struct gdi_font, file[len + 1] ));
1695 font->refcount = 1;
1696 font->matrix.eM11 = font->matrix.eM22 = 1.0;
1697 font->scale_y = 1;
1698 font->kern_count = -1;
1699 list_init( &font->child_fonts );
1701 if (file)
1703 WIN32_FILE_ATTRIBUTE_DATA info;
1704 if (GetFileAttributesExW( file, GetFileExInfoStandard, &info ))
1706 font->writetime = info.ftLastWriteTime;
1707 font->data_size = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
1708 memcpy( font->file, file, len * sizeof(WCHAR) );
1711 else
1713 font->data_ptr = data_ptr;
1714 font->data_size = data_size;
1717 font->handle = alloc_font_handle( font );
1718 return font;
1721 static void free_gdi_font( struct gdi_font *font )
1723 DWORD i;
1724 struct gdi_font *child, *child_next;
1726 if (font->private) font_funcs->destroy_font( font );
1727 free_font_handle( font->handle );
1728 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, struct gdi_font, entry )
1730 list_remove( &child->entry );
1731 free_gdi_font( child );
1733 for (i = 0; i < font->gm_size; i++) HeapFree( GetProcessHeap(), 0, font->gm[i] );
1734 HeapFree( GetProcessHeap(), 0, font->otm.otmpFamilyName );
1735 HeapFree( GetProcessHeap(), 0, font->otm.otmpStyleName );
1736 HeapFree( GetProcessHeap(), 0, font->otm.otmpFaceName );
1737 HeapFree( GetProcessHeap(), 0, font->otm.otmpFullName );
1738 HeapFree( GetProcessHeap(), 0, font->gm );
1739 HeapFree( GetProcessHeap(), 0, font->kern_pairs );
1740 HeapFree( GetProcessHeap(), 0, font->gsub_table );
1741 HeapFree( GetProcessHeap(), 0, font );
1744 static inline const WCHAR *get_gdi_font_name( struct gdi_font *font )
1746 return (WCHAR *)font->otm.otmpFamilyName;
1749 static struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const WCHAR *family_name,
1750 const LOGFONTW *lf )
1752 struct gdi_font *font;
1754 if (!(font = alloc_gdi_font( face->file, face->data_ptr, face->data_size ))) return NULL;
1755 font->fs = face->fs;
1756 font->lf = *lf;
1757 font->fake_italic = (lf->lfItalic && !(face->ntmFlags & NTM_ITALIC));
1758 font->fake_bold = (lf->lfWeight > 550 && !(face->ntmFlags & NTM_BOLD));
1759 font->scalable = face->scalable;
1760 font->face_index = face->face_index;
1761 font->ntmFlags = face->ntmFlags;
1762 font->aa_flags = HIWORD( face->flags );
1763 if (!family_name) family_name = face->family->family_name;
1764 font->otm.otmpFamilyName = (char *)strdupW( family_name );
1765 font->otm.otmpStyleName = (char *)strdupW( face->style_name );
1766 font->otm.otmpFaceName = (char *)strdupW( face->full_name );
1767 return font;
1770 struct glyph_metrics
1772 GLYPHMETRICS gm;
1773 ABC abc; /* metrics of the unrotated char */
1774 BOOL init;
1777 #define GM_BLOCK_SIZE 128
1779 /* TODO: GGO format support */
1780 static BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
1782 UINT block = index / GM_BLOCK_SIZE;
1783 UINT entry = index % GM_BLOCK_SIZE;
1785 if (block < font->gm_size && font->gm[block] && font->gm[block][entry].init)
1787 *gm = font->gm[block][entry].gm;
1788 *abc = font->gm[block][entry].abc;
1790 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
1791 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
1792 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
1793 return TRUE;
1796 return FALSE;
1799 static void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
1800 const GLYPHMETRICS *gm, const ABC *abc )
1802 UINT block = index / GM_BLOCK_SIZE;
1803 UINT entry = index % GM_BLOCK_SIZE;
1805 if (block >= font->gm_size)
1807 struct glyph_metrics **ptr;
1809 if (font->gm)
1810 ptr = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm, (block + 1) * sizeof(*ptr) );
1811 else
1812 ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, (block + 1) * sizeof(*ptr) );
1813 if (!ptr) return;
1814 font->gm_size = block + 1;
1815 font->gm = ptr;
1817 if (!font->gm[block])
1819 font->gm[block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**font->gm) * GM_BLOCK_SIZE );
1820 if (!font->gm[block]) return;
1822 font->gm[block][entry].gm = *gm;
1823 font->gm[block][entry].abc = *abc;
1824 font->gm[block][entry].init = TRUE;
1828 /* GSUB table support */
1830 typedef struct
1832 DWORD version;
1833 WORD ScriptList;
1834 WORD FeatureList;
1835 WORD LookupList;
1836 } GSUB_Header;
1838 typedef struct
1840 CHAR ScriptTag[4];
1841 WORD Script;
1842 } GSUB_ScriptRecord;
1844 typedef struct
1846 WORD ScriptCount;
1847 GSUB_ScriptRecord ScriptRecord[1];
1848 } GSUB_ScriptList;
1850 typedef struct
1852 CHAR LangSysTag[4];
1853 WORD LangSys;
1854 } GSUB_LangSysRecord;
1856 typedef struct
1858 WORD DefaultLangSys;
1859 WORD LangSysCount;
1860 GSUB_LangSysRecord LangSysRecord[1];
1861 } GSUB_Script;
1863 typedef struct
1865 WORD LookupOrder; /* Reserved */
1866 WORD ReqFeatureIndex;
1867 WORD FeatureCount;
1868 WORD FeatureIndex[1];
1869 } GSUB_LangSys;
1871 typedef struct
1873 CHAR FeatureTag[4];
1874 WORD Feature;
1875 } GSUB_FeatureRecord;
1877 typedef struct
1879 WORD FeatureCount;
1880 GSUB_FeatureRecord FeatureRecord[1];
1881 } GSUB_FeatureList;
1883 typedef struct
1885 WORD FeatureParams; /* Reserved */
1886 WORD LookupCount;
1887 WORD LookupListIndex[1];
1888 } GSUB_Feature;
1890 typedef struct
1892 WORD LookupCount;
1893 WORD Lookup[1];
1894 } GSUB_LookupList;
1896 typedef struct
1898 WORD LookupType;
1899 WORD LookupFlag;
1900 WORD SubTableCount;
1901 WORD SubTable[1];
1902 } GSUB_LookupTable;
1904 typedef struct
1906 WORD CoverageFormat;
1907 WORD GlyphCount;
1908 WORD GlyphArray[1];
1909 } GSUB_CoverageFormat1;
1911 typedef struct
1913 WORD Start;
1914 WORD End;
1915 WORD StartCoverageIndex;
1916 } GSUB_RangeRecord;
1918 typedef struct
1920 WORD CoverageFormat;
1921 WORD RangeCount;
1922 GSUB_RangeRecord RangeRecord[1];
1923 } GSUB_CoverageFormat2;
1925 typedef struct
1927 WORD SubstFormat; /* = 1 */
1928 WORD Coverage;
1929 WORD DeltaGlyphID;
1930 } GSUB_SingleSubstFormat1;
1932 typedef struct
1934 WORD SubstFormat; /* = 2 */
1935 WORD Coverage;
1936 WORD GlyphCount;
1937 WORD Substitute[1];
1938 } GSUB_SingleSubstFormat2;
1940 static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
1942 GSUB_ScriptList *script;
1943 GSUB_Script *deflt = NULL;
1944 int i;
1946 script = (GSUB_ScriptList *)((BYTE *)header + GET_BE_WORD(header->ScriptList));
1947 TRACE("%i scripts in this font\n", GET_BE_WORD(script->ScriptCount) );
1948 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
1950 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
1951 GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
1952 if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
1953 if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
1955 return deflt;
1958 static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
1960 int i, offset;
1961 GSUB_LangSys *lang;
1963 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
1965 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
1967 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
1968 lang = (GSUB_LangSys *)((BYTE *)script + offset);
1969 if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
1971 offset = GET_BE_WORD(script->DefaultLangSys);
1972 if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
1973 return NULL;
1976 static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
1978 int i;
1979 const GSUB_FeatureList *feature;
1981 feature = (GSUB_FeatureList *)((BYTE *)header + GET_BE_WORD(header->FeatureList));
1982 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
1983 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
1985 int index = GET_BE_WORD(lang->FeatureIndex[i]);
1986 if (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
1987 return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
1989 return NULL;
1992 static const char *get_opentype_script( const struct gdi_font *font )
1995 * I am not sure if this is the correct way to generate our script tag
1997 switch (font->charset)
1999 case ANSI_CHARSET: return "latn";
2000 case BALTIC_CHARSET: return "latn"; /* ?? */
2001 case CHINESEBIG5_CHARSET: return "hani";
2002 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
2003 case GB2312_CHARSET: return "hani";
2004 case GREEK_CHARSET: return "grek";
2005 case HANGUL_CHARSET: return "hang";
2006 case RUSSIAN_CHARSET: return "cyrl";
2007 case SHIFTJIS_CHARSET: return "kana";
2008 case TURKISH_CHARSET: return "latn"; /* ?? */
2009 case VIETNAMESE_CHARSET: return "latn";
2010 case JOHAB_CHARSET: return "latn"; /* ?? */
2011 case ARABIC_CHARSET: return "arab";
2012 case HEBREW_CHARSET: return "hebr";
2013 case THAI_CHARSET: return "thai";
2014 default: return "latn";
2018 static void *get_GSUB_vert_feature( struct gdi_font *font )
2020 GSUB_Header *header;
2021 GSUB_Script *script;
2022 GSUB_LangSys *language;
2023 GSUB_Feature *feature;
2024 DWORD length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
2026 if (length == GDI_ERROR) return NULL;
2028 header = HeapAlloc( GetProcessHeap(), 0, length );
2029 font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
2030 TRACE( "Loaded GSUB table of %i bytes\n", length );
2032 if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
2034 if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
2036 feature = GSUB_get_feature( header, language, "vrt2" );
2037 if (!feature) feature = GSUB_get_feature( header, language, "vert" );
2038 if (feature)
2040 font->gsub_table = header;
2041 return feature;
2043 TRACE("vrt2/vert feature not found\n");
2045 else TRACE("Language not found\n");
2047 else TRACE("Script not found\n");
2049 HeapFree( GetProcessHeap(), 0, header );
2050 return NULL;
2053 static int GSUB_is_glyph_covered( void *table, UINT glyph )
2055 GSUB_CoverageFormat1 *cf1 = table;
2057 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
2059 int i, count = GET_BE_WORD(cf1->GlyphCount);
2061 TRACE("Coverage Format 1, %i glyphs\n",count);
2062 for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
2063 return -1;
2065 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
2067 int i, count;
2068 GSUB_CoverageFormat2 *cf2 = table;
2070 count = GET_BE_WORD(cf2->RangeCount);
2071 TRACE("Coverage Format 2, %i ranges\n",count);
2072 for (i = 0; i < count; i++)
2074 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
2075 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
2076 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
2078 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
2079 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
2082 return -1;
2084 else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
2086 return -1;
2089 static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
2091 GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
2092 int i, j, offset;
2094 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
2095 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
2097 GSUB_LookupTable *look;
2098 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
2099 look = (GSUB_LookupTable *)((BYTE *)lookup + offset);
2100 TRACE("type %i, flag %x, subtables %i\n",
2101 GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
2102 if (GET_BE_WORD(look->LookupType) == 1)
2104 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2106 GSUB_SingleSubstFormat1 *ssf1;
2107 offset = GET_BE_WORD(look->SubTable[j]);
2108 ssf1 = (GSUB_SingleSubstFormat1 *)((BYTE *)look + offset);
2109 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
2111 int offset = GET_BE_WORD(ssf1->Coverage);
2112 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
2113 if (GSUB_is_glyph_covered( (BYTE *) ssf1 + offset, glyph ) != -1)
2115 TRACE(" Glyph 0x%x ->",glyph);
2116 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
2117 TRACE(" 0x%x\n",glyph);
2120 else
2122 GSUB_SingleSubstFormat2 *ssf2;
2123 int index, offset;
2125 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
2126 offset = GET_BE_WORD(ssf1->Coverage);
2127 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
2128 index = GSUB_is_glyph_covered( (BYTE *)ssf2 + offset, glyph );
2129 TRACE(" Coverage index %i\n",index);
2130 if (index != -1)
2132 TRACE(" Glyph is 0x%x ->",glyph);
2133 glyph = GET_BE_WORD(ssf2->Substitute[index]);
2134 TRACE("0x%x\n",glyph);
2139 else FIXME("We only handle SubType 1\n");
2141 return glyph;
2144 static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
2146 if (!glyph) return glyph;
2147 if (!font->gsub_table) return glyph;
2148 return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
2151 static void add_child_font( struct gdi_font *font, const WCHAR *family_name )
2153 FONTSIGNATURE fs = {{0}};
2154 struct gdi_font *child;
2155 struct gdi_font_face *face;
2157 if (!(face = find_matching_face_by_name( family_name, NULL, &font->lf, fs, FALSE ))) return;
2159 if (!(child = create_gdi_font( face, family_name, &font->lf ))) return;
2160 child->matrix = font->matrix;
2161 child->can_use_bitmap = font->can_use_bitmap;
2162 child->scale_y = font->scale_y;
2163 child->aveWidth = font->aveWidth;
2164 child->charset = font->charset;
2165 child->codepage = font->codepage;
2166 child->base_font = font;
2167 list_add_tail( &font->child_fonts, &child->entry );
2168 TRACE( "created child font %p for base %p\n", child, font );
2171 static void create_child_font_list( struct gdi_font *font )
2173 struct gdi_font_link *font_link;
2174 struct gdi_font_link_entry *entry;
2175 const WCHAR* font_name;
2177 if (!(font_name = get_gdi_font_subst( get_gdi_font_name(font), -1, NULL )))
2178 font_name = get_gdi_font_name( font );
2180 if ((font_link = find_gdi_font_link( font_name )))
2182 TRACE("found entry in system list\n");
2183 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2184 add_child_font( font, entry->family_name );
2187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2188 * Sans Serif. This is how asian windows get default fallbacks for fonts
2190 if (is_dbcs_ansi_cp(GetACP()) && font->charset != SYMBOL_CHARSET && font->charset != OEM_CHARSET &&
2191 facename_compare( font_name, L"Microsoft Sans Serif", -1 ) != 0)
2193 if ((font_link = find_gdi_font_link( L"Microsoft Sans Serif" )))
2195 TRACE("found entry in default fallback list\n");
2196 LIST_FOR_EACH_ENTRY( entry, &font_link->links, struct gdi_font_link_entry, entry )
2197 add_child_font( font, entry->family_name );
2202 /* font cache */
2204 static struct list gdi_font_list = LIST_INIT( gdi_font_list );
2205 static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
2206 static unsigned int unused_font_count;
2207 #define UNUSED_CACHE_SIZE 10
2209 static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
2210 const FMAT2 *matrix, BOOL can_use_bitmap )
2212 if (font->hash != hash) return TRUE;
2213 if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
2214 if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2215 if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
2216 return facename_compare( font->lf.lfFaceName, lf->lfFaceName, -1 );
2219 static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2221 DWORD hash = 0, *ptr, two_chars;
2222 WORD *pwc;
2223 unsigned int i;
2225 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
2226 hash ^= *ptr;
2227 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
2228 hash ^= *ptr;
2229 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
2231 two_chars = *ptr;
2232 pwc = (WCHAR *)&two_chars;
2233 if(!*pwc) break;
2234 *pwc = towupper(*pwc);
2235 pwc++;
2236 *pwc = towupper(*pwc);
2237 hash ^= two_chars;
2238 if(!*pwc) break;
2240 hash ^= !can_use_bitmap;
2241 return hash;
2244 static void cache_gdi_font( struct gdi_font *font )
2246 static DWORD cache_num = 1;
2248 font->cache_num = cache_num++;
2249 font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
2250 list_add_head( &gdi_font_list, &font->entry );
2251 TRACE( "font %p\n", font );
2254 static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
2256 struct gdi_font *font;
2257 DWORD hash = hash_font( lf, matrix, can_use_bitmap );
2259 /* try the in-use list */
2260 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
2262 if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
2263 list_remove( &font->entry );
2264 list_add_head( &gdi_font_list, &font->entry );
2265 if (!font->refcount++)
2267 list_remove( &font->unused_entry );
2268 unused_font_count--;
2270 return font;
2272 return NULL;
2275 static void release_gdi_font( struct gdi_font *font )
2277 if (!font) return;
2278 if (--font->refcount) return;
2280 TRACE( "font %p\n", font );
2282 /* add it to the unused list */
2283 EnterCriticalSection( &font_cs );
2284 list_add_head( &unused_gdi_font_list, &font->unused_entry );
2285 if (unused_font_count > UNUSED_CACHE_SIZE)
2287 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
2288 TRACE( "freeing %p\n", font );
2289 list_remove( &font->entry );
2290 list_remove( &font->unused_entry );
2291 free_gdi_font( font );
2293 else unused_font_count++;
2294 LeaveCriticalSection( &font_cs );
2297 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
2299 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
2301 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2302 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2303 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
2304 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2307 static void set_value_key(HKEY hkey, const char *name, const char *value)
2309 if (value)
2310 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2311 else if (name)
2312 RegDeleteValueA(hkey, name);
2315 static void update_font_association_info(UINT current_ansi_codepage)
2317 if (is_dbcs_ansi_cp(current_ansi_codepage))
2319 HKEY hkey;
2320 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\FontAssoc", &hkey) == ERROR_SUCCESS)
2322 HKEY hsubkey;
2323 if (RegCreateKeyW(hkey, L"Associated Charset", &hsubkey) == ERROR_SUCCESS)
2325 switch (current_ansi_codepage)
2327 case 932:
2328 set_value_key(hsubkey, "ANSI(00)", "NO");
2329 set_value_key(hsubkey, "OEM(FF)", "NO");
2330 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2331 break;
2332 case 936:
2333 case 949:
2334 case 950:
2335 set_value_key(hsubkey, "ANSI(00)", "YES");
2336 set_value_key(hsubkey, "OEM(FF)", "YES");
2337 set_value_key(hsubkey, "SYMBOL(02)", "NO");
2338 break;
2340 RegCloseKey(hsubkey);
2343 /* TODO: Associated DefaultFonts */
2345 RegCloseKey(hkey);
2348 else
2349 RegDeleteTreeW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\FontAssoc");
2352 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
2354 if (value)
2355 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
2356 else if (name)
2357 RegDeleteValueW(hkey, name);
2360 static void update_font_system_link_info(UINT current_ansi_codepage)
2362 static const WCHAR system_link_simplified_chinese[] =
2363 L"SIMSUN.TTC,SimSun\0"
2364 L"MINGLIU.TTC,PMingLiu\0"
2365 L"MSGOTHIC.TTC,MS UI Gothic\0"
2366 L"BATANG.TTC,Batang\0";
2367 static const WCHAR system_link_traditional_chinese[] =
2368 L"MINGLIU.TTC,PMingLiu\0"
2369 L"SIMSUN.TTC,SimSun\0"
2370 L"MSGOTHIC.TTC,MS UI Gothic\0"
2371 L"BATANG.TTC,Batang\0";
2372 static const WCHAR system_link_japanese[] =
2373 L"MSGOTHIC.TTC,MS UI Gothic\0"
2374 L"MINGLIU.TTC,PMingLiU\0"
2375 L"SIMSUN.TTC,SimSun\0"
2376 L"GULIM.TTC,Gulim\0";
2377 static const WCHAR system_link_korean[] =
2378 L"GULIM.TTC,Gulim\0"
2379 L"MSGOTHIC.TTC,MS UI Gothic\0"
2380 L"MINGLIU.TTC,PMingLiU\0"
2381 L"SIMSUN.TTC,SimSun\0";
2382 static const WCHAR system_link_non_cjk[] =
2383 L"MSGOTHIC.TTC,MS UI Gothic\0"
2384 L"MINGLIU.TTC,PMingLiU\0"
2385 L"SIMSUN.TTC,SimSun\0"
2386 L"GULIM.TTC,Gulim\0";
2387 HKEY hkey;
2389 if (!RegCreateKeyW(HKEY_LOCAL_MACHINE,
2390 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", &hkey))
2392 const WCHAR *link;
2393 DWORD len;
2395 switch (current_ansi_codepage)
2397 case 932:
2398 link = system_link_japanese;
2399 len = sizeof(system_link_japanese);
2400 break;
2401 case 936:
2402 link = system_link_simplified_chinese;
2403 len = sizeof(system_link_simplified_chinese);
2404 break;
2405 case 949:
2406 link = system_link_korean;
2407 len = sizeof(system_link_korean);
2408 break;
2409 case 950:
2410 link = system_link_traditional_chinese;
2411 len = sizeof(system_link_traditional_chinese);
2412 break;
2413 default:
2414 link = system_link_non_cjk;
2415 len = sizeof(system_link_non_cjk);
2417 set_multi_value_key(hkey, L"Lucida Sans Unicode", link, len);
2418 set_multi_value_key(hkey, L"Microsoft Sans Serif", link, len);
2419 set_multi_value_key(hkey, L"Tahoma", link, len);
2420 RegCloseKey(hkey);
2424 static void update_codepage(void)
2426 char buf[40], cpbuf[40];
2427 HKEY hkey;
2428 DWORD len, type, size;
2429 UINT i, ansi_cp, oem_cp;
2430 DWORD screen_dpi, font_dpi = 0;
2431 BOOL done = FALSE;
2433 screen_dpi = get_dpi();
2434 if (!screen_dpi) screen_dpi = 96;
2436 size = sizeof(DWORD);
2437 if (RegQueryValueExW(wine_fonts_key, L"LogPixels", NULL, &type, (BYTE *)&font_dpi, &size) ||
2438 type != REG_DWORD || size != sizeof(DWORD))
2439 font_dpi = 0;
2441 ansi_cp = GetACP();
2442 oem_cp = GetOEMCP();
2443 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2445 buf[0] = 0;
2446 len = sizeof(buf);
2447 if (!RegQueryValueExA(wine_fonts_key, "Codepages", 0, &type, (BYTE *)buf, &len) && type == REG_SZ)
2449 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) return; /* already set correctly */
2450 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
2451 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
2453 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
2454 ansi_cp, oem_cp, screen_dpi);
2456 RegSetValueExA(wine_fonts_key, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2457 RegSetValueExW(wine_fonts_key, L"LogPixels", 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
2459 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
2461 if (nls_update_font_list[i].ansi_cp == ansi_cp && nls_update_font_list[i].oem_cp == oem_cp)
2463 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &hkey ))
2465 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem,
2466 strlen(nls_update_font_list[i].oem)+1);
2467 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed,
2468 strlen(nls_update_font_list[i].fixed)+1);
2469 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system,
2470 strlen(nls_update_font_list[i].system)+1);
2471 RegCloseKey(hkey);
2473 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE,
2474 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey ))
2476 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2477 RegCloseKey(hkey);
2479 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE,
2480 L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey ))
2482 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
2483 RegCloseKey(hkey);
2485 /* Only update these if the Codepage changed. */
2486 if (strcmp( buf, cpbuf ) && !RegCreateKeyW( HKEY_LOCAL_MACHINE,
2487 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2489 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2490 strlen(nls_update_font_list[i].shelldlg)+1);
2491 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2492 strlen(nls_update_font_list[i].tmsrmn)+1);
2494 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2495 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2496 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2497 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2498 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2499 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2500 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2501 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2503 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2504 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2505 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2507 RegCloseKey(hkey);
2509 done = TRUE;
2511 else
2513 /* Delete the FontSubstitutes from other locales */
2514 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2516 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2517 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2518 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2519 RegCloseKey(hkey);
2523 if (!done)
2524 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2526 /* update locale dependent font association info and font system link info in registry.
2527 update only when codepages changed, not logpixels. */
2528 if (strcmp(buf, cpbuf) != 0)
2530 update_font_association_info(ansi_cp);
2531 update_font_system_link_info(ansi_cp);
2536 /*************************************************************
2537 * font_CreateDC
2539 static BOOL CDECL font_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
2540 LPCWSTR output, const DEVMODEW *devmode )
2542 struct font_physdev *physdev;
2544 if (!font_funcs) return TRUE;
2545 if (!(physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) ))) return FALSE;
2546 push_dc_driver( dev, &physdev->dev, &font_driver );
2547 return TRUE;
2551 /*************************************************************
2552 * font_DeleteDC
2554 static BOOL CDECL font_DeleteDC( PHYSDEV dev )
2556 struct font_physdev *physdev = get_font_dev( dev );
2558 release_gdi_font( physdev->font );
2559 HeapFree( GetProcessHeap(), 0, physdev );
2560 return TRUE;
2564 struct gdi_font_enum_data
2566 ENUMLOGFONTEXW elf;
2567 NEWTEXTMETRICEXW ntm;
2570 struct enum_charset
2572 DWORD mask;
2573 DWORD charset;
2574 DWORD script;
2577 static int load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
2579 HRSRC rsrc;
2580 HGLOBAL hMem;
2581 WCHAR *p;
2582 int i;
2584 id += IDS_FIRST_SCRIPT;
2585 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
2586 if (!rsrc) return 0;
2587 hMem = LoadResource( gdi32_module, rsrc );
2588 if (!hMem) return 0;
2590 p = LockResource( hMem );
2591 id &= 0x000f;
2592 while (id--) p += *p + 1;
2594 i = min(LF_FACESIZE - 1, *p);
2595 memcpy(buffer, p + 1, i * sizeof(WCHAR));
2596 buffer[i] = 0;
2597 return i;
2600 static BOOL is_complex_script_ansi_cp( UINT ansi_cp )
2602 return (ansi_cp == 874 /* Thai */
2603 || ansi_cp == 1255 /* Hebrew */
2604 || ansi_cp == 1256 /* Arabic */
2608 /***************************************************
2609 * create_enum_charset_list
2611 * This function creates charset enumeration list because in DEFAULT_CHARSET
2612 * case, the ANSI codepage's charset takes precedence over other charsets.
2613 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
2614 * This function works as a filter other than DEFAULT_CHARSET case.
2616 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset *list)
2618 struct enum_charset *start = list;
2619 CHARSETINFO csi;
2620 int i;
2622 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET ) && csi.fs.fsCsb[0] != 0)
2624 list->mask = csi.fs.fsCsb[0];
2625 list->charset = csi.ciCharset;
2626 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2627 list++;
2629 else /* charset is DEFAULT_CHARSET or invalid. */
2631 int acp = GetACP();
2632 DWORD mask = 0;
2634 /* Set the current codepage's charset as the first element. */
2635 if (!is_complex_script_ansi_cp(acp) &&
2636 TranslateCharsetInfo( (DWORD *)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE ) &&
2637 csi.fs.fsCsb[0] != 0)
2639 list->mask = csi.fs.fsCsb[0];
2640 list->charset = csi.ciCharset;
2641 for (i = 0; i < 32; i++) if (csi.fs.fsCsb[0] & (1u << i)) list->script = i;
2642 mask |= csi.fs.fsCsb[0];
2643 list++;
2646 /* Fill out left elements. */
2647 for (i = 0; i < 32; i++)
2649 FONTSIGNATURE fs;
2650 fs.fsCsb[0] = 1u << i;
2651 fs.fsCsb[1] = 0;
2652 if (fs.fsCsb[0] & mask) continue; /* skip, already added. */
2653 if (!TranslateCharsetInfo( fs.fsCsb, &csi, TCI_SRCFONTSIG ))
2654 continue; /* skip, this is an invalid fsCsb bit. */
2655 list->mask = fs.fsCsb[0];
2656 list->charset = csi.ciCharset;
2657 list->script = i;
2658 mask |= fs.fsCsb[0];
2659 list++;
2661 /* add catch all mask for remaining bits */
2662 if (~mask)
2664 list->mask = ~mask;
2665 list->charset = DEFAULT_CHARSET;
2666 list->script = IDS_OTHER - IDS_FIRST_SCRIPT;
2667 list++;
2670 return list - start;
2673 static UINT get_font_type( const NEWTEXTMETRICEXW *ntm )
2675 UINT ret = 0;
2677 if (ntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) ret |= TRUETYPE_FONTTYPE;
2678 if (ntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE) ret |= DEVICE_FONTTYPE;
2679 if (!(ntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR)) ret |= RASTER_FONTTYPE;
2680 return ret;
2683 static BOOL get_face_enum_data( struct gdi_font_face *face, ENUMLOGFONTEXW *elf, NEWTEXTMETRICEXW *ntm )
2685 struct gdi_font *font;
2686 LOGFONTW lf = { .lfHeight = -4096 /* preferable EM Square size */ };
2688 if (!face->scalable) lf.lfHeight = 0;
2690 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2692 if (!font_funcs->load_font( font ))
2694 free_gdi_font( font );
2695 return FALSE;
2698 if (font->scalable && -lf.lfHeight % font->otm.otmEMSquare != 0)
2700 /* reload with the original EM Square size */
2701 lf.lfHeight = -font->otm.otmEMSquare;
2702 free_gdi_font( font );
2704 if (!(font = create_gdi_font( face, NULL, &lf ))) return FALSE;
2705 if (!font_funcs->load_font( font ))
2707 free_gdi_font( font );
2708 return FALSE;
2712 if (font_funcs->set_outline_text_metrics( font ))
2714 static const DWORD ntm_ppem = 32;
2715 UINT cell_height;
2717 #define TM font->otm.otmTextMetrics
2718 #define SCALE_NTM(value) (MulDiv( ntm->ntmTm.tmHeight, (value), TM.tmHeight ))
2719 cell_height = TM.tmHeight / ( -lf.lfHeight / font->otm.otmEMSquare );
2720 ntm->ntmTm.tmHeight = MulDiv( ntm_ppem, cell_height, font->otm.otmEMSquare );
2721 ntm->ntmTm.tmAscent = SCALE_NTM( TM.tmAscent );
2722 ntm->ntmTm.tmDescent = ntm->ntmTm.tmHeight - ntm->ntmTm.tmAscent;
2723 ntm->ntmTm.tmInternalLeading = SCALE_NTM( TM.tmInternalLeading );
2724 ntm->ntmTm.tmExternalLeading = SCALE_NTM( TM.tmExternalLeading );
2725 ntm->ntmTm.tmAveCharWidth = SCALE_NTM( TM.tmAveCharWidth );
2726 ntm->ntmTm.tmMaxCharWidth = SCALE_NTM( TM.tmMaxCharWidth );
2728 memcpy((char *)&ntm->ntmTm + offsetof( TEXTMETRICW, tmWeight ),
2729 (const char *)&TM + offsetof( TEXTMETRICW, tmWeight ),
2730 sizeof(TEXTMETRICW) - offsetof( TEXTMETRICW, tmWeight ));
2731 ntm->ntmTm.ntmSizeEM = font->otm.otmEMSquare;
2732 ntm->ntmTm.ntmCellHeight = cell_height;
2733 ntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
2734 #undef SCALE_NTM
2735 #undef TM
2737 else if (font_funcs->set_bitmap_text_metrics( font ))
2739 memcpy( &ntm->ntmTm, &font->otm.otmTextMetrics, sizeof(TEXTMETRICW) );
2740 ntm->ntmTm.ntmSizeEM = ntm->ntmTm.tmHeight - ntm->ntmTm.tmInternalLeading;
2741 ntm->ntmTm.ntmCellHeight = ntm->ntmTm.tmHeight;
2742 ntm->ntmTm.ntmAvgWidth = ntm->ntmTm.tmAveCharWidth;
2744 ntm->ntmTm.ntmFlags = font->ntmFlags;
2745 ntm->ntmFontSig = font->fs;
2747 elf->elfLogFont.lfEscapement = 0;
2748 elf->elfLogFont.lfOrientation = 0;
2749 elf->elfLogFont.lfHeight = ntm->ntmTm.tmHeight;
2750 elf->elfLogFont.lfWidth = ntm->ntmTm.tmAveCharWidth;
2751 elf->elfLogFont.lfWeight = ntm->ntmTm.tmWeight;
2752 elf->elfLogFont.lfItalic = ntm->ntmTm.tmItalic;
2753 elf->elfLogFont.lfUnderline = ntm->ntmTm.tmUnderlined;
2754 elf->elfLogFont.lfStrikeOut = ntm->ntmTm.tmStruckOut;
2755 elf->elfLogFont.lfCharSet = ntm->ntmTm.tmCharSet;
2756 elf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2757 elf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2758 elf->elfLogFont.lfQuality = DRAFT_QUALITY;
2759 elf->elfLogFont.lfPitchAndFamily = (ntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
2760 lstrcpynW( elf->elfLogFont.lfFaceName, (WCHAR *)font->otm.otmpFamilyName, LF_FACESIZE );
2761 lstrcpynW( elf->elfFullName, (WCHAR *)font->otm.otmpFaceName, LF_FULLFACESIZE );
2762 lstrcpynW( elf->elfStyle, (WCHAR *)font->otm.otmpStyleName, LF_FACESIZE );
2764 free_gdi_font( font );
2765 return TRUE;
2768 static BOOL family_matches( struct gdi_font_family *family, const WCHAR *face_name )
2770 struct gdi_font_face *face;
2772 if (!facename_compare( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
2773 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2774 if (!facename_compare( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
2775 return FALSE;
2778 static BOOL face_matches( const WCHAR *family_name, struct gdi_font_face *face, const WCHAR *face_name )
2780 if (!facename_compare( face_name, family_name, LF_FACESIZE - 1)) return TRUE;
2781 return !facename_compare( face_name, face->full_name, LF_FACESIZE - 1 );
2784 static BOOL enum_face_charsets( const struct gdi_font_family *family, struct gdi_font_face *face,
2785 struct enum_charset *list, DWORD count, FONTENUMPROCW proc, LPARAM lparam,
2786 const WCHAR *subst )
2788 ENUMLOGFONTEXW elf;
2789 NEWTEXTMETRICEXW ntm;
2790 DWORD type, i;
2792 if (!face->cached_enum_data)
2794 struct gdi_font_enum_data *data;
2796 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )) ||
2797 !get_face_enum_data( face, &data->elf, &data->ntm ))
2799 HeapFree( GetProcessHeap(), 0, data );
2800 return TRUE;
2802 face->cached_enum_data = data;
2805 elf = face->cached_enum_data->elf;
2806 ntm = face->cached_enum_data->ntm;
2807 type = get_font_type( &ntm );
2809 /* font replacement */
2810 if (family != face->family)
2812 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
2813 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
2815 if (subst) lstrcpynW( elf.elfLogFont.lfFaceName, subst, LF_FACESIZE );
2817 for (i = 0; i < count; i++)
2819 if (face->fs.fsCsb[0] == 0) /* OEM */
2821 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2822 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
2823 i = count; /* break out of loop after enumeration */
2825 else
2827 if (!(face->fs.fsCsb[0] & list[i].mask)) continue;
2828 /* use the DEFAULT_CHARSET case only if no other charset is present */
2829 if (list[i].charset == DEFAULT_CHARSET && (face->fs.fsCsb[0] & ~list[i].mask)) continue;
2830 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list[i].charset;
2831 load_script_name( list[i].script, elf.elfScript );
2832 if (!elf.elfScript[0]) FIXME("Unknown elfscript for id %u\n", list[i].script);
2834 TRACE( "face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2835 debugstr_w(elf.elfLogFont.lfFaceName), debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2836 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
2837 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, ntm.ntmTm.ntmFlags );
2838 /* release section before callback (FIXME) */
2839 LeaveCriticalSection( &font_cs );
2840 if (!proc( &elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam )) return FALSE;
2841 EnterCriticalSection( &font_cs );
2843 return TRUE;
2846 /*************************************************************
2847 * font_EnumFonts
2849 static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
2851 struct gdi_font_family *family;
2852 struct gdi_font_face *face;
2853 struct enum_charset enum_charsets[32];
2854 DWORD count, charset;
2856 charset = lf ? lf->lfCharSet : DEFAULT_CHARSET;
2858 count = create_enum_charset_list( charset, enum_charsets );
2860 EnterCriticalSection( &font_cs );
2862 if (lf && lf->lfFaceName[0])
2864 const WCHAR *face_name = get_gdi_font_subst( lf->lfFaceName, charset, NULL );
2865 const WCHAR *orig_name = NULL;
2867 TRACE( "facename = %s charset %d\n", debugstr_w(lf->lfFaceName), charset );
2868 if (face_name)
2870 orig_name = lf->lfFaceName;
2871 TRACE( "substituting %s -> %s\n", debugstr_w(lf->lfFaceName), debugstr_w(face_name) );
2873 else face_name = lf->lfFaceName;
2875 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2877 if (!family_matches(family, face_name)) continue;
2878 LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry )
2880 if (!face_matches( family->family_name, face, face_name )) continue;
2881 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, orig_name ))
2882 return FALSE;
2886 else
2888 TRACE( "charset %d\n", charset );
2889 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
2891 face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry );
2892 if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL ))
2893 return FALSE;
2896 LeaveCriticalSection( &font_cs );
2897 return TRUE;
2901 static BOOL check_unicode_tategaki( WCHAR ch )
2903 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
2904 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[ch >> 8]+((ch >> 4) & 0x0f)]+ (ch & 0xf)];
2906 /* We only reach this code if typographical substitution did not occur */
2907 /* Type: U or Type: Tu */
2908 return (orientation == 1 || orientation == 3);
2911 static UINT get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2913 UINT index;
2915 if (glyph < 0x100) glyph += 0xf000;
2916 /* there are a number of old pre-Unicode "broken" TTFs, which
2917 do have symbols at U+00XX instead of U+f0XX */
2918 index = glyph;
2919 font_funcs->get_glyph_index( font, &index, FALSE );
2920 if (!index)
2922 index = glyph - 0xf000;
2923 font_funcs->get_glyph_index( font, &index, FALSE );
2925 return index;
2928 static UINT get_glyph_index( struct gdi_font *font, UINT glyph )
2930 WCHAR wc = glyph;
2931 char ch;
2932 BOOL used;
2934 if (font_funcs->get_glyph_index( font, &glyph, TRUE )) return glyph;
2936 if (font->codepage == CP_SYMBOL)
2938 glyph = get_glyph_index_symbol( font, wc );
2939 if (!glyph)
2941 if (WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, &wc, 1, &ch, 1, NULL, NULL ))
2942 glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2945 else if (WideCharToMultiByte( font->codepage, WC_NO_BEST_FIT_CHARS, &wc, 1, &ch, 1, NULL, &used ) && !used)
2947 glyph = (unsigned char)ch;
2948 font_funcs->get_glyph_index( font, &glyph, FALSE );
2950 else return 0;
2952 return glyph;
2955 static UINT get_glyph_index_linked( struct gdi_font **font, UINT glyph )
2957 struct gdi_font *child;
2958 UINT res;
2960 if ((res = get_glyph_index( *font, glyph ))) return res;
2961 if (glyph < 32) return 0; /* don't check linked fonts for control characters */
2963 LIST_FOR_EACH_ENTRY( child, &(*font)->child_fonts, struct gdi_font, entry )
2965 if (!child->private && !font_funcs->load_font( child )) continue;
2966 if ((res = get_glyph_index( child, glyph )))
2968 *font = child;
2969 return res;
2972 return 0;
2975 static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
2976 GLYPHMETRICS *gm_ret, ABC *abc_ret, DWORD buflen, void *buf,
2977 const MAT2 *mat )
2979 GLYPHMETRICS gm;
2980 ABC abc;
2981 DWORD ret = 1;
2982 UINT index = glyph;
2983 BOOL tategaki = (*get_gdi_font_name( font ) == '@');
2985 if (format & GGO_GLYPH_INDEX)
2987 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
2988 as glyph index. "Treasure Adventure Game" depends on this. */
2989 font_funcs->get_glyph_index( font, &index, FALSE );
2990 format &= ~GGO_GLYPH_INDEX;
2991 /* TODO: Window also turns off tategaki for glyphs passed in by index
2992 if their unicode code points fall outside of the range that is
2993 rotated. */
2995 else
2997 index = get_glyph_index_linked( &font, glyph );
2998 if (tategaki)
3000 UINT orig = index;
3001 index = get_GSUB_vert_glyph( font, index );
3002 if (index == orig) tategaki = check_unicode_tategaki( glyph );
3006 if (mat && !memcmp( mat, &identity, sizeof(*mat) )) mat = NULL;
3008 if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc ))
3009 goto done;
3011 ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki );
3012 if (ret == GDI_ERROR) return ret;
3014 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && !mat)
3015 set_gdi_font_glyph_metrics( font, index, &gm, &abc );
3017 done:
3018 if (gm_ret) *gm_ret = gm;
3019 if (abc_ret) *abc_ret = abc;
3020 return ret;
3024 /*************************************************************
3025 * font_FontIsLinked
3027 static BOOL CDECL font_FontIsLinked( PHYSDEV dev )
3029 struct font_physdev *physdev = get_font_dev( dev );
3031 if (!physdev->font)
3033 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
3034 return dev->funcs->pFontIsLinked( dev );
3036 return !list_empty( &physdev->font->child_fonts );
3040 /*************************************************************
3041 * font_GetCharABCWidths
3043 static BOOL CDECL font_GetCharABCWidths( PHYSDEV dev, UINT first, UINT last, ABC *buffer )
3045 struct font_physdev *physdev = get_font_dev( dev );
3046 UINT c;
3048 if (!physdev->font)
3050 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
3051 return dev->funcs->pGetCharABCWidths( dev, first, last, buffer );
3054 TRACE( "%p, %u, %u, %p\n", physdev->font, first, last, buffer );
3056 EnterCriticalSection( &font_cs );
3057 for (c = first; c <= last; c++, buffer++)
3058 get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, buffer, 0, NULL, NULL );
3059 LeaveCriticalSection( &font_cs );
3060 return TRUE;
3064 /*************************************************************
3065 * font_GetCharABCWidthsI
3067 static BOOL CDECL font_GetCharABCWidthsI( PHYSDEV dev, UINT first, UINT count, WORD *gi, ABC *buffer )
3069 struct font_physdev *physdev = get_font_dev( dev );
3070 UINT c;
3072 if (!physdev->font)
3074 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
3075 return dev->funcs->pGetCharABCWidthsI( dev, first, count, gi, buffer );
3078 TRACE( "%p, %u, %u, %p\n", physdev->font, first, count, buffer );
3080 EnterCriticalSection( &font_cs );
3081 for (c = 0; c < count; c++, buffer++)
3082 get_glyph_outline( physdev->font, gi ? gi[c] : first + c, GGO_METRICS | GGO_GLYPH_INDEX,
3083 NULL, buffer, 0, NULL, NULL );
3084 LeaveCriticalSection( &font_cs );
3085 return TRUE;
3089 /*************************************************************
3090 * font_GetCharWidth
3092 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT last, INT *buffer )
3094 struct font_physdev *physdev = get_font_dev( dev );
3095 ABC abc;
3096 UINT c;
3098 if (!physdev->font)
3100 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
3101 return dev->funcs->pGetCharWidth( dev, first, last, buffer );
3104 TRACE( "%p, %d, %d, %p\n", physdev->font, first, last, buffer );
3106 EnterCriticalSection( &font_cs );
3107 for (c = first; c <= last; c++)
3109 if (get_glyph_outline( physdev->font, c, GGO_METRICS, NULL, &abc, 0, NULL, NULL ) == GDI_ERROR)
3110 buffer[c - first] = 0;
3111 else
3112 buffer[c - first] = abc.abcA + abc.abcB + abc.abcC;
3114 LeaveCriticalSection( &font_cs );
3115 return TRUE;
3119 /*************************************************************
3120 * font_GetCharWidthInfo
3122 static BOOL CDECL font_GetCharWidthInfo( PHYSDEV dev, void *ptr )
3124 struct font_physdev *physdev = get_font_dev( dev );
3125 struct char_width_info *info = ptr;
3127 if (!physdev->font)
3129 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
3130 return dev->funcs->pGetCharWidthInfo( dev, ptr );
3133 info->unk = 0;
3134 if (!physdev->font->scalable || !font_funcs->get_char_width_info( physdev->font, info ))
3135 info->lsb = info->rsb = 0;
3137 return TRUE;
3141 /*************************************************************
3142 * font_GetFontData
3144 static DWORD CDECL font_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, void *buf, DWORD size )
3146 struct font_physdev *physdev = get_font_dev( dev );
3148 if (!physdev->font)
3150 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
3151 return dev->funcs->pGetFontData( dev, table, offset, buf, size );
3153 return font_funcs->get_font_data( physdev->font, table, offset, buf, size );
3157 /*************************************************************
3158 * font_GetFontRealizationInfo
3160 static BOOL CDECL font_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
3162 struct font_physdev *physdev = get_font_dev( dev );
3163 struct font_realization_info *info = ptr;
3165 if (!physdev->font)
3167 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
3168 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
3171 TRACE( "(%p, %p)\n", physdev->font, info);
3173 info->flags = 1;
3174 if (physdev->font->scalable) info->flags |= 2;
3176 info->cache_num = physdev->font->cache_num;
3177 info->instance_id = physdev->font->handle;
3178 if (info->size == sizeof(*info))
3180 info->file_count = 1;
3181 info->face_index = physdev->font->face_index;
3182 info->simulations = 0;
3183 if (physdev->font->fake_bold) info->simulations |= 0x1;
3184 if (physdev->font->fake_italic) info->simulations |= 0x2;
3186 return TRUE;
3190 /*************************************************************
3191 * font_GetFontUnicodeRanges
3193 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
3195 struct font_physdev *physdev = get_font_dev( dev );
3196 DWORD size, num_ranges;
3198 if (!physdev->font)
3200 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
3201 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
3204 num_ranges = font_funcs->get_unicode_ranges( physdev->font, glyphset );
3205 size = offsetof( GLYPHSET, ranges[num_ranges] );
3206 if (glyphset)
3208 glyphset->cbThis = size;
3209 glyphset->cRanges = num_ranges;
3210 glyphset->flAccel = 0;
3212 return size;
3216 /*************************************************************
3217 * font_GetGlyphIndices
3219 static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT count, WORD *gi, DWORD flags )
3221 struct font_physdev *physdev = get_font_dev( dev );
3222 UINT default_char;
3223 char ch;
3224 BOOL used, got_default = FALSE;
3225 int i;
3227 if (!physdev->font)
3229 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
3230 return dev->funcs->pGetGlyphIndices( dev, str, count, gi, flags );
3233 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3235 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
3236 got_default = TRUE;
3239 EnterCriticalSection( &font_cs );
3241 for (i = 0; i < count; i++)
3243 UINT glyph = str[i];
3245 if (!font_funcs->get_glyph_index( physdev->font, &glyph, TRUE ))
3247 glyph = 0;
3248 if (physdev->font->codepage == CP_SYMBOL)
3250 if (str[i] >= 0xf020 && str[i] <= 0xf100) glyph = str[i] - 0xf000;
3251 else if (str[i] < 0x100) glyph = str[i];
3253 else if (WideCharToMultiByte( physdev->font->codepage, WC_NO_BEST_FIT_CHARS, &str[i], 1,
3254 &ch, 1, NULL, &used ) && !used)
3255 glyph = (unsigned char)ch;
3257 if (!glyph)
3259 if (!got_default)
3261 default_char = font_funcs->get_default_glyph( physdev->font );
3262 got_default = TRUE;
3264 gi[i] = default_char;
3266 else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
3269 LeaveCriticalSection( &font_cs );
3270 return count;
3274 /*************************************************************
3275 * font_GetGlyphOutline
3277 static DWORD CDECL font_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
3278 GLYPHMETRICS *gm, DWORD buflen, void *buf, const MAT2 *mat )
3280 struct font_physdev *physdev = get_font_dev( dev );
3281 DWORD ret;
3283 if (!physdev->font)
3285 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
3286 return dev->funcs->pGetGlyphOutline( dev, glyph, format, gm, buflen, buf, mat );
3288 EnterCriticalSection( &font_cs );
3289 ret = get_glyph_outline( physdev->font, glyph, format, gm, NULL, buflen, buf, mat );
3290 LeaveCriticalSection( &font_cs );
3291 return ret;
3295 /*************************************************************
3296 * font_GetKerningPairs
3298 static DWORD CDECL font_GetKerningPairs( PHYSDEV dev, DWORD count, KERNINGPAIR *pairs )
3300 struct font_physdev *physdev = get_font_dev( dev );
3302 if (!physdev->font)
3304 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
3305 return dev->funcs->pGetKerningPairs( dev, count, pairs );
3308 EnterCriticalSection( &font_cs );
3309 if (physdev->font->kern_count == -1)
3310 physdev->font->kern_count = font_funcs->get_kerning_pairs( physdev->font,
3311 &physdev->font->kern_pairs );
3312 LeaveCriticalSection( &font_cs );
3314 if (count && pairs)
3316 count = min( count, physdev->font->kern_count );
3317 memcpy( pairs, physdev->font->kern_pairs, count * sizeof(*pairs) );
3319 else count = physdev->font->kern_count;
3321 return count;
3325 static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXTMETRICW *otm )
3327 double scale_x, scale_y;
3329 if (font->aveWidth)
3331 scale_x = (double)font->aveWidth;
3332 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3334 else
3335 scale_x = font->scale_y;
3337 scale_x *= fabs(font->matrix.eM11);
3338 scale_y = font->scale_y * fabs(font->matrix.eM22);
3340 /* Windows scales these values as signed integers even if they are unsigned */
3341 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
3342 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
3344 SCALE_Y(otm->otmTextMetrics.tmHeight);
3345 SCALE_Y(otm->otmTextMetrics.tmAscent);
3346 SCALE_Y(otm->otmTextMetrics.tmDescent);
3347 SCALE_Y(otm->otmTextMetrics.tmInternalLeading);
3348 SCALE_Y(otm->otmTextMetrics.tmExternalLeading);
3350 SCALE_X(otm->otmTextMetrics.tmOverhang);
3351 if (font->fake_bold)
3353 if (!font->scalable) otm->otmTextMetrics.tmOverhang++;
3354 otm->otmTextMetrics.tmAveCharWidth++;
3355 otm->otmTextMetrics.tmMaxCharWidth++;
3357 SCALE_X(otm->otmTextMetrics.tmAveCharWidth);
3358 SCALE_X(otm->otmTextMetrics.tmMaxCharWidth);
3360 SCALE_Y(otm->otmAscent);
3361 SCALE_Y(otm->otmDescent);
3362 SCALE_Y(otm->otmLineGap);
3363 SCALE_Y(otm->otmsCapEmHeight);
3364 SCALE_Y(otm->otmsXHeight);
3365 SCALE_Y(otm->otmrcFontBox.top);
3366 SCALE_Y(otm->otmrcFontBox.bottom);
3367 SCALE_X(otm->otmrcFontBox.left);
3368 SCALE_X(otm->otmrcFontBox.right);
3369 SCALE_Y(otm->otmMacAscent);
3370 SCALE_Y(otm->otmMacDescent);
3371 SCALE_Y(otm->otmMacLineGap);
3372 SCALE_X(otm->otmptSubscriptSize.x);
3373 SCALE_Y(otm->otmptSubscriptSize.y);
3374 SCALE_X(otm->otmptSubscriptOffset.x);
3375 SCALE_Y(otm->otmptSubscriptOffset.y);
3376 SCALE_X(otm->otmptSuperscriptSize.x);
3377 SCALE_Y(otm->otmptSuperscriptSize.y);
3378 SCALE_X(otm->otmptSuperscriptOffset.x);
3379 SCALE_Y(otm->otmptSuperscriptOffset.y);
3380 SCALE_Y(otm->otmsStrikeoutSize);
3381 SCALE_Y(otm->otmsStrikeoutPosition);
3382 SCALE_Y(otm->otmsUnderscoreSize);
3383 SCALE_Y(otm->otmsUnderscorePosition);
3385 #undef SCALE_X
3386 #undef SCALE_Y
3389 /*************************************************************
3390 * font_GetOutlineTextMetrics
3392 static UINT CDECL font_GetOutlineTextMetrics( PHYSDEV dev, UINT size, OUTLINETEXTMETRICW *metrics )
3394 struct font_physdev *physdev = get_font_dev( dev );
3395 UINT ret = 0;
3397 if (!physdev->font)
3399 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
3400 return dev->funcs->pGetOutlineTextMetrics( dev, size, metrics );
3403 if (!physdev->font->scalable) return 0;
3405 EnterCriticalSection( &font_cs );
3406 if (font_funcs->set_outline_text_metrics( physdev->font ))
3408 ret = physdev->font->otm.otmSize;
3409 if (metrics && size >= physdev->font->otm.otmSize)
3411 WCHAR *ptr = (WCHAR *)(metrics + 1);
3412 *metrics = physdev->font->otm;
3413 metrics->otmpFamilyName = (char *)ptr - (ULONG_PTR)metrics;
3414 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFamilyName );
3415 ptr += lstrlenW(ptr) + 1;
3416 metrics->otmpStyleName = (char *)ptr - (ULONG_PTR)metrics;
3417 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpStyleName );
3418 ptr += lstrlenW(ptr) + 1;
3419 metrics->otmpFaceName = (char *)ptr - (ULONG_PTR)metrics;
3420 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFaceName );
3421 ptr += lstrlenW(ptr) + 1;
3422 metrics->otmpFullName = (char *)ptr - (ULONG_PTR)metrics;
3423 lstrcpyW( ptr, (WCHAR *)physdev->font->otm.otmpFullName );
3424 scale_outline_font_metrics( physdev->font, metrics );
3427 LeaveCriticalSection( &font_cs );
3428 return ret;
3432 /*************************************************************
3433 * font_GetTextCharsetInfo
3435 static UINT CDECL font_GetTextCharsetInfo( PHYSDEV dev, FONTSIGNATURE *fs, DWORD flags )
3437 struct font_physdev *physdev = get_font_dev( dev );
3439 if (!physdev->font)
3441 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
3442 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3444 if (fs) *fs = physdev->font->fs;
3445 return physdev->font->charset;
3449 /*************************************************************
3450 * font_GetTextExtentExPoint
3452 static BOOL CDECL font_GetTextExtentExPoint( PHYSDEV dev, const WCHAR *str, INT count, INT *dxs )
3454 struct font_physdev *physdev = get_font_dev( dev );
3455 INT i, pos;
3456 ABC abc;
3458 if (!physdev->font)
3460 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
3461 return dev->funcs->pGetTextExtentExPoint( dev, str, count, dxs );
3464 TRACE( "%p, %s, %d\n", physdev->font, debugstr_wn(str, count), count );
3466 EnterCriticalSection( &font_cs );
3467 for (i = pos = 0; i < count; i++)
3469 get_glyph_outline( physdev->font, str[i], GGO_METRICS, NULL, &abc, 0, NULL, NULL );
3470 pos += abc.abcA + abc.abcB + abc.abcC;
3471 dxs[i] = pos;
3473 LeaveCriticalSection( &font_cs );
3474 return TRUE;
3478 /*************************************************************
3479 * font_GetTextExtentExPointI
3481 static BOOL CDECL font_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, INT *dxs )
3483 struct font_physdev *physdev = get_font_dev( dev );
3484 INT i, pos;
3485 ABC abc;
3487 if (!physdev->font)
3489 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
3490 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
3493 TRACE( "%p, %p, %d\n", physdev->font, indices, count );
3495 EnterCriticalSection( &font_cs );
3496 for (i = pos = 0; i < count; i++)
3498 get_glyph_outline( physdev->font, indices[i], GGO_METRICS | GGO_GLYPH_INDEX,
3499 NULL, &abc, 0, NULL, NULL );
3500 pos += abc.abcA + abc.abcB + abc.abcC;
3501 dxs[i] = pos;
3503 LeaveCriticalSection( &font_cs );
3504 return TRUE;
3508 /*************************************************************
3509 * font_GetTextFace
3511 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
3513 struct font_physdev *physdev = get_font_dev( dev );
3514 INT len;
3516 if (!physdev->font)
3518 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
3519 return dev->funcs->pGetTextFace( dev, count, str );
3521 len = lstrlenW( get_gdi_font_name(physdev->font) ) + 1;
3522 if (str)
3524 lstrcpynW( str, get_gdi_font_name(physdev->font), count );
3525 len = min( count, len );
3527 return len;
3531 static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm )
3533 double scale_x, scale_y;
3535 /* Make sure that the font has sane width/height ratio */
3536 if (font->aveWidth && (font->aveWidth + tm->tmHeight - 1) / tm->tmHeight > 100)
3538 WARN( "Ignoring too large font->aveWidth %d\n", font->aveWidth );
3539 font->aveWidth = 0;
3542 if (font->aveWidth)
3544 scale_x = (double)font->aveWidth;
3545 scale_x /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
3547 else
3548 scale_x = font->scale_y;
3550 scale_x *= fabs(font->matrix.eM11);
3551 scale_y = font->scale_y * fabs(font->matrix.eM22);
3553 #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x)
3554 #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y)
3556 SCALE_Y(tm->tmHeight);
3557 SCALE_Y(tm->tmAscent);
3558 SCALE_Y(tm->tmDescent);
3559 SCALE_Y(tm->tmInternalLeading);
3560 SCALE_Y(tm->tmExternalLeading);
3562 SCALE_X(tm->tmOverhang);
3563 if (font->fake_bold)
3565 if (!font->scalable) tm->tmOverhang++;
3566 tm->tmAveCharWidth++;
3567 tm->tmMaxCharWidth++;
3569 SCALE_X(tm->tmAveCharWidth);
3570 SCALE_X(tm->tmMaxCharWidth);
3572 #undef SCALE_X
3573 #undef SCALE_Y
3576 /*************************************************************
3577 * font_GetTextMetrics
3579 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
3581 struct font_physdev *physdev = get_font_dev( dev );
3582 BOOL ret = FALSE;
3584 if (!physdev->font)
3586 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
3587 return dev->funcs->pGetTextMetrics( dev, metrics );
3590 EnterCriticalSection( &font_cs );
3591 if (font_funcs->set_outline_text_metrics( physdev->font ) ||
3592 font_funcs->set_bitmap_text_metrics( physdev->font ))
3594 *metrics = physdev->font->otm.otmTextMetrics;
3595 scale_font_metrics( physdev->font, metrics );
3596 ret = TRUE;
3598 LeaveCriticalSection( &font_cs );
3599 return ret;
3603 static void get_nearest_charset( const WCHAR *family_name, struct gdi_font_face *face, CHARSETINFO *csi )
3605 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3606 a single face with the requested charset. The idea is to check if
3607 the selected font supports the current ANSI codepage, if it does
3608 return the corresponding charset, else return the first charset */
3610 int i;
3612 if (TranslateCharsetInfo( (DWORD*)(INT_PTR)GetACP(), csi, TCI_SRCCODEPAGE ))
3614 const struct gdi_font_link *font_link;
3616 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0]) return;
3617 font_link = find_gdi_font_link(family_name);
3618 if (font_link && (csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])) return;
3620 for (i = 0; i < 32; i++)
3622 DWORD fs0 = 1u << i;
3623 if (face->fs.fsCsb[0] & fs0)
3625 if (TranslateCharsetInfo(&fs0, csi, TCI_SRCFONTSIG)) return;
3626 FIXME("TCI failing on %x\n", fs0);
3630 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3631 face->fs.fsCsb[0], debugstr_w(face->file));
3632 csi->ciACP = GetACP();
3633 csi->ciCharset = DEFAULT_CHARSET;
3636 static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bitmap )
3638 struct gdi_font *font;
3639 struct gdi_font_face *face;
3640 INT height;
3641 CHARSETINFO csi;
3642 const WCHAR *orig_name = NULL;
3644 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3645 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3646 original value lfCharSet. Note this is a special case for
3647 Symbol and doesn't happen at least for "Wingdings*" */
3648 if (!facename_compare( lf->lfFaceName, L"Symbol", -1 )) lf->lfCharSet = SYMBOL_CHARSET;
3650 /* check the cache first */
3651 if ((font = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
3653 TRACE( "returning cached gdiFont(%p)\n", font );
3654 return font;
3656 if (!(face = find_matching_face( lf, &csi, can_use_bitmap, &orig_name )))
3658 FIXME( "can't find a single appropriate font - bailing\n" );
3659 return NULL;
3661 height = lf->lfHeight;
3663 font = create_gdi_font( face, orig_name, lf );
3664 font->matrix = dcmat;
3665 font->can_use_bitmap = can_use_bitmap;
3666 if (!csi.fs.fsCsb[0]) get_nearest_charset( face->family->family_name, face, &csi );
3667 font->charset = csi.ciCharset;
3668 font->codepage = csi.ciACP;
3670 TRACE( "Chosen: %s (%s/%p:%u)\n", debugstr_w(face->full_name), debugstr_w(face->file),
3671 face->data_ptr, face->face_index );
3673 font->aveWidth = height ? lf->lfWidth : 0;
3674 if (!face->scalable)
3676 /* Windows uses integer scaling factors for bitmap fonts */
3677 INT scale, scaled_height, diff;
3678 struct gdi_font *cachedfont;
3680 if (height > 0)
3681 diff = height - (signed int)face->size.height;
3682 else
3683 diff = -height - ((signed int)face->size.height - face->size.internal_leading);
3685 /* FIXME: rotation of bitmap fonts is ignored */
3686 height = abs(GDI_ROUND( (double)height * font->matrix.eM22 ));
3687 if (font->aveWidth)
3688 font->aveWidth = (double)font->aveWidth * font->matrix.eM11;
3689 font->matrix.eM11 = font->matrix.eM22 = 1.0;
3690 dcmat.eM11 = dcmat.eM22 = 1.0;
3691 /* As we changed the matrix, we need to search the cache for the font again,
3692 * otherwise we might explode the cache. */
3693 if ((cachedfont = find_cached_gdi_font( lf, &dcmat, can_use_bitmap )))
3695 TRACE("Found cached font after non-scalable matrix rescale!\n");
3696 free_gdi_font( font );
3697 return cachedfont;
3700 if (height != 0) height = diff;
3701 height += face->size.height;
3703 scale = (height + face->size.height - 1) / face->size.height;
3704 scaled_height = scale * face->size.height;
3705 /* Only jump to the next height if the difference <= 25% original height */
3706 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3707 /* The jump between unscaled and doubled is delayed by 1 */
3708 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3709 font->scale_y = scale;
3710 TRACE("font scale y: %d\n", font->scale_y);
3713 if (!font_funcs->load_font( font ))
3715 free_gdi_font( font );
3716 return NULL;
3719 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
3720 font->vert_feature = get_GSUB_vert_feature( font );
3722 create_child_font_list( font );
3724 TRACE( "caching: gdiFont=%p\n", font );
3725 cache_gdi_font( font );
3726 return font;
3729 /*************************************************************
3730 * font_SelectFont
3732 static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
3734 struct font_physdev *physdev = get_font_dev( dev );
3735 struct gdi_font *font = NULL, *prev = physdev->font;
3736 DC *dc = get_physdev_dc( dev );
3738 if (hfont)
3740 LOGFONTW lf;
3741 FMAT2 dcmat;
3742 BOOL can_use_bitmap = !!(GetDeviceCaps( dc->hSelf, TEXTCAPS ) & TC_RA_ABLE);
3744 GetObjectW( hfont, sizeof(lf), &lf );
3745 switch (lf.lfQuality)
3747 case NONANTIALIASED_QUALITY:
3748 if (!*aa_flags) *aa_flags = GGO_BITMAP;
3749 break;
3750 case ANTIALIASED_QUALITY:
3751 if (!*aa_flags) *aa_flags = GGO_GRAY4_BITMAP;
3752 break;
3755 lf.lfWidth = abs(lf.lfWidth);
3757 TRACE( "%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3758 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3759 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3760 lf.lfEscapement );
3762 if (dc->attr->graphics_mode == GM_ADVANCED)
3764 memcpy( &dcmat, &dc->xformWorld2Vport, sizeof(FMAT2) );
3765 /* try to avoid not necessary glyph transformations */
3766 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3768 lf.lfHeight *= fabs(dcmat.eM11);
3769 lf.lfWidth *= fabs(dcmat.eM11);
3770 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
3773 else
3775 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited font scaling abilities */
3776 dcmat.eM11 = dcmat.eM22 = 1.0;
3777 dcmat.eM21 = dcmat.eM12 = 0;
3778 lf.lfOrientation = lf.lfEscapement;
3779 if (dc->vport2WorldValid)
3781 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3782 lf.lfOrientation = -lf.lfOrientation;
3783 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3784 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3787 TRACE( "DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12, dcmat.eM21, dcmat.eM22 );
3789 EnterCriticalSection( &font_cs );
3791 font = select_font( &lf, dcmat, can_use_bitmap );
3793 if (font)
3795 if (!*aa_flags) *aa_flags = font->aa_flags;
3796 if (!*aa_flags)
3798 if (lf.lfQuality == CLEARTYPE_QUALITY || lf.lfQuality == CLEARTYPE_NATURAL_QUALITY)
3799 *aa_flags = subpixel_orientation;
3800 else
3801 *aa_flags = font_smoothing;
3803 *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes );
3805 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
3806 LeaveCriticalSection( &font_cs );
3808 physdev->font = font;
3809 if (prev) release_gdi_font( prev );
3810 return font ? hfont : 0;
3814 const struct gdi_dc_funcs font_driver =
3816 NULL, /* pAbortDoc */
3817 NULL, /* pAbortPath */
3818 NULL, /* pAlphaBlend */
3819 NULL, /* pAngleArc */
3820 NULL, /* pArc */
3821 NULL, /* pArcTo */
3822 NULL, /* pBeginPath */
3823 NULL, /* pBlendImage */
3824 NULL, /* pChord */
3825 NULL, /* pCloseFigure */
3826 NULL, /* pCreateCompatibleDC */
3827 font_CreateDC, /* pCreateDC */
3828 font_DeleteDC, /* pDeleteDC */
3829 NULL, /* pDeleteObject */
3830 NULL, /* pDeviceCapabilities */
3831 NULL, /* pEllipse */
3832 NULL, /* pEndDoc */
3833 NULL, /* pEndPage */
3834 NULL, /* pEndPath */
3835 font_EnumFonts, /* pEnumFonts */
3836 NULL, /* pEnumICMProfiles */
3837 NULL, /* pExtDeviceMode */
3838 NULL, /* pExtEscape */
3839 NULL, /* pExtFloodFill */
3840 NULL, /* pExtTextOut */
3841 NULL, /* pFillPath */
3842 NULL, /* pFillRgn */
3843 NULL, /* pFlattenPath */
3844 font_FontIsLinked, /* pFontIsLinked */
3845 NULL, /* pFrameRgn */
3846 NULL, /* pGdiComment */
3847 NULL, /* pGetBoundsRect */
3848 font_GetCharABCWidths, /* pGetCharABCWidths */
3849 font_GetCharABCWidthsI, /* pGetCharABCWidthsI */
3850 font_GetCharWidth, /* pGetCharWidth */
3851 font_GetCharWidthInfo, /* pGetCharWidthInfo */
3852 NULL, /* pGetDeviceCaps */
3853 NULL, /* pGetDeviceGammaRamp */
3854 font_GetFontData, /* pGetFontData */
3855 font_GetFontRealizationInfo, /* pGetFontRealizationInfo */
3856 font_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
3857 font_GetGlyphIndices, /* pGetGlyphIndices */
3858 font_GetGlyphOutline, /* pGetGlyphOutline */
3859 NULL, /* pGetICMProfile */
3860 NULL, /* pGetImage */
3861 font_GetKerningPairs, /* pGetKerningPairs */
3862 NULL, /* pGetNearestColor */
3863 font_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
3864 NULL, /* pGetPixel */
3865 NULL, /* pGetSystemPaletteEntries */
3866 font_GetTextCharsetInfo, /* pGetTextCharsetInfo */
3867 font_GetTextExtentExPoint, /* pGetTextExtentExPoint */
3868 font_GetTextExtentExPointI, /* pGetTextExtentExPointI */
3869 font_GetTextFace, /* pGetTextFace */
3870 font_GetTextMetrics, /* pGetTextMetrics */
3871 NULL, /* pGradientFill */
3872 NULL, /* pInvertRgn */
3873 NULL, /* pLineTo */
3874 NULL, /* pModifyWorldTransform */
3875 NULL, /* pMoveTo */
3876 NULL, /* pOffsetViewportOrg */
3877 NULL, /* pOffsetWindowOrg */
3878 NULL, /* pPaintRgn */
3879 NULL, /* pPatBlt */
3880 NULL, /* pPie */
3881 NULL, /* pPolyBezier */
3882 NULL, /* pPolyBezierTo */
3883 NULL, /* pPolyDraw */
3884 NULL, /* pPolyPolygon */
3885 NULL, /* pPolyPolyline */
3886 NULL, /* pPolylineTo */
3887 NULL, /* pPutImage */
3888 NULL, /* pRealizeDefaultPalette */
3889 NULL, /* pRealizePalette */
3890 NULL, /* pRectangle */
3891 NULL, /* pResetDC */
3892 NULL, /* pRestoreDC */
3893 NULL, /* pRoundRect */
3894 NULL, /* pSelectBitmap */
3895 NULL, /* pSelectBrush */
3896 NULL, /* pSelectClipPath */
3897 font_SelectFont, /* pSelectFont */
3898 NULL, /* pSelectPalette */
3899 NULL, /* pSelectPen */
3900 NULL, /* pSetBkColor */
3901 NULL, /* pSetBoundsRect */
3902 NULL, /* pSetDCBrushColor */
3903 NULL, /* pSetDCPenColor */
3904 NULL, /* pSetDIBitsToDevice */
3905 NULL, /* pSetDeviceClipping */
3906 NULL, /* pSetDeviceGammaRamp */
3907 NULL, /* pSetPixel */
3908 NULL, /* pSetTextColor */
3909 NULL, /* pSetViewportExt */
3910 NULL, /* pSetViewportOrg */
3911 NULL, /* pSetWindowExt */
3912 NULL, /* pSetWindowOrg */
3913 NULL, /* pSetWorldTransform */
3914 NULL, /* pStartDoc */
3915 NULL, /* pStartPage */
3916 NULL, /* pStretchBlt */
3917 NULL, /* pStretchDIBits */
3918 NULL, /* pStrokeAndFillPath */
3919 NULL, /* pStrokePath */
3920 NULL, /* pUnrealizePalette */
3921 NULL, /* pWidenPath */
3922 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
3923 NULL, /* pD3DKMTSetVidPnSourceOwner */
3924 NULL, /* wine_get_wgl_driver */
3925 NULL, /* wine_get_vulkan_driver */
3926 GDI_PRIORITY_FONT_DRV /* priority */
3929 static DWORD get_key_value( HKEY key, const WCHAR *name, DWORD *value )
3931 WCHAR buf[12];
3932 DWORD count = sizeof(buf), type, err;
3934 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
3935 if (!err)
3937 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
3938 else *value = wcstol( buf, NULL, 10 );
3940 return err;
3943 static void init_font_options(void)
3945 HKEY key;
3946 DWORD i, type, size, val, gamma = 1400;
3947 WCHAR buffer[20];
3949 size = sizeof(buffer);
3950 if (!RegQueryValueExW( wine_fonts_key, L"AntialiasFakeBoldOrItalic", NULL,
3951 &type, (BYTE *)buffer, &size) && type == REG_SZ && size >= 1)
3953 antialias_fakes = (wcschr(L"yYtT1", buffer[0]) != NULL);
3956 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Control Panel\\Desktop", &key ))
3958 /* FIXME: handle vertical orientations even though Windows doesn't */
3959 if (!get_key_value( key, L"FontSmoothingOrientation", &val ))
3961 switch (val)
3963 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
3964 subpixel_orientation = WINE_GGO_HBGR_BITMAP;
3965 break;
3966 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
3967 subpixel_orientation = WINE_GGO_HRGB_BITMAP;
3968 break;
3971 if (!get_key_value( key, L"FontSmoothing", &val ) && val /* enabled */)
3973 if (!get_key_value( key, L"FontSmoothingType", &val ) && val == 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
3974 font_smoothing = subpixel_orientation;
3975 else
3976 font_smoothing = GGO_GRAY4_BITMAP;
3978 if (!get_key_value( key, L"FontSmoothingGamma", &val ) && val)
3980 gamma = min( max( val, 1000 ), 2200 );
3982 RegCloseKey( key );
3985 /* Calibrating the difference between the registry value and the Wine gamma value.
3986 This looks roughly similar to Windows Native with the same registry value.
3987 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
3988 gamma = 1000 * gamma / 1400;
3989 if (gamma != 1000)
3991 for (i = 0; i < 256; i++)
3993 font_gamma_ramp.encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
3994 font_gamma_ramp.decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
3997 font_gamma_ramp.gamma = gamma;
3998 TRACE("gamma %d\n", font_gamma_ramp.gamma);
4002 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
4004 memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
4005 MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
4006 LF_FACESIZE);
4007 fontW->lfFaceName[LF_FACESIZE-1] = 0;
4010 static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
4012 memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
4013 WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
4014 LF_FACESIZE, NULL, NULL);
4015 fontA->lfFaceName[LF_FACESIZE-1] = 0;
4018 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
4020 FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
4022 WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
4023 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
4024 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
4025 WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
4026 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
4027 fontA->elfStyle[LF_FACESIZE-1] = '\0';
4028 WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
4029 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
4030 fontA->elfScript[LF_FACESIZE-1] = '\0';
4033 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
4035 FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );
4037 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
4038 fontW->elfFullName, LF_FULLFACESIZE );
4039 fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
4040 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
4041 fontW->elfStyle, LF_FACESIZE );
4042 fontW->elfStyle[LF_FACESIZE-1] = '\0';
4043 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
4044 fontW->elfScript, LF_FACESIZE );
4045 fontW->elfScript[LF_FACESIZE-1] = '\0';
4048 /***********************************************************************
4049 * TEXTMETRIC conversion functions.
4051 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
4053 ptmA->tmHeight = ptmW->tmHeight;
4054 ptmA->tmAscent = ptmW->tmAscent;
4055 ptmA->tmDescent = ptmW->tmDescent;
4056 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
4057 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
4058 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
4059 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
4060 ptmA->tmWeight = ptmW->tmWeight;
4061 ptmA->tmOverhang = ptmW->tmOverhang;
4062 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
4063 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
4064 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
4065 if (ptmW->tmCharSet == SYMBOL_CHARSET)
4067 ptmA->tmFirstChar = 0x1e;
4068 ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
4070 else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
4072 ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
4073 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
4075 else
4077 ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
4078 ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
4080 ptmA->tmDefaultChar = ptmW->tmDefaultChar;
4081 ptmA->tmBreakChar = ptmW->tmBreakChar;
4082 ptmA->tmItalic = ptmW->tmItalic;
4083 ptmA->tmUnderlined = ptmW->tmUnderlined;
4084 ptmA->tmStruckOut = ptmW->tmStruckOut;
4085 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
4086 ptmA->tmCharSet = ptmW->tmCharSet;
4090 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
4092 FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
4093 ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags;
4094 ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM;
4095 ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight;
4096 ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth;
4097 memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
4100 /* compute positions for text rendering, in device coords */
4101 static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
4103 TEXTMETRICW tm;
4104 PHYSDEV dev;
4106 size->cx = size->cy = 0;
4107 if (!count) return TRUE;
4109 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4110 dev->funcs->pGetTextMetrics( dev, &tm );
4112 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
4113 if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, dx )) return FALSE;
4115 if (dc->breakExtra || dc->breakRem)
4117 int i, space = 0, rem = dc->breakRem;
4119 for (i = 0; i < count; i++)
4121 if (str[i] == tm.tmBreakChar)
4123 space += dc->breakExtra;
4124 if (rem > 0)
4126 space++;
4127 rem--;
4130 dx[i] += space;
4133 size->cx = dx[count - 1];
4134 size->cy = tm.tmHeight;
4135 return TRUE;
4138 /* compute positions for text rendering, in device coords */
4139 static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size )
4141 TEXTMETRICW tm;
4142 PHYSDEV dev;
4144 size->cx = size->cy = 0;
4145 if (!count) return TRUE;
4147 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
4148 dev->funcs->pGetTextMetrics( dev, &tm );
4150 dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
4151 if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, dx )) return FALSE;
4153 if (dc->breakExtra || dc->breakRem)
4155 WORD space_index;
4156 int i, space = 0, rem = dc->breakRem;
4158 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
4159 dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 );
4161 for (i = 0; i < count; i++)
4163 if (indices[i] == space_index)
4165 space += dc->breakExtra;
4166 if (rem > 0)
4168 space++;
4169 rem--;
4172 dx[i] += space;
4175 size->cx = dx[count - 1];
4176 size->cy = tm.tmHeight;
4177 return TRUE;
4180 /***********************************************************************
4181 * GdiGetCodePage (GDI32.@)
4183 DWORD WINAPI GdiGetCodePage( HDC hdc )
4185 UINT cp = CP_ACP;
4186 DC *dc = get_dc_ptr( hdc );
4188 if (dc)
4190 cp = dc->font_code_page;
4191 release_dc_ptr( dc );
4193 return cp;
4196 /***********************************************************************
4197 * get_text_charset_info
4199 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
4201 static UINT get_text_charset_info(DC *dc, FONTSIGNATURE *fs, DWORD flags)
4203 UINT ret = DEFAULT_CHARSET;
4204 PHYSDEV dev;
4206 dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
4207 ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
4209 if (ret == DEFAULT_CHARSET && fs)
4210 memset(fs, 0, sizeof(FONTSIGNATURE));
4211 return ret;
4214 /***********************************************************************
4215 * GetTextCharsetInfo (GDI32.@)
4217 UINT WINAPI GetTextCharsetInfo(HDC hdc, FONTSIGNATURE *fs, DWORD flags)
4219 UINT ret = DEFAULT_CHARSET;
4220 DC *dc = get_dc_ptr(hdc);
4222 if (dc)
4224 ret = get_text_charset_info( dc, fs, flags );
4225 release_dc_ptr( dc );
4227 return ret;
4230 /***********************************************************************
4231 * FONT_mbtowc
4233 * Returns a Unicode translation of str using the charset of the
4234 * currently selected font in hdc. If count is -1 then str is assumed
4235 * to be '\0' terminated, otherwise it contains the number of bytes to
4236 * convert. If plenW is non-NULL, on return it will point to the
4237 * number of WCHARs that have been written. If pCP is non-NULL, on
4238 * return it will point to the codepage used in the conversion. The
4239 * caller should free the returned LPWSTR from the process heap
4240 * itself.
4242 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
4244 UINT cp;
4245 INT lenW;
4246 LPWSTR strW;
4248 cp = GdiGetCodePage( hdc );
4250 if(count == -1) count = strlen(str);
4251 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
4252 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
4253 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
4254 TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
4255 if(plenW) *plenW = lenW;
4256 if(pCP) *pCP = cp;
4257 return strW;
4260 /***********************************************************************
4261 * CreateFontIndirectExA (GDI32.@)
4263 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
4265 ENUMLOGFONTEXDVW enumexW;
4267 if (!penumexA) return 0;
4269 FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
4270 enumexW.elfDesignVector = penumexA->elfDesignVector;
4271 return CreateFontIndirectExW( &enumexW );
4274 /***********************************************************************
4275 * CreateFontIndirectExW (GDI32.@)
4277 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
4279 HFONT hFont;
4280 FONTOBJ *fontPtr;
4281 const LOGFONTW *plf;
4283 if (!penumex) return 0;
4285 if (penumex->elfEnumLogfontEx.elfFullName[0] ||
4286 penumex->elfEnumLogfontEx.elfStyle[0] ||
4287 penumex->elfEnumLogfontEx.elfScript[0])
4289 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
4290 debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
4291 debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
4292 debugstr_w(penumex->elfEnumLogfontEx.elfScript));
4295 plf = &penumex->elfEnumLogfontEx.elfLogFont;
4296 if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
4298 fontPtr->logfont = *plf;
4300 if (!(hFont = alloc_gdi_handle( &fontPtr->obj, NTGDI_OBJ_FONT, &fontobj_funcs )))
4302 HeapFree( GetProcessHeap(), 0, fontPtr );
4303 return 0;
4306 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
4307 plf->lfHeight, plf->lfWidth,
4308 plf->lfEscapement, plf->lfOrientation,
4309 plf->lfPitchAndFamily,
4310 plf->lfOutPrecision, plf->lfClipPrecision,
4311 plf->lfQuality, plf->lfCharSet,
4312 debugstr_w(plf->lfFaceName),
4313 plf->lfWeight > 400 ? "Bold" : "",
4314 plf->lfItalic ? "Italic" : "",
4315 plf->lfUnderline ? "Underline" : "", hFont);
4317 return hFont;
4320 /***********************************************************************
4321 * CreateFontIndirectA (GDI32.@)
4323 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
4325 LOGFONTW lfW;
4327 if (!plfA) return 0;
4329 FONT_LogFontAToW( plfA, &lfW );
4330 return CreateFontIndirectW( &lfW );
4333 /***********************************************************************
4334 * CreateFontIndirectW (GDI32.@)
4336 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
4338 ENUMLOGFONTEXDVW exdv;
4340 if (!plf) return 0;
4342 exdv.elfEnumLogfontEx.elfLogFont = *plf;
4343 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
4344 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
4345 exdv.elfEnumLogfontEx.elfScript[0] = 0;
4346 return CreateFontIndirectExW( &exdv );
4349 /*************************************************************************
4350 * CreateFontA (GDI32.@)
4352 HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
4353 INT orient, INT weight, DWORD italic,
4354 DWORD underline, DWORD strikeout, DWORD charset,
4355 DWORD outpres, DWORD clippres, DWORD quality,
4356 DWORD pitch, LPCSTR name )
4358 LOGFONTA logfont;
4360 logfont.lfHeight = height;
4361 logfont.lfWidth = width;
4362 logfont.lfEscapement = esc;
4363 logfont.lfOrientation = orient;
4364 logfont.lfWeight = weight;
4365 logfont.lfItalic = italic;
4366 logfont.lfUnderline = underline;
4367 logfont.lfStrikeOut = strikeout;
4368 logfont.lfCharSet = charset;
4369 logfont.lfOutPrecision = outpres;
4370 logfont.lfClipPrecision = clippres;
4371 logfont.lfQuality = quality;
4372 logfont.lfPitchAndFamily = pitch;
4374 if (name)
4375 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
4376 else
4377 logfont.lfFaceName[0] = '\0';
4379 return CreateFontIndirectA( &logfont );
4382 /*************************************************************************
4383 * CreateFontW (GDI32.@)
4385 HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
4386 INT orient, INT weight, DWORD italic,
4387 DWORD underline, DWORD strikeout, DWORD charset,
4388 DWORD outpres, DWORD clippres, DWORD quality,
4389 DWORD pitch, LPCWSTR name )
4391 LOGFONTW logfont;
4393 logfont.lfHeight = height;
4394 logfont.lfWidth = width;
4395 logfont.lfEscapement = esc;
4396 logfont.lfOrientation = orient;
4397 logfont.lfWeight = weight;
4398 logfont.lfItalic = italic;
4399 logfont.lfUnderline = underline;
4400 logfont.lfStrikeOut = strikeout;
4401 logfont.lfCharSet = charset;
4402 logfont.lfOutPrecision = outpres;
4403 logfont.lfClipPrecision = clippres;
4404 logfont.lfQuality = quality;
4405 logfont.lfPitchAndFamily = pitch;
4407 if (name)
4408 lstrcpynW(logfont.lfFaceName, name, ARRAY_SIZE(logfont.lfFaceName));
4409 else
4410 logfont.lfFaceName[0] = '\0';
4412 return CreateFontIndirectW( &logfont );
4415 #define ASSOC_CHARSET_OEM 1
4416 #define ASSOC_CHARSET_ANSI 2
4417 #define ASSOC_CHARSET_SYMBOL 4
4419 static DWORD get_associated_charset_info(void)
4421 static DWORD associated_charset = -1;
4423 if (associated_charset == -1)
4425 HKEY hkey;
4426 WCHAR dataW[32];
4427 DWORD type, data_len;
4429 associated_charset = 0;
4431 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
4432 L"System\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset", &hkey))
4433 return 0;
4435 data_len = sizeof(dataW);
4436 if (!RegQueryValueExW(hkey, L"ANSI(00)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4437 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4438 associated_charset |= ASSOC_CHARSET_ANSI;
4440 data_len = sizeof(dataW);
4441 if (!RegQueryValueExW(hkey, L"OEM(FF)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4442 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4443 associated_charset |= ASSOC_CHARSET_OEM;
4445 data_len = sizeof(dataW);
4446 if (!RegQueryValueExW(hkey, L"SYMBOL(02)", NULL, &type, (LPBYTE)dataW, &data_len) &&
4447 type == REG_SZ && !wcsicmp(dataW, L"yes"))
4448 associated_charset |= ASSOC_CHARSET_SYMBOL;
4450 RegCloseKey(hkey);
4452 TRACE("associated_charset = %d\n", associated_charset);
4455 return associated_charset;
4458 static void update_font_code_page( DC *dc, HANDLE font )
4460 CHARSETINFO csi;
4461 int charset = get_text_charset_info( dc, NULL, 0 );
4463 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
4465 LOGFONTW lf;
4467 GetObjectW( font, sizeof(lf), &lf );
4468 if (!(lf.lfClipPrecision & CLIP_DFA_DISABLE))
4469 charset = DEFAULT_CHARSET;
4472 /* Hmm, nicely designed api this one! */
4473 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
4474 dc->font_code_page = csi.ciACP;
4475 else {
4476 switch(charset) {
4477 case OEM_CHARSET:
4478 dc->font_code_page = GetOEMCP();
4479 break;
4480 case DEFAULT_CHARSET:
4481 dc->font_code_page = GetACP();
4482 break;
4484 case VISCII_CHARSET:
4485 case TCVN_CHARSET:
4486 case KOI8_CHARSET:
4487 case ISO3_CHARSET:
4488 case ISO4_CHARSET:
4489 case ISO10_CHARSET:
4490 case CELTIC_CHARSET:
4491 /* FIXME: These have no place here, but because x11drv
4492 enumerates fonts with these (made up) charsets some apps
4493 might use them and then the FIXME below would become
4494 annoying. Now we could pick the intended codepage for
4495 each of these, but since it's broken anyway we'll just
4496 use CP_ACP and hope it'll go away...
4498 dc->font_code_page = CP_ACP;
4499 break;
4501 default:
4502 FIXME("Can't find codepage for charset %d\n", charset);
4503 dc->font_code_page = CP_ACP;
4504 break;
4508 TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
4511 /***********************************************************************
4512 * NtGdiSelectFont (win32u.@)
4514 HGDIOBJ WINAPI NtGdiSelectFont( HDC hdc, HGDIOBJ handle )
4516 HGDIOBJ ret = 0;
4517 DC *dc = get_dc_ptr( hdc );
4518 PHYSDEV physdev;
4519 UINT aa_flags = 0;
4521 if (!dc) return 0;
4523 if (!GDI_inc_ref_count( handle ))
4525 release_dc_ptr( dc );
4526 return 0;
4529 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
4530 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
4532 ret = dc->hFont;
4533 dc->hFont = handle;
4534 dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
4535 update_font_code_page( dc, handle );
4536 if (dc->font_gamma_ramp == NULL)
4537 dc->font_gamma_ramp = &font_gamma_ramp;
4538 GDI_dec_ref_count( ret );
4540 else GDI_dec_ref_count( handle );
4542 release_dc_ptr( dc );
4543 return ret;
4547 /***********************************************************************
4548 * FONT_GetObjectW
4550 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
4552 FONTOBJ *font = GDI_GetObjPtr( handle, NTGDI_OBJ_FONT );
4554 if (!font) return 0;
4555 if (buffer)
4557 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
4558 memcpy( buffer, &font->logfont, count );
4560 else count = sizeof(LOGFONTW);
4561 GDI_ReleaseObj( handle );
4562 return count;
4566 /***********************************************************************
4567 * FONT_DeleteObject
4569 static BOOL FONT_DeleteObject( HGDIOBJ handle )
4571 FONTOBJ *obj;
4573 if (!(obj = free_gdi_handle( handle ))) return FALSE;
4574 HeapFree( GetProcessHeap(), 0, obj );
4575 return TRUE;
4579 /***********************************************************************
4580 * FONT_EnumInstance
4582 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
4583 * We have to use other types because of the FONTENUMPROCW definition.
4585 static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
4586 DWORD fType, LPARAM lp )
4588 struct font_enum *pfe = (struct font_enum *)lp;
4589 INT ret = 1;
4591 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
4592 if ((!pfe->lpLogFontParam ||
4593 pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
4594 pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
4595 (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
4597 /* convert font metrics */
4598 ENUMLOGFONTEXA logfont;
4599 NEWTEXTMETRICEXA tmA;
4601 if (!pfe->unicode)
4603 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
4604 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
4605 plf = (LOGFONTW *)&logfont.elfLogFont;
4606 ptm = (TEXTMETRICW *)&tmA;
4608 ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
4609 pfe->retval = ret;
4611 return ret;
4614 /***********************************************************************
4615 * FONT_EnumFontFamiliesEx
4617 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
4618 LPARAM lParam, BOOL unicode )
4620 INT ret = 0;
4621 DC *dc = get_dc_ptr( hDC );
4622 struct font_enum fe;
4624 if (dc)
4626 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
4628 if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4629 fe.lpLogFontParam = plf;
4630 fe.lpEnumFunc = efproc;
4631 fe.lpData = lParam;
4632 fe.unicode = unicode;
4633 fe.hdc = hDC;
4634 fe.retval = 1;
4635 ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
4636 release_dc_ptr( dc );
4638 return ret ? fe.retval : 0;
4641 /***********************************************************************
4642 * EnumFontFamiliesExW (GDI32.@)
4644 INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
4645 FONTENUMPROCW efproc,
4646 LPARAM lParam, DWORD dwFlags )
4648 return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
4651 /***********************************************************************
4652 * EnumFontFamiliesExA (GDI32.@)
4654 INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
4655 FONTENUMPROCA efproc,
4656 LPARAM lParam, DWORD dwFlags)
4658 LOGFONTW lfW, *plfW;
4660 if (plf)
4662 FONT_LogFontAToW( plf, &lfW );
4663 plfW = &lfW;
4665 else plfW = NULL;
4667 return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
4670 /***********************************************************************
4671 * EnumFontFamiliesA (GDI32.@)
4673 INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
4674 FONTENUMPROCA efproc, LPARAM lpData )
4676 LOGFONTA lf, *plf;
4678 if (lpFamily)
4680 if (!*lpFamily) return 1;
4681 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
4682 lf.lfCharSet = DEFAULT_CHARSET;
4683 lf.lfPitchAndFamily = 0;
4684 plf = &lf;
4686 else plf = NULL;
4688 return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
4691 /***********************************************************************
4692 * EnumFontFamiliesW (GDI32.@)
4694 INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
4695 FONTENUMPROCW efproc, LPARAM lpData )
4697 LOGFONTW lf, *plf;
4699 if (lpFamily)
4701 if (!*lpFamily) return 1;
4702 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
4703 lf.lfCharSet = DEFAULT_CHARSET;
4704 lf.lfPitchAndFamily = 0;
4705 plf = &lf;
4707 else plf = NULL;
4709 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
4712 /***********************************************************************
4713 * EnumFontsA (GDI32.@)
4715 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
4716 LPARAM lpData )
4718 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
4721 /***********************************************************************
4722 * EnumFontsW (GDI32.@)
4724 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
4725 LPARAM lpData )
4727 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
4731 /***********************************************************************
4732 * NtGdiSetTextJustification (win32u.@)
4734 BOOL WINAPI NtGdiSetTextJustification( HDC hdc, INT extra, INT breaks )
4736 DC *dc;
4738 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
4740 extra = abs( (extra * dc->attr->vport_ext.cx + dc->attr->wnd_ext.cx / 2) /
4741 dc->attr->wnd_ext.cx );
4742 if (!extra) breaks = 0;
4743 if (breaks)
4745 dc->breakExtra = extra / breaks;
4746 dc->breakRem = extra - (breaks * dc->breakExtra);
4748 else
4750 dc->breakExtra = 0;
4751 dc->breakRem = 0;
4754 release_dc_ptr( dc );
4755 return TRUE;
4759 /***********************************************************************
4760 * GetTextFaceA (GDI32.@)
4762 INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
4764 INT res = GetTextFaceW(hdc, 0, NULL);
4765 LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
4766 GetTextFaceW( hdc, res, nameW );
4768 if (name)
4770 if (count)
4772 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
4773 if (res == 0)
4774 res = count;
4775 name[count-1] = 0;
4776 /* GetTextFaceA does NOT include the nul byte in the return count. */
4777 res--;
4779 else
4780 res = 0;
4782 else
4783 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
4784 HeapFree( GetProcessHeap(), 0, nameW );
4785 return res;
4788 /***********************************************************************
4789 * GetTextFaceW (GDI32.@)
4791 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
4793 PHYSDEV dev;
4794 INT ret;
4796 DC * dc = get_dc_ptr( hdc );
4797 if (!dc) return 0;
4799 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
4800 ret = dev->funcs->pGetTextFace( dev, count, name );
4801 release_dc_ptr( dc );
4802 return ret;
4806 /***********************************************************************
4807 * GetTextExtentPoint32A (GDI32.@)
4809 * See GetTextExtentPoint32W.
4811 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
4812 LPSIZE size )
4814 BOOL ret = FALSE;
4815 INT wlen;
4816 LPWSTR p;
4818 if (count < 0) return FALSE;
4820 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
4822 if (p)
4824 ret = GetTextExtentPoint32W( hdc, p, wlen, size );
4825 HeapFree( GetProcessHeap(), 0, p );
4828 TRACE("(%p %s %d %p): returning %d x %d\n",
4829 hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
4830 return ret;
4834 /***********************************************************************
4835 * GetTextExtentPoint32W [GDI32.@]
4837 * Computes width/height for a string.
4839 * Computes width and height of the specified string.
4841 * RETURNS
4842 * Success: TRUE
4843 * Failure: FALSE
4845 BOOL WINAPI GetTextExtentPoint32W(
4846 HDC hdc, /* [in] Handle of device context */
4847 LPCWSTR str, /* [in] Address of text string */
4848 INT count, /* [in] Number of characters in string */
4849 LPSIZE size) /* [out] Address of structure for string size */
4851 return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
4854 /***********************************************************************
4855 * GetTextExtentExPointI [GDI32.@]
4857 * Computes width and height of the array of glyph indices.
4859 * PARAMS
4860 * hdc [I] Handle of device context.
4861 * indices [I] Glyph index array.
4862 * count [I] Number of glyphs in array.
4863 * max_ext [I] Maximum width in glyphs.
4864 * nfit [O] Maximum number of characters.
4865 * dxs [O] Partial string widths.
4866 * size [O] Returned string size.
4868 * RETURNS
4869 * Success: TRUE
4870 * Failure: FALSE
4872 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
4873 LPINT nfit, LPINT dxs, LPSIZE size )
4875 DC *dc;
4876 int i;
4877 BOOL ret;
4878 INT buffer[256], *pos = dxs;
4880 if (count < 0) return FALSE;
4882 dc = get_dc_ptr( hdc );
4883 if (!dc) return FALSE;
4885 if (!dxs)
4887 pos = buffer;
4888 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
4890 release_dc_ptr( dc );
4891 return FALSE;
4895 ret = get_char_positions_indices( dc, indices, count, pos, size );
4896 if (ret)
4898 if (dxs || nfit)
4900 for (i = 0; i < count; i++)
4902 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
4903 (i + 1) * dc->attr->char_extra;
4904 if (nfit && dx > (unsigned int)max_ext) break;
4905 if (dxs) dxs[i] = dx;
4907 if (nfit) *nfit = i;
4910 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
4911 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
4914 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
4915 release_dc_ptr( dc );
4917 TRACE("(%p %p %d %p): returning %d x %d\n",
4918 hdc, indices, count, size, size->cx, size->cy );
4919 return ret;
4922 /***********************************************************************
4923 * GetTextExtentPointI [GDI32.@]
4925 * Computes width and height of the array of glyph indices.
4927 * PARAMS
4928 * hdc [I] Handle of device context.
4929 * indices [I] Glyph index array.
4930 * count [I] Number of glyphs in array.
4931 * size [O] Returned string size.
4933 * RETURNS
4934 * Success: TRUE
4935 * Failure: FALSE
4937 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
4939 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
4943 /***********************************************************************
4944 * GetTextExtentPointA (GDI32.@)
4946 BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
4947 LPSIZE size )
4949 TRACE("not bug compatible.\n");
4950 return GetTextExtentPoint32A( hdc, str, count, size );
4953 /***********************************************************************
4954 * GetTextExtentPointW (GDI32.@)
4956 BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
4957 LPSIZE size )
4959 TRACE("not bug compatible.\n");
4960 return GetTextExtentPoint32W( hdc, str, count, size );
4964 /***********************************************************************
4965 * GetTextExtentExPointA (GDI32.@)
4967 BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
4968 INT maxExt, LPINT lpnFit,
4969 LPINT alpDx, LPSIZE size )
4971 BOOL ret;
4972 INT wlen;
4973 INT *walpDx = NULL;
4974 LPWSTR p = NULL;
4976 if (count < 0) return FALSE;
4977 if (maxExt < -1) return FALSE;
4979 if (alpDx)
4981 walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
4982 if (!walpDx) return FALSE;
4985 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
4986 ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
4987 if (walpDx)
4989 INT n = lpnFit ? *lpnFit : wlen;
4990 INT i, j;
4991 for(i = 0, j = 0; i < n; i++, j++)
4993 alpDx[j] = walpDx[i];
4994 if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
4997 if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
4998 HeapFree( GetProcessHeap(), 0, p );
4999 HeapFree( GetProcessHeap(), 0, walpDx );
5000 return ret;
5004 /***********************************************************************
5005 * GetTextExtentExPointW (GDI32.@)
5007 * Return the size of the string as it would be if it was output properly by
5008 * e.g. TextOut.
5010 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
5011 LPINT nfit, LPINT dxs, LPSIZE size )
5013 DC *dc;
5014 int i;
5015 BOOL ret;
5016 INT buffer[256], *pos = dxs;
5018 if (count < 0) return FALSE;
5020 dc = get_dc_ptr(hdc);
5021 if (!dc) return FALSE;
5023 if (!dxs)
5025 pos = buffer;
5026 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
5028 release_dc_ptr( dc );
5029 return FALSE;
5033 ret = get_char_positions( dc, str, count, pos, size );
5034 if (ret)
5036 if (dxs || nfit)
5038 for (i = 0; i < count; i++)
5040 unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) +
5041 (i + 1) * dc->attr->char_extra;
5042 if (nfit && dx > (unsigned int)max_ext) break;
5043 if (dxs) dxs[i] = dx;
5045 if (nfit) *nfit = i;
5048 size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->attr->char_extra;
5049 size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy ));
5052 if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos );
5053 release_dc_ptr( dc );
5055 TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy );
5056 return ret;
5059 /***********************************************************************
5060 * GetTextMetricsA (GDI32.@)
5062 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
5064 TEXTMETRICW tm32;
5066 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
5067 FONT_TextMetricWToA( &tm32, metrics );
5068 return TRUE;
5071 /***********************************************************************
5072 * GetTextMetricsW (GDI32.@)
5074 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
5076 PHYSDEV physdev;
5077 BOOL ret = FALSE;
5078 DC * dc = get_dc_ptr( hdc );
5079 if (!dc) return FALSE;
5081 physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
5082 ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
5084 if (ret)
5086 /* device layer returns values in device units
5087 * therefore we have to convert them to logical */
5089 metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
5090 metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
5091 metrics->tmHeight = height_to_LP( dc, metrics->tmHeight );
5092 metrics->tmAscent = height_to_LP( dc, metrics->tmAscent );
5093 metrics->tmDescent = height_to_LP( dc, metrics->tmDescent );
5094 metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading );
5095 metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading );
5096 metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth );
5097 metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth );
5098 metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang );
5099 ret = TRUE;
5101 TRACE("text metrics:\n"
5102 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
5103 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
5104 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
5105 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
5106 " PitchAndFamily = %02x\n"
5107 " --------------------\n"
5108 " InternalLeading = %i\n"
5109 " Ascent = %i\n"
5110 " Descent = %i\n"
5111 " Height = %i\n",
5112 metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth,
5113 metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth,
5114 metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang,
5115 metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet,
5116 metrics->tmPitchAndFamily,
5117 metrics->tmInternalLeading,
5118 metrics->tmAscent,
5119 metrics->tmDescent,
5120 metrics->tmHeight );
5122 release_dc_ptr( dc );
5123 return ret;
5127 /***********************************************************************
5128 * GetOutlineTextMetricsA (GDI32.@)
5129 * Gets metrics for TrueType fonts.
5131 * NOTES
5132 * If the supplied buffer isn't big enough Windows partially fills it up to
5133 * its given length and returns that length.
5135 * RETURNS
5136 * Success: Non-zero or size of required buffer
5137 * Failure: 0
5139 UINT WINAPI GetOutlineTextMetricsA(
5140 HDC hdc, /* [in] Handle of device context */
5141 UINT cbData, /* [in] Size of metric data array */
5142 LPOUTLINETEXTMETRICA lpOTM) /* [out] Address of metric data array */
5144 char buf[512], *ptr;
5145 UINT ret, needed;
5146 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
5147 OUTLINETEXTMETRICA *output = lpOTM;
5148 INT left, len;
5150 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
5151 return 0;
5152 if(ret > sizeof(buf))
5153 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
5154 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
5156 needed = sizeof(OUTLINETEXTMETRICA);
5157 if(lpOTMW->otmpFamilyName)
5158 needed += WideCharToMultiByte(CP_ACP, 0,
5159 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
5160 NULL, 0, NULL, NULL);
5161 if(lpOTMW->otmpFaceName)
5162 needed += WideCharToMultiByte(CP_ACP, 0,
5163 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
5164 NULL, 0, NULL, NULL);
5165 if(lpOTMW->otmpStyleName)
5166 needed += WideCharToMultiByte(CP_ACP, 0,
5167 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
5168 NULL, 0, NULL, NULL);
5169 if(lpOTMW->otmpFullName)
5170 needed += WideCharToMultiByte(CP_ACP, 0,
5171 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
5172 NULL, 0, NULL, NULL);
5174 if(!lpOTM) {
5175 ret = needed;
5176 goto end;
5179 TRACE("needed = %d\n", needed);
5180 if(needed > cbData)
5181 /* Since the supplied buffer isn't big enough, we'll alloc one
5182 that is and memcpy the first cbData bytes into the lpOTM at
5183 the end. */
5184 output = HeapAlloc(GetProcessHeap(), 0, needed);
5186 ret = output->otmSize = min(needed, cbData);
5187 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
5188 output->otmFiller = 0;
5189 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
5190 output->otmfsSelection = lpOTMW->otmfsSelection;
5191 output->otmfsType = lpOTMW->otmfsType;
5192 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
5193 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
5194 output->otmItalicAngle = lpOTMW->otmItalicAngle;
5195 output->otmEMSquare = lpOTMW->otmEMSquare;
5196 output->otmAscent = lpOTMW->otmAscent;
5197 output->otmDescent = lpOTMW->otmDescent;
5198 output->otmLineGap = lpOTMW->otmLineGap;
5199 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
5200 output->otmsXHeight = lpOTMW->otmsXHeight;
5201 output->otmrcFontBox = lpOTMW->otmrcFontBox;
5202 output->otmMacAscent = lpOTMW->otmMacAscent;
5203 output->otmMacDescent = lpOTMW->otmMacDescent;
5204 output->otmMacLineGap = lpOTMW->otmMacLineGap;
5205 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
5206 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
5207 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
5208 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
5209 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
5210 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
5211 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
5212 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
5213 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
5216 ptr = (char*)(output + 1);
5217 left = needed - sizeof(*output);
5219 if(lpOTMW->otmpFamilyName) {
5220 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
5221 len = WideCharToMultiByte(CP_ACP, 0,
5222 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
5223 ptr, left, NULL, NULL);
5224 left -= len;
5225 ptr += len;
5226 } else
5227 output->otmpFamilyName = 0;
5229 if(lpOTMW->otmpFaceName) {
5230 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
5231 len = WideCharToMultiByte(CP_ACP, 0,
5232 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
5233 ptr, left, NULL, NULL);
5234 left -= len;
5235 ptr += len;
5236 } else
5237 output->otmpFaceName = 0;
5239 if(lpOTMW->otmpStyleName) {
5240 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
5241 len = WideCharToMultiByte(CP_ACP, 0,
5242 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
5243 ptr, left, NULL, NULL);
5244 left -= len;
5245 ptr += len;
5246 } else
5247 output->otmpStyleName = 0;
5249 if(lpOTMW->otmpFullName) {
5250 output->otmpFullName = (LPSTR)(ptr - (char*)output);
5251 len = WideCharToMultiByte(CP_ACP, 0,
5252 (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
5253 ptr, left, NULL, NULL);
5254 left -= len;
5255 } else
5256 output->otmpFullName = 0;
5258 assert(left == 0);
5260 if(output != lpOTM) {
5261 memcpy(lpOTM, output, cbData);
5262 HeapFree(GetProcessHeap(), 0, output);
5264 /* check if the string offsets really fit into the provided size */
5265 /* FIXME: should we check string length as well? */
5266 /* make sure that we don't read/write beyond the provided buffer */
5267 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
5269 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
5270 lpOTM->otmpFamilyName = 0; /* doesn't fit */
5273 /* make sure that we don't read/write beyond the provided buffer */
5274 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
5276 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
5277 lpOTM->otmpFaceName = 0; /* doesn't fit */
5280 /* make sure that we don't read/write beyond the provided buffer */
5281 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
5283 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
5284 lpOTM->otmpStyleName = 0; /* doesn't fit */
5287 /* make sure that we don't read/write beyond the provided buffer */
5288 if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
5290 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
5291 lpOTM->otmpFullName = 0; /* doesn't fit */
5295 end:
5296 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
5297 HeapFree(GetProcessHeap(), 0, lpOTMW);
5299 return ret;
5303 /***********************************************************************
5304 * GetOutlineTextMetricsW [GDI32.@]
5306 UINT WINAPI GetOutlineTextMetricsW(
5307 HDC hdc, /* [in] Handle of device context */
5308 UINT cbData, /* [in] Size of metric data array */
5309 LPOUTLINETEXTMETRICW lpOTM) /* [out] Address of metric data array */
5311 DC *dc = get_dc_ptr( hdc );
5312 OUTLINETEXTMETRICW *output = lpOTM;
5313 PHYSDEV dev;
5314 UINT ret;
5316 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
5317 if(!dc) return 0;
5319 dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
5320 ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
5322 if (lpOTM && ret > cbData)
5324 output = HeapAlloc(GetProcessHeap(), 0, ret);
5325 ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
5328 if (lpOTM && ret)
5330 output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
5331 output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
5332 output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight );
5333 output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent );
5334 output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent );
5335 output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading );
5336 output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading );
5337 output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth );
5338 output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth );
5339 output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang );
5340 output->otmAscent = height_to_LP( dc, output->otmAscent);
5341 output->otmDescent = height_to_LP( dc, output->otmDescent);
5342 output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap);
5343 output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight);
5344 output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight);
5345 output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top);
5346 output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom);
5347 output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left);
5348 output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right);
5349 output->otmMacAscent = height_to_LP( dc, output->otmMacAscent);
5350 output->otmMacDescent = height_to_LP( dc, output->otmMacDescent);
5351 output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap);
5352 output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x);
5353 output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y);
5354 output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x);
5355 output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y);
5356 output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x);
5357 output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y);
5358 output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x);
5359 output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y);
5360 output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize);
5361 output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition);
5362 output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize);
5363 output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition);
5365 if(output != lpOTM)
5367 memcpy(lpOTM, output, cbData);
5368 HeapFree(GetProcessHeap(), 0, output);
5369 ret = cbData;
5372 release_dc_ptr(dc);
5373 return ret;
5376 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
5378 INT i, count = lastChar - firstChar + 1;
5379 UINT mbcp;
5380 UINT c;
5381 LPSTR str;
5383 if (count <= 0)
5384 return NULL;
5386 mbcp = GdiGetCodePage(hdc);
5387 switch (mbcp)
5389 case 932:
5390 case 936:
5391 case 949:
5392 case 950:
5393 case 1361:
5394 if (lastChar > 0xffff)
5395 return NULL;
5396 if ((firstChar ^ lastChar) > 0xff)
5397 return NULL;
5398 break;
5399 default:
5400 if (lastChar > 0xff)
5401 return NULL;
5402 mbcp = 0;
5403 break;
5406 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
5407 if (str == NULL)
5408 return NULL;
5410 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
5412 if (mbcp) {
5413 if (c > 0xff)
5414 str[i++] = (BYTE)(c >> 8);
5415 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
5416 str[i] = 0x1f; /* FIXME: use default character */
5417 else
5418 str[i] = (BYTE)c;
5420 else
5421 str[i] = (BYTE)c;
5423 str[i] = '\0';
5425 *pByteLen = i;
5427 return str;
5430 /***********************************************************************
5431 * GetCharWidthW (GDI32.@)
5432 * GetCharWidth32W (GDI32.@)
5434 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
5435 LPINT buffer )
5437 UINT i;
5438 BOOL ret;
5439 PHYSDEV dev;
5440 DC * dc = get_dc_ptr( hdc );
5442 if (!dc) return FALSE;
5444 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
5445 ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
5447 if (ret)
5449 /* convert device units to logical */
5450 for( i = firstChar; i <= lastChar; i++, buffer++ )
5451 *buffer = width_to_LP( dc, *buffer );
5453 release_dc_ptr( dc );
5454 return ret;
5458 /***********************************************************************
5459 * GetCharWidthA (GDI32.@)
5460 * GetCharWidth32A (GDI32.@)
5462 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
5463 LPINT buffer )
5465 INT i, wlen;
5466 LPSTR str;
5467 LPWSTR wstr;
5468 BOOL ret = TRUE;
5470 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
5471 if(str == NULL)
5472 return FALSE;
5474 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
5476 for(i = 0; i < wlen; i++)
5478 if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer))
5480 ret = FALSE;
5481 break;
5483 buffer++;
5486 HeapFree(GetProcessHeap(), 0, str);
5487 HeapFree(GetProcessHeap(), 0, wstr);
5489 return ret;
5493 /* helper for nulldrv_ExtTextOut */
5494 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT flags, UINT aa_flags,
5495 GLYPHMETRICS *metrics, struct gdi_image_bits *image )
5497 UINT indices[3] = {0, 0, 0x20};
5498 unsigned int i;
5499 DWORD ret, size;
5500 int stride;
5502 indices[0] = index;
5503 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
5505 for (i = 0; i < ARRAY_SIZE( indices ); i++)
5507 index = indices[i];
5508 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, 0, NULL, &identity );
5509 if (ret != GDI_ERROR) break;
5512 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
5513 if (!image) return ERROR_SUCCESS;
5515 image->ptr = NULL;
5516 image->free = NULL;
5517 if (!ret) /* empty glyph */
5519 metrics->gmBlackBoxX = metrics->gmBlackBoxY = 0;
5520 return ERROR_SUCCESS;
5523 stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5524 size = metrics->gmBlackBoxY * stride;
5526 if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
5527 image->is_copy = TRUE;
5528 image->free = free_heap_bits;
5530 ret = GetGlyphOutlineW( hdc, index, aa_flags, metrics, size, image->ptr, &identity );
5531 if (ret == GDI_ERROR)
5533 HeapFree( GetProcessHeap(), 0, image->ptr );
5534 return ERROR_NOT_FOUND;
5536 return ERROR_SUCCESS;
5539 /* helper for nulldrv_ExtTextOut */
5540 static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
5541 LPCWSTR str, UINT count, const INT *dx )
5543 UINT i;
5544 RECT rect, bounds;
5546 reset_bounds( &bounds );
5547 for (i = 0; i < count; i++)
5549 GLYPHMETRICS metrics;
5551 if (get_glyph_bitmap( hdc, str[i], flags, aa_flags, &metrics, NULL )) continue;
5553 rect.left = x + metrics.gmptGlyphOrigin.x;
5554 rect.top = y - metrics.gmptGlyphOrigin.y;
5555 rect.right = rect.left + metrics.gmBlackBoxX;
5556 rect.bottom = rect.top + metrics.gmBlackBoxY;
5557 add_bounds_rect( &bounds, &rect );
5559 if (dx)
5561 if (flags & ETO_PDY)
5563 x += dx[ i * 2 ];
5564 y += dx[ i * 2 + 1];
5566 else x += dx[ i ];
5568 else
5570 x += metrics.gmCellIncX;
5571 y += metrics.gmCellIncY;
5574 return bounds;
5577 /* helper for nulldrv_ExtTextOut */
5578 static void draw_glyph( DC *dc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
5579 const struct gdi_image_bits *image, const RECT *clip )
5581 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5582 UINT i, count, max_count;
5583 LONG x, y;
5584 BYTE *ptr = image->ptr;
5585 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
5586 POINT *pts;
5587 RECT rect, clipped_rect;
5589 rect.left = origin_x + metrics->gmptGlyphOrigin.x;
5590 rect.top = origin_y - metrics->gmptGlyphOrigin.y;
5591 rect.right = rect.left + metrics->gmBlackBoxX;
5592 rect.bottom = rect.top + metrics->gmBlackBoxY;
5593 if (!clip) clipped_rect = rect;
5594 else if (!intersect_rect( &clipped_rect, &rect, clip )) return;
5596 max_count = (metrics->gmBlackBoxX + 1) * metrics->gmBlackBoxY;
5597 pts = HeapAlloc( GetProcessHeap(), 0, max_count * sizeof(*pts) );
5598 if (!pts) return;
5600 count = 0;
5601 ptr += (clipped_rect.top - rect.top) * stride;
5602 for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
5604 for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
5606 while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
5607 pts[count].x = rect.left + x;
5608 while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
5609 pts[count + 1].x = rect.left + x;
5610 if (pts[count + 1].x > pts[count].x)
5612 pts[count].y = pts[count + 1].y = y;
5613 count += 2;
5617 assert( count <= max_count );
5618 dp_to_lp( dc, pts, count );
5619 for (i = 0; i < count; i += 2) Polyline( dc->hSelf, pts + i, 2 );
5620 HeapFree( GetProcessHeap(), 0, pts );
5623 /***********************************************************************
5624 * nulldrv_ExtTextOut
5626 BOOL CDECL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
5627 LPCWSTR str, UINT count, const INT *dx )
5629 DC *dc = get_nulldrv_dc( dev );
5630 UINT i;
5631 DWORD err;
5632 HGDIOBJ orig;
5633 HPEN pen;
5635 if (flags & ETO_OPAQUE)
5637 RECT rc = *rect;
5638 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, dc->attr->background_color ) );
5640 if (brush)
5642 orig = NtGdiSelectBrush( dev->hdc, brush );
5643 dp_to_lp( dc, (POINT *)&rc, 2 );
5644 NtGdiPatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
5645 NtGdiSelectBrush( dev->hdc, orig );
5646 DeleteObject( brush );
5650 if (!count) return TRUE;
5652 if (dc->aa_flags != GGO_BITMAP)
5654 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
5655 BITMAPINFO *info = (BITMAPINFO *)buffer;
5656 struct gdi_image_bits bits;
5657 struct bitblt_coords src, dst;
5658 PHYSDEV dst_dev;
5659 /* FIXME Subpixel modes */
5660 UINT aa_flags = GGO_GRAY4_BITMAP;
5662 dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
5663 src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
5664 if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
5665 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
5667 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
5668 src.x = src.visrect.left;
5669 src.y = src.visrect.top;
5670 src.width = src.visrect.right - src.visrect.left;
5671 src.height = src.visrect.bottom - src.visrect.top;
5672 dst = src;
5673 if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
5674 (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
5676 /* we can avoid the GetImage, just query the needed format */
5677 memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
5678 info->bmiHeader.biSize = sizeof(info->bmiHeader);
5679 info->bmiHeader.biWidth = src.width;
5680 info->bmiHeader.biHeight = -src.height;
5681 info->bmiHeader.biSizeImage = get_dib_image_size( info );
5682 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, NULL, NULL, NULL, 0 );
5683 if (!err || err == ERROR_BAD_FORMAT)
5685 /* make the source rectangle relative to the source bits */
5686 src.x = src.y = 0;
5687 src.visrect.left = src.visrect.top = 0;
5688 src.visrect.right = src.width;
5689 src.visrect.bottom = src.height;
5691 bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
5692 if (!bits.ptr) return ERROR_OUTOFMEMORY;
5693 bits.is_copy = TRUE;
5694 bits.free = free_heap_bits;
5695 err = ERROR_SUCCESS;
5698 else
5700 PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
5701 err = src_dev->funcs->pGetImage( src_dev, info, &bits, &src );
5702 if (!err && !bits.is_copy)
5704 void *ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
5705 if (!ptr)
5707 if (bits.free) bits.free( &bits );
5708 return ERROR_OUTOFMEMORY;
5710 memcpy( ptr, bits.ptr, info->bmiHeader.biSizeImage );
5711 if (bits.free) bits.free( &bits );
5712 bits.ptr = ptr;
5713 bits.is_copy = TRUE;
5714 bits.free = free_heap_bits;
5717 if (!err)
5719 /* make x,y relative to the image bits */
5720 x += src.visrect.left - dst.visrect.left;
5721 y += src.visrect.top - dst.visrect.top;
5722 render_aa_text_bitmapinfo( dc, info, &bits, &src, x, y, flags,
5723 aa_flags, str, count, dx );
5724 err = dst_dev->funcs->pPutImage( dst_dev, 0, info, &bits, &src, &dst, SRCCOPY );
5725 if (bits.free) bits.free( &bits );
5726 return !err;
5730 pen = CreatePen( PS_SOLID, 1, dc->attr->text_color );
5731 orig = NtGdiSelectPen( dev->hdc, pen );
5733 for (i = 0; i < count; i++)
5735 GLYPHMETRICS metrics;
5736 struct gdi_image_bits image;
5738 err = get_glyph_bitmap( dev->hdc, str[i], flags, GGO_BITMAP, &metrics, &image );
5739 if (err) continue;
5741 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
5742 if (image.free) image.free( &image );
5744 if (dx)
5746 if (flags & ETO_PDY)
5748 x += dx[ i * 2 ];
5749 y += dx[ i * 2 + 1];
5751 else x += dx[ i ];
5753 else
5755 x += metrics.gmCellIncX;
5756 y += metrics.gmCellIncY;
5760 NtGdiSelectPen( dev->hdc, orig );
5761 DeleteObject( pen );
5762 return TRUE;
5766 /***********************************************************************
5767 * ExtTextOutA (GDI32.@)
5769 * See ExtTextOutW.
5771 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
5772 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
5774 INT wlen;
5775 UINT codepage;
5776 LPWSTR p;
5777 BOOL ret;
5778 LPINT lpDxW = NULL;
5780 if (count > INT_MAX) return FALSE;
5782 if (flags & ETO_GLYPH_INDEX)
5783 return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
5785 p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
5787 if (lpDx) {
5788 unsigned int i = 0, j = 0;
5790 /* allocate enough for a ETO_PDY */
5791 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
5792 while(i < count) {
5793 if(IsDBCSLeadByteEx(codepage, str[i]))
5795 if(flags & ETO_PDY)
5797 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
5798 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
5800 else
5801 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
5802 i = i + 2;
5804 else
5806 if(flags & ETO_PDY)
5808 lpDxW[j++] = lpDx[i * 2];
5809 lpDxW[j++] = lpDx[i * 2 + 1];
5811 else
5812 lpDxW[j++] = lpDx[i];
5813 i = i + 1;
5818 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
5820 HeapFree( GetProcessHeap(), 0, p );
5821 HeapFree( GetProcessHeap(), 0, lpDxW );
5822 return ret;
5825 /***********************************************************************
5826 * get_line_width
5828 * Scale the underline / strikeout line width.
5830 static inline int get_line_width( DC *dc, int metric_size )
5832 int width = abs( INTERNAL_YWSTODS( dc, metric_size ));
5833 if (width == 0) width = 1;
5834 if (metric_size < 0) width = -width;
5835 return width;
5838 /***********************************************************************
5839 * NtGdiExtTextOutW (win32u.@)
5841 * Draws text using the currently selected font, background color, and text color.
5844 * PARAMS
5845 * x,y [I] coordinates of string
5846 * flags [I]
5847 * ETO_GRAYED - undocumented on MSDN
5848 * ETO_OPAQUE - use background color for fill the rectangle
5849 * ETO_CLIPPED - clipping text to the rectangle
5850 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
5851 * than encoded characters. Implies ETO_IGNORELANGUAGE
5852 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
5853 * Affects BiDi ordering
5854 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
5855 * ETO_PDY - unimplemented
5856 * ETO_NUMERICSLATIN - unimplemented always assumed -
5857 * do not translate numbers into locale representations
5858 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
5859 * lprect [I] dimensions for clipping or/and opaquing
5860 * str [I] text string
5861 * count [I] number of symbols in string
5862 * lpDx [I] optional parameter with distance between drawing characters
5864 * RETURNS
5865 * Success: TRUE
5866 * Failure: FALSE
5868 BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
5869 const WCHAR *str, UINT count, const INT *lpDx, DWORD cp )
5871 BOOL ret = FALSE;
5872 LPWSTR reordered_str = (LPWSTR)str;
5873 WORD *glyphs = NULL;
5874 UINT align;
5875 DWORD layout;
5876 POINT pt;
5877 TEXTMETRICW tm;
5878 LOGFONTW lf;
5879 double cosEsc, sinEsc;
5880 INT char_extra;
5881 SIZE sz;
5882 RECT rc;
5883 POINT *deltas = NULL, width = {0, 0};
5884 DWORD type;
5885 DC * dc = get_dc_ptr( hdc );
5886 PHYSDEV physdev;
5887 INT breakRem;
5888 static int quietfixme = 0;
5890 if (!dc) return FALSE;
5891 if (count > INT_MAX) return FALSE;
5893 align = dc->attr->text_align;
5894 breakRem = dc->breakRem;
5895 layout = dc->attr->layout;
5897 if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
5899 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
5900 quietfixme = 1;
5903 update_dc( dc );
5904 physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
5905 type = GetObjectType(hdc);
5906 if(type == OBJ_METADC || type == OBJ_ENHMETADC)
5908 ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
5909 release_dc_ptr( dc );
5910 return ret;
5913 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
5914 if (layout & LAYOUT_RTL)
5916 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
5917 align ^= TA_RTLREADING;
5920 if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
5922 INT cGlyphs;
5923 reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
5925 BIDI_Reorder( hdc, str, count, GCP_REORDER,
5926 (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
5927 reordered_str, count, NULL, &glyphs, &cGlyphs);
5929 flags |= ETO_IGNORELANGUAGE;
5930 if (glyphs)
5932 flags |= ETO_GLYPH_INDEX;
5933 if (cGlyphs != count)
5934 count = cGlyphs;
5937 else if(flags & ETO_GLYPH_INDEX)
5938 glyphs = reordered_str;
5940 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
5941 wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
5942 TRACE("align = %x bkmode = %x mapmode = %x\n", align, dc->attr->background_mode,
5943 dc->attr->map_mode);
5945 if(align & TA_UPDATECP)
5947 pt = dc->attr->cur_pos;
5948 x = pt.x;
5949 y = pt.y;
5952 GetTextMetricsW(hdc, &tm);
5953 GetObjectW(dc->hFont, sizeof(lf), &lf);
5955 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
5956 lf.lfEscapement = 0;
5958 if ((dc->attr->graphics_mode == GM_COMPATIBLE) &&
5959 (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
5961 lf.lfEscapement = -lf.lfEscapement;
5964 if(lf.lfEscapement != 0)
5966 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
5967 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
5969 else
5971 cosEsc = 1;
5972 sinEsc = 0;
5975 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
5977 rc = *lprect;
5978 lp_to_dp(dc, (POINT*)&rc, 2);
5979 order_rect( &rc );
5980 if (flags & ETO_OPAQUE)
5981 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
5983 else flags &= ~ETO_CLIPPED;
5985 if(count == 0)
5987 ret = TRUE;
5988 goto done;
5991 pt.x = x;
5992 pt.y = y;
5993 lp_to_dp(dc, &pt, 1);
5994 x = pt.x;
5995 y = pt.y;
5997 char_extra = GetTextCharacterExtra(hdc);
5998 if (char_extra && lpDx && GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER)
5999 char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */
6001 if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
6003 UINT i;
6004 POINT total = {0, 0}, desired[2];
6006 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
6007 if (lpDx)
6009 if (flags & ETO_PDY)
6011 for (i = 0; i < count; i++)
6013 deltas[i].x = lpDx[i * 2] + char_extra;
6014 deltas[i].y = -lpDx[i * 2 + 1];
6017 else
6019 for (i = 0; i < count; i++)
6021 deltas[i].x = lpDx[i] + char_extra;
6022 deltas[i].y = 0;
6026 else
6028 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
6030 if (flags & ETO_GLYPH_INDEX)
6031 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
6032 else
6033 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
6035 deltas[0].x = dx[0];
6036 deltas[0].y = 0;
6037 for (i = 1; i < count; i++)
6039 deltas[i].x = dx[i] - dx[i - 1];
6040 deltas[i].y = 0;
6042 HeapFree( GetProcessHeap(), 0, dx );
6045 for(i = 0; i < count; i++)
6047 total.x += deltas[i].x;
6048 total.y += deltas[i].y;
6050 desired[0].x = desired[0].y = 0;
6052 desired[1].x = cosEsc * total.x + sinEsc * total.y;
6053 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
6055 lp_to_dp(dc, desired, 2);
6056 desired[1].x -= desired[0].x;
6057 desired[1].y -= desired[0].y;
6059 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6061 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6062 desired[1].x = -desired[1].x;
6063 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6064 desired[1].y = -desired[1].y;
6067 deltas[i].x = desired[1].x - width.x;
6068 deltas[i].y = desired[1].y - width.y;
6070 width = desired[1];
6072 flags |= ETO_PDY;
6074 else
6076 POINT desired[2];
6078 if(flags & ETO_GLYPH_INDEX)
6079 GetTextExtentPointI(hdc, glyphs, count, &sz);
6080 else
6081 GetTextExtentPointW(hdc, reordered_str, count, &sz);
6082 desired[0].x = desired[0].y = 0;
6083 desired[1].x = sz.cx;
6084 desired[1].y = 0;
6085 lp_to_dp(dc, desired, 2);
6086 desired[1].x -= desired[0].x;
6087 desired[1].y -= desired[0].y;
6089 if (dc->attr->graphics_mode == GM_COMPATIBLE)
6091 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
6092 desired[1].x = -desired[1].x;
6093 if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
6094 desired[1].y = -desired[1].y;
6096 width = desired[1];
6099 tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
6100 tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
6101 switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
6103 case TA_LEFT:
6104 if (align & TA_UPDATECP)
6106 pt.x = x + width.x;
6107 pt.y = y + width.y;
6108 dp_to_lp(dc, &pt, 1);
6109 MoveToEx(hdc, pt.x, pt.y, NULL);
6111 break;
6113 case TA_CENTER:
6114 x -= width.x / 2;
6115 y -= width.y / 2;
6116 break;
6118 case TA_RIGHT:
6119 x -= width.x;
6120 y -= width.y;
6121 if (align & TA_UPDATECP)
6123 pt.x = x;
6124 pt.y = y;
6125 dp_to_lp(dc, &pt, 1);
6126 MoveToEx(hdc, pt.x, pt.y, NULL);
6128 break;
6131 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
6133 case TA_TOP:
6134 y += tm.tmAscent * cosEsc;
6135 x += tm.tmAscent * sinEsc;
6136 break;
6138 case TA_BOTTOM:
6139 y -= tm.tmDescent * cosEsc;
6140 x -= tm.tmDescent * sinEsc;
6141 break;
6143 case TA_BASELINE:
6144 break;
6147 if (dc->attr->background_mode != TRANSPARENT)
6149 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
6151 if(!(flags & ETO_OPAQUE) || !lprect ||
6152 x < rc.left || x + width.x >= rc.right ||
6153 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
6155 RECT text_box;
6156 text_box.left = x;
6157 text_box.right = x + width.x;
6158 text_box.top = y - tm.tmAscent;
6159 text_box.bottom = y + tm.tmDescent;
6161 if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
6162 if (!is_rect_empty( &text_box ))
6163 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
6168 ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
6169 glyphs ? glyphs : reordered_str, count, (INT*)deltas );
6171 done:
6172 HeapFree(GetProcessHeap(), 0, deltas);
6173 if(glyphs != reordered_str)
6174 HeapFree(GetProcessHeap(), 0, glyphs);
6175 if(reordered_str != str)
6176 HeapFree(GetProcessHeap(), 0, reordered_str);
6178 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
6180 int underlinePos, strikeoutPos;
6181 int underlineWidth, strikeoutWidth;
6182 UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
6183 OUTLINETEXTMETRICW* otm = NULL;
6184 POINT pts[5];
6185 HPEN hpen = NtGdiSelectPen(hdc, GetStockObject(NULL_PEN));
6186 HBRUSH hbrush = CreateSolidBrush( dc->attr->text_color );
6188 hbrush = NtGdiSelectBrush(hdc, hbrush);
6190 if(!size)
6192 underlinePos = 0;
6193 underlineWidth = tm.tmAscent / 20 + 1;
6194 strikeoutPos = tm.tmAscent / 2;
6195 strikeoutWidth = underlineWidth;
6197 else
6199 otm = HeapAlloc(GetProcessHeap(), 0, size);
6200 GetOutlineTextMetricsW(hdc, size, otm);
6201 underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
6202 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
6203 underlineWidth = get_line_width( dc, otm->otmsUnderscoreSize );
6204 strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
6205 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
6206 strikeoutWidth = get_line_width( dc, otm->otmsStrikeoutSize );
6207 HeapFree(GetProcessHeap(), 0, otm);
6211 if (lf.lfUnderline)
6213 const UINT cnt = 5;
6214 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
6215 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
6216 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
6217 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
6218 pts[2].x = pts[1].x + underlineWidth * sinEsc;
6219 pts[2].y = pts[1].y + underlineWidth * cosEsc;
6220 pts[3].x = pts[0].x + underlineWidth * sinEsc;
6221 pts[3].y = pts[0].y + underlineWidth * cosEsc;
6222 pts[4].x = pts[0].x;
6223 pts[4].y = pts[0].y;
6224 dp_to_lp(dc, pts, 5);
6225 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6228 if (lf.lfStrikeOut)
6230 const UINT cnt = 5;
6231 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6232 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6233 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
6234 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
6235 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
6236 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
6237 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
6238 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
6239 pts[4].x = pts[0].x;
6240 pts[4].y = pts[0].y;
6241 dp_to_lp(dc, pts, 5);
6242 NtGdiPolyPolyDraw( hdc, pts, &cnt, 1, NtGdiPolyPolygon );
6245 NtGdiSelectPen(hdc, hpen);
6246 hbrush = NtGdiSelectBrush(hdc, hbrush);
6247 DeleteObject(hbrush);
6250 release_dc_ptr( dc );
6252 return ret;
6256 /***********************************************************************
6257 * TextOutA (GDI32.@)
6259 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count )
6261 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
6265 /***********************************************************************
6266 * TextOutW (GDI32.@)
6268 BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count)
6270 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
6274 /***********************************************************************
6275 * PolyTextOutA (GDI32.@)
6277 * See PolyTextOutW.
6279 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
6281 for (; cStrings>0; cStrings--, pptxt++)
6282 if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
6283 return FALSE;
6284 return TRUE;
6289 /***********************************************************************
6290 * PolyTextOutW (GDI32.@)
6292 * Draw several Strings
6294 * RETURNS
6295 * TRUE: Success.
6296 * FALSE: Failure.
6298 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
6300 for (; cStrings>0; cStrings--, pptxt++)
6301 if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx ))
6302 return FALSE;
6303 return TRUE;
6307 /***********************************************************************
6308 * GetAspectRatioFilterEx (GDI32.@)
6310 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
6312 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
6313 return FALSE;
6317 /***********************************************************************
6318 * GetCharABCWidthsA (GDI32.@)
6320 * See GetCharABCWidthsW.
6322 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
6323 LPABC abc )
6325 INT i, wlen;
6326 LPSTR str;
6327 LPWSTR wstr;
6328 BOOL ret = TRUE;
6330 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
6331 if (str == NULL)
6332 return FALSE;
6334 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
6335 if (wstr == NULL)
6337 HeapFree(GetProcessHeap(), 0, str);
6338 return FALSE;
6341 for(i = 0; i < wlen; i++)
6343 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
6345 ret = FALSE;
6346 break;
6348 abc++;
6351 HeapFree(GetProcessHeap(), 0, str);
6352 HeapFree(GetProcessHeap(), 0, wstr);
6354 return ret;
6358 /******************************************************************************
6359 * GetCharABCWidthsW [GDI32.@]
6361 * Retrieves widths of characters in range.
6363 * PARAMS
6364 * hdc [I] Handle of device context
6365 * firstChar [I] First character in range to query
6366 * lastChar [I] Last character in range to query
6367 * abc [O] Address of character-width structure
6369 * NOTES
6370 * Only works with TrueType fonts
6372 * RETURNS
6373 * Success: TRUE
6374 * Failure: FALSE
6376 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
6377 LPABC abc )
6379 DC *dc = get_dc_ptr(hdc);
6380 PHYSDEV dev;
6381 unsigned int i;
6382 BOOL ret;
6383 TEXTMETRICW tm;
6385 if (!dc) return FALSE;
6387 if (!abc)
6389 release_dc_ptr( dc );
6390 return FALSE;
6393 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
6394 dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
6395 if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_VECTOR))
6397 release_dc_ptr( dc );
6398 return FALSE;
6401 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
6402 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
6403 if (ret)
6405 /* convert device units to logical */
6406 for( i = firstChar; i <= lastChar; i++, abc++ ) {
6407 abc->abcA = width_to_LP(dc, abc->abcA);
6408 abc->abcB = width_to_LP(dc, abc->abcB);
6409 abc->abcC = width_to_LP(dc, abc->abcC);
6413 release_dc_ptr( dc );
6414 return ret;
6418 /******************************************************************************
6419 * GetCharABCWidthsI [GDI32.@]
6421 * Retrieves widths of characters in range.
6423 * PARAMS
6424 * hdc [I] Handle of device context
6425 * firstChar [I] First glyphs in range to query
6426 * count [I] Last glyphs in range to query
6427 * pgi [i] Array of glyphs to query
6428 * abc [O] Address of character-width structure
6430 * NOTES
6431 * Only works with TrueType fonts
6433 * RETURNS
6434 * Success: TRUE
6435 * Failure: FALSE
6437 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
6438 LPWORD pgi, LPABC abc)
6440 DC *dc = get_dc_ptr(hdc);
6441 PHYSDEV dev;
6442 unsigned int i;
6443 BOOL ret;
6445 if (!dc) return FALSE;
6447 if (!abc)
6449 release_dc_ptr( dc );
6450 return FALSE;
6453 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
6454 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
6455 if (ret)
6457 /* convert device units to logical */
6458 for( i = 0; i < count; i++, abc++ ) {
6459 abc->abcA = width_to_LP(dc, abc->abcA);
6460 abc->abcB = width_to_LP(dc, abc->abcB);
6461 abc->abcC = width_to_LP(dc, abc->abcC);
6465 release_dc_ptr( dc );
6466 return ret;
6470 /***********************************************************************
6471 * GetGlyphOutlineA (GDI32.@)
6473 DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
6474 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
6475 LPVOID lpBuffer, const MAT2 *lpmat2 )
6477 if (!lpmat2) return GDI_ERROR;
6479 if(!(fuFormat & GGO_GLYPH_INDEX)) {
6480 UINT cp;
6481 int len;
6482 char mbchs[2];
6483 WCHAR wChar;
6485 cp = GdiGetCodePage(hdc);
6486 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
6487 len = 2;
6488 mbchs[0] = (uChar & 0xff00) >> 8;
6489 mbchs[1] = (uChar & 0xff);
6490 } else {
6491 len = 1;
6492 mbchs[0] = (uChar & 0xff);
6494 wChar = 0;
6495 MultiByteToWideChar(cp, 0, mbchs, len, &wChar, 1);
6496 uChar = wChar;
6499 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
6500 lpmat2);
6503 /***********************************************************************
6504 * GetGlyphOutlineW (GDI32.@)
6506 DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
6507 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
6508 LPVOID lpBuffer, const MAT2 *lpmat2 )
6510 DC *dc;
6511 DWORD ret;
6512 PHYSDEV dev;
6514 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
6515 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
6517 if (!lpmat2) return GDI_ERROR;
6519 dc = get_dc_ptr(hdc);
6520 if(!dc) return GDI_ERROR;
6522 uChar &= 0xffff;
6524 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
6525 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
6526 release_dc_ptr( dc );
6527 return ret;
6531 /***********************************************************************
6532 * CreateScalableFontResourceA (GDI32.@)
6534 BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
6535 LPCSTR lpszResourceFile,
6536 LPCSTR lpszFontFile,
6537 LPCSTR lpszCurrentPath )
6539 LPWSTR lpszResourceFileW = NULL;
6540 LPWSTR lpszFontFileW = NULL;
6541 LPWSTR lpszCurrentPathW = NULL;
6542 int len;
6543 BOOL ret;
6545 if (lpszResourceFile)
6547 len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
6548 lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6549 MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
6552 if (lpszFontFile)
6554 len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
6555 lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6556 MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
6559 if (lpszCurrentPath)
6561 len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
6562 lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6563 MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
6566 ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
6567 lpszFontFileW, lpszCurrentPathW);
6569 HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
6570 HeapFree(GetProcessHeap(), 0, lpszFontFileW);
6571 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);
6573 return ret;
6576 #define NE_FFLAGS_LIBMODULE 0x8000
6577 #define NE_OSFLAGS_WINDOWS 0x02
6579 static const char dos_string[0x40] = "This is a TrueType resource file";
6580 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
6582 #include <pshpack1.h>
6583 struct fontdir
6585 WORD num_of_resources;
6586 WORD res_id;
6587 WORD dfVersion;
6588 DWORD dfSize;
6589 CHAR dfCopyright[60];
6590 WORD dfType;
6591 WORD dfPoints;
6592 WORD dfVertRes;
6593 WORD dfHorizRes;
6594 WORD dfAscent;
6595 WORD dfInternalLeading;
6596 WORD dfExternalLeading;
6597 BYTE dfItalic;
6598 BYTE dfUnderline;
6599 BYTE dfStrikeOut;
6600 WORD dfWeight;
6601 BYTE dfCharSet;
6602 WORD dfPixWidth;
6603 WORD dfPixHeight;
6604 BYTE dfPitchAndFamily;
6605 WORD dfAvgWidth;
6606 WORD dfMaxWidth;
6607 BYTE dfFirstChar;
6608 BYTE dfLastChar;
6609 BYTE dfDefaultChar;
6610 BYTE dfBreakChar;
6611 WORD dfWidthBytes;
6612 DWORD dfDevice;
6613 DWORD dfFace;
6614 DWORD dfReserved;
6615 CHAR szFaceName[LF_FACESIZE];
6617 #include <poppack.h>
6619 #include <pshpack2.h>
6621 struct ne_typeinfo
6623 WORD type_id;
6624 WORD count;
6625 DWORD res;
6628 struct ne_nameinfo
6630 WORD off;
6631 WORD len;
6632 WORD flags;
6633 WORD id;
6634 DWORD res;
6637 struct rsrc_tab
6639 WORD align;
6640 struct ne_typeinfo fontdir_type;
6641 struct ne_nameinfo fontdir_name;
6642 struct ne_typeinfo scalable_type;
6643 struct ne_nameinfo scalable_name;
6644 WORD end_of_rsrc;
6645 BYTE fontdir_res_name[8];
6648 #include <poppack.h>
6650 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
6652 BOOL ret = FALSE;
6653 HANDLE file;
6654 DWORD size, written;
6655 BYTE *ptr, *start;
6656 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
6657 char *font_fileA, *last_part, *ext;
6658 IMAGE_DOS_HEADER dos;
6659 IMAGE_OS2_HEADER ne =
6661 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
6662 0, 0, 0, 0, 0, 0,
6663 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
6664 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
6666 struct rsrc_tab rsrc_tab =
6669 { 0x8007, 1, 0 },
6670 { 0, 0, 0x0c50, 0x2c, 0 },
6671 { 0x80cc, 1, 0 },
6672 { 0, 0, 0x0c50, 0x8001, 0 },
6674 { 7,'F','O','N','T','D','I','R'}
6677 memset( &dos, 0, sizeof(dos) );
6678 dos.e_magic = IMAGE_DOS_SIGNATURE;
6679 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
6681 /* import name is last part\0, resident name is last part without extension
6682 non-resident name is "FONTRES:" + lfFaceName */
6684 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
6685 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
6686 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
6688 last_part = strrchr( font_fileA, '\\' );
6689 if (last_part) last_part++;
6690 else last_part = font_fileA;
6691 import_name_len = strlen( last_part ) + 1;
6693 ext = strchr( last_part, '.' );
6694 if (ext) res_name_len = ext - last_part;
6695 else res_name_len = import_name_len - 1;
6697 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
6699 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
6700 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
6701 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
6702 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
6703 ne.ne_cbenttab = 2;
6704 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
6706 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
6707 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
6708 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
6709 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
6711 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
6712 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
6714 if (!ptr)
6716 HeapFree( GetProcessHeap(), 0, font_fileA );
6717 return FALSE;
6720 memcpy( ptr, &dos, sizeof(dos) );
6721 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
6722 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
6724 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
6725 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
6727 ptr = start + dos.e_lfanew + ne.ne_restab;
6728 *ptr++ = res_name_len;
6729 memcpy( ptr, last_part, res_name_len );
6731 ptr = start + dos.e_lfanew + ne.ne_imptab;
6732 *ptr++ = import_name_len;
6733 memcpy( ptr, last_part, import_name_len );
6735 ptr = start + ne.ne_nrestab;
6736 *ptr++ = non_res_name_len;
6737 memcpy( ptr, FONTRES, sizeof(FONTRES) );
6738 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
6740 ptr = start + (rsrc_tab.scalable_name.off << 4);
6741 memcpy( ptr, font_fileA, font_file_len );
6743 ptr = start + (rsrc_tab.fontdir_name.off << 4);
6744 memcpy( ptr, fontdir, fontdir->dfSize );
6746 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
6747 if (file != INVALID_HANDLE_VALUE)
6749 if (WriteFile( file, start, size, &written, NULL ) && written == size)
6750 ret = TRUE;
6751 CloseHandle( file );
6754 HeapFree( GetProcessHeap(), 0, start );
6755 HeapFree( GetProcessHeap(), 0, font_fileA );
6757 return ret;
6760 /***********************************************************************
6761 * CreateScalableFontResourceW (GDI32.@)
6763 BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
6764 LPCWSTR font_file, LPCWSTR font_path )
6766 struct fontdir fontdir = { 0 };
6767 struct gdi_font *font = NULL;
6768 WCHAR path[MAX_PATH];
6770 TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
6771 debugstr_w(font_file), debugstr_w(font_path) );
6773 if (!font_funcs) return FALSE;
6775 if (!font_file) goto done;
6776 if (font_path && font_path[0])
6778 int len = lstrlenW( font_path ) + lstrlenW( font_file ) + 2;
6779 if (len > MAX_PATH) goto done;
6780 lstrcpynW( path, font_path, MAX_PATH );
6781 lstrcatW( path, L"\\" );
6782 lstrcatW( path, font_file );
6784 else if (!GetFullPathNameW( font_file, MAX_PATH, path, NULL )) goto done;
6786 if (!(font = alloc_gdi_font( path, NULL, 0 ))) goto done;
6787 font->lf.lfHeight = 100;
6788 if (!font_funcs->load_font( font )) goto done;
6789 if (!font_funcs->set_outline_text_metrics( font )) goto done;
6791 if (!(font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) goto done;
6793 fontdir.num_of_resources = 1;
6794 fontdir.res_id = 0;
6795 fontdir.dfVersion = 0x200;
6796 fontdir.dfSize = sizeof(fontdir);
6797 strcpy( fontdir.dfCopyright, "Wine fontdir" );
6798 fontdir.dfType = 0x4003; /* 0x0080 set if private */
6799 fontdir.dfPoints = font->otm.otmEMSquare;
6800 fontdir.dfVertRes = 72;
6801 fontdir.dfHorizRes = 72;
6802 fontdir.dfAscent = font->otm.otmTextMetrics.tmAscent;
6803 fontdir.dfInternalLeading = font->otm.otmTextMetrics.tmInternalLeading;
6804 fontdir.dfExternalLeading = font->otm.otmTextMetrics.tmExternalLeading;
6805 fontdir.dfItalic = font->otm.otmTextMetrics.tmItalic;
6806 fontdir.dfUnderline = font->otm.otmTextMetrics.tmUnderlined;
6807 fontdir.dfStrikeOut = font->otm.otmTextMetrics.tmStruckOut;
6808 fontdir.dfWeight = font->otm.otmTextMetrics.tmWeight;
6809 fontdir.dfCharSet = font->otm.otmTextMetrics.tmCharSet;
6810 fontdir.dfPixWidth = 0;
6811 fontdir.dfPixHeight = font->otm.otmTextMetrics.tmHeight;
6812 fontdir.dfPitchAndFamily = font->otm.otmTextMetrics.tmPitchAndFamily;
6813 fontdir.dfAvgWidth = font->otm.otmTextMetrics.tmAveCharWidth;
6814 fontdir.dfMaxWidth = font->otm.otmTextMetrics.tmMaxCharWidth;
6815 fontdir.dfFirstChar = font->otm.otmTextMetrics.tmFirstChar;
6816 fontdir.dfLastChar = font->otm.otmTextMetrics.tmLastChar;
6817 fontdir.dfDefaultChar = font->otm.otmTextMetrics.tmDefaultChar;
6818 fontdir.dfBreakChar = font->otm.otmTextMetrics.tmBreakChar;
6819 fontdir.dfWidthBytes = 0;
6820 fontdir.dfDevice = 0;
6821 fontdir.dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
6822 fontdir.dfReserved = 0;
6823 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)font->otm.otmpFamilyName, -1,
6824 fontdir.szFaceName, LF_FACESIZE, NULL, NULL );
6825 free_gdi_font( font );
6827 if (hidden) fontdir.dfType |= 0x80;
6828 return create_fot( resource_file, font_file, &fontdir );
6830 done:
6831 if (font) free_gdi_font( font );
6832 SetLastError( ERROR_INVALID_PARAMETER );
6833 return FALSE;
6836 /*************************************************************************
6837 * GetKerningPairsA (GDI32.@)
6839 DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
6840 LPKERNINGPAIR kern_pairA )
6842 UINT cp;
6843 CPINFO cpi;
6844 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
6845 KERNINGPAIR *kern_pairW;
6847 if (!cPairs && kern_pairA)
6849 SetLastError(ERROR_INVALID_PARAMETER);
6850 return 0;
6853 cp = GdiGetCodePage(hDC);
6855 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
6856 * to fail on an invalid character for CP_SYMBOL.
6858 cpi.DefaultChar[0] = 0;
6859 if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
6861 FIXME("Can't find codepage %u info\n", cp);
6862 return 0;
6865 total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
6866 if (!total_kern_pairs) return 0;
6868 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
6869 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
6871 for (i = 0; i < total_kern_pairs; i++)
6873 char first, second;
6875 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
6876 continue;
6878 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
6879 continue;
6881 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
6882 continue;
6884 if (kern_pairA)
6886 if (kern_pairs_copied >= cPairs) break;
6888 kern_pairA->wFirst = (BYTE)first;
6889 kern_pairA->wSecond = (BYTE)second;
6890 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
6891 kern_pairA++;
6893 kern_pairs_copied++;
6896 HeapFree(GetProcessHeap(), 0, kern_pairW);
6898 return kern_pairs_copied;
6901 /*************************************************************************
6902 * GetKerningPairsW (GDI32.@)
6904 DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
6905 LPKERNINGPAIR lpKerningPairs )
6907 DC *dc;
6908 DWORD ret;
6909 PHYSDEV dev;
6911 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
6913 if (!cPairs && lpKerningPairs)
6915 SetLastError(ERROR_INVALID_PARAMETER);
6916 return 0;
6919 dc = get_dc_ptr(hDC);
6920 if (!dc) return 0;
6922 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
6923 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
6924 release_dc_ptr( dc );
6925 return ret;
6928 /*************************************************************************
6929 * TranslateCharsetInfo [GDI32.@]
6931 * Fills a CHARSETINFO structure for a character set, code page, or
6932 * font. This allows making the correspondence between different labels
6933 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
6934 * of the same encoding.
6936 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
6937 * only one codepage should be set in *lpSrc.
6939 * RETURNS
6940 * TRUE on success, FALSE on failure.
6943 BOOL WINAPI TranslateCharsetInfo(
6944 LPDWORD lpSrc, /* [in]
6945 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
6946 if flags == TCI_SRCCHARSET: a character set value
6947 if flags == TCI_SRCCODEPAGE: a code page value
6949 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
6950 DWORD flags /* [in] determines interpretation of lpSrc */)
6952 int index = 0;
6953 switch (flags) {
6954 case TCI_SRCFONTSIG:
6955 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
6956 break;
6957 case TCI_SRCCODEPAGE:
6958 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
6959 break;
6960 case TCI_SRCCHARSET:
6961 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
6962 break;
6963 default:
6964 return FALSE;
6966 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
6967 *lpCs = FONT_tci[index];
6968 return TRUE;
6971 /*************************************************************************
6972 * GetFontLanguageInfo (GDI32.@)
6974 DWORD WINAPI GetFontLanguageInfo(HDC hdc)
6976 FONTSIGNATURE fontsig;
6977 static const DWORD GCP_DBCS_MASK=FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB,
6978 GCP_DIACRITIC_MASK=0x00000000,
6979 FLI_GLYPHS_MASK=0x00000000,
6980 GCP_GLYPHSHAPE_MASK=FS_ARABIC,
6981 GCP_KASHIDA_MASK=0x00000000,
6982 GCP_LIGATE_MASK=0x00000000,
6983 GCP_REORDER_MASK=FS_HEBREW|FS_ARABIC;
6985 DWORD result=0;
6987 GetTextCharsetInfo( hdc, &fontsig, 0 );
6988 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
6990 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
6991 result|=GCP_DBCS;
6993 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
6994 result|=GCP_DIACRITIC;
6996 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
6997 result|=FLI_GLYPHS;
6999 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
7000 result|=GCP_GLYPHSHAPE;
7002 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
7003 result|=GCP_KASHIDA;
7005 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
7006 result|=GCP_LIGATE;
7008 if( GetKerningPairsW( hdc, 0, NULL ) )
7009 result|=GCP_USEKERNING;
7011 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
7012 if( GetTextAlign( hdc) & TA_RTLREADING )
7013 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
7014 result|=GCP_REORDER;
7016 return result;
7020 /*************************************************************************
7021 * GetFontData [GDI32.@]
7023 * Retrieve data for TrueType font.
7025 * RETURNS
7027 * success: Number of bytes returned
7028 * failure: GDI_ERROR
7030 * NOTES
7032 * Calls SetLastError()
7035 DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
7036 LPVOID buffer, DWORD length)
7038 DC *dc = get_dc_ptr(hdc);
7039 PHYSDEV dev;
7040 DWORD ret;
7042 if(!dc) return GDI_ERROR;
7044 dev = GET_DC_PHYSDEV( dc, pGetFontData );
7045 ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
7046 release_dc_ptr( dc );
7047 return ret;
7050 /*************************************************************************
7051 * GetGlyphIndicesA [GDI32.@]
7053 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
7054 LPWORD pgi, DWORD flags)
7056 DWORD ret;
7057 WCHAR *lpstrW;
7058 INT countW;
7060 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7061 hdc, debugstr_an(lpstr, count), count, pgi, flags);
7063 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
7064 ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
7065 HeapFree(GetProcessHeap(), 0, lpstrW);
7067 return ret;
7070 /*************************************************************************
7071 * GetGlyphIndicesW [GDI32.@]
7073 DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count,
7074 LPWORD pgi, DWORD flags)
7076 DC *dc = get_dc_ptr(hdc);
7077 PHYSDEV dev;
7078 DWORD ret;
7080 TRACE("(%p, %s, %d, %p, 0x%x)\n",
7081 hdc, debugstr_wn(lpstr, count), count, pgi, flags);
7083 if(!dc) return GDI_ERROR;
7085 dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
7086 ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
7087 release_dc_ptr( dc );
7088 return ret;
7091 /*************************************************************************
7092 * GetCharacterPlacementA [GDI32.@]
7094 * See GetCharacterPlacementW.
7096 * NOTES:
7097 * the web browser control of ie4 calls this with dwFlags=0
7099 DWORD WINAPI
7100 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
7101 INT nMaxExtent, GCP_RESULTSA *lpResults,
7102 DWORD dwFlags)
7104 WCHAR *lpStringW;
7105 INT uCountW;
7106 GCP_RESULTSW resultsW;
7107 DWORD ret;
7108 UINT font_cp;
7110 TRACE("%s, %d, %d, 0x%08x\n",
7111 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
7113 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
7115 if (!lpResults)
7117 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, NULL, dwFlags);
7118 HeapFree(GetProcessHeap(), 0, lpStringW);
7119 return ret;
7122 /* both structs are equal in size */
7123 memcpy(&resultsW, lpResults, sizeof(resultsW));
7125 if(lpResults->lpOutString)
7126 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
7128 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
7130 lpResults->nGlyphs = resultsW.nGlyphs;
7131 lpResults->nMaxFit = resultsW.nMaxFit;
7133 if(lpResults->lpOutString) {
7134 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
7135 lpResults->lpOutString, uCount, NULL, NULL );
7138 HeapFree(GetProcessHeap(), 0, lpStringW);
7139 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
7141 return ret;
7144 static int kern_pair(const KERNINGPAIR *kern, int count, WCHAR c1, WCHAR c2)
7146 int i;
7148 for (i = 0; i < count; i++)
7150 if (kern[i].wFirst == c1 && kern[i].wSecond == c2)
7151 return kern[i].iKernAmount;
7154 return 0;
7157 static int *kern_string(HDC hdc, const WCHAR *str, int len, int *kern_total)
7159 int i, count;
7160 KERNINGPAIR *kern = NULL;
7161 int *ret;
7163 *kern_total = 0;
7165 ret = heap_alloc(len * sizeof(*ret));
7166 if (!ret) return NULL;
7168 count = GetKerningPairsW(hdc, 0, NULL);
7169 if (count)
7171 kern = heap_alloc(count * sizeof(*kern));
7172 if (!kern)
7174 heap_free(ret);
7175 return NULL;
7178 GetKerningPairsW(hdc, count, kern);
7181 for (i = 0; i < len - 1; i++)
7183 ret[i] = kern_pair(kern, count, str[i], str[i + 1]);
7184 *kern_total += ret[i];
7187 ret[len - 1] = 0; /* no kerning for last element */
7189 heap_free(kern);
7190 return ret;
7193 /*************************************************************************
7194 * GetCharacterPlacementW [GDI32.@]
7196 * Retrieve information about a string. This includes the width, reordering,
7197 * Glyphing and so on.
7199 * RETURNS
7201 * The width and height of the string if successful, 0 if failed.
7203 * BUGS
7205 * All flags except GCP_REORDER are not yet implemented.
7206 * Reordering is not 100% compliant to the Windows BiDi method.
7207 * Caret positioning is not yet implemented for BiDi.
7208 * Classes are not yet implemented.
7211 DWORD WINAPI
7212 GetCharacterPlacementW(
7213 HDC hdc, /* [in] Device context for which the rendering is to be done */
7214 LPCWSTR lpString, /* [in] The string for which information is to be returned */
7215 INT uCount, /* [in] Number of WORDS in string. */
7216 INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */
7217 GCP_RESULTSW *lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */
7218 DWORD dwFlags /* [in] Flags specifying how to process the string */
7221 DWORD ret=0;
7222 SIZE size;
7223 UINT i, nSet;
7224 int *kern = NULL, kern_total = 0;
7226 TRACE("%s, %d, %d, 0x%08x\n",
7227 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
7229 if (!uCount)
7230 return 0;
7232 if (!lpResults)
7233 return GetTextExtentPoint32W(hdc, lpString, uCount, &size) ? MAKELONG(size.cx, size.cy) : 0;
7235 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
7236 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
7237 lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
7238 lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
7239 lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
7241 if (dwFlags & ~(GCP_REORDER | GCP_USEKERNING))
7242 FIXME("flags 0x%08x ignored\n", dwFlags);
7243 if (lpResults->lpClass)
7244 FIXME("classes not implemented\n");
7245 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
7246 FIXME("Caret positions for complex scripts not implemented\n");
7248 nSet = (UINT)uCount;
7249 if (nSet > lpResults->nGlyphs)
7250 nSet = lpResults->nGlyphs;
7252 /* return number of initialized fields */
7253 lpResults->nGlyphs = nSet;
7255 if (!(dwFlags & GCP_REORDER))
7257 /* Treat the case where no special handling was requested in a fastpath way */
7258 /* copy will do if the GCP_REORDER flag is not set */
7259 if (lpResults->lpOutString)
7260 memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
7262 if (lpResults->lpOrder)
7264 for (i = 0; i < nSet; i++)
7265 lpResults->lpOrder[i] = i;
7268 else
7270 BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
7271 nSet, lpResults->lpOrder, NULL, NULL );
7274 if (dwFlags & GCP_USEKERNING)
7276 kern = kern_string(hdc, lpString, nSet, &kern_total);
7277 if (!kern)
7279 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
7280 return 0;
7284 /* FIXME: Will use the placement chars */
7285 if (lpResults->lpDx)
7287 int c;
7288 for (i = 0; i < nSet; i++)
7290 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
7292 lpResults->lpDx[i] = c;
7293 if (dwFlags & GCP_USEKERNING)
7294 lpResults->lpDx[i] += kern[i];
7299 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
7301 int pos = 0;
7303 lpResults->lpCaretPos[0] = 0;
7304 for (i = 0; i < nSet - 1; i++)
7306 if (dwFlags & GCP_USEKERNING)
7307 pos += kern[i];
7309 if (GetTextExtentPoint32W(hdc, &lpString[i], 1, &size))
7310 lpResults->lpCaretPos[i + 1] = (pos += size.cx);
7314 if (lpResults->lpGlyphs)
7315 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
7317 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
7318 ret = MAKELONG(size.cx + kern_total, size.cy);
7320 heap_free(kern);
7322 return ret;
7325 /*************************************************************************
7326 * GetCharABCWidthsFloatA [GDI32.@]
7328 * See GetCharABCWidthsFloatW.
7330 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
7332 INT i, wlen;
7333 LPSTR str;
7334 LPWSTR wstr;
7335 BOOL ret = TRUE;
7337 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
7338 if (str == NULL)
7339 return FALSE;
7341 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
7343 for (i = 0; i < wlen; i++)
7345 if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
7347 ret = FALSE;
7348 break;
7350 abcf++;
7353 HeapFree( GetProcessHeap(), 0, str );
7354 HeapFree( GetProcessHeap(), 0, wstr );
7356 return ret;
7359 /*************************************************************************
7360 * GetCharABCWidthsFloatW [GDI32.@]
7362 * Retrieves widths of a range of characters.
7364 * PARAMS
7365 * hdc [I] Handle to device context.
7366 * first [I] First character in range to query.
7367 * last [I] Last character in range to query.
7368 * abcf [O] Array of LPABCFLOAT structures.
7370 * RETURNS
7371 * Success: TRUE
7372 * Failure: FALSE
7374 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
7376 UINT i;
7377 ABC *abc;
7378 PHYSDEV dev;
7379 BOOL ret = FALSE;
7380 DC *dc = get_dc_ptr( hdc );
7382 TRACE("%p, %d, %d, %p\n", hdc, first, last, abcf);
7384 if (!dc) return FALSE;
7386 if (!abcf) goto done;
7387 if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
7389 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
7390 ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
7391 if (ret)
7393 /* convert device units to logical */
7394 FLOAT scale = fabs( dc->xformVport2World.eM11 );
7395 for (i = first; i <= last; i++, abcf++)
7397 abcf->abcfA = abc[i - first].abcA * scale;
7398 abcf->abcfB = abc[i - first].abcB * scale;
7399 abcf->abcfC = abc[i - first].abcC * scale;
7402 HeapFree( GetProcessHeap(), 0, abc );
7404 done:
7405 release_dc_ptr( dc );
7406 return ret;
7409 /*************************************************************************
7410 * GetCharWidthFloatA [GDI32.@]
7412 BOOL WINAPI GetCharWidthFloatA( HDC hdc, UINT first, UINT last, float *buffer )
7414 WCHAR *wstr;
7415 int i, wlen;
7416 char *str;
7418 if (!(str = FONT_GetCharsByRangeA( hdc, first, last, &i )))
7419 return FALSE;
7420 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
7421 heap_free(str);
7423 for (i = 0; i < wlen; ++i)
7425 if (!GetCharWidthFloatW( hdc, wstr[i], wstr[i], &buffer[i] ))
7427 heap_free(wstr);
7428 return FALSE;
7431 heap_free(wstr);
7432 return TRUE;
7435 /*************************************************************************
7436 * GetCharWidthFloatW [GDI32.@]
7438 BOOL WINAPI GetCharWidthFloatW( HDC hdc, UINT first, UINT last, float *buffer )
7440 DC *dc = get_dc_ptr( hdc );
7441 int *ibuffer;
7442 PHYSDEV dev;
7443 BOOL ret;
7444 UINT i;
7446 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc, first, last, buffer);
7448 if (!dc) return FALSE;
7450 if (!(ibuffer = heap_alloc( (last - first + 1) * sizeof(int) )))
7452 release_dc_ptr( dc );
7453 return FALSE;
7456 dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
7457 if ((ret = dev->funcs->pGetCharWidth( dev, first, last, ibuffer )))
7459 float scale = fabs( dc->xformVport2World.eM11 ) / 16.0f;
7460 for (i = first; i <= last; ++i)
7461 buffer[i - first] = ibuffer[i - first] * scale;
7464 heap_free(ibuffer);
7465 return ret;
7468 /***********************************************************************
7470 * Font Resource API *
7472 ***********************************************************************/
7474 /***********************************************************************
7475 * AddFontResourceA (GDI32.@)
7477 INT WINAPI AddFontResourceA( LPCSTR str )
7479 return AddFontResourceExA( str, 0, NULL);
7482 /***********************************************************************
7483 * AddFontResourceW (GDI32.@)
7485 INT WINAPI AddFontResourceW( LPCWSTR str )
7487 return AddFontResourceExW(str, 0, NULL);
7491 /***********************************************************************
7492 * AddFontResourceExA (GDI32.@)
7494 INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
7496 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
7497 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7498 INT ret;
7500 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
7501 ret = AddFontResourceExW(strW, fl, pdv);
7502 HeapFree(GetProcessHeap(), 0, strW);
7503 return ret;
7506 static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
7508 HRSRC rsrc = FindResourceW(hModule, name, type);
7509 HGLOBAL hMem = LoadResource(hModule, rsrc);
7510 LPVOID *pMem = LockResource(hMem);
7511 int *num_total = (int *)lParam;
7512 DWORD num_in_res;
7514 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
7515 if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
7517 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
7518 return FALSE;
7521 *num_total += num_in_res;
7522 return TRUE;
7525 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
7527 HANDLE file, mapping;
7528 void *ptr;
7530 file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
7531 if (file == INVALID_HANDLE_VALUE) return NULL;
7533 if (!GetFileSizeEx( file, size ) || size->u.HighPart)
7535 CloseHandle( file );
7536 return NULL;
7539 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
7540 CloseHandle( file );
7541 if (!mapping) return NULL;
7543 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
7544 CloseHandle( mapping );
7546 return ptr;
7549 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
7551 WORD align, type_id, count;
7552 DWORD res_off;
7554 if (size < rsrc_off + 10) return NULL;
7555 align = *(WORD *)(ptr + rsrc_off);
7556 rsrc_off += 2;
7557 type_id = *(WORD *)(ptr + rsrc_off);
7558 while (type_id && type_id != type)
7560 count = *(WORD *)(ptr + rsrc_off + 2);
7561 rsrc_off += 8 + count * 12;
7562 if (size < rsrc_off + 8) return NULL;
7563 type_id = *(WORD *)(ptr + rsrc_off);
7565 if (!type_id) return NULL;
7566 count = *(WORD *)(ptr + rsrc_off + 2);
7567 if (size < rsrc_off + 8 + count * 12) return NULL;
7568 res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
7569 *len = *(WORD *)(ptr + rsrc_off + 10) << align;
7570 if (size < res_off + *len) return NULL;
7571 return ptr + res_off;
7574 static WCHAR *get_scalable_filename( const WCHAR *res, BOOL *hidden )
7576 LARGE_INTEGER size;
7577 BYTE *ptr = map_file( res, &size );
7578 const IMAGE_DOS_HEADER *dos;
7579 const IMAGE_OS2_HEADER *ne;
7580 WORD *fontdir;
7581 char *data;
7582 WCHAR *name = NULL;
7583 DWORD len;
7585 if (!ptr) return NULL;
7587 if (size.u.LowPart < sizeof( *dos )) goto fail;
7588 dos = (const IMAGE_DOS_HEADER *)ptr;
7589 if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
7590 if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
7591 ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
7593 fontdir = find_resource( ptr, 0x8007, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
7594 if (!fontdir) goto fail;
7595 *hidden = (fontdir[35] & 0x80) != 0; /* fontdir->dfType */
7597 data = find_resource( ptr, 0x80cc, dos->e_lfanew + ne->ne_rsrctab, size.u.LowPart, &len );
7598 if (!data) goto fail;
7599 if (!memchr( data, 0, len )) goto fail;
7601 len = MultiByteToWideChar( CP_ACP, 0, data, -1, NULL, 0 );
7602 name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
7603 if (name) MultiByteToWideChar( CP_ACP, 0, data, -1, name, len );
7605 fail:
7606 UnmapViewOfFile( ptr );
7607 return name;
7610 static int add_system_font_resource( const WCHAR *file, DWORD flags )
7612 WCHAR path[MAX_PATH];
7613 int ret;
7615 /* try in %WINDIR%/fonts, needed for Fotobuch Designer */
7616 get_fonts_win_dir_path( file, path );
7617 EnterCriticalSection( &font_cs );
7618 ret = font_funcs->add_font( path, flags );
7619 LeaveCriticalSection( &font_cs );
7620 /* try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
7621 if (!ret)
7623 get_fonts_data_dir_path( file, path );
7624 EnterCriticalSection( &font_cs );
7625 ret = font_funcs->add_font( path, flags );
7626 LeaveCriticalSection( &font_cs );
7628 return ret;
7631 static BOOL remove_system_font_resource( LPCWSTR file, DWORD flags )
7633 WCHAR path[MAX_PATH];
7634 int ret;
7636 get_fonts_win_dir_path( file, path );
7637 if (!(ret = remove_font( path, flags )))
7639 get_fonts_data_dir_path( file, path );
7640 ret = remove_font( path, flags );
7642 return ret;
7645 static int add_font_resource( LPCWSTR file, DWORD flags )
7647 WCHAR path[MAX_PATH];
7648 int ret = 0;
7650 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
7652 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
7654 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
7655 EnterCriticalSection( &font_cs );
7656 ret = font_funcs->add_font( path, addfont_flags );
7657 LeaveCriticalSection( &font_cs );
7660 if (!ret && !wcschr( file, '\\' ))
7661 ret = add_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
7663 return ret;
7666 static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
7668 WCHAR path[MAX_PATH];
7669 BOOL ret = FALSE;
7671 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
7673 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
7675 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
7676 ret = remove_font( path, addfont_flags );
7679 if (!ret && !wcschr( file, '\\' ))
7680 ret = remove_system_font_resource( file, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
7682 return ret;
7685 static void load_system_bitmap_fonts(void)
7687 static const WCHAR * const fonts[] = { L"FONTS.FON", L"OEMFONT.FON", L"FIXEDFON.FON" };
7688 HKEY hkey;
7689 WCHAR data[MAX_PATH];
7690 DWORD i, dlen, type;
7692 if (RegOpenKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &hkey )) return;
7693 for (i = 0; i < ARRAY_SIZE(fonts); i++)
7695 dlen = sizeof(data);
7696 if (!RegQueryValueExW( hkey, fonts[i], 0, &type, (BYTE *)data, &dlen ) && type == REG_SZ)
7697 add_system_font_resource( data, ADDFONT_ALLOW_BITMAP );
7699 RegCloseKey( hkey );
7702 static void load_directory_fonts( WCHAR *path, UINT flags )
7704 HANDLE handle;
7705 WIN32_FIND_DATAW data;
7706 WCHAR *p;
7708 p = path + lstrlenW(path) - 1;
7709 TRACE( "loading fonts from %s\n", debugstr_w(path) );
7710 handle = FindFirstFileW( path, &data );
7711 if (handle == INVALID_HANDLE_VALUE) return;
7714 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
7715 lstrcpyW( p, data.cFileName );
7716 font_funcs->add_font( path, flags );
7717 } while (FindNextFileW( handle, &data ));
7718 FindClose( handle );
7721 static void load_file_system_fonts(void)
7723 WCHAR *ptr, *next, path[MAX_PATH], value[1024];
7724 DWORD len = ARRAY_SIZE(value);
7726 /* Windows directory */
7727 get_fonts_win_dir_path( L"*", path );
7728 load_directory_fonts( path, 0 );
7730 /* Wine data directory */
7731 get_fonts_data_dir_path( L"*", path );
7732 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
7734 /* custom paths */
7735 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
7736 if (!RegQueryValueExW( wine_fonts_key, L"Path", NULL, NULL, (BYTE *)value, &len ))
7738 for (ptr = value; ptr; ptr = next)
7740 if ((next = wcschr( ptr, ';' ))) *next++ = 0;
7741 if (next && next - ptr < 2) continue;
7742 lstrcpynW( path, ptr, MAX_PATH - 2 );
7743 lstrcatW( path, L"\\*" );
7744 load_directory_fonts( path, ADDFONT_EXTERNAL_FONT );
7749 struct external_key
7751 struct list entry;
7752 WCHAR value[LF_FULLFACESIZE + 12];
7755 static void update_external_font_keys(void)
7757 struct list external_keys = LIST_INIT(external_keys);
7758 HKEY winnt_key = 0, win9x_key = 0;
7759 struct gdi_font_family *family;
7760 struct external_key *key, *next;
7761 struct gdi_font_face *face;
7762 DWORD len, i = 0, type, dlen, vlen;
7763 WCHAR value[LF_FULLFACESIZE + 12], path[MAX_PATH], *tmp;
7764 WCHAR *file;
7765 HKEY hkey;
7767 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
7768 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL );
7769 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
7770 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL );
7772 /* enumerate the fonts and add external ones to the two keys */
7774 if (RegCreateKeyW( wine_fonts_key, L"External Fonts", &hkey )) return;
7776 vlen = ARRAY_SIZE(value);
7777 dlen = sizeof(path);
7778 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)path, &dlen ))
7780 if (type != REG_SZ) goto next;
7781 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, L" (TrueType)", -1 )) *tmp = 0;
7782 if ((face = find_face_from_full_name( value )) && !wcsicmp( face->file, path ))
7784 face->flags |= ADDFONT_EXTERNAL_FOUND;
7785 goto next;
7787 if (tmp && !*tmp) *tmp = ' ';
7788 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) ))) break;
7789 lstrcpyW( key->value, value );
7790 list_add_tail( &external_keys, &key->entry );
7791 next:
7792 vlen = ARRAY_SIZE(value);
7793 dlen = sizeof(path);
7796 WINE_RB_FOR_EACH_ENTRY( family, &family_name_tree, struct gdi_font_family, name_entry )
7798 LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
7800 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
7801 if ((face->flags & ADDFONT_EXTERNAL_FOUND)) continue;
7803 lstrcpyW( value, face->full_name );
7804 if (face->scalable) lstrcatW( value, L" (TrueType)" );
7806 if (GetFullPathNameW( face->file, MAX_PATH, path, NULL ))
7807 file = path;
7808 else if ((file = wcsrchr( face->file, '\\' )))
7809 file++;
7810 else
7811 file = face->file;
7813 len = (lstrlenW(file) + 1) * sizeof(WCHAR);
7814 RegSetValueExW( winnt_key, value, 0, REG_SZ, (BYTE *)file, len );
7815 RegSetValueExW( win9x_key, value, 0, REG_SZ, (BYTE *)file, len );
7816 RegSetValueExW( hkey, value, 0, REG_SZ, (BYTE *)file, len );
7819 LIST_FOR_EACH_ENTRY_SAFE( key, next, &external_keys, struct external_key, entry )
7821 RegDeleteValueW( win9x_key, key->value );
7822 RegDeleteValueW( winnt_key, key->value );
7823 RegDeleteValueW( hkey, key->value );
7824 list_remove( &key->entry );
7825 HeapFree( GetProcessHeap(), 0, key );
7827 RegCloseKey( win9x_key );
7828 RegCloseKey( winnt_key );
7829 RegCloseKey( hkey );
7832 static void load_registry_fonts(void)
7834 WCHAR value[LF_FULLFACESIZE + 12], data[MAX_PATH], *tmp;
7835 DWORD i = 0, type, dlen, vlen;
7836 HKEY hkey;
7838 /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
7839 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
7840 full path as the entry. Also look for any .fon fonts, since ReadFontDir
7841 will skip these. */
7842 if (RegOpenKeyW( HKEY_LOCAL_MACHINE,
7843 is_win9x() ? L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts" :
7844 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey ))
7845 return;
7847 vlen = ARRAY_SIZE(value);
7848 dlen = sizeof(data);
7849 while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, NULL, NULL ))
7851 if (type != REG_SZ) goto next;
7852 dlen /= sizeof(WCHAR);
7853 if ((tmp = wcsrchr( value, ' ' )) && !facename_compare( tmp, L" (TrueType)", -1 )) *tmp = 0;
7854 if (find_face_from_full_name( value )) goto next;
7855 if (tmp && !*tmp) *tmp = ' ';
7857 if (RegQueryValueExW( hkey, value, NULL, NULL, (LPBYTE)data, &dlen ))
7859 WARN( "Unable to get face path %s\n", debugstr_w(value) );
7860 goto next;
7863 dlen /= sizeof(WCHAR);
7864 if (data[0] && data[1] == ':')
7865 add_font_resource( data, ADDFONT_ALLOW_BITMAP );
7866 else if (dlen >= 6 && !wcsicmp( data + dlen - 5, L".fon" ))
7867 add_system_font_resource( data, ADDFONT_ALLOW_BITMAP );
7868 next:
7869 vlen = ARRAY_SIZE(value);
7870 dlen = sizeof(data);
7872 RegCloseKey( hkey );
7875 static const struct font_callback_funcs callback_funcs = { add_gdi_face };
7877 /***********************************************************************
7878 * font_init
7880 void font_init(void)
7882 HANDLE mutex;
7883 DWORD disposition;
7885 if (RegCreateKeyExW( HKEY_CURRENT_USER, L"Software\\Wine\\Fonts", 0, NULL, 0,
7886 KEY_ALL_ACCESS, NULL, &wine_fonts_key, NULL ))
7887 return;
7889 init_font_options();
7890 update_codepage();
7891 if (__wine_init_unix_lib( gdi32_module, DLL_PROCESS_ATTACH, &callback_funcs, &font_funcs )) return;
7893 load_system_bitmap_fonts();
7894 load_file_system_fonts();
7895 font_funcs->load_fonts();
7897 if (!(mutex = CreateMutexW( NULL, FALSE, L"__WINE_FONT_MUTEX__" ))) return;
7898 WaitForSingleObject( mutex, INFINITE );
7900 RegCreateKeyExW( wine_fonts_key, L"Cache", 0, NULL, REG_OPTION_VOLATILE,
7901 KEY_ALL_ACCESS, NULL, &wine_fonts_cache_key, &disposition );
7903 if (disposition == REG_CREATED_NEW_KEY)
7905 load_registry_fonts();
7906 update_external_font_keys();
7909 ReleaseMutex( mutex );
7911 if (disposition != REG_CREATED_NEW_KEY)
7913 load_registry_fonts();
7914 load_font_list_from_cache();
7917 reorder_font_list();
7918 load_gdi_font_subst();
7919 load_gdi_font_replacements();
7920 load_system_links();
7921 dump_gdi_font_list();
7922 dump_gdi_font_subst();
7925 /***********************************************************************
7926 * AddFontResourceExW (GDI32.@)
7928 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD flags, PVOID pdv )
7930 int ret;
7931 WCHAR *filename;
7932 BOOL hidden;
7934 if (!font_funcs) return 1;
7935 if (!(ret = add_font_resource( str, flags )))
7937 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
7938 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
7939 if (hModule != NULL)
7941 int num_resources = 0;
7942 LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8); /* we don't want to include winuser.h */
7944 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
7945 wine_dbgstr_w(str));
7946 if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
7947 ret = num_resources;
7948 FreeLibrary(hModule);
7950 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
7952 if (hidden) flags |= FR_PRIVATE | FR_NOT_ENUM;
7953 ret = add_font_resource( filename, flags );
7954 HeapFree( GetProcessHeap(), 0, filename );
7957 return ret;
7960 /***********************************************************************
7961 * RemoveFontResourceA (GDI32.@)
7963 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
7965 return RemoveFontResourceExA(str, 0, 0);
7968 /***********************************************************************
7969 * RemoveFontResourceW (GDI32.@)
7971 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
7973 return RemoveFontResourceExW(str, 0, 0);
7976 /***********************************************************************
7977 * AddFontMemResourceEx (GDI32.@)
7979 HANDLE WINAPI AddFontMemResourceEx( PVOID ptr, DWORD size, PVOID pdv, DWORD *pcFonts )
7981 HANDLE ret;
7982 DWORD num_fonts;
7983 void *copy;
7985 if (!ptr || !size || !pcFonts)
7987 SetLastError(ERROR_INVALID_PARAMETER);
7988 return NULL;
7990 if (!font_funcs) return NULL;
7991 if (!(copy = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
7992 memcpy( copy, ptr, size );
7994 EnterCriticalSection( &font_cs );
7995 num_fonts = font_funcs->add_mem_font( copy, size, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
7996 LeaveCriticalSection( &font_cs );
7998 if (!num_fonts)
8000 HeapFree( GetProcessHeap(), 0, copy );
8001 return NULL;
8004 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
8005 * For now return something unique but quite random
8007 ret = (HANDLE)((INT_PTR)copy ^ 0x87654321);
8009 __TRY
8011 *pcFonts = num_fonts;
8013 __EXCEPT_PAGE_FAULT
8015 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
8016 RemoveFontMemResourceEx( ret );
8017 ret = 0;
8019 __ENDTRY
8020 TRACE( "Returning handle %p\n", ret );
8021 return ret;
8024 /***********************************************************************
8025 * RemoveFontMemResourceEx (GDI32.@)
8027 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
8029 FIXME("(%p) stub\n", fh);
8030 return TRUE;
8033 /***********************************************************************
8034 * RemoveFontResourceExA (GDI32.@)
8036 BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv )
8038 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
8039 LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8040 INT ret;
8042 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
8043 ret = RemoveFontResourceExW(strW, fl, pdv);
8044 HeapFree(GetProcessHeap(), 0, strW);
8045 return ret;
8048 /***********************************************************************
8049 * RemoveFontResourceExW (GDI32.@)
8051 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD flags, PVOID pdv )
8053 int ret;
8054 WCHAR *filename;
8055 BOOL hidden;
8057 if (!font_funcs) return TRUE;
8059 if (!(ret = remove_font_resource( str, flags )))
8061 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
8062 HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
8063 if (hModule != NULL)
8065 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str));
8066 FreeLibrary(hModule);
8068 else if ((filename = get_scalable_filename( str, &hidden )) != NULL)
8070 if (hidden) flags |= FR_PRIVATE | FR_NOT_ENUM;
8071 ret = remove_font_resource( filename, flags );
8072 HeapFree( GetProcessHeap(), 0, filename );
8075 return ret;
8078 /***********************************************************************
8079 * GetFontResourceInfoW (GDI32.@)
8081 BOOL WINAPI GetFontResourceInfoW( LPCWSTR str, LPDWORD size, PVOID buffer, DWORD type )
8083 FIXME("%s %p(%d) %p %d\n", debugstr_w(str), size, size ? *size : 0, buffer, type);
8084 return FALSE;
8087 /***********************************************************************
8088 * GetTextCharset (GDI32.@)
8090 UINT WINAPI GetTextCharset(HDC hdc)
8092 /* MSDN docs say this is equivalent */
8093 return GetTextCharsetInfo(hdc, NULL, 0);
8096 /***********************************************************************
8097 * GdiGetCharDimensions (GDI32.@)
8099 * Gets the average width of the characters in the English alphabet.
8101 * PARAMS
8102 * hdc [I] Handle to the device context to measure on.
8103 * lptm [O] Pointer to memory to store the text metrics into.
8104 * height [O] On exit, the maximum height of characters in the English alphabet.
8106 * RETURNS
8107 * The average width of characters in the English alphabet.
8109 * NOTES
8110 * This function is used by the dialog manager to get the size of a dialog
8111 * unit. It should also be used by other pieces of code that need to know
8112 * the size of a dialog unit in logical units without having access to the
8113 * window handle of the dialog.
8114 * Windows caches the font metrics from this function, but we don't and
8115 * there doesn't appear to be an immediate advantage to do so.
8117 * SEE ALSO
8118 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
8120 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
8122 SIZE sz;
8124 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
8126 if(!GetTextExtentPointW(hdc, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52, &sz))
8127 return 0;
8129 if (height) *height = sz.cy;
8130 return (sz.cx / 26 + 1) / 2;
8133 BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
8135 FIXME("(%d): stub\n", fEnableEUDC);
8136 return FALSE;
8139 /***********************************************************************
8140 * GetCharWidthI (GDI32.@)
8142 * Retrieve widths of characters.
8144 * PARAMS
8145 * hdc [I] Handle to a device context.
8146 * first [I] First glyph in range to query.
8147 * count [I] Number of glyph indices to query.
8148 * glyphs [I] Array of glyphs to query.
8149 * buffer [O] Buffer to receive character widths.
8151 * NOTES
8152 * Only works with TrueType fonts.
8154 * RETURNS
8155 * Success: TRUE
8156 * Failure: FALSE
8158 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
8160 ABC *abc;
8161 unsigned int i;
8163 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
8165 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
8166 return FALSE;
8168 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
8170 HeapFree(GetProcessHeap(), 0, abc);
8171 return FALSE;
8174 for (i = 0; i < count; i++)
8175 buffer[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
8177 HeapFree(GetProcessHeap(), 0, abc);
8178 return TRUE;
8181 /***********************************************************************
8182 * GetFontUnicodeRanges (GDI32.@)
8184 * Retrieve a list of supported Unicode characters in a font.
8186 * PARAMS
8187 * hdc [I] Handle to a device context.
8188 * lpgs [O] GLYPHSET structure specifying supported character ranges.
8190 * RETURNS
8191 * Success: Number of bytes written to the buffer pointed to by lpgs.
8192 * Failure: 0
8195 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
8197 DWORD ret;
8198 PHYSDEV dev;
8199 DC *dc = get_dc_ptr(hdc);
8201 TRACE("(%p, %p)\n", hdc, lpgs);
8203 if (!dc) return 0;
8205 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
8206 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
8207 release_dc_ptr(dc);
8208 return ret;
8212 /*************************************************************
8213 * FontIsLinked (GDI32.@)
8215 BOOL WINAPI FontIsLinked(HDC hdc)
8217 DC *dc = get_dc_ptr(hdc);
8218 PHYSDEV dev;
8219 BOOL ret;
8221 if (!dc) return FALSE;
8222 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
8223 ret = dev->funcs->pFontIsLinked( dev );
8224 release_dc_ptr(dc);
8225 TRACE("returning %d\n", ret);
8226 return ret;
8229 /*************************************************************
8230 * GetFontRealizationInfo (GDI32.@)
8232 BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info)
8234 BOOL is_v0 = info->size == FIELD_OFFSET(struct font_realization_info, file_count);
8235 PHYSDEV dev;
8236 BOOL ret;
8237 DC *dc;
8239 if (info->size != sizeof(*info) && !is_v0)
8240 return FALSE;
8242 dc = get_dc_ptr(hdc);
8243 if (!dc) return FALSE;
8244 dev = GET_DC_PHYSDEV( dc, pGetFontRealizationInfo );
8245 ret = dev->funcs->pGetFontRealizationInfo( dev, info );
8246 release_dc_ptr(dc);
8247 return ret;
8250 /*************************************************************************
8251 * GetRasterizerCaps (GDI32.@)
8253 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8255 lprs->nSize = sizeof(RASTERIZER_STATUS);
8256 lprs->wFlags = font_funcs ? (TT_AVAILABLE | TT_ENABLED) : 0;
8257 lprs->nLanguageID = 0;
8258 return TRUE;
8261 /*************************************************************************
8262 * GetFontFileData (GDI32.@)
8264 BOOL WINAPI GetFontFileData( DWORD instance_id, DWORD file_index, UINT64 offset, void *buff, DWORD buff_size )
8266 struct gdi_font *font;
8267 DWORD tag = 0, size;
8268 BOOL ret = FALSE;
8270 if (!font_funcs) return FALSE;
8271 EnterCriticalSection( &font_cs );
8272 if ((font = get_font_from_handle( instance_id )))
8274 if (font->ttc_item_offset) tag = MS_TTCF_TAG;
8275 size = font_funcs->get_font_data( font, tag, 0, NULL, 0 );
8276 if (size != GDI_ERROR && size >= buff_size && offset <= size - buff_size)
8277 ret = font_funcs->get_font_data( font, tag, offset, buff, buff_size ) != GDI_ERROR;
8278 else
8279 SetLastError( ERROR_INVALID_PARAMETER );
8281 LeaveCriticalSection( &font_cs );
8282 return ret;
8285 /* Undocumented structure filled in by GetFontFileInfo */
8286 struct font_fileinfo
8288 FILETIME writetime;
8289 LARGE_INTEGER size;
8290 WCHAR path[1];
8293 /*************************************************************************
8294 * GetFontFileInfo (GDI32.@)
8296 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD file_index, struct font_fileinfo *info,
8297 SIZE_T size, SIZE_T *needed )
8299 SIZE_T required_size = 0;
8300 struct gdi_font *font;
8301 BOOL ret = FALSE;
8303 EnterCriticalSection( &font_cs );
8305 if ((font = get_font_from_handle( instance_id )))
8307 required_size = sizeof(*info) + lstrlenW( font->file ) * sizeof(WCHAR);
8308 if (required_size <= size)
8310 info->writetime = font->writetime;
8311 info->size.QuadPart = font->data_size;
8312 lstrcpyW( info->path, font->file );
8313 ret = TRUE;
8315 else SetLastError( ERROR_INSUFFICIENT_BUFFER );
8318 LeaveCriticalSection( &font_cs );
8319 if (needed) *needed = required_size;
8320 return ret;
8323 struct realization_info
8325 DWORD flags; /* 1 for bitmap fonts, 3 for scalable fonts */
8326 DWORD cache_num; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
8327 DWORD instance_id; /* identifies a realized font instance */
8330 /*************************************************************
8331 * GdiRealizationInfo (GDI32.@)
8333 * Returns a structure that contains some font information.
8335 BOOL WINAPI GdiRealizationInfo(HDC hdc, struct realization_info *info)
8337 struct font_realization_info ri;
8338 BOOL ret;
8340 ri.size = sizeof(ri);
8341 ret = GetFontRealizationInfo( hdc, &ri );
8342 if (ret)
8344 info->flags = ri.flags;
8345 info->cache_num = ri.cache_num;
8346 info->instance_id = ri.instance_id;
8349 return ret;
8352 /*************************************************************
8353 * GetCharWidthInfo (GDI32.@)
8356 BOOL WINAPI GetCharWidthInfo(HDC hdc, struct char_width_info *info)
8358 PHYSDEV dev;
8359 BOOL ret;
8360 DC *dc;
8362 dc = get_dc_ptr(hdc);
8363 if (!dc) return FALSE;
8364 dev = GET_DC_PHYSDEV( dc, pGetCharWidthInfo );
8365 ret = dev->funcs->pGetCharWidthInfo( dev, info );
8367 if (ret)
8369 info->lsb = width_to_LP( dc, info->lsb );
8370 info->rsb = width_to_LP( dc, info->rsb );
8372 release_dc_ptr(dc);
8373 return ret;