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