ddraw: Avoid LPDIRECT3DEXECUTEBUFFER.
[wine/testsucceed.git] / dlls / gdi32 / freetype.c
blob8b5633066f25fc0c4c79a9f757a51341024a3483
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
206 #endif
208 #undef MAKE_FUNCPTR
210 #ifndef FT_MAKE_TAG
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
214 #endif
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
218 #endif
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #endif
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #endif
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
227 #endif
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
231 #else
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
233 #endif
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
236 typedef struct {
237 FT_Short height;
238 FT_Short width;
239 FT_Pos size;
240 FT_Pos x_ppem;
241 FT_Pos y_ppem;
242 FT_Short internal_leading;
243 } Bitmap_Size;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
248 typedef struct {
249 FT_Short height, width;
250 FT_Pos size, x_ppem, y_ppem;
251 } My_FT_Bitmap_Size;
253 struct enum_data
255 ENUMLOGFONTEXW elf;
256 NEWTEXTMETRICEXW ntm;
257 DWORD type;
260 typedef struct tagFace {
261 struct list entry;
262 WCHAR *StyleName;
263 WCHAR *FullName;
264 WCHAR *file;
265 void *font_data_ptr;
266 DWORD font_data_size;
267 FT_Long face_index;
268 FONTSIGNATURE fs;
269 DWORD ntmFlags;
270 FT_Fixed font_version;
271 BOOL scalable;
272 BOOL vertical;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 DWORD aa_flags;
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
279 } Face;
281 typedef struct tagFamily {
282 struct list entry;
283 WCHAR *FamilyName;
284 WCHAR *EnglishName;
285 struct list faces;
286 struct list *replacement;
287 } Family;
289 typedef struct {
290 GLYPHMETRICS gm;
291 INT adv; /* These three hold to widths of the unrotated chars */
292 INT lsb;
293 INT bbx;
294 BOOL init;
295 } GM;
297 typedef struct {
298 FLOAT eM11, eM12;
299 FLOAT eM21, eM22;
300 } FMAT2;
302 typedef struct {
303 DWORD hash;
304 LOGFONTW lf;
305 FMAT2 matrix;
306 BOOL can_use_bitmap;
307 } FONT_DESC;
309 typedef struct tagHFONTLIST {
310 struct list entry;
311 HFONT hfont;
312 } HFONTLIST;
314 typedef struct {
315 struct list entry;
316 Face *face;
317 GdiFont *font;
318 } CHILD_FONT;
320 struct tagGdiFont {
321 struct list entry;
322 GM **gm;
323 DWORD gmsize;
324 struct list hfontlist;
325 OUTLINETEXTMETRICW *potm;
326 DWORD total_kern_pairs;
327 KERNINGPAIR *kern_pairs;
328 struct list child_fonts;
330 /* the following members can be accessed without locking, they are never modified after creation */
331 FT_Face ft_face;
332 struct font_mapping *mapping;
333 LPWSTR name;
334 int charset;
335 int codepage;
336 BOOL fake_italic;
337 BOOL fake_bold;
338 BYTE underline;
339 BYTE strikeout;
340 INT orientation;
341 FONT_DESC font_desc;
342 LONG aveWidth, ppem;
343 double scale_y;
344 SHORT yMax;
345 SHORT yMin;
346 DWORD ntmFlags;
347 DWORD aa_flags;
348 UINT ntmCellHeight, ntmAvgWidth;
349 FONTSIGNATURE fs;
350 GdiFont *base_font;
351 VOID *GSUB_Table;
352 DWORD cache_num;
355 typedef struct {
356 struct list entry;
357 const WCHAR *font_name;
358 FONTSIGNATURE fs;
359 struct list links;
360 } SYSTEM_LINKS;
362 struct enum_charset_element {
363 DWORD mask;
364 DWORD charset;
365 WCHAR name[LF_FACESIZE];
368 struct enum_charset_list {
369 DWORD total;
370 struct enum_charset_element element[32];
373 #define GM_BLOCK_SIZE 128
374 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
376 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
377 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
378 #define UNUSED_CACHE_SIZE 10
379 static struct list child_font_list = LIST_INIT(child_font_list);
380 static struct list system_links = LIST_INIT(system_links);
382 static struct list font_subst_list = LIST_INIT(font_subst_list);
384 static struct list font_list = LIST_INIT(font_list);
386 struct freetype_physdev
388 struct gdi_physdev dev;
389 GdiFont *font;
392 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
394 return (struct freetype_physdev *)dev;
397 static const struct gdi_dc_funcs freetype_funcs;
399 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
400 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
401 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
403 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
404 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
410 'W','i','n','d','o','w','s',' ','N','T','\\',
411 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
412 'F','o','n','t','s','\0'};
414 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
415 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
416 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
417 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
419 static const WCHAR * const SystemFontValues[] = {
420 System_Value,
421 OEMFont_Value,
422 FixedSys_Value,
423 NULL
426 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
427 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
429 /* Interesting and well-known (frequently-assumed!) font names */
430 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
431 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 };
432 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
433 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
434 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
435 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
436 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
437 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
439 static const WCHAR arial[] = {'A','r','i','a','l',0};
440 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
441 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};
442 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};
443 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
444 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
445 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
446 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
447 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
448 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
450 static const WCHAR *default_serif_list[] =
452 times_new_roman,
453 liberation_serif,
454 bitstream_vera_serif,
455 NULL
458 static const WCHAR *default_fixed_list[] =
460 courier_new,
461 liberation_mono,
462 bitstream_vera_sans_mono,
463 NULL
466 static const WCHAR *default_sans_list[] =
468 arial,
469 liberation_sans,
470 bitstream_vera_sans,
471 NULL
474 typedef struct {
475 WCHAR *name;
476 INT charset;
477 } NameCs;
479 typedef struct tagFontSubst {
480 struct list entry;
481 NameCs from;
482 NameCs to;
483 } FontSubst;
485 /* Registry font cache key and value names */
486 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
487 'F','o','n','t','s',0};
488 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
489 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
490 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
491 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
492 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
493 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
494 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
495 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
496 static const WCHAR face_size_value[] = {'S','i','z','e',0};
497 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
498 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
499 static const WCHAR face_aa_value[] = {'A','n','t','i','a','l','i','a','s','i','n','g',0};
500 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
501 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
502 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
503 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
506 struct font_mapping
508 struct list entry;
509 int refcount;
510 dev_t dev;
511 ino_t ino;
512 void *data;
513 size_t size;
516 static struct list mappings_list = LIST_INIT( mappings_list );
518 static UINT default_aa_flags;
520 static CRITICAL_SECTION freetype_cs;
521 static CRITICAL_SECTION_DEBUG critsect_debug =
523 0, 0, &freetype_cs,
524 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
525 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
527 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
529 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
531 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
532 static BOOL use_default_fallback = FALSE;
534 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
535 static BOOL get_outline_text_metrics(GdiFont *font);
536 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
538 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
539 'W','i','n','d','o','w','s',' ','N','T','\\',
540 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
541 'S','y','s','t','e','m','L','i','n','k',0};
543 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
544 'F','o','n','t','L','i','n','k','\\',
545 'S','y','s','t','e','m','L','i','n','k',0};
547 /****************************************
548 * Notes on .fon files
550 * The fonts System, FixedSys and Terminal are special. There are typically multiple
551 * versions installed for different resolutions and codepages. Windows stores which one to use
552 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
553 * Key Meaning
554 * FIXEDFON.FON FixedSys
555 * FONTS.FON System
556 * OEMFONT.FON Terminal
557 * LogPixels Current dpi set by the display control panel applet
558 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
559 * also has a LogPixels value that appears to mirror this)
561 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
562 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
563 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
564 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
565 * so that makes sense.
567 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
568 * to be mapped into the registry on Windows 2000 at least).
569 * I have
570 * woafont=app850.fon
571 * ega80woa.fon=ega80850.fon
572 * ega40woa.fon=ega40850.fon
573 * cga80woa.fon=cga80850.fon
574 * cga40woa.fon=cga40850.fon
577 /* These are all structures needed for the GSUB table */
579 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
580 #define TATEGAKI_LOWER_BOUND 0x02F1
582 typedef struct {
583 DWORD version;
584 WORD ScriptList;
585 WORD FeatureList;
586 WORD LookupList;
587 } GSUB_Header;
589 typedef struct {
590 CHAR ScriptTag[4];
591 WORD Script;
592 } GSUB_ScriptRecord;
594 typedef struct {
595 WORD ScriptCount;
596 GSUB_ScriptRecord ScriptRecord[1];
597 } GSUB_ScriptList;
599 typedef struct {
600 CHAR LangSysTag[4];
601 WORD LangSys;
602 } GSUB_LangSysRecord;
604 typedef struct {
605 WORD DefaultLangSys;
606 WORD LangSysCount;
607 GSUB_LangSysRecord LangSysRecord[1];
608 } GSUB_Script;
610 typedef struct {
611 WORD LookupOrder; /* Reserved */
612 WORD ReqFeatureIndex;
613 WORD FeatureCount;
614 WORD FeatureIndex[1];
615 } GSUB_LangSys;
617 typedef struct {
618 CHAR FeatureTag[4];
619 WORD Feature;
620 } GSUB_FeatureRecord;
622 typedef struct {
623 WORD FeatureCount;
624 GSUB_FeatureRecord FeatureRecord[1];
625 } GSUB_FeatureList;
627 typedef struct {
628 WORD FeatureParams; /* Reserved */
629 WORD LookupCount;
630 WORD LookupListIndex[1];
631 } GSUB_Feature;
633 typedef struct {
634 WORD LookupCount;
635 WORD Lookup[1];
636 } GSUB_LookupList;
638 typedef struct {
639 WORD LookupType;
640 WORD LookupFlag;
641 WORD SubTableCount;
642 WORD SubTable[1];
643 } GSUB_LookupTable;
645 typedef struct {
646 WORD CoverageFormat;
647 WORD GlyphCount;
648 WORD GlyphArray[1];
649 } GSUB_CoverageFormat1;
651 typedef struct {
652 WORD Start;
653 WORD End;
654 WORD StartCoverageIndex;
655 } GSUB_RangeRecord;
657 typedef struct {
658 WORD CoverageFormat;
659 WORD RangeCount;
660 GSUB_RangeRecord RangeRecord[1];
661 } GSUB_CoverageFormat2;
663 typedef struct {
664 WORD SubstFormat; /* = 1 */
665 WORD Coverage;
666 WORD DeltaGlyphID;
667 } GSUB_SingleSubstFormat1;
669 typedef struct {
670 WORD SubstFormat; /* = 2 */
671 WORD Coverage;
672 WORD GlyphCount;
673 WORD Substitute[1];
674 }GSUB_SingleSubstFormat2;
676 #ifdef HAVE_CARBON_CARBON_H
677 static char *find_cache_dir(void)
679 FSRef ref;
680 OSErr err;
681 static char cached_path[MAX_PATH];
682 static const char *wine = "/Wine", *fonts = "/Fonts";
684 if(*cached_path) return cached_path;
686 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
687 if(err != noErr)
689 WARN("can't create cached data folder\n");
690 return NULL;
692 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
693 if(err != noErr)
695 WARN("can't create cached data path\n");
696 *cached_path = '\0';
697 return NULL;
699 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
701 ERR("Could not create full path\n");
702 *cached_path = '\0';
703 return NULL;
705 strcat(cached_path, wine);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
710 *cached_path = '\0';
711 return NULL;
713 strcat(cached_path, fonts);
714 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
716 WARN("Couldn't mkdir %s\n", cached_path);
717 *cached_path = '\0';
718 return NULL;
720 return cached_path;
723 /******************************************************************
724 * expand_mac_font
726 * Extracts individual TrueType font files from a Mac suitcase font
727 * and saves them into the user's caches directory (see
728 * find_cache_dir()).
729 * Returns a NULL terminated array of filenames.
731 * We do this because they are apps that try to read ttf files
732 * themselves and they don't like Mac suitcase files.
734 static char **expand_mac_font(const char *path)
736 FSRef ref;
737 SInt16 res_ref;
738 OSStatus s;
739 unsigned int idx;
740 const char *out_dir;
741 const char *filename;
742 int output_len;
743 struct {
744 char **array;
745 unsigned int size, max_size;
746 } ret;
748 TRACE("path %s\n", path);
750 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
751 if(s != noErr)
753 WARN("failed to get ref\n");
754 return NULL;
757 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
758 if(s != noErr)
760 TRACE("no data fork, so trying resource fork\n");
761 res_ref = FSOpenResFile(&ref, fsRdPerm);
762 if(res_ref == -1)
764 TRACE("unable to open resource fork\n");
765 return NULL;
769 ret.size = 0;
770 ret.max_size = 10;
771 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
772 if(!ret.array)
774 CloseResFile(res_ref);
775 return NULL;
778 out_dir = find_cache_dir();
780 filename = strrchr(path, '/');
781 if(!filename) filename = path;
782 else filename++;
784 /* output filename has the form out_dir/filename_%04x.ttf */
785 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
787 UseResFile(res_ref);
788 idx = 1;
789 while(1)
791 FamRec *fam_rec;
792 unsigned short *num_faces_ptr, num_faces, face;
793 AsscEntry *assoc;
794 Handle fond;
795 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
797 fond = Get1IndResource(fond_res, idx);
798 if(!fond) break;
799 TRACE("got fond resource %d\n", idx);
800 HLock(fond);
802 fam_rec = *(FamRec**)fond;
803 num_faces_ptr = (unsigned short *)(fam_rec + 1);
804 num_faces = GET_BE_WORD(*num_faces_ptr);
805 num_faces++;
806 assoc = (AsscEntry*)(num_faces_ptr + 1);
807 TRACE("num faces %04x\n", num_faces);
808 for(face = 0; face < num_faces; face++, assoc++)
810 Handle sfnt;
811 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
812 unsigned short size, font_id;
813 char *output;
815 size = GET_BE_WORD(assoc->fontSize);
816 font_id = GET_BE_WORD(assoc->fontID);
817 if(size != 0)
819 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
820 continue;
823 TRACE("trying to load sfnt id %04x\n", font_id);
824 sfnt = GetResource(sfnt_res, font_id);
825 if(!sfnt)
827 TRACE("can't get sfnt resource %04x\n", font_id);
828 continue;
831 output = HeapAlloc(GetProcessHeap(), 0, output_len);
832 if(output)
834 int fd;
836 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
838 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
839 if(fd != -1 || errno == EEXIST)
841 if(fd != -1)
843 unsigned char *sfnt_data;
845 HLock(sfnt);
846 sfnt_data = *(unsigned char**)sfnt;
847 write(fd, sfnt_data, GetHandleSize(sfnt));
848 HUnlock(sfnt);
849 close(fd);
851 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
853 ret.max_size *= 2;
854 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
856 ret.array[ret.size++] = output;
858 else
860 WARN("unable to create %s\n", output);
861 HeapFree(GetProcessHeap(), 0, output);
864 ReleaseResource(sfnt);
866 HUnlock(fond);
867 ReleaseResource(fond);
868 idx++;
870 CloseResFile(res_ref);
872 return ret.array;
875 #endif /* HAVE_CARBON_CARBON_H */
877 static inline BOOL is_win9x(void)
879 return GetVersion() & 0x80000000;
882 This function builds an FT_Fixed from a double. It fails if the absolute
883 value of the float number is greater than 32768.
885 static inline FT_Fixed FT_FixedFromFloat(double f)
887 return f * 0x10000;
891 This function builds an FT_Fixed from a FIXED. It simply put f.value
892 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
894 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
896 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
899 static BOOL is_hinting_enabled(void)
901 static int enabled = -1;
903 if (enabled == -1)
905 /* Use the >= 2.2.0 function if available */
906 if (pFT_Get_TrueType_Engine_Type)
908 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
909 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
911 #ifdef FT_DRIVER_HAS_HINTER
912 else
914 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
915 FT_Module mod = pFT_Get_Module(library, "truetype");
916 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
918 #endif
919 else enabled = FALSE;
920 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
922 return enabled;
925 static BOOL is_subpixel_rendering_enabled( void )
927 #ifdef HAVE_FREETYPE_FTLCDFIL_H
928 static int enabled = -1;
929 if (enabled == -1)
931 enabled = (pFT_Library_SetLcdFilter &&
932 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
933 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
935 return enabled;
936 #else
937 return FALSE;
938 #endif
942 static const struct list *get_face_list_from_family(const Family *family)
944 if (!list_empty(&family->faces))
945 return &family->faces;
946 else
947 return family->replacement;
950 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
952 Family *family;
953 Face *face;
954 const WCHAR *file;
956 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
958 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
960 const struct list *face_list;
961 if(face_name && strcmpiW(face_name, family->FamilyName))
962 continue;
963 face_list = get_face_list_from_family(family);
964 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
966 if (!face->file)
967 continue;
968 file = strrchrW(face->file, '/');
969 if(!file)
970 file = face->file;
971 else
972 file++;
973 if(!strcmpiW(file, file_name)) return face;
976 return NULL;
979 static Family *find_family_from_name(const WCHAR *name)
981 Family *family;
983 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
985 if(!strcmpiW(family->FamilyName, name))
986 return family;
989 return NULL;
992 static Family *find_family_from_any_name(const WCHAR *name)
994 Family *family;
996 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
998 if(!strcmpiW(family->FamilyName, name))
999 return family;
1000 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1001 return family;
1004 return NULL;
1007 static void DumpSubstList(void)
1009 FontSubst *psub;
1011 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1013 if(psub->from.charset != -1 || psub->to.charset != -1)
1014 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1015 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1016 else
1017 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1018 debugstr_w(psub->to.name));
1020 return;
1023 static LPWSTR strdupW(LPCWSTR p)
1025 LPWSTR ret;
1026 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1027 ret = HeapAlloc(GetProcessHeap(), 0, len);
1028 memcpy(ret, p, len);
1029 return ret;
1032 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1033 INT from_charset)
1035 FontSubst *element;
1037 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1039 if(!strcmpiW(element->from.name, from_name) &&
1040 (element->from.charset == from_charset ||
1041 element->from.charset == -1))
1042 return element;
1045 return NULL;
1048 #define ADD_FONT_SUBST_FORCE 1
1050 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1052 FontSubst *from_exist, *to_exist;
1054 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1056 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1058 list_remove(&from_exist->entry);
1059 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1060 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1061 HeapFree(GetProcessHeap(), 0, from_exist);
1062 from_exist = NULL;
1065 if(!from_exist)
1067 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1069 if(to_exist)
1071 HeapFree(GetProcessHeap(), 0, subst->to.name);
1072 subst->to.name = strdupW(to_exist->to.name);
1075 list_add_tail(subst_list, &subst->entry);
1077 return TRUE;
1080 HeapFree(GetProcessHeap(), 0, subst->from.name);
1081 HeapFree(GetProcessHeap(), 0, subst->to.name);
1082 HeapFree(GetProcessHeap(), 0, subst);
1083 return FALSE;
1086 static WCHAR *towstr(UINT cp, const char *str)
1088 int len;
1089 WCHAR *wstr;
1091 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1092 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1093 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1094 return wstr;
1097 static char *strWtoA(UINT cp, const WCHAR *str)
1099 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1100 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1101 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1102 return ret;
1105 static void split_subst_info(NameCs *nc, LPSTR str)
1107 CHAR *p = strrchr(str, ',');
1109 nc->charset = -1;
1110 if(p && *(p+1)) {
1111 nc->charset = strtol(p+1, NULL, 10);
1112 *p = '\0';
1114 nc->name = towstr(CP_ACP, str);
1117 static void LoadSubstList(void)
1119 FontSubst *psub;
1120 HKEY hkey;
1121 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1122 LPSTR value;
1123 LPVOID data;
1125 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1126 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1127 &hkey) == ERROR_SUCCESS) {
1129 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1130 &valuelen, &datalen, NULL, NULL);
1132 valuelen++; /* returned value doesn't include room for '\0' */
1133 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1134 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1136 dlen = datalen;
1137 vlen = valuelen;
1138 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1139 &dlen) == ERROR_SUCCESS) {
1140 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1142 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1143 split_subst_info(&psub->from, value);
1144 split_subst_info(&psub->to, data);
1146 /* Win 2000 doesn't allow mapping between different charsets
1147 or mapping of DEFAULT_CHARSET */
1148 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1149 psub->to.charset == DEFAULT_CHARSET) {
1150 HeapFree(GetProcessHeap(), 0, psub->to.name);
1151 HeapFree(GetProcessHeap(), 0, psub->from.name);
1152 HeapFree(GetProcessHeap(), 0, psub);
1153 } else {
1154 add_font_subst(&font_subst_list, psub, 0);
1156 /* reset dlen and vlen */
1157 dlen = datalen;
1158 vlen = valuelen;
1160 HeapFree(GetProcessHeap(), 0, data);
1161 HeapFree(GetProcessHeap(), 0, value);
1162 RegCloseKey(hkey);
1167 /*****************************************************************
1168 * get_name_table_entry
1170 * Supply the platform, encoding, language and name ids in req
1171 * and if the name exists the function will fill in the string
1172 * and string_len members. The string is owned by FreeType so
1173 * don't free it. Returns TRUE if the name is found else FALSE.
1175 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1177 FT_SfntName name;
1178 FT_UInt num_names, name_index;
1180 if(FT_IS_SFNT(ft_face))
1182 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1184 for(name_index = 0; name_index < num_names; name_index++)
1186 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1188 if((name.platform_id == req->platform_id) &&
1189 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1190 (name.language_id == req->language_id) &&
1191 (name.name_id == req->name_id))
1193 req->string = name.string;
1194 req->string_len = name.string_len;
1195 return TRUE;
1200 req->string = NULL;
1201 req->string_len = 0;
1202 return FALSE;
1205 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1207 WCHAR *ret = NULL;
1208 FT_SfntName name;
1210 name.platform_id = TT_PLATFORM_MICROSOFT;
1211 name.language_id = language_id;
1212 name.name_id = name_id;
1214 if(get_name_table_entry(ft_face, &name))
1216 FT_UInt i;
1218 /* String is not nul terminated and string_len is a byte length. */
1219 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1220 for(i = 0; i < name.string_len / 2; i++)
1222 WORD *tmp = (WORD *)&name.string[i * 2];
1223 ret[i] = GET_BE_WORD(*tmp);
1225 ret[i] = 0;
1226 TRACE("Got localised name %s\n", debugstr_w(ret));
1229 return ret;
1232 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1234 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1235 if (f1->scalable) return TRUE;
1236 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1237 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1240 static inline void free_face( Face *face )
1242 HeapFree( GetProcessHeap(), 0, face->file );
1243 HeapFree( GetProcessHeap(), 0, face->StyleName );
1244 HeapFree( GetProcessHeap(), 0, face->FullName );
1245 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1246 HeapFree( GetProcessHeap(), 0, face );
1249 static inline void free_family( Family *family )
1251 Face *face, *cursor2;
1253 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1255 list_remove( &face->entry );
1256 free_face( face );
1258 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1259 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1260 HeapFree( GetProcessHeap(), 0, family );
1263 static inline int style_order(const Face *face)
1265 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1267 case NTM_REGULAR:
1268 return 0;
1269 case NTM_BOLD:
1270 return 1;
1271 case NTM_ITALIC:
1272 return 2;
1273 case NTM_BOLD | NTM_ITALIC:
1274 return 3;
1275 default:
1276 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1277 debugstr_w(face->family->FamilyName),
1278 debugstr_w(face->StyleName),
1279 face->ntmFlags);
1280 return 9999;
1284 static BOOL insert_face_in_family_list( Face *face, Family *family )
1286 Face *cursor;
1288 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1290 if (faces_equal( face, cursor ))
1292 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1293 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1294 cursor->font_version, face->font_version);
1296 if (face->font_version <= cursor->font_version)
1298 TRACE("Original font %s is newer so skipping %s\n",
1299 debugstr_w(cursor->file), debugstr_w(face->file));
1300 return FALSE;
1302 else
1304 TRACE("Replacing original %s with %s\n",
1305 debugstr_w(cursor->file), debugstr_w(face->file));
1306 list_add_before( &cursor->entry, &face->entry );
1307 face->family = family;
1308 list_remove( &cursor->entry);
1309 free_face( cursor );
1310 return TRUE;
1313 else
1314 TRACE("Adding new %s\n", debugstr_w(face->file));
1316 if (style_order( face ) < style_order( cursor )) break;
1319 list_add_before( &cursor->entry, &face->entry );
1320 face->family = family;
1321 return TRUE;
1324 /****************************************************************
1325 * NB This function stores the ptrs to the strings to save copying.
1326 * Don't free them after calling.
1328 static Family *create_family( WCHAR *name, WCHAR *english_name )
1330 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1331 family->FamilyName = name;
1332 family->EnglishName = english_name;
1333 list_init( &family->faces );
1334 family->replacement = &family->faces;
1336 return family;
1339 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1341 DWORD type, size = sizeof(DWORD);
1343 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1344 type != REG_DWORD || size != sizeof(DWORD))
1346 *data = 0;
1347 return ERROR_BAD_CONFIGURATION;
1349 return ERROR_SUCCESS;
1352 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1354 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1357 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1359 DWORD needed, strike_index = 0;
1360 HKEY hkey_strike;
1362 /* If we have a File Name key then this is a real font, not just the parent
1363 key of a bunch of non-scalable strikes */
1364 needed = buffer_size;
1365 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1367 Face *face;
1368 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1369 face->cached_enum_data = NULL;
1371 face->file = strdupW( buffer );
1372 face->StyleName = strdupW(face_name);
1374 needed = buffer_size;
1375 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1376 face->FullName = strdupW( buffer );
1377 else
1378 face->FullName = NULL;
1380 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1381 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1382 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1383 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1384 reg_load_dword(hkey_face, face_aa_value, (DWORD*)&face->aa_flags);
1386 needed = sizeof(face->fs);
1387 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1389 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1391 face->scalable = TRUE;
1392 memset(&face->size, 0, sizeof(face->size));
1394 else
1396 face->scalable = FALSE;
1397 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1398 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1399 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1400 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1401 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1403 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1404 face->size.height, face->size.width, face->size.size >> 6,
1405 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1408 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1409 face->fs.fsCsb[0], face->fs.fsCsb[1],
1410 face->fs.fsUsb[0], face->fs.fsUsb[1],
1411 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1413 insert_face_in_family_list(face, family);
1415 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1418 /* load bitmap strikes */
1420 needed = buffer_size;
1421 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1423 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1425 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1426 RegCloseKey(hkey_strike);
1428 needed = buffer_size;
1432 static void load_font_list_from_cache(HKEY hkey_font_cache)
1434 DWORD size, family_index = 0;
1435 Family *family;
1436 HKEY hkey_family;
1437 WCHAR buffer[4096];
1439 size = sizeof(buffer);
1440 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1442 WCHAR *english_family = NULL;
1443 WCHAR *family_name = strdupW( buffer );
1444 DWORD face_index = 0;
1446 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1447 TRACE("opened family key %s\n", debugstr_w(family_name));
1448 size = sizeof(buffer);
1449 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1450 english_family = strdupW( buffer );
1452 family = create_family(family_name, english_family);
1453 list_add_tail(&font_list, &family->entry);
1455 if(english_family)
1457 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1458 subst->from.name = strdupW(english_family);
1459 subst->from.charset = -1;
1460 subst->to.name = strdupW(family_name);
1461 subst->to.charset = -1;
1462 add_font_subst(&font_subst_list, subst, 0);
1465 size = sizeof(buffer);
1466 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1468 WCHAR *face_name = strdupW( buffer );
1469 HKEY hkey_face;
1471 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1473 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1474 RegCloseKey(hkey_face);
1476 HeapFree( GetProcessHeap(), 0, face_name );
1477 size = sizeof(buffer);
1479 RegCloseKey(hkey_family);
1480 size = sizeof(buffer);
1484 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1486 LONG ret;
1487 HKEY hkey_wine_fonts;
1489 /* We don't want to create the fonts key as volatile, so open this first */
1490 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1491 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1492 if(ret != ERROR_SUCCESS)
1494 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1495 return ret;
1498 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1499 KEY_ALL_ACCESS, NULL, hkey, disposition);
1500 RegCloseKey(hkey_wine_fonts);
1501 return ret;
1504 static void add_face_to_cache(Face *face)
1506 HKEY hkey_font_cache, hkey_family, hkey_face;
1507 WCHAR *face_key_name;
1509 create_font_cache_key(&hkey_font_cache, NULL);
1511 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1512 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1513 if(face->family->EnglishName)
1514 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1515 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1517 if(face->scalable)
1518 face_key_name = face->StyleName;
1519 else
1521 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1522 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1523 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1525 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1526 &hkey_face, NULL);
1527 if(!face->scalable)
1528 HeapFree(GetProcessHeap(), 0, face_key_name);
1530 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1531 (strlenW(face->file) + 1) * sizeof(WCHAR));
1532 if (face->FullName)
1533 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1534 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1536 reg_save_dword(hkey_face, face_index_value, face->face_index);
1537 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1538 reg_save_dword(hkey_face, face_version_value, face->font_version);
1539 if (face->vertical) reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1540 if (face->aa_flags) reg_save_dword(hkey_face, face_aa_value, face->aa_flags);
1542 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1544 if(!face->scalable)
1546 reg_save_dword(hkey_face, face_height_value, face->size.height);
1547 reg_save_dword(hkey_face, face_width_value, face->size.width);
1548 reg_save_dword(hkey_face, face_size_value, face->size.size);
1549 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1550 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1551 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1553 RegCloseKey(hkey_face);
1554 RegCloseKey(hkey_family);
1555 RegCloseKey(hkey_font_cache);
1558 static WCHAR *prepend_at(WCHAR *family)
1560 WCHAR *str;
1562 if (!family)
1563 return NULL;
1565 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1566 str[0] = '@';
1567 strcpyW(str + 1, family);
1568 HeapFree(GetProcessHeap(), 0, family);
1569 return str;
1572 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1574 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1575 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1577 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1578 if (!*name)
1580 *name = *english;
1581 *english = NULL;
1583 else if (!strcmpiW( *name, *english ))
1585 HeapFree( GetProcessHeap(), 0, *english );
1586 *english = NULL;
1589 if (vertical)
1591 *name = prepend_at( *name );
1592 *english = prepend_at( *english );
1596 static Family *get_family( FT_Face ft_face, BOOL vertical )
1598 Family *family;
1599 WCHAR *name, *english_name;
1601 get_family_names( ft_face, &name, &english_name, vertical );
1603 family = find_family_from_name( name );
1605 if (!family)
1607 family = create_family( name, english_name );
1608 list_add_tail( &font_list, &family->entry );
1610 if (english_name)
1612 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1613 subst->from.name = strdupW( english_name );
1614 subst->from.charset = -1;
1615 subst->to.name = strdupW( name );
1616 subst->to.charset = -1;
1617 add_font_subst( &font_subst_list, subst, 0 );
1620 else
1622 HeapFree( GetProcessHeap(), 0, name );
1623 HeapFree( GetProcessHeap(), 0, english_name );
1626 return family;
1629 static inline FT_Fixed get_font_version( FT_Face ft_face )
1631 FT_Fixed version = 0;
1632 TT_Header *header;
1634 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1635 if (header) version = header->Font_Revision;
1637 return version;
1640 static inline DWORD get_ntm_flags( FT_Face ft_face )
1642 DWORD flags = 0;
1643 FT_ULong table_size = 0;
1645 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1646 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1647 if (flags == 0) flags = NTM_REGULAR;
1649 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1650 flags |= NTM_PS_OPENTYPE;
1652 return flags;
1655 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1657 int internal_leading = 0;
1658 FT_WinFNT_HeaderRec winfnt_header;
1660 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1661 internal_leading = winfnt_header.internal_leading;
1663 return internal_leading;
1666 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1668 TT_OS2 *os2;
1669 FT_UInt dummy;
1670 CHARSETINFO csi;
1671 FT_WinFNT_HeaderRec winfnt_header;
1672 int i;
1674 memset( fs, 0, sizeof(*fs) );
1676 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1677 if (os2)
1679 fs->fsUsb[0] = os2->ulUnicodeRange1;
1680 fs->fsUsb[1] = os2->ulUnicodeRange2;
1681 fs->fsUsb[2] = os2->ulUnicodeRange3;
1682 fs->fsUsb[3] = os2->ulUnicodeRange4;
1684 if (os2->version == 0)
1686 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1687 fs->fsCsb[0] = FS_LATIN1;
1688 else
1689 fs->fsCsb[0] = FS_SYMBOL;
1691 else
1693 fs->fsCsb[0] = os2->ulCodePageRange1;
1694 fs->fsCsb[1] = os2->ulCodePageRange2;
1697 else
1699 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1701 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1702 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1703 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1704 *fs = csi.fs;
1708 if (fs->fsCsb[0] == 0)
1710 /* let's see if we can find any interesting cmaps */
1711 for (i = 0; i < ft_face->num_charmaps; i++)
1713 switch (ft_face->charmaps[i]->encoding)
1715 case FT_ENCODING_UNICODE:
1716 case FT_ENCODING_APPLE_ROMAN:
1717 fs->fsCsb[0] |= FS_LATIN1;
1718 break;
1719 case FT_ENCODING_MS_SYMBOL:
1720 fs->fsCsb[0] |= FS_SYMBOL;
1721 break;
1722 default:
1723 break;
1729 #define ADDFONT_EXTERNAL_FONT 0x01
1730 #define ADDFONT_FORCE_BITMAP 0x02
1731 #define ADDFONT_ADD_TO_CACHE 0x04
1732 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1734 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1735 DWORD flags, BOOL vertical, DWORD aa_flags )
1737 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1738 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1740 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1741 if (!face->StyleName)
1742 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1743 if (!face->StyleName)
1745 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1748 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1749 if (!face->FullName)
1750 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1751 if (vertical)
1752 face->FullName = prepend_at( face->FullName );
1754 if (file)
1756 face->file = towstr( CP_UNIXCP, file );
1757 face->font_data_ptr = NULL;
1758 face->font_data_size = 0;
1760 else
1762 face->file = NULL;
1763 face->font_data_ptr = font_data_ptr;
1764 face->font_data_size = font_data_size;
1767 face->face_index = face_index;
1768 get_fontsig( ft_face, &face->fs );
1769 face->ntmFlags = get_ntm_flags( ft_face );
1770 face->font_version = get_font_version( ft_face );
1772 if (FT_IS_SCALABLE( ft_face ))
1774 memset( &face->size, 0, sizeof(face->size) );
1775 face->scalable = TRUE;
1777 else
1779 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1780 size->height, size->width, size->size >> 6,
1781 size->x_ppem >> 6, size->y_ppem >> 6);
1782 face->size.height = size->height;
1783 face->size.width = size->width;
1784 face->size.size = size->size;
1785 face->size.x_ppem = size->x_ppem;
1786 face->size.y_ppem = size->y_ppem;
1787 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1788 face->scalable = FALSE;
1791 face->vertical = vertical;
1792 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1793 face->aa_flags = aa_flags;
1794 face->family = NULL;
1795 face->cached_enum_data = NULL;
1797 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1798 face->fs.fsCsb[0], face->fs.fsCsb[1],
1799 face->fs.fsUsb[0], face->fs.fsUsb[1],
1800 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1802 return face;
1805 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1806 FT_Long face_index, DWORD flags, BOOL vertical, DWORD aa_flags )
1808 Face *face;
1809 Family *family;
1811 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical, aa_flags );
1812 family = get_family( ft_face, vertical );
1813 if (!insert_face_in_family_list( face, family ))
1815 free_face( face );
1816 return;
1819 if (flags & ADDFONT_ADD_TO_CACHE)
1820 add_face_to_cache( face );
1822 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1823 debugstr_w(face->StyleName));
1826 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1827 FT_Long face_index, BOOL allow_bitmap )
1829 FT_Error err;
1830 TT_OS2 *pOS2;
1831 FT_Face ft_face;
1833 if (file)
1835 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1836 err = pFT_New_Face(library, file, face_index, &ft_face);
1838 else
1840 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1841 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1844 if (err != 0)
1846 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1847 return NULL;
1850 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1851 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1853 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1854 goto fail;
1857 if (!FT_IS_SFNT( ft_face ))
1859 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1861 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1862 goto fail;
1865 else
1867 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1868 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1869 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1871 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1872 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1873 goto fail;
1876 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1877 we don't want to load these. */
1878 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1880 FT_ULong len = 0;
1882 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1884 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1885 goto fail;
1890 if (!ft_face->family_name || !ft_face->style_name)
1892 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1893 goto fail;
1896 return ft_face;
1897 fail:
1898 pFT_Done_Face( ft_face );
1899 return NULL;
1902 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1904 FT_Face ft_face;
1905 FT_Long face_index = 0, num_faces;
1906 INT ret = 0;
1907 DWORD aa_flags = HIWORD( flags );
1909 if (!aa_flags) aa_flags = default_aa_flags;
1911 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1912 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1914 #ifdef HAVE_CARBON_CARBON_H
1915 if(file)
1917 char **mac_list = expand_mac_font(file);
1918 if(mac_list)
1920 BOOL had_one = FALSE;
1921 char **cursor;
1922 for(cursor = mac_list; *cursor; cursor++)
1924 had_one = TRUE;
1925 AddFontToList(*cursor, NULL, 0, flags);
1926 HeapFree(GetProcessHeap(), 0, *cursor);
1928 HeapFree(GetProcessHeap(), 0, mac_list);
1929 if(had_one)
1930 return 1;
1933 #endif /* HAVE_CARBON_CARBON_H */
1935 do {
1936 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1937 if (!ft_face) return 0;
1939 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1941 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1942 pFT_Done_Face(ft_face);
1943 return 0;
1946 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE, aa_flags);
1947 ++ret;
1949 if (FT_HAS_VERTICAL(ft_face))
1951 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE, aa_flags);
1952 ++ret;
1955 num_faces = ft_face->num_faces;
1956 pFT_Done_Face(ft_face);
1957 } while(num_faces > ++face_index);
1958 return ret;
1961 static void DumpFontList(void)
1963 Family *family;
1964 Face *face;
1965 struct list *family_elem_ptr, *face_elem_ptr;
1967 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1968 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1969 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1970 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1971 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1972 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1973 if(!face->scalable)
1974 TRACE(" %d", face->size.height);
1975 TRACE("\n");
1978 return;
1981 /***********************************************************
1982 * The replacement list is a way to map an entire font
1983 * family onto another family. For example adding
1985 * [HKCU\Software\Wine\Fonts\Replacements]
1986 * "Wingdings"="Winedings"
1988 * would enumerate the Winedings font both as Winedings and
1989 * Wingdings. However if a real Wingdings font is present the
1990 * replacement does not take place.
1993 static void LoadReplaceList(void)
1995 HKEY hkey;
1996 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1997 LPWSTR value;
1998 LPVOID data;
2000 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2001 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2003 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2004 &valuelen, &datalen, NULL, NULL);
2006 valuelen++; /* returned value doesn't include room for '\0' */
2007 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2008 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2010 dlen = datalen;
2011 vlen = valuelen;
2012 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2013 &dlen) == ERROR_SUCCESS) {
2014 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2015 /* "NewName"="Oldname" */
2016 if(!find_family_from_any_name(value))
2018 Family * const family = find_family_from_any_name(data);
2019 if (family != NULL)
2021 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2022 if (new_family != NULL)
2024 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2025 new_family->FamilyName = strdupW(value);
2026 new_family->EnglishName = NULL;
2027 list_init(&new_family->faces);
2028 new_family->replacement = &family->faces;
2029 list_add_tail(&font_list, &new_family->entry);
2032 else
2034 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2037 else
2039 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2041 /* reset dlen and vlen */
2042 dlen = datalen;
2043 vlen = valuelen;
2045 HeapFree(GetProcessHeap(), 0, data);
2046 HeapFree(GetProcessHeap(), 0, value);
2047 RegCloseKey(hkey);
2051 static const WCHAR *font_links_list[] =
2053 Lucida_Sans_Unicode,
2054 Microsoft_Sans_Serif,
2055 Tahoma
2058 static const struct font_links_defaults_list
2060 /* Keyed off substitution for "MS Shell Dlg" */
2061 const WCHAR *shelldlg;
2062 /* Maximum of four substitutes, plus terminating NULL pointer */
2063 const WCHAR *substitutes[5];
2064 } font_links_defaults_list[] =
2066 /* Non East-Asian */
2067 { Tahoma, /* FIXME unverified ordering */
2068 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2070 /* Below lists are courtesy of
2071 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2073 /* Japanese */
2074 { MS_UI_Gothic,
2075 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2077 /* Chinese Simplified */
2078 { SimSun,
2079 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2081 /* Korean */
2082 { Gulim,
2083 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2085 /* Chinese Traditional */
2086 { PMingLiU,
2087 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2092 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2094 SYSTEM_LINKS *font_link;
2096 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2098 if(!strcmpiW(font_link->font_name, name))
2099 return font_link;
2102 return NULL;
2105 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2107 const WCHAR *value;
2108 int i;
2109 FontSubst *psub;
2110 Family *family;
2111 Face *face;
2112 const WCHAR *file;
2114 if (values)
2116 SYSTEM_LINKS *font_link;
2118 psub = get_font_subst(&font_subst_list, name, -1);
2119 /* Don't store fonts that are only substitutes for other fonts */
2120 if(psub)
2122 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2123 return;
2126 font_link = find_font_link(name);
2127 if (font_link == NULL)
2129 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2130 font_link->font_name = strdupW(name);
2131 list_init(&font_link->links);
2132 list_add_tail(&system_links, &font_link->entry);
2135 memset(&font_link->fs, 0, sizeof font_link->fs);
2136 for (i = 0; values[i] != NULL; i++)
2138 const struct list *face_list;
2139 CHILD_FONT *child_font;
2141 value = values[i];
2142 if (!strcmpiW(name,value))
2143 continue;
2144 psub = get_font_subst(&font_subst_list, value, -1);
2145 if(psub)
2146 value = psub->to.name;
2147 family = find_family_from_name(value);
2148 if (!family)
2149 continue;
2150 file = NULL;
2151 /* Use first extant filename for this Family */
2152 face_list = get_face_list_from_family(family);
2153 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2155 if (!face->file)
2156 continue;
2157 file = strrchrW(face->file, '/');
2158 if (!file)
2159 file = face->file;
2160 else
2161 file++;
2162 break;
2164 if (!file)
2165 continue;
2166 face = find_face_from_filename(file, value);
2167 if(!face)
2169 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2170 continue;
2173 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2174 child_font->face = face;
2175 child_font->font = NULL;
2176 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2177 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2178 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2179 child_font->face->face_index);
2180 list_add_tail(&font_link->links, &child_font->entry);
2182 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2188 /*************************************************************
2189 * init_system_links
2191 static BOOL init_system_links(void)
2193 HKEY hkey;
2194 BOOL ret = FALSE;
2195 DWORD type, max_val, max_data, val_len, data_len, index;
2196 WCHAR *value, *data;
2197 WCHAR *entry, *next;
2198 SYSTEM_LINKS *font_link, *system_font_link;
2199 CHILD_FONT *child_font;
2200 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2201 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2202 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2203 Face *face;
2204 FontSubst *psub;
2205 UINT i, j;
2207 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2209 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2210 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2211 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2212 val_len = max_val + 1;
2213 data_len = max_data;
2214 index = 0;
2215 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2217 psub = get_font_subst(&font_subst_list, value, -1);
2218 /* Don't store fonts that are only substitutes for other fonts */
2219 if(psub)
2221 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2222 goto next;
2224 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2225 font_link->font_name = strdupW(value);
2226 memset(&font_link->fs, 0, sizeof font_link->fs);
2227 list_init(&font_link->links);
2228 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2230 WCHAR *face_name;
2231 CHILD_FONT *child_font;
2233 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2235 next = entry + strlenW(entry) + 1;
2237 face_name = strchrW(entry, ',');
2238 if(face_name)
2240 *face_name++ = 0;
2241 while(isspaceW(*face_name))
2242 face_name++;
2244 psub = get_font_subst(&font_subst_list, face_name, -1);
2245 if(psub)
2246 face_name = psub->to.name;
2248 face = find_face_from_filename(entry, face_name);
2249 if(!face)
2251 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2252 continue;
2255 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2256 child_font->face = face;
2257 child_font->font = NULL;
2258 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2259 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2260 TRACE("Adding file %s index %ld\n",
2261 debugstr_w(child_font->face->file), child_font->face->face_index);
2262 list_add_tail(&font_link->links, &child_font->entry);
2264 list_add_tail(&system_links, &font_link->entry);
2265 next:
2266 val_len = max_val + 1;
2267 data_len = max_data;
2270 HeapFree(GetProcessHeap(), 0, value);
2271 HeapFree(GetProcessHeap(), 0, data);
2272 RegCloseKey(hkey);
2276 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2277 if (!psub) {
2278 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2279 goto skip_internal;
2282 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2284 const FontSubst *psub2;
2285 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2287 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2289 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2290 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2292 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2293 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2295 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2297 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2301 skip_internal:
2303 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2304 that Tahoma has */
2306 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2307 system_font_link->font_name = strdupW(System);
2308 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2309 list_init(&system_font_link->links);
2311 face = find_face_from_filename(tahoma_ttf, Tahoma);
2312 if(face)
2314 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2315 child_font->face = face;
2316 child_font->font = NULL;
2317 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2318 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2319 TRACE("Found Tahoma in %s index %ld\n",
2320 debugstr_w(child_font->face->file), child_font->face->face_index);
2321 list_add_tail(&system_font_link->links, &child_font->entry);
2323 font_link = find_font_link(Tahoma);
2324 if (font_link != NULL)
2326 CHILD_FONT *font_link_entry;
2327 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2329 CHILD_FONT *new_child;
2330 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2331 new_child->face = font_link_entry->face;
2332 new_child->font = NULL;
2333 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2334 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2335 list_add_tail(&system_font_link->links, &new_child->entry);
2338 list_add_tail(&system_links, &system_font_link->entry);
2339 return ret;
2342 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2344 DIR *dir;
2345 struct dirent *dent;
2346 char path[MAX_PATH];
2348 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2350 dir = opendir(dirname);
2351 if(!dir) {
2352 WARN("Can't open directory %s\n", debugstr_a(dirname));
2353 return FALSE;
2355 while((dent = readdir(dir)) != NULL) {
2356 struct stat statbuf;
2358 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2359 continue;
2361 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2363 sprintf(path, "%s/%s", dirname, dent->d_name);
2365 if(stat(path, &statbuf) == -1)
2367 WARN("Can't stat %s\n", debugstr_a(path));
2368 continue;
2370 if(S_ISDIR(statbuf.st_mode))
2371 ReadFontDir(path, external_fonts);
2372 else
2374 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2375 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2376 AddFontToList(path, NULL, 0, addfont_flags);
2379 closedir(dir);
2380 return TRUE;
2383 #ifdef SONAME_LIBFONTCONFIG
2385 static BOOL fontconfig_enabled;
2387 static UINT parse_aa_pattern( FcPattern *pattern )
2389 FcBool antialias;
2390 int rgba;
2391 UINT aa_flags = 0;
2393 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2394 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2396 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2398 switch (rgba)
2400 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2401 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2402 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2403 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2404 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2407 return aa_flags;
2410 static void init_fontconfig(void)
2412 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2414 if (!fc_handle)
2416 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2417 return;
2420 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2421 LOAD_FUNCPTR(FcConfigSubstitute);
2422 LOAD_FUNCPTR(FcFontList);
2423 LOAD_FUNCPTR(FcFontSetDestroy);
2424 LOAD_FUNCPTR(FcInit);
2425 LOAD_FUNCPTR(FcObjectSetAdd);
2426 LOAD_FUNCPTR(FcObjectSetCreate);
2427 LOAD_FUNCPTR(FcObjectSetDestroy);
2428 LOAD_FUNCPTR(FcPatternCreate);
2429 LOAD_FUNCPTR(FcPatternDestroy);
2430 LOAD_FUNCPTR(FcPatternGetBool);
2431 LOAD_FUNCPTR(FcPatternGetInteger);
2432 LOAD_FUNCPTR(FcPatternGetString);
2433 #undef LOAD_FUNCPTR
2435 if (pFcInit())
2437 FcPattern *pattern = pFcPatternCreate();
2438 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2439 default_aa_flags = parse_aa_pattern( pattern );
2440 pFcPatternDestroy( pattern );
2441 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2442 fontconfig_enabled = TRUE;
2446 static void load_fontconfig_fonts(void)
2448 FcPattern *pat;
2449 FcObjectSet *os;
2450 FcFontSet *fontset;
2451 int i, len;
2452 char *file;
2453 const char *ext;
2455 if (!fontconfig_enabled) return;
2457 pat = pFcPatternCreate();
2458 os = pFcObjectSetCreate();
2459 pFcObjectSetAdd(os, FC_FILE);
2460 pFcObjectSetAdd(os, FC_SCALABLE);
2461 pFcObjectSetAdd(os, FC_ANTIALIAS);
2462 pFcObjectSetAdd(os, FC_RGBA);
2463 fontset = pFcFontList(NULL, pat, os);
2464 if(!fontset) return;
2465 for(i = 0; i < fontset->nfont; i++) {
2466 FcBool scalable;
2467 DWORD aa_flags;
2469 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2470 continue;
2472 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2474 /* We're just interested in OT/TT fonts for now, so this hack just
2475 picks up the scalable fonts without extensions .pf[ab] to save time
2476 loading every other font */
2478 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2480 TRACE("not scalable\n");
2481 continue;
2484 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2485 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2487 len = strlen( file );
2488 if(len < 4) continue;
2489 ext = &file[ len - 3 ];
2490 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2491 AddFontToList(file, NULL, 0,
2492 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2494 pFcFontSetDestroy(fontset);
2495 pFcObjectSetDestroy(os);
2496 pFcPatternDestroy(pat);
2499 #elif defined(HAVE_CARBON_CARBON_H)
2501 static void load_mac_font_callback(const void *value, void *context)
2503 CFStringRef pathStr = value;
2504 CFIndex len;
2505 char* path;
2507 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2508 path = HeapAlloc(GetProcessHeap(), 0, len);
2509 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2511 TRACE("font file %s\n", path);
2512 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2514 HeapFree(GetProcessHeap(), 0, path);
2517 static void load_mac_fonts(void)
2519 CFStringRef removeDupesKey;
2520 CFBooleanRef removeDupesValue;
2521 CFDictionaryRef options;
2522 CTFontCollectionRef col;
2523 CFArrayRef descs;
2524 CFMutableSetRef paths;
2525 CFIndex i;
2527 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2528 removeDupesValue = kCFBooleanTrue;
2529 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2530 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2531 col = CTFontCollectionCreateFromAvailableFonts(options);
2532 if (options) CFRelease(options);
2533 if (!col)
2535 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2536 return;
2539 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2540 CFRelease(col);
2541 if (!descs)
2543 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2544 return;
2547 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2548 if (!paths)
2550 WARN("CFSetCreateMutable failed\n");
2551 CFRelease(descs);
2552 return;
2555 for (i = 0; i < CFArrayGetCount(descs); i++)
2557 CTFontDescriptorRef desc;
2558 CTFontRef font;
2559 ATSFontRef atsFont;
2560 OSStatus status;
2561 FSRef fsref;
2562 CFURLRef url;
2563 CFStringRef ext;
2564 CFStringRef path;
2566 desc = CFArrayGetValueAtIndex(descs, i);
2568 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2569 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2570 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2571 if (!font) continue;
2573 atsFont = CTFontGetPlatformFont(font, NULL);
2574 if (!atsFont)
2576 CFRelease(font);
2577 continue;
2580 status = ATSFontGetFileReference(atsFont, &fsref);
2581 CFRelease(font);
2582 if (status != noErr) continue;
2584 url = CFURLCreateFromFSRef(NULL, &fsref);
2585 if (!url) continue;
2587 ext = CFURLCopyPathExtension(url);
2588 if (ext)
2590 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2591 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2592 CFRelease(ext);
2593 if (skip)
2595 CFRelease(url);
2596 continue;
2600 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2601 CFRelease(url);
2602 if (!path) continue;
2604 CFSetAddValue(paths, path);
2605 CFRelease(path);
2608 CFRelease(descs);
2610 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2611 CFRelease(paths);
2614 #endif
2616 static BOOL load_font_from_data_dir(LPCWSTR file)
2618 BOOL ret = FALSE;
2619 const char *data_dir = wine_get_data_dir();
2621 if (!data_dir) data_dir = wine_get_build_dir();
2623 if (data_dir)
2625 INT len;
2626 char *unix_name;
2628 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2630 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2632 strcpy(unix_name, data_dir);
2633 strcat(unix_name, "/fonts/");
2635 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2637 EnterCriticalSection( &freetype_cs );
2638 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2639 LeaveCriticalSection( &freetype_cs );
2640 HeapFree(GetProcessHeap(), 0, unix_name);
2642 return ret;
2645 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2647 static const WCHAR slashW[] = {'\\','\0'};
2648 BOOL ret = FALSE;
2649 WCHAR windowsdir[MAX_PATH];
2650 char *unixname;
2652 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2653 strcatW(windowsdir, fontsW);
2654 strcatW(windowsdir, slashW);
2655 strcatW(windowsdir, file);
2656 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2657 EnterCriticalSection( &freetype_cs );
2658 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2659 LeaveCriticalSection( &freetype_cs );
2660 HeapFree(GetProcessHeap(), 0, unixname);
2662 return ret;
2665 static void load_system_fonts(void)
2667 HKEY hkey;
2668 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2669 const WCHAR * const *value;
2670 DWORD dlen, type;
2671 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2672 char *unixname;
2674 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2675 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2676 strcatW(windowsdir, fontsW);
2677 for(value = SystemFontValues; *value; value++) {
2678 dlen = sizeof(data);
2679 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2680 type == REG_SZ) {
2681 BOOL added = FALSE;
2683 sprintfW(pathW, fmtW, windowsdir, data);
2684 if((unixname = wine_get_unix_file_name(pathW))) {
2685 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2686 HeapFree(GetProcessHeap(), 0, unixname);
2688 if (!added)
2689 load_font_from_data_dir(data);
2692 RegCloseKey(hkey);
2696 /*************************************************************
2698 * This adds registry entries for any externally loaded fonts
2699 * (fonts from fontconfig or FontDirs). It also deletes entries
2700 * of no longer existing fonts.
2703 static void update_reg_entries(void)
2705 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2706 LPWSTR valueW;
2707 DWORD len;
2708 Family *family;
2709 Face *face;
2710 struct list *family_elem_ptr, *face_elem_ptr;
2711 WCHAR *file, *path;
2712 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2714 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2715 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2716 ERR("Can't create Windows font reg key\n");
2717 goto end;
2720 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2721 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2722 ERR("Can't create Windows font reg key\n");
2723 goto end;
2726 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2727 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2728 ERR("Can't create external font reg key\n");
2729 goto end;
2732 /* enumerate the fonts and add external ones to the two keys */
2734 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2735 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2736 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2737 char *buffer;
2738 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2739 if(!face->external) continue;
2741 if(face->FullName)
2743 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2744 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2745 strcpyW(valueW, face->FullName);
2747 else
2749 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2750 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2751 strcpyW(valueW, family->FamilyName);
2754 buffer = strWtoA( CP_UNIXCP, face->file );
2755 path = wine_get_dos_file_name( buffer );
2756 HeapFree( GetProcessHeap(), 0, buffer );
2758 if (path)
2759 file = path;
2760 else if ((file = strrchrW(face->file, '/')))
2761 file++;
2762 else
2763 file = face->file;
2765 len = strlenW(file) + 1;
2766 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2767 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2768 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2770 HeapFree(GetProcessHeap(), 0, path);
2771 HeapFree(GetProcessHeap(), 0, valueW);
2774 end:
2775 if(external_key) RegCloseKey(external_key);
2776 if(win9x_key) RegCloseKey(win9x_key);
2777 if(winnt_key) RegCloseKey(winnt_key);
2778 return;
2781 static void delete_external_font_keys(void)
2783 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2784 DWORD dlen, vlen, datalen, valuelen, i, type;
2785 LPWSTR valueW;
2786 LPVOID data;
2788 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2789 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2790 ERR("Can't create Windows font reg key\n");
2791 goto end;
2794 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2795 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2796 ERR("Can't create Windows font reg key\n");
2797 goto end;
2800 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2801 ERR("Can't create external font reg key\n");
2802 goto end;
2805 /* Delete all external fonts added last time */
2807 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2808 &valuelen, &datalen, NULL, NULL);
2809 valuelen++; /* returned value doesn't include room for '\0' */
2810 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2811 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2813 dlen = datalen * sizeof(WCHAR);
2814 vlen = valuelen;
2815 i = 0;
2816 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2817 &dlen) == ERROR_SUCCESS) {
2819 RegDeleteValueW(winnt_key, valueW);
2820 RegDeleteValueW(win9x_key, valueW);
2821 /* reset dlen and vlen */
2822 dlen = datalen;
2823 vlen = valuelen;
2825 HeapFree(GetProcessHeap(), 0, data);
2826 HeapFree(GetProcessHeap(), 0, valueW);
2828 /* Delete the old external fonts key */
2829 RegCloseKey(external_key);
2830 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2832 end:
2833 if(win9x_key) RegCloseKey(win9x_key);
2834 if(winnt_key) RegCloseKey(winnt_key);
2837 /*************************************************************
2838 * WineEngAddFontResourceEx
2841 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2843 INT ret = 0;
2845 GDI_CheckNotLock();
2847 if (ft_handle) /* do it only if we have freetype up and running */
2849 char *unixname;
2851 if(flags)
2852 FIXME("Ignoring flags %x\n", flags);
2854 if((unixname = wine_get_unix_file_name(file)))
2856 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2858 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2859 EnterCriticalSection( &freetype_cs );
2860 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2861 LeaveCriticalSection( &freetype_cs );
2862 HeapFree(GetProcessHeap(), 0, unixname);
2864 if (!ret && !strchrW(file, '\\')) {
2865 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2866 ret = load_font_from_winfonts_dir(file);
2867 if (!ret) {
2868 /* Try in datadir/fonts (or builddir/fonts),
2869 * needed for Magic the Gathering Online
2871 ret = load_font_from_data_dir(file);
2875 return ret;
2878 /*************************************************************
2879 * WineEngAddFontMemResourceEx
2882 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2884 GDI_CheckNotLock();
2886 if (ft_handle) /* do it only if we have freetype up and running */
2888 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2890 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2891 memcpy(pFontCopy, pbFont, cbFont);
2893 EnterCriticalSection( &freetype_cs );
2894 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2895 LeaveCriticalSection( &freetype_cs );
2897 if (*pcFonts == 0)
2899 TRACE("AddFontToList failed\n");
2900 HeapFree(GetProcessHeap(), 0, pFontCopy);
2901 return 0;
2903 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2904 * For now return something unique but quite random
2906 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2907 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2910 *pcFonts = 0;
2911 return 0;
2914 /*************************************************************
2915 * WineEngRemoveFontResourceEx
2918 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2920 GDI_CheckNotLock();
2921 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2922 return TRUE;
2925 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2927 WCHAR *fullname;
2928 char *unix_name;
2929 int file_len;
2931 if (!font_file) return NULL;
2933 file_len = strlenW( font_file );
2935 if (font_path && font_path[0])
2937 int path_len = strlenW( font_path );
2938 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2939 if (!fullname) return NULL;
2940 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2941 fullname[path_len] = '\\';
2942 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2944 else
2946 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2947 if (!len) return NULL;
2948 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2949 if (!fullname) return NULL;
2950 GetFullPathNameW( font_file, len, fullname, NULL );
2953 unix_name = wine_get_unix_file_name( fullname );
2954 HeapFree( GetProcessHeap(), 0, fullname );
2955 return unix_name;
2958 #include <pshpack1.h>
2959 struct fontdir
2961 WORD num_of_resources;
2962 WORD res_id;
2963 WORD dfVersion;
2964 DWORD dfSize;
2965 CHAR dfCopyright[60];
2966 WORD dfType;
2967 WORD dfPoints;
2968 WORD dfVertRes;
2969 WORD dfHorizRes;
2970 WORD dfAscent;
2971 WORD dfInternalLeading;
2972 WORD dfExternalLeading;
2973 BYTE dfItalic;
2974 BYTE dfUnderline;
2975 BYTE dfStrikeOut;
2976 WORD dfWeight;
2977 BYTE dfCharSet;
2978 WORD dfPixWidth;
2979 WORD dfPixHeight;
2980 BYTE dfPitchAndFamily;
2981 WORD dfAvgWidth;
2982 WORD dfMaxWidth;
2983 BYTE dfFirstChar;
2984 BYTE dfLastChar;
2985 BYTE dfDefaultChar;
2986 BYTE dfBreakChar;
2987 WORD dfWidthBytes;
2988 DWORD dfDevice;
2989 DWORD dfFace;
2990 DWORD dfReserved;
2991 CHAR szFaceName[LF_FACESIZE];
2994 #include <poppack.h>
2996 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2997 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2999 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3001 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3002 Face *face;
3003 Family *family;
3004 WCHAR *name, *english_name;
3005 ENUMLOGFONTEXW elf;
3006 NEWTEXTMETRICEXW ntm;
3007 DWORD type;
3009 if (!ft_face) return FALSE;
3010 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE, 0 );
3011 get_family_names( ft_face, &name, &english_name, FALSE );
3012 family = create_family( name, english_name );
3013 insert_face_in_family_list( face, family );
3014 pFT_Done_Face( ft_face );
3016 GetEnumStructs( face, &elf, &ntm, &type );
3017 free_family( family );
3019 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3021 memset( fd, 0, sizeof(*fd) );
3023 fd->num_of_resources = 1;
3024 fd->res_id = 0;
3025 fd->dfVersion = 0x200;
3026 fd->dfSize = sizeof(*fd);
3027 strcpy( fd->dfCopyright, "Wine fontdir" );
3028 fd->dfType = 0x4003; /* 0x0080 set if private */
3029 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3030 fd->dfVertRes = 72;
3031 fd->dfHorizRes = 72;
3032 fd->dfAscent = ntm.ntmTm.tmAscent;
3033 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3034 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3035 fd->dfItalic = ntm.ntmTm.tmItalic;
3036 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3037 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3038 fd->dfWeight = ntm.ntmTm.tmWeight;
3039 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3040 fd->dfPixWidth = 0;
3041 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3042 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3043 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3044 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3045 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3046 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3047 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3048 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3049 fd->dfWidthBytes = 0;
3050 fd->dfDevice = 0;
3051 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3052 fd->dfReserved = 0;
3053 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3055 return TRUE;
3058 #define NE_FFLAGS_LIBMODULE 0x8000
3059 #define NE_OSFLAGS_WINDOWS 0x02
3061 static const char dos_string[0x40] = "This is a TrueType resource file";
3062 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3064 #include <pshpack2.h>
3066 struct ne_typeinfo
3068 WORD type_id;
3069 WORD count;
3070 DWORD res;
3073 struct ne_nameinfo
3075 WORD off;
3076 WORD len;
3077 WORD flags;
3078 WORD id;
3079 DWORD res;
3082 struct rsrc_tab
3084 WORD align;
3085 struct ne_typeinfo fontdir_type;
3086 struct ne_nameinfo fontdir_name;
3087 struct ne_typeinfo scalable_type;
3088 struct ne_nameinfo scalable_name;
3089 WORD end_of_rsrc;
3090 BYTE fontdir_res_name[8];
3093 #include <poppack.h>
3095 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3097 BOOL ret = FALSE;
3098 HANDLE file;
3099 DWORD size, written;
3100 BYTE *ptr, *start;
3101 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3102 char *font_fileA, *last_part, *ext;
3103 IMAGE_DOS_HEADER dos;
3104 IMAGE_OS2_HEADER ne =
3106 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3107 0, 0, 0, 0, 0, 0,
3108 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3109 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3111 struct rsrc_tab rsrc_tab =
3114 { 0x8007, 1, 0 },
3115 { 0, 0, 0x0c50, 0x2c, 0 },
3116 { 0x80cc, 1, 0 },
3117 { 0, 0, 0x0c50, 0x8001, 0 },
3119 { 7,'F','O','N','T','D','I','R'}
3122 memset( &dos, 0, sizeof(dos) );
3123 dos.e_magic = IMAGE_DOS_SIGNATURE;
3124 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3126 /* import name is last part\0, resident name is last part without extension
3127 non-resident name is "FONTRES:" + lfFaceName */
3129 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3130 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3131 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3133 last_part = strrchr( font_fileA, '\\' );
3134 if (last_part) last_part++;
3135 else last_part = font_fileA;
3136 import_name_len = strlen( last_part ) + 1;
3138 ext = strchr( last_part, '.' );
3139 if (ext) res_name_len = ext - last_part;
3140 else res_name_len = import_name_len - 1;
3142 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3144 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3145 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3146 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3147 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3148 ne.ne_cbenttab = 2;
3149 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3151 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3152 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3153 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3154 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3156 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3157 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3159 if (!ptr)
3161 HeapFree( GetProcessHeap(), 0, font_fileA );
3162 return FALSE;
3165 memcpy( ptr, &dos, sizeof(dos) );
3166 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3167 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3169 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3170 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3172 ptr = start + dos.e_lfanew + ne.ne_restab;
3173 *ptr++ = res_name_len;
3174 memcpy( ptr, last_part, res_name_len );
3176 ptr = start + dos.e_lfanew + ne.ne_imptab;
3177 *ptr++ = import_name_len;
3178 memcpy( ptr, last_part, import_name_len );
3180 ptr = start + ne.ne_nrestab;
3181 *ptr++ = non_res_name_len;
3182 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3183 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3185 ptr = start + (rsrc_tab.scalable_name.off << 4);
3186 memcpy( ptr, font_fileA, font_file_len );
3188 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3189 memcpy( ptr, fontdir, fontdir->dfSize );
3191 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3192 if (file != INVALID_HANDLE_VALUE)
3194 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3195 ret = TRUE;
3196 CloseHandle( file );
3199 HeapFree( GetProcessHeap(), 0, start );
3200 HeapFree( GetProcessHeap(), 0, font_fileA );
3202 return ret;
3205 /*************************************************************
3206 * WineEngCreateScalableFontResource
3209 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3210 LPCWSTR font_file, LPCWSTR font_path )
3212 char *unix_name = get_ttf_file_name( font_file, font_path );
3213 struct fontdir fontdir;
3214 BOOL ret = FALSE;
3216 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3217 SetLastError( ERROR_INVALID_PARAMETER );
3218 else
3220 if (hidden) fontdir.dfType |= 0x80;
3221 ret = create_fot( resource, font_file, &fontdir );
3224 HeapFree( GetProcessHeap(), 0, unix_name );
3225 return ret;
3228 static const struct nls_update_font_list
3230 UINT ansi_cp, oem_cp;
3231 const char *oem, *fixed, *system;
3232 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3233 /* these are for font substitutes */
3234 const char *shelldlg, *tmsrmn;
3235 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3236 *helv_0, *tmsrmn_0;
3237 const struct subst
3239 const char *from, *to;
3240 } arial_0, courier_new_0, times_new_roman_0;
3241 } nls_update_font_list[] =
3243 /* Latin 1 (United States) */
3244 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3245 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3246 "Tahoma","Times New Roman",
3247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3248 { 0 }, { 0 }, { 0 }
3250 /* Latin 1 (Multilingual) */
3251 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3253 "Tahoma","Times New Roman", /* FIXME unverified */
3254 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3255 { 0 }, { 0 }, { 0 }
3257 /* Eastern Europe */
3258 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3259 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3260 "Tahoma","Times New Roman", /* FIXME unverified */
3261 "Fixedsys,238", "System,238",
3262 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3263 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3264 { "Arial CE,0", "Arial,238" },
3265 { "Courier New CE,0", "Courier New,238" },
3266 { "Times New Roman CE,0", "Times New Roman,238" }
3268 /* Cyrillic */
3269 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3270 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3271 "Tahoma","Times New Roman", /* FIXME unverified */
3272 "Fixedsys,204", "System,204",
3273 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3274 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3275 { "Arial Cyr,0", "Arial,204" },
3276 { "Courier New Cyr,0", "Courier New,204" },
3277 { "Times New Roman Cyr,0", "Times New Roman,204" }
3279 /* Greek */
3280 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3281 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3282 "Tahoma","Times New Roman", /* FIXME unverified */
3283 "Fixedsys,161", "System,161",
3284 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3285 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3286 { "Arial Greek,0", "Arial,161" },
3287 { "Courier New Greek,0", "Courier New,161" },
3288 { "Times New Roman Greek,0", "Times New Roman,161" }
3290 /* Turkish */
3291 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3292 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3293 "Tahoma","Times New Roman", /* FIXME unverified */
3294 "Fixedsys,162", "System,162",
3295 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3296 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3297 { "Arial Tur,0", "Arial,162" },
3298 { "Courier New Tur,0", "Courier New,162" },
3299 { "Times New Roman Tur,0", "Times New Roman,162" }
3301 /* Hebrew */
3302 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3303 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3304 "Tahoma","Times New Roman", /* FIXME unverified */
3305 "Fixedsys,177", "System,177",
3306 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3307 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3308 { 0 }, { 0 }, { 0 }
3310 /* Arabic */
3311 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3312 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3313 "Tahoma","Times New Roman", /* FIXME unverified */
3314 "Fixedsys,178", "System,178",
3315 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3316 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3317 { 0 }, { 0 }, { 0 }
3319 /* Baltic */
3320 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3321 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3322 "Tahoma","Times New Roman", /* FIXME unverified */
3323 "Fixedsys,186", "System,186",
3324 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3325 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3326 { "Arial Baltic,0", "Arial,186" },
3327 { "Courier New Baltic,0", "Courier New,186" },
3328 { "Times New Roman Baltic,0", "Times New Roman,186" }
3330 /* Vietnamese */
3331 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3332 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3333 "Tahoma","Times New Roman", /* FIXME unverified */
3334 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3335 { 0 }, { 0 }, { 0 }
3337 /* Thai */
3338 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3339 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3340 "Tahoma","Times New Roman", /* FIXME unverified */
3341 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3342 { 0 }, { 0 }, { 0 }
3344 /* Japanese */
3345 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3346 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3347 "MS UI Gothic","MS Serif",
3348 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3349 { 0 }, { 0 }, { 0 }
3351 /* Chinese Simplified */
3352 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3353 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3354 "SimSun", "NSimSun",
3355 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3356 { 0 }, { 0 }, { 0 }
3358 /* Korean */
3359 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3360 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3361 "Gulim", "Batang",
3362 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3363 { 0 }, { 0 }, { 0 }
3365 /* Chinese Traditional */
3366 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3367 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3368 "PMingLiU", "MingLiU",
3369 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3370 { 0 }, { 0 }, { 0 }
3374 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3376 return ( ansi_cp == 932 /* CP932 for Japanese */
3377 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3378 || ansi_cp == 949 /* CP949 for Korean */
3379 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3382 static inline HKEY create_fonts_NT_registry_key(void)
3384 HKEY hkey = 0;
3386 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3387 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3388 return hkey;
3391 static inline HKEY create_fonts_9x_registry_key(void)
3393 HKEY hkey = 0;
3395 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3396 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3397 return hkey;
3400 static inline HKEY create_config_fonts_registry_key(void)
3402 HKEY hkey = 0;
3404 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3405 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3406 return hkey;
3409 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3411 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3413 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3414 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3415 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3416 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3419 static void set_value_key(HKEY hkey, const char *name, const char *value)
3421 if (value)
3422 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3423 else if (name)
3424 RegDeleteValueA(hkey, name);
3427 static void update_font_info(void)
3429 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3430 char buf[40], cpbuf[40];
3431 DWORD len, type;
3432 HKEY hkey = 0;
3433 UINT i, ansi_cp = 0, oem_cp = 0;
3434 DWORD screen_dpi = 96, font_dpi = 0;
3435 BOOL done = FALSE;
3437 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3438 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3439 &hkey) == ERROR_SUCCESS)
3441 reg_load_dword(hkey, logpixels, &screen_dpi);
3442 RegCloseKey(hkey);
3445 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3446 return;
3448 reg_load_dword(hkey, logpixels, &font_dpi);
3450 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3451 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3452 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3453 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3454 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3456 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3457 if (is_dbcs_ansi_cp(ansi_cp))
3458 use_default_fallback = TRUE;
3460 len = sizeof(buf);
3461 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3463 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3465 RegCloseKey(hkey);
3466 return;
3468 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3469 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3471 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3472 ansi_cp, oem_cp, screen_dpi);
3474 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3475 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3476 RegCloseKey(hkey);
3478 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3480 HKEY hkey;
3482 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3483 nls_update_font_list[i].oem_cp == oem_cp)
3485 hkey = create_config_fonts_registry_key();
3486 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3487 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3488 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3489 RegCloseKey(hkey);
3491 hkey = create_fonts_NT_registry_key();
3492 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3493 RegCloseKey(hkey);
3495 hkey = create_fonts_9x_registry_key();
3496 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3497 RegCloseKey(hkey);
3499 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3501 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3502 strlen(nls_update_font_list[i].shelldlg)+1);
3503 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3504 strlen(nls_update_font_list[i].tmsrmn)+1);
3506 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3507 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3508 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3509 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3510 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3511 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3512 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3513 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3515 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3516 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3517 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3519 RegCloseKey(hkey);
3521 done = TRUE;
3523 else
3525 /* Delete the FontSubstitutes from other locales */
3526 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3528 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3529 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3530 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3531 RegCloseKey(hkey);
3535 if (!done)
3536 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3539 static BOOL init_freetype(void)
3541 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3542 if(!ft_handle) {
3543 WINE_MESSAGE(
3544 "Wine cannot find the FreeType font library. To enable Wine to\n"
3545 "use TrueType fonts please install a version of FreeType greater than\n"
3546 "or equal to 2.0.5.\n"
3547 "http://www.freetype.org\n");
3548 return FALSE;
3551 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
3553 LOAD_FUNCPTR(FT_Done_Face)
3554 LOAD_FUNCPTR(FT_Get_Char_Index)
3555 LOAD_FUNCPTR(FT_Get_First_Char)
3556 LOAD_FUNCPTR(FT_Get_Module)
3557 LOAD_FUNCPTR(FT_Get_Next_Char)
3558 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3559 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3560 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3561 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3562 LOAD_FUNCPTR(FT_Init_FreeType)
3563 LOAD_FUNCPTR(FT_Library_Version)
3564 LOAD_FUNCPTR(FT_Load_Glyph)
3565 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3566 LOAD_FUNCPTR(FT_Matrix_Multiply)
3567 #ifndef FT_MULFIX_INLINED
3568 LOAD_FUNCPTR(FT_MulFix)
3569 #endif
3570 LOAD_FUNCPTR(FT_New_Face)
3571 LOAD_FUNCPTR(FT_New_Memory_Face)
3572 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3573 LOAD_FUNCPTR(FT_Outline_Transform)
3574 LOAD_FUNCPTR(FT_Outline_Translate)
3575 LOAD_FUNCPTR(FT_Render_Glyph)
3576 LOAD_FUNCPTR(FT_Select_Charmap)
3577 LOAD_FUNCPTR(FT_Set_Charmap)
3578 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3579 LOAD_FUNCPTR(FT_Vector_Transform)
3580 LOAD_FUNCPTR(FT_Vector_Unit)
3581 #undef LOAD_FUNCPTR
3582 /* Don't warn if these ones are missing */
3583 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3584 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3585 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3586 #endif
3588 if(pFT_Init_FreeType(&library) != 0) {
3589 ERR("Can't init FreeType library\n");
3590 wine_dlclose(ft_handle, NULL, 0);
3591 ft_handle = NULL;
3592 return FALSE;
3594 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3596 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3597 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3598 ((FT_Version.minor << 8) & 0x00ff00) |
3599 ((FT_Version.patch ) & 0x0000ff);
3601 font_driver = &freetype_funcs;
3602 return TRUE;
3604 sym_not_found:
3605 WINE_MESSAGE(
3606 "Wine cannot find certain functions that it needs inside the FreeType\n"
3607 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3608 "FreeType to at least version 2.1.4.\n"
3609 "http://www.freetype.org\n");
3610 wine_dlclose(ft_handle, NULL, 0);
3611 ft_handle = NULL;
3612 return FALSE;
3615 static void init_font_list(void)
3617 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3618 static const WCHAR pathW[] = {'P','a','t','h',0};
3619 HKEY hkey;
3620 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3621 WCHAR windowsdir[MAX_PATH];
3622 char *unixname;
3623 const char *data_dir;
3625 #ifdef SONAME_LIBFONTCONFIG
3626 init_fontconfig();
3627 #endif
3629 delete_external_font_keys();
3631 /* load the system bitmap fonts */
3632 load_system_fonts();
3634 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3635 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3636 strcatW(windowsdir, fontsW);
3637 if((unixname = wine_get_unix_file_name(windowsdir)))
3639 ReadFontDir(unixname, FALSE);
3640 HeapFree(GetProcessHeap(), 0, unixname);
3643 /* load the system truetype fonts */
3644 data_dir = wine_get_data_dir();
3645 if (!data_dir) data_dir = wine_get_build_dir();
3646 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3648 strcpy(unixname, data_dir);
3649 strcat(unixname, "/fonts/");
3650 ReadFontDir(unixname, TRUE);
3651 HeapFree(GetProcessHeap(), 0, unixname);
3654 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3655 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3656 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3657 will skip these. */
3658 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3659 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3660 &hkey) == ERROR_SUCCESS)
3662 LPWSTR data, valueW;
3663 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3664 &valuelen, &datalen, NULL, NULL);
3666 valuelen++; /* returned value doesn't include room for '\0' */
3667 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3668 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3669 if (valueW && data)
3671 dlen = datalen * sizeof(WCHAR);
3672 vlen = valuelen;
3673 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3674 &dlen) == ERROR_SUCCESS)
3676 if(data[0] && (data[1] == ':'))
3678 if((unixname = wine_get_unix_file_name(data)))
3680 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3681 HeapFree(GetProcessHeap(), 0, unixname);
3684 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3686 WCHAR pathW[MAX_PATH];
3687 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3688 BOOL added = FALSE;
3690 sprintfW(pathW, fmtW, windowsdir, data);
3691 if((unixname = wine_get_unix_file_name(pathW)))
3693 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3694 HeapFree(GetProcessHeap(), 0, unixname);
3696 if (!added)
3697 load_font_from_data_dir(data);
3699 /* reset dlen and vlen */
3700 dlen = datalen;
3701 vlen = valuelen;
3704 HeapFree(GetProcessHeap(), 0, data);
3705 HeapFree(GetProcessHeap(), 0, valueW);
3706 RegCloseKey(hkey);
3709 #ifdef SONAME_LIBFONTCONFIG
3710 load_fontconfig_fonts();
3711 #elif defined(HAVE_CARBON_CARBON_H)
3712 load_mac_fonts();
3713 #endif
3715 /* then look in any directories that we've specified in the config file */
3716 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3717 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3719 DWORD len;
3720 LPWSTR valueW;
3721 LPSTR valueA, ptr;
3723 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3725 len += sizeof(WCHAR);
3726 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3727 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3729 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3730 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3731 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3732 TRACE( "got font path %s\n", debugstr_a(valueA) );
3733 ptr = valueA;
3734 while (ptr)
3736 const char* home;
3737 LPSTR next = strchr( ptr, ':' );
3738 if (next) *next++ = 0;
3739 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3740 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3742 strcpy( unixname, home );
3743 strcat( unixname, ptr + 1 );
3744 ReadFontDir( unixname, TRUE );
3745 HeapFree( GetProcessHeap(), 0, unixname );
3747 else
3748 ReadFontDir( ptr, TRUE );
3749 ptr = next;
3751 HeapFree( GetProcessHeap(), 0, valueA );
3753 HeapFree( GetProcessHeap(), 0, valueW );
3755 RegCloseKey(hkey);
3759 static BOOL move_to_front(const WCHAR *name)
3761 Family *family, *cursor2;
3762 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3764 if(!strcmpiW(family->FamilyName, name))
3766 list_remove(&family->entry);
3767 list_add_head(&font_list, &family->entry);
3768 return TRUE;
3771 return FALSE;
3774 static BOOL set_default(const WCHAR **name_list)
3776 while (*name_list)
3778 if (move_to_front(*name_list)) return TRUE;
3779 name_list++;
3782 return FALSE;
3785 static void reorder_font_list(void)
3787 set_default( default_serif_list );
3788 set_default( default_fixed_list );
3789 set_default( default_sans_list );
3792 /*************************************************************
3793 * WineEngInit
3795 * Initialize FreeType library and create a list of available faces
3797 BOOL WineEngInit(void)
3799 HKEY hkey_font_cache;
3800 DWORD disposition;
3801 HANDLE font_mutex;
3803 /* update locale dependent font info in registry */
3804 update_font_info();
3806 if(!init_freetype()) return FALSE;
3808 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3810 ERR("Failed to create font mutex\n");
3811 return FALSE;
3813 WaitForSingleObject(font_mutex, INFINITE);
3815 create_font_cache_key(&hkey_font_cache, &disposition);
3817 if(disposition == REG_CREATED_NEW_KEY)
3818 init_font_list();
3819 else
3820 load_font_list_from_cache(hkey_font_cache);
3822 RegCloseKey(hkey_font_cache);
3824 reorder_font_list();
3826 DumpFontList();
3827 LoadSubstList();
3828 DumpSubstList();
3829 LoadReplaceList();
3831 if(disposition == REG_CREATED_NEW_KEY)
3832 update_reg_entries();
3834 init_system_links();
3836 ReleaseMutex(font_mutex);
3837 return TRUE;
3841 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3843 TT_OS2 *pOS2;
3844 TT_HoriHeader *pHori;
3846 LONG ppem;
3848 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3849 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3851 if(height == 0) height = 16;
3853 /* Calc. height of EM square:
3855 * For +ve lfHeight we have
3856 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3857 * Re-arranging gives:
3858 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3860 * For -ve lfHeight we have
3861 * |lfHeight| = ppem
3862 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3863 * with il = winAscent + winDescent - units_per_em]
3867 if(height > 0) {
3868 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3869 ppem = MulDiv(ft_face->units_per_EM, height,
3870 pHori->Ascender - pHori->Descender);
3871 else
3872 ppem = MulDiv(ft_face->units_per_EM, height,
3873 pOS2->usWinAscent + pOS2->usWinDescent);
3875 else
3876 ppem = -height;
3878 return ppem;
3881 static struct font_mapping *map_font_file( const char *name )
3883 struct font_mapping *mapping;
3884 struct stat st;
3885 int fd;
3887 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3888 if (fstat( fd, &st ) == -1) goto error;
3890 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3892 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3894 mapping->refcount++;
3895 close( fd );
3896 return mapping;
3899 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3900 goto error;
3902 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3903 close( fd );
3905 if (mapping->data == MAP_FAILED)
3907 HeapFree( GetProcessHeap(), 0, mapping );
3908 return NULL;
3910 mapping->refcount = 1;
3911 mapping->dev = st.st_dev;
3912 mapping->ino = st.st_ino;
3913 mapping->size = st.st_size;
3914 list_add_tail( &mappings_list, &mapping->entry );
3915 return mapping;
3917 error:
3918 close( fd );
3919 return NULL;
3922 static void unmap_font_file( struct font_mapping *mapping )
3924 if (!--mapping->refcount)
3926 list_remove( &mapping->entry );
3927 munmap( mapping->data, mapping->size );
3928 HeapFree( GetProcessHeap(), 0, mapping );
3932 static LONG load_VDMX(GdiFont*, LONG);
3934 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3936 FT_Error err;
3937 FT_Face ft_face;
3938 void *data_ptr;
3939 DWORD data_size;
3941 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3943 if (face->file)
3945 char *filename = strWtoA( CP_UNIXCP, face->file );
3946 font->mapping = map_font_file( filename );
3947 HeapFree( GetProcessHeap(), 0, filename );
3948 if (!font->mapping)
3950 WARN("failed to map %s\n", debugstr_w(face->file));
3951 return 0;
3953 data_ptr = font->mapping->data;
3954 data_size = font->mapping->size;
3956 else
3958 data_ptr = face->font_data_ptr;
3959 data_size = face->font_data_size;
3962 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3963 if(err) {
3964 ERR("FT_New_Face rets %d\n", err);
3965 return 0;
3968 /* set it here, as load_VDMX needs it */
3969 font->ft_face = ft_face;
3971 if(FT_IS_SCALABLE(ft_face)) {
3972 /* load the VDMX table if we have one */
3973 font->ppem = load_VDMX(font, height);
3974 if(font->ppem == 0)
3975 font->ppem = calc_ppem_for_height(ft_face, height);
3976 TRACE("height %d => ppem %d\n", height, font->ppem);
3978 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3979 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3980 } else {
3981 font->ppem = height;
3982 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3983 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3985 return ft_face;
3989 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3991 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3992 a single face with the requested charset. The idea is to check if
3993 the selected font supports the current ANSI codepage, if it does
3994 return the corresponding charset, else return the first charset */
3996 CHARSETINFO csi;
3997 int acp = GetACP(), i;
3998 DWORD fs0;
4000 *cp = acp;
4001 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4003 const SYSTEM_LINKS *font_link;
4005 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4006 return csi.ciCharset;
4008 font_link = find_font_link(family_name);
4009 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4010 return csi.ciCharset;
4013 for(i = 0; i < 32; i++) {
4014 fs0 = 1L << i;
4015 if(face->fs.fsCsb[0] & fs0) {
4016 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4017 *cp = csi.ciACP;
4018 return csi.ciCharset;
4020 else
4021 FIXME("TCI failing on %x\n", fs0);
4025 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4026 face->fs.fsCsb[0], debugstr_w(face->file));
4027 *cp = acp;
4028 return DEFAULT_CHARSET;
4031 static GdiFont *alloc_font(void)
4033 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4034 ret->gmsize = 1;
4035 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4036 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4037 ret->potm = NULL;
4038 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4039 ret->total_kern_pairs = (DWORD)-1;
4040 ret->kern_pairs = NULL;
4041 list_init(&ret->hfontlist);
4042 list_init(&ret->child_fonts);
4043 return ret;
4046 static void free_font(GdiFont *font)
4048 struct list *cursor, *cursor2;
4049 DWORD i;
4051 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
4053 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
4054 list_remove(cursor);
4055 if(child->font)
4056 free_font(child->font);
4057 HeapFree(GetProcessHeap(), 0, child);
4060 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
4062 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
4063 DeleteObject(hfontlist->hfont);
4064 list_remove(&hfontlist->entry);
4065 HeapFree(GetProcessHeap(), 0, hfontlist);
4068 if (font->ft_face) pFT_Done_Face(font->ft_face);
4069 if (font->mapping) unmap_font_file( font->mapping );
4070 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4071 HeapFree(GetProcessHeap(), 0, font->potm);
4072 HeapFree(GetProcessHeap(), 0, font->name);
4073 for (i = 0; i < font->gmsize; i++)
4074 HeapFree(GetProcessHeap(),0,font->gm[i]);
4075 HeapFree(GetProcessHeap(), 0, font->gm);
4076 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4077 HeapFree(GetProcessHeap(), 0, font);
4081 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4083 FT_Face ft_face = font->ft_face;
4084 FT_ULong len;
4085 FT_Error err;
4087 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4089 if(!buf)
4090 len = 0;
4091 else
4092 len = cbData;
4094 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4096 /* make sure value of len is the value freetype says it needs */
4097 if (buf && len)
4099 FT_ULong needed = 0;
4100 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4101 if( !err && needed < len) len = needed;
4103 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4104 if (err)
4106 TRACE("Can't find table %c%c%c%c\n",
4107 /* bytes were reversed */
4108 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4109 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4110 return GDI_ERROR;
4112 return len;
4115 /*************************************************************
4116 * load_VDMX
4118 * load the vdmx entry for the specified height
4121 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4122 ( ( (FT_ULong)_x4 << 24 ) | \
4123 ( (FT_ULong)_x3 << 16 ) | \
4124 ( (FT_ULong)_x2 << 8 ) | \
4125 (FT_ULong)_x1 )
4127 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4129 typedef struct {
4130 BYTE bCharSet;
4131 BYTE xRatio;
4132 BYTE yStartRatio;
4133 BYTE yEndRatio;
4134 } Ratios;
4136 typedef struct {
4137 WORD recs;
4138 BYTE startsz;
4139 BYTE endsz;
4140 } VDMX_group;
4142 static LONG load_VDMX(GdiFont *font, LONG height)
4144 WORD hdr[3], tmp;
4145 VDMX_group group;
4146 BYTE devXRatio, devYRatio;
4147 USHORT numRecs, numRatios;
4148 DWORD result, offset = -1;
4149 LONG ppem = 0;
4150 int i;
4152 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4154 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4155 return ppem;
4157 /* FIXME: need the real device aspect ratio */
4158 devXRatio = 1;
4159 devYRatio = 1;
4161 numRecs = GET_BE_WORD(hdr[1]);
4162 numRatios = GET_BE_WORD(hdr[2]);
4164 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4165 for(i = 0; i < numRatios; i++) {
4166 Ratios ratio;
4168 offset = (3 * 2) + (i * sizeof(Ratios));
4169 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4170 offset = -1;
4172 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4174 if((ratio.xRatio == 0 &&
4175 ratio.yStartRatio == 0 &&
4176 ratio.yEndRatio == 0) ||
4177 (devXRatio == ratio.xRatio &&
4178 devYRatio >= ratio.yStartRatio &&
4179 devYRatio <= ratio.yEndRatio))
4181 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4182 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4183 offset = GET_BE_WORD(tmp);
4184 break;
4188 if(offset == -1) {
4189 FIXME("No suitable ratio found\n");
4190 return ppem;
4193 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4194 USHORT recs;
4195 BYTE startsz, endsz;
4196 WORD *vTable;
4198 recs = GET_BE_WORD(group.recs);
4199 startsz = group.startsz;
4200 endsz = group.endsz;
4202 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4204 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4205 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4206 if(result == GDI_ERROR) {
4207 FIXME("Failed to retrieve vTable\n");
4208 goto end;
4211 if(height > 0) {
4212 for(i = 0; i < recs; i++) {
4213 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4214 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4215 ppem = GET_BE_WORD(vTable[i * 3]);
4217 if(yMax + -yMin == height) {
4218 font->yMax = yMax;
4219 font->yMin = yMin;
4220 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4221 break;
4223 if(yMax + -yMin > height) {
4224 if(--i < 0) {
4225 ppem = 0;
4226 goto end; /* failed */
4228 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4229 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4230 ppem = GET_BE_WORD(vTable[i * 3]);
4231 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4232 break;
4235 if(!font->yMax) {
4236 ppem = 0;
4237 TRACE("ppem not found for height %d\n", height);
4240 end:
4241 HeapFree(GetProcessHeap(), 0, vTable);
4244 return ppem;
4247 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4249 if(font->font_desc.hash != fd->hash) return TRUE;
4250 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4251 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4252 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4253 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4256 static void calc_hash(FONT_DESC *pfd)
4258 DWORD hash = 0, *ptr, two_chars;
4259 WORD *pwc;
4260 unsigned int i;
4262 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4263 hash ^= *ptr;
4264 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4265 hash ^= *ptr;
4266 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4267 two_chars = *ptr;
4268 pwc = (WCHAR *)&two_chars;
4269 if(!*pwc) break;
4270 *pwc = toupperW(*pwc);
4271 pwc++;
4272 *pwc = toupperW(*pwc);
4273 hash ^= two_chars;
4274 if(!*pwc) break;
4276 hash ^= !pfd->can_use_bitmap;
4277 pfd->hash = hash;
4278 return;
4281 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4283 GdiFont *ret;
4284 FONT_DESC fd;
4285 HFONTLIST *hflist;
4286 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4288 fd.lf = *plf;
4289 fd.matrix = *pmat;
4290 fd.can_use_bitmap = can_use_bitmap;
4291 calc_hash(&fd);
4293 /* try the child list */
4294 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4295 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4296 if(!fontcmp(ret, &fd)) {
4297 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4298 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4299 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4300 if(hflist->hfont == hfont)
4301 return ret;
4306 /* try the in-use list */
4307 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4308 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4309 if(!fontcmp(ret, &fd)) {
4310 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4311 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4312 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4313 if(hflist->hfont == hfont)
4314 return ret;
4316 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4317 hflist->hfont = hfont;
4318 list_add_head(&ret->hfontlist, &hflist->entry);
4319 return ret;
4323 /* then the unused list */
4324 font_elem_ptr = list_head(&unused_gdi_font_list);
4325 while(font_elem_ptr) {
4326 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4327 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4328 if(!fontcmp(ret, &fd)) {
4329 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4330 assert(list_empty(&ret->hfontlist));
4331 TRACE("Found %p in unused list\n", ret);
4332 list_remove(&ret->entry);
4333 list_add_head(&gdi_font_list, &ret->entry);
4334 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4335 hflist->hfont = hfont;
4336 list_add_head(&ret->hfontlist, &hflist->entry);
4337 return ret;
4340 return NULL;
4343 static void add_to_cache(GdiFont *font)
4345 static DWORD cache_num = 1;
4347 font->cache_num = cache_num++;
4348 list_add_head(&gdi_font_list, &font->entry);
4351 /*************************************************************
4352 * create_child_font_list
4354 static BOOL create_child_font_list(GdiFont *font)
4356 BOOL ret = FALSE;
4357 SYSTEM_LINKS *font_link;
4358 CHILD_FONT *font_link_entry, *new_child;
4359 FontSubst *psub;
4360 WCHAR* font_name;
4362 psub = get_font_subst(&font_subst_list, font->name, -1);
4363 font_name = psub ? psub->to.name : font->name;
4364 font_link = find_font_link(font_name);
4365 if (font_link != NULL)
4367 TRACE("found entry in system list\n");
4368 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4370 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4371 new_child->face = font_link_entry->face;
4372 new_child->font = NULL;
4373 list_add_tail(&font->child_fonts, &new_child->entry);
4374 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4376 ret = TRUE;
4379 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4380 * Sans Serif. This is how asian windows get default fallbacks for fonts
4382 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4383 font->charset != OEM_CHARSET &&
4384 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4386 font_link = find_font_link(szDefaultFallbackLink);
4387 if (font_link != NULL)
4389 TRACE("found entry in default fallback list\n");
4390 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4392 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4393 new_child->face = font_link_entry->face;
4394 new_child->font = NULL;
4395 list_add_tail(&font->child_fonts, &new_child->entry);
4396 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4398 ret = TRUE;
4402 return ret;
4405 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4407 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4409 if (pFT_Set_Charmap)
4411 FT_Int i;
4412 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4414 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4416 for (i = 0; i < ft_face->num_charmaps; i++)
4418 if (ft_face->charmaps[i]->encoding == encoding)
4420 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4421 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4423 switch (ft_face->charmaps[i]->platform_id)
4425 default:
4426 cmap_def = ft_face->charmaps[i];
4427 break;
4428 case 0: /* Apple Unicode */
4429 cmap0 = ft_face->charmaps[i];
4430 break;
4431 case 1: /* Macintosh */
4432 cmap1 = ft_face->charmaps[i];
4433 break;
4434 case 2: /* ISO */
4435 cmap2 = ft_face->charmaps[i];
4436 break;
4437 case 3: /* Microsoft */
4438 cmap3 = ft_face->charmaps[i];
4439 break;
4443 if (cmap3) /* prefer Microsoft cmap table */
4444 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4445 else if (cmap1)
4446 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4447 else if (cmap2)
4448 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4449 else if (cmap0)
4450 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4451 else if (cmap_def)
4452 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4454 return ft_err == FT_Err_Ok;
4457 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4461 /*************************************************************
4462 * freetype_CreateDC
4464 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4465 LPCWSTR output, const DEVMODEW *devmode )
4467 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4469 if (!physdev) return FALSE;
4470 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4471 return TRUE;
4475 /*************************************************************
4476 * freetype_DeleteDC
4478 static BOOL freetype_DeleteDC( PHYSDEV dev )
4480 struct freetype_physdev *physdev = get_freetype_dev( dev );
4481 HeapFree( GetProcessHeap(), 0, physdev );
4482 return TRUE;
4485 static FT_Encoding pick_charmap( FT_Face face, int charset )
4487 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4488 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4489 const FT_Encoding *encs = regular_order;
4491 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4493 while (*encs != 0)
4495 if (select_charmap( face, *encs )) break;
4496 encs++;
4498 return *encs;
4501 #define GASP_GRIDFIT 0x01
4502 #define GASP_DOGRAY 0x02
4503 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4505 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4507 DWORD size;
4508 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4509 WORD *alloced = NULL, *ptr = buf;
4510 WORD num_recs, version;
4511 BOOL ret = FALSE;
4513 *flags = 0;
4514 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4515 if (size == GDI_ERROR) return FALSE;
4516 if (size < 4 * sizeof(WORD)) return FALSE;
4517 if (size > sizeof(buf))
4519 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4520 if (!ptr) return FALSE;
4523 get_font_data( font, GASP_TAG, 0, ptr, size );
4525 version = GET_BE_WORD( *ptr++ );
4526 num_recs = GET_BE_WORD( *ptr++ );
4528 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4530 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4531 goto done;
4534 while (num_recs--)
4536 *flags = GET_BE_WORD( *(ptr + 1) );
4537 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4538 ptr += 2;
4540 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4541 ret = TRUE;
4543 done:
4544 HeapFree( GetProcessHeap(), 0, alloced );
4545 return ret;
4548 /*************************************************************
4549 * freetype_SelectFont
4551 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4553 struct freetype_physdev *physdev = get_freetype_dev( dev );
4554 GdiFont *ret;
4555 Face *face, *best, *best_bitmap;
4556 Family *family, *last_resort_family;
4557 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4558 INT height, width = 0;
4559 unsigned int score = 0, new_score;
4560 signed int diff = 0, newdiff;
4561 BOOL bd, it, can_use_bitmap, want_vertical;
4562 LOGFONTW lf;
4563 CHARSETINFO csi;
4564 HFONTLIST *hflist;
4565 FMAT2 dcmat;
4566 FontSubst *psub = NULL;
4567 DC *dc = get_dc_ptr( dev->hdc );
4568 const SYSTEM_LINKS *font_link;
4570 if (!hfont) /* notification that the font has been changed by another driver */
4572 dc->gdiFont = NULL;
4573 physdev->font = NULL;
4574 release_dc_ptr( dc );
4575 return 0;
4578 GetObjectW( hfont, sizeof(lf), &lf );
4579 lf.lfWidth = abs(lf.lfWidth);
4581 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4583 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4584 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4585 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4586 lf.lfEscapement);
4588 if(dc->GraphicsMode == GM_ADVANCED)
4590 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4591 /* Try to avoid not necessary glyph transformations */
4592 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4594 lf.lfHeight *= fabs(dcmat.eM11);
4595 lf.lfWidth *= fabs(dcmat.eM11);
4596 dcmat.eM11 = dcmat.eM22 = 1.0;
4599 else
4601 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4602 font scaling abilities. */
4603 dcmat.eM11 = dcmat.eM22 = 1.0;
4604 dcmat.eM21 = dcmat.eM12 = 0;
4605 if (dc->vport2WorldValid)
4607 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4608 lf.lfOrientation = -lf.lfOrientation;
4609 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4610 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4614 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4615 dcmat.eM21, dcmat.eM22);
4617 GDI_CheckNotLock();
4618 EnterCriticalSection( &freetype_cs );
4620 /* check the cache first */
4621 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4622 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4623 goto done;
4626 if(list_empty(&font_list)) /* No fonts installed */
4628 TRACE("No fonts installed\n");
4629 goto done;
4632 TRACE("not in cache\n");
4633 ret = alloc_font();
4635 ret->font_desc.matrix = dcmat;
4636 ret->font_desc.lf = lf;
4637 ret->font_desc.can_use_bitmap = can_use_bitmap;
4638 calc_hash(&ret->font_desc);
4639 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4640 hflist->hfont = hfont;
4641 list_add_head(&ret->hfontlist, &hflist->entry);
4643 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4644 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4645 original value lfCharSet. Note this is a special case for
4646 Symbol and doesn't happen at least for "Wingdings*" */
4648 if(!strcmpiW(lf.lfFaceName, SymbolW))
4649 lf.lfCharSet = SYMBOL_CHARSET;
4651 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4652 switch(lf.lfCharSet) {
4653 case DEFAULT_CHARSET:
4654 csi.fs.fsCsb[0] = 0;
4655 break;
4656 default:
4657 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4658 csi.fs.fsCsb[0] = 0;
4659 break;
4663 family = NULL;
4664 if(lf.lfFaceName[0] != '\0') {
4665 CHILD_FONT *font_link_entry;
4666 LPWSTR FaceName = lf.lfFaceName;
4668 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4670 if(psub) {
4671 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4672 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4673 if (psub->to.charset != -1)
4674 lf.lfCharSet = psub->to.charset;
4677 /* We want a match on name and charset or just name if
4678 charset was DEFAULT_CHARSET. If the latter then
4679 we fixup the returned charset later in get_nearest_charset
4680 where we'll either use the charset of the current ansi codepage
4681 or if that's unavailable the first charset that the font supports.
4683 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4684 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4685 if (!strcmpiW(family->FamilyName, FaceName) ||
4686 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4688 font_link = find_font_link(family->FamilyName);
4689 face_list = get_face_list_from_family(family);
4690 LIST_FOR_EACH(face_elem_ptr, face_list) {
4691 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4692 if (!(face->scalable || can_use_bitmap))
4693 continue;
4694 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4695 goto found;
4696 if (font_link != NULL &&
4697 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4698 goto found;
4699 if (!csi.fs.fsCsb[0])
4700 goto found;
4705 /* Search by full face name. */
4706 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4707 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4708 face_list = get_face_list_from_family(family);
4709 LIST_FOR_EACH(face_elem_ptr, face_list) {
4710 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4711 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4712 (face->scalable || can_use_bitmap))
4714 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4715 goto found_face;
4716 font_link = find_font_link(family->FamilyName);
4717 if (font_link != NULL &&
4718 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4719 goto found_face;
4725 * Try check the SystemLink list first for a replacement font.
4726 * We may find good replacements there.
4728 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4730 if(!strcmpiW(font_link->font_name, FaceName) ||
4731 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4733 TRACE("found entry in system list\n");
4734 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4736 const SYSTEM_LINKS *links;
4738 face = font_link_entry->face;
4739 if (!(face->scalable || can_use_bitmap))
4740 continue;
4741 family = face->family;
4742 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4743 goto found;
4744 links = find_font_link(family->FamilyName);
4745 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4746 goto found;
4752 psub = NULL; /* substitution is no more relevant */
4754 /* If requested charset was DEFAULT_CHARSET then try using charset
4755 corresponding to the current ansi codepage */
4756 if (!csi.fs.fsCsb[0])
4758 INT acp = GetACP();
4759 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4760 FIXME("TCI failed on codepage %d\n", acp);
4761 csi.fs.fsCsb[0] = 0;
4762 } else
4763 lf.lfCharSet = csi.ciCharset;
4766 want_vertical = (lf.lfFaceName[0] == '@');
4768 /* Face families are in the top 4 bits of lfPitchAndFamily,
4769 so mask with 0xF0 before testing */
4771 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4772 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4773 strcpyW(lf.lfFaceName, defFixed);
4774 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4775 strcpyW(lf.lfFaceName, defSerif);
4776 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4777 strcpyW(lf.lfFaceName, defSans);
4778 else
4779 strcpyW(lf.lfFaceName, defSans);
4780 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4781 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4782 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4783 font_link = find_font_link(family->FamilyName);
4784 face_list = get_face_list_from_family(family);
4785 LIST_FOR_EACH(face_elem_ptr, face_list) {
4786 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4787 if (!(face->scalable || can_use_bitmap))
4788 continue;
4789 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4790 goto found;
4791 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4792 goto found;
4797 last_resort_family = NULL;
4798 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4799 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4800 font_link = find_font_link(family->FamilyName);
4801 face_list = get_face_list_from_family(family);
4802 LIST_FOR_EACH(face_elem_ptr, face_list) {
4803 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4804 if(face->vertical == want_vertical &&
4805 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4806 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4807 if(face->scalable)
4808 goto found;
4809 if(can_use_bitmap && !last_resort_family)
4810 last_resort_family = family;
4815 if(last_resort_family) {
4816 family = last_resort_family;
4817 csi.fs.fsCsb[0] = 0;
4818 goto found;
4821 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4822 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4823 face_list = get_face_list_from_family(family);
4824 LIST_FOR_EACH(face_elem_ptr, face_list) {
4825 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4826 if(face->scalable && face->vertical == want_vertical) {
4827 csi.fs.fsCsb[0] = 0;
4828 WARN("just using first face for now\n");
4829 goto found;
4831 if(can_use_bitmap && !last_resort_family)
4832 last_resort_family = family;
4835 if(!last_resort_family) {
4836 FIXME("can't find a single appropriate font - bailing\n");
4837 free_font(ret);
4838 ret = NULL;
4839 goto done;
4842 WARN("could only find a bitmap font - this will probably look awful!\n");
4843 family = last_resort_family;
4844 csi.fs.fsCsb[0] = 0;
4846 found:
4847 it = lf.lfItalic ? 1 : 0;
4848 bd = lf.lfWeight > 550 ? 1 : 0;
4850 height = lf.lfHeight;
4852 face = best = best_bitmap = NULL;
4853 font_link = find_font_link(family->FamilyName);
4854 face_list = get_face_list_from_family(family);
4855 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4857 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4858 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4859 !csi.fs.fsCsb[0])
4861 BOOL italic, bold;
4863 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4864 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4865 new_score = (italic ^ it) + (bold ^ bd);
4866 if(!best || new_score <= score)
4868 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4869 italic, bold, it, bd);
4870 score = new_score;
4871 best = face;
4872 if(best->scalable && score == 0) break;
4873 if(!best->scalable)
4875 if(height > 0)
4876 newdiff = height - (signed int)(best->size.height);
4877 else
4878 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4879 if(!best_bitmap || new_score < score ||
4880 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4882 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4883 diff = newdiff;
4884 best_bitmap = best;
4885 if(score == 0 && diff == 0) break;
4891 if(best)
4892 face = best->scalable ? best : best_bitmap;
4893 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4894 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4896 found_face:
4897 height = lf.lfHeight;
4899 ret->fs = face->fs;
4901 if(csi.fs.fsCsb[0]) {
4902 ret->charset = lf.lfCharSet;
4903 ret->codepage = csi.ciACP;
4905 else
4906 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4908 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4909 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4911 ret->aveWidth = height ? lf.lfWidth : 0;
4913 if(!face->scalable) {
4914 /* Windows uses integer scaling factors for bitmap fonts */
4915 INT scale, scaled_height;
4916 GdiFont *cachedfont;
4918 /* FIXME: rotation of bitmap fonts is ignored */
4919 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4920 if (ret->aveWidth)
4921 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4922 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4923 dcmat.eM11 = dcmat.eM22 = 1.0;
4924 /* As we changed the matrix, we need to search the cache for the font again,
4925 * otherwise we might explode the cache. */
4926 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4927 TRACE("Found cached font after non-scalable matrix rescale!\n");
4928 free_font( ret );
4929 ret = cachedfont;
4930 goto done;
4932 calc_hash(&ret->font_desc);
4934 if (height != 0) height = diff;
4935 height += face->size.height;
4937 scale = (height + face->size.height - 1) / face->size.height;
4938 scaled_height = scale * face->size.height;
4939 /* Only jump to the next height if the difference <= 25% original height */
4940 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4941 /* The jump between unscaled and doubled is delayed by 1 */
4942 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4943 ret->scale_y = scale;
4945 width = face->size.x_ppem >> 6;
4946 height = face->size.y_ppem >> 6;
4948 else
4949 ret->scale_y = 1.0;
4950 TRACE("font scale y: %f\n", ret->scale_y);
4952 ret->ft_face = OpenFontFace(ret, face, width, height);
4954 if (!ret->ft_face)
4956 free_font( ret );
4957 ret = NULL;
4958 goto done;
4961 ret->ntmFlags = face->ntmFlags;
4963 pick_charmap( ret->ft_face, ret->charset );
4965 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4966 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4967 ret->underline = lf.lfUnderline ? 0xff : 0;
4968 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4969 create_child_font_list(ret);
4971 if (face->vertical) /* We need to try to load the GSUB table */
4973 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4974 if (length != GDI_ERROR)
4976 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4977 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4978 TRACE("Loaded GSUB table of %i bytes\n",length);
4981 ret->aa_flags = face->aa_flags;
4983 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4985 add_to_cache(ret);
4986 done:
4987 if (ret)
4989 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
4991 switch (lf.lfQuality)
4993 case NONANTIALIASED_QUALITY:
4994 case ANTIALIASED_QUALITY:
4995 next->funcs->pSelectFont( dev, hfont, aa_flags );
4996 break;
4997 case CLEARTYPE_QUALITY:
4998 case CLEARTYPE_NATURAL_QUALITY:
4999 default:
5000 if (!*aa_flags) *aa_flags = ret->aa_flags;
5001 next->funcs->pSelectFont( dev, hfont, aa_flags );
5003 /* fixup the antialiasing flags for that font */
5004 switch (*aa_flags)
5006 case WINE_GGO_HRGB_BITMAP:
5007 case WINE_GGO_HBGR_BITMAP:
5008 case WINE_GGO_VRGB_BITMAP:
5009 case WINE_GGO_VBGR_BITMAP:
5010 if (is_subpixel_rendering_enabled()) break;
5011 *aa_flags = GGO_GRAY4_BITMAP;
5012 /* fall through */
5013 case GGO_GRAY2_BITMAP:
5014 case GGO_GRAY4_BITMAP:
5015 case GGO_GRAY8_BITMAP:
5016 case WINE_GGO_GRAY16_BITMAP:
5017 if (is_hinting_enabled())
5019 WORD gasp_flags;
5020 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5022 TRACE( "font %s %d aa disabled by GASP\n",
5023 debugstr_w(lf.lfFaceName), lf.lfHeight );
5024 *aa_flags = GGO_BITMAP;
5029 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5030 dc->gdiFont = ret;
5031 physdev->font = ret;
5033 LeaveCriticalSection( &freetype_cs );
5034 release_dc_ptr( dc );
5035 return ret ? hfont : 0;
5038 static void dump_gdi_font_list(void)
5040 GdiFont *gdiFont;
5041 struct list *elem_ptr;
5043 TRACE("---------- gdiFont Cache ----------\n");
5044 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
5045 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5046 TRACE("gdiFont=%p %s %d\n",
5047 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5050 TRACE("---------- Unused gdiFont Cache ----------\n");
5051 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
5052 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5053 TRACE("gdiFont=%p %s %d\n",
5054 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5057 TRACE("---------- Child gdiFont Cache ----------\n");
5058 LIST_FOR_EACH(elem_ptr, &child_font_list) {
5059 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5060 TRACE("gdiFont=%p %s %d\n",
5061 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5065 /*************************************************************
5066 * WineEngDestroyFontInstance
5068 * free the gdiFont associated with this handle
5071 BOOL WineEngDestroyFontInstance(HFONT handle)
5073 GdiFont *gdiFont;
5074 HFONTLIST *hflist;
5075 BOOL ret = FALSE;
5076 struct list *font_elem_ptr, *hfontlist_elem_ptr;
5077 int i = 0;
5079 GDI_CheckNotLock();
5080 EnterCriticalSection( &freetype_cs );
5082 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
5084 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
5085 while(hfontlist_elem_ptr) {
5086 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
5087 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
5088 if(hflist->hfont == handle) {
5089 TRACE("removing child font %p from child list\n", gdiFont);
5090 list_remove(&gdiFont->entry);
5091 LeaveCriticalSection( &freetype_cs );
5092 return TRUE;
5097 TRACE("destroying hfont=%p\n", handle);
5098 if(TRACE_ON(font))
5099 dump_gdi_font_list();
5101 font_elem_ptr = list_head(&gdi_font_list);
5102 while(font_elem_ptr) {
5103 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
5104 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
5106 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
5107 while(hfontlist_elem_ptr) {
5108 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
5109 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
5110 if(hflist->hfont == handle) {
5111 list_remove(&hflist->entry);
5112 HeapFree(GetProcessHeap(), 0, hflist);
5113 ret = TRUE;
5116 if(list_empty(&gdiFont->hfontlist)) {
5117 TRACE("Moving to Unused list\n");
5118 list_remove(&gdiFont->entry);
5119 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
5124 font_elem_ptr = list_head(&unused_gdi_font_list);
5125 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
5126 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
5127 while(font_elem_ptr) {
5128 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
5129 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
5130 TRACE("freeing %p\n", gdiFont);
5131 list_remove(&gdiFont->entry);
5132 free_font(gdiFont);
5134 LeaveCriticalSection( &freetype_cs );
5135 return ret;
5138 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5140 HRSRC rsrc;
5141 HGLOBAL hMem;
5142 WCHAR *p;
5143 int i;
5145 id += IDS_FIRST_SCRIPT;
5146 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5147 if (!rsrc) return 0;
5148 hMem = LoadResource( gdi32_module, rsrc );
5149 if (!hMem) return 0;
5151 p = LockResource( hMem );
5152 id &= 0x000f;
5153 while (id--) p += *p + 1;
5155 i = min(LF_FACESIZE - 1, *p);
5156 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5157 buffer[i] = 0;
5158 return i;
5162 /***************************************************
5163 * create_enum_charset_list
5165 * This function creates charset enumeration list because in DEFAULT_CHARSET
5166 * case, the ANSI codepage's charset takes precedence over other charsets.
5167 * This function works as a filter other than DEFAULT_CHARSET case.
5169 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5171 CHARSETINFO csi;
5172 DWORD n = 0;
5174 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5175 csi.fs.fsCsb[0] != 0) {
5176 list->element[n].mask = csi.fs.fsCsb[0];
5177 list->element[n].charset = csi.ciCharset;
5178 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5179 n++;
5181 else { /* charset is DEFAULT_CHARSET or invalid. */
5182 INT acp, i;
5183 DWORD mask = 0;
5185 /* Set the current codepage's charset as the first element. */
5186 acp = GetACP();
5187 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5188 csi.fs.fsCsb[0] != 0) {
5189 list->element[n].mask = csi.fs.fsCsb[0];
5190 list->element[n].charset = csi.ciCharset;
5191 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5192 mask |= csi.fs.fsCsb[0];
5193 n++;
5196 /* Fill out left elements. */
5197 for (i = 0; i < 32; i++) {
5198 FONTSIGNATURE fs;
5199 fs.fsCsb[0] = 1L << i;
5200 fs.fsCsb[1] = 0;
5201 if (fs.fsCsb[0] & mask)
5202 continue; /* skip, already added. */
5203 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5204 continue; /* skip, this is an invalid fsCsb bit. */
5206 list->element[n].mask = fs.fsCsb[0];
5207 list->element[n].charset = csi.ciCharset;
5208 load_script_name( i, list->element[n].name );
5209 mask |= fs.fsCsb[0];
5210 n++;
5213 /* add catch all mask for remaining bits */
5214 if (~mask)
5216 list->element[n].mask = ~mask;
5217 list->element[n].charset = DEFAULT_CHARSET;
5218 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5219 n++;
5222 list->total = n;
5224 return n;
5227 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5228 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5230 GdiFont *font;
5231 LONG width, height;
5233 if (face->cached_enum_data)
5235 TRACE("Cached\n");
5236 *pelf = face->cached_enum_data->elf;
5237 *pntm = face->cached_enum_data->ntm;
5238 *ptype = face->cached_enum_data->type;
5239 return;
5242 font = alloc_font();
5244 if(face->scalable) {
5245 height = 100;
5246 width = 0;
5247 } else {
5248 height = face->size.y_ppem >> 6;
5249 width = face->size.x_ppem >> 6;
5251 font->scale_y = 1.0;
5253 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5255 free_font(font);
5256 return;
5259 font->name = strdupW(face->family->FamilyName);
5260 font->ntmFlags = face->ntmFlags;
5262 if (get_outline_text_metrics(font))
5264 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5266 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5267 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5268 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5270 lstrcpynW(pelf->elfLogFont.lfFaceName,
5271 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5272 LF_FACESIZE);
5273 lstrcpynW(pelf->elfFullName,
5274 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5275 LF_FULLFACESIZE);
5276 lstrcpynW(pelf->elfStyle,
5277 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5278 LF_FACESIZE);
5280 else
5282 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5284 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5285 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5286 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5288 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5289 if (face->FullName)
5290 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5291 else
5292 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5293 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5296 pntm->ntmTm.ntmFlags = face->ntmFlags;
5297 pntm->ntmFontSig = face->fs;
5299 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5301 pelf->elfLogFont.lfEscapement = 0;
5302 pelf->elfLogFont.lfOrientation = 0;
5303 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5304 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5305 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5306 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5307 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5308 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5309 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5310 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5311 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5312 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5313 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5315 *ptype = 0;
5316 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5317 *ptype |= TRUETYPE_FONTTYPE;
5318 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5319 *ptype |= DEVICE_FONTTYPE;
5320 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5321 *ptype |= RASTER_FONTTYPE;
5323 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5324 if (face->cached_enum_data)
5326 face->cached_enum_data->elf = *pelf;
5327 face->cached_enum_data->ntm = *pntm;
5328 face->cached_enum_data->type = *ptype;
5331 free_font(font);
5334 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5336 const struct list *face_list, *face_elem_ptr;
5338 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5340 face_list = get_face_list_from_family(family);
5341 LIST_FOR_EACH(face_elem_ptr, face_list)
5343 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5345 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5348 return FALSE;
5351 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5353 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5355 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5358 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5359 FONTENUMPROCW proc, LPARAM lparam)
5361 ENUMLOGFONTEXW elf;
5362 NEWTEXTMETRICEXW ntm;
5363 DWORD type = 0;
5364 int i;
5366 GetEnumStructs(face, &elf, &ntm, &type);
5367 for(i = 0; i < list->total; i++) {
5368 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5369 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5370 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5371 i = list->total; /* break out of loop after enumeration */
5373 else
5375 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5376 /* use the DEFAULT_CHARSET case only if no other charset is present */
5377 if (list->element[i].charset == DEFAULT_CHARSET &&
5378 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5379 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5380 strcpyW(elf.elfScript, list->element[i].name);
5381 if (!elf.elfScript[0])
5382 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5384 /* Font Replacement */
5385 if (family != face->family)
5387 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5388 if (face->FullName)
5389 strcpyW(elf.elfFullName, face->FullName);
5390 else
5391 strcpyW(elf.elfFullName, family->FamilyName);
5393 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5394 debugstr_w(elf.elfLogFont.lfFaceName),
5395 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5396 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5397 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5398 ntm.ntmTm.ntmFlags);
5399 /* release section before callback (FIXME) */
5400 LeaveCriticalSection( &freetype_cs );
5401 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5402 EnterCriticalSection( &freetype_cs );
5404 return TRUE;
5407 /*************************************************************
5408 * freetype_EnumFonts
5410 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5412 Family *family;
5413 Face *face;
5414 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5415 LOGFONTW lf;
5416 struct enum_charset_list enum_charsets;
5418 if (!plf)
5420 lf.lfCharSet = DEFAULT_CHARSET;
5421 lf.lfPitchAndFamily = 0;
5422 lf.lfFaceName[0] = 0;
5423 plf = &lf;
5426 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5428 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5430 GDI_CheckNotLock();
5431 EnterCriticalSection( &freetype_cs );
5432 if(plf->lfFaceName[0]) {
5433 FontSubst *psub;
5434 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5436 if(psub) {
5437 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5438 debugstr_w(psub->to.name));
5439 lf = *plf;
5440 strcpyW(lf.lfFaceName, psub->to.name);
5441 plf = &lf;
5444 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5445 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5446 if(family_matches(family, plf)) {
5447 face_list = get_face_list_from_family(family);
5448 LIST_FOR_EACH(face_elem_ptr, face_list) {
5449 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5450 if (!face_matches(family->FamilyName, face, plf)) continue;
5451 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5455 } else {
5456 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5457 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5458 face_list = get_face_list_from_family(family);
5459 face_elem_ptr = list_head(face_list);
5460 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5461 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5464 LeaveCriticalSection( &freetype_cs );
5465 return TRUE;
5468 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5470 pt->x.value = vec->x >> 6;
5471 pt->x.fract = (vec->x & 0x3f) << 10;
5472 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5473 pt->y.value = vec->y >> 6;
5474 pt->y.fract = (vec->y & 0x3f) << 10;
5475 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5476 return;
5479 /***************************************************
5480 * According to the MSDN documentation on WideCharToMultiByte,
5481 * certain codepages cannot set the default_used parameter.
5482 * This returns TRUE if the codepage can set that parameter, false else
5483 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5485 static BOOL codepage_sets_default_used(UINT codepage)
5487 switch (codepage)
5489 case CP_UTF7:
5490 case CP_UTF8:
5491 case CP_SYMBOL:
5492 return FALSE;
5493 default:
5494 return TRUE;
5499 * GSUB Table handling functions
5502 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5504 const GSUB_CoverageFormat1* cf1;
5506 cf1 = table;
5508 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5510 int count = GET_BE_WORD(cf1->GlyphCount);
5511 int i;
5512 TRACE("Coverage Format 1, %i glyphs\n",count);
5513 for (i = 0; i < count; i++)
5514 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5515 return i;
5516 return -1;
5518 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5520 const GSUB_CoverageFormat2* cf2;
5521 int i;
5522 int count;
5523 cf2 = (const GSUB_CoverageFormat2*)cf1;
5525 count = GET_BE_WORD(cf2->RangeCount);
5526 TRACE("Coverage Format 2, %i ranges\n",count);
5527 for (i = 0; i < count; i++)
5529 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5530 return -1;
5531 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5532 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5534 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5535 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5538 return -1;
5540 else
5541 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5543 return -1;
5546 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5548 const GSUB_ScriptList *script;
5549 const GSUB_Script *deflt = NULL;
5550 int i;
5551 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5553 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5554 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5556 const GSUB_Script *scr;
5557 int offset;
5559 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5560 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5562 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5563 return scr;
5564 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5565 deflt = scr;
5567 return deflt;
5570 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5572 int i;
5573 int offset;
5574 const GSUB_LangSys *Lang;
5576 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5578 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5580 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5581 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5583 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5584 return Lang;
5586 offset = GET_BE_WORD(script->DefaultLangSys);
5587 if (offset)
5589 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5590 return Lang;
5592 return NULL;
5595 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5597 int i;
5598 const GSUB_FeatureList *feature;
5599 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5601 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5602 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5604 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5605 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5607 const GSUB_Feature *feat;
5608 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5609 return feat;
5612 return NULL;
5615 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5617 int i;
5618 int offset;
5619 const GSUB_LookupList *lookup;
5620 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5622 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5623 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5625 const GSUB_LookupTable *look;
5626 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5627 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5628 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5629 if (GET_BE_WORD(look->LookupType) != 1)
5630 FIXME("We only handle SubType 1\n");
5631 else
5633 int j;
5635 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5637 const GSUB_SingleSubstFormat1 *ssf1;
5638 offset = GET_BE_WORD(look->SubTable[j]);
5639 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5640 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5642 int offset = GET_BE_WORD(ssf1->Coverage);
5643 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5644 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5646 TRACE(" Glyph 0x%x ->",glyph);
5647 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5648 TRACE(" 0x%x\n",glyph);
5651 else
5653 const GSUB_SingleSubstFormat2 *ssf2;
5654 INT index;
5655 INT offset;
5657 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5658 offset = GET_BE_WORD(ssf1->Coverage);
5659 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5660 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5661 TRACE(" Coverage index %i\n",index);
5662 if (index != -1)
5664 TRACE(" Glyph is 0x%x ->",glyph);
5665 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5666 TRACE("0x%x\n",glyph);
5672 return glyph;
5675 static const char* get_opentype_script(const GdiFont *font)
5678 * I am not sure if this is the correct way to generate our script tag
5681 switch (font->charset)
5683 case ANSI_CHARSET: return "latn";
5684 case BALTIC_CHARSET: return "latn"; /* ?? */
5685 case CHINESEBIG5_CHARSET: return "hani";
5686 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5687 case GB2312_CHARSET: return "hani";
5688 case GREEK_CHARSET: return "grek";
5689 case HANGUL_CHARSET: return "hang";
5690 case RUSSIAN_CHARSET: return "cyrl";
5691 case SHIFTJIS_CHARSET: return "kana";
5692 case TURKISH_CHARSET: return "latn"; /* ?? */
5693 case VIETNAMESE_CHARSET: return "latn";
5694 case JOHAB_CHARSET: return "latn"; /* ?? */
5695 case ARABIC_CHARSET: return "arab";
5696 case HEBREW_CHARSET: return "hebr";
5697 case THAI_CHARSET: return "thai";
5698 default: return "latn";
5702 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5704 const GSUB_Header *header;
5705 const GSUB_Script *script;
5706 const GSUB_LangSys *language;
5707 const GSUB_Feature *feature;
5709 if (!font->GSUB_Table)
5710 return glyph;
5712 header = font->GSUB_Table;
5714 script = GSUB_get_script_table(header, get_opentype_script(font));
5715 if (!script)
5717 TRACE("Script not found\n");
5718 return glyph;
5720 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5721 if (!language)
5723 TRACE("Language not found\n");
5724 return glyph;
5726 feature = GSUB_get_feature(header, language, "vrt2");
5727 if (!feature)
5728 feature = GSUB_get_feature(header, language, "vert");
5729 if (!feature)
5731 TRACE("vrt2/vert feature not found\n");
5732 return glyph;
5734 return GSUB_apply_feature(header, feature, glyph);
5737 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5739 FT_UInt glyphId;
5741 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5742 WCHAR wc = (WCHAR)glyph;
5743 BOOL default_used;
5744 BOOL *default_used_pointer;
5745 FT_UInt ret;
5746 char buf;
5747 default_used_pointer = NULL;
5748 default_used = FALSE;
5749 if (codepage_sets_default_used(font->codepage))
5750 default_used_pointer = &default_used;
5751 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5753 if (font->codepage == CP_SYMBOL && wc < 0x100)
5754 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5755 else
5756 ret = 0;
5758 else
5759 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5760 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5761 return ret;
5764 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5766 if (glyph < 0x100) glyph += 0xf000;
5767 /* there is a number of old pre-Unicode "broken" TTFs, which
5768 do have symbols at U+00XX instead of U+f0XX */
5769 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5770 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5772 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5774 return glyphId;
5777 /*************************************************************
5778 * freetype_GetGlyphIndices
5780 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5782 struct freetype_physdev *physdev = get_freetype_dev( dev );
5783 int i;
5784 WORD default_char;
5785 BOOL got_default = FALSE;
5787 if (!physdev->font)
5789 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5790 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5793 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5795 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5796 got_default = TRUE;
5799 GDI_CheckNotLock();
5800 EnterCriticalSection( &freetype_cs );
5802 for(i = 0; i < count; i++)
5804 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5805 if (pgi[i] == 0)
5807 if (!got_default)
5809 if (FT_IS_SFNT(physdev->font->ft_face))
5811 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5812 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5814 else
5816 TEXTMETRICW textm;
5817 get_text_metrics(physdev->font, &textm);
5818 default_char = textm.tmDefaultChar;
5820 got_default = TRUE;
5822 pgi[i] = default_char;
5825 LeaveCriticalSection( &freetype_cs );
5826 return count;
5829 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5831 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5832 return !memcmp(matrix, &identity, sizeof(FMAT2));
5835 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5837 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5838 return !memcmp(matrix, &identity, sizeof(MAT2));
5841 static inline BYTE get_max_level( UINT format )
5843 switch( format )
5845 case GGO_GRAY2_BITMAP: return 4;
5846 case GGO_GRAY4_BITMAP: return 16;
5847 case GGO_GRAY8_BITMAP: return 64;
5849 return 255;
5852 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5854 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5855 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5856 const MAT2* lpmat)
5858 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5859 FT_Face ft_face = incoming_font->ft_face;
5860 GdiFont *font = incoming_font;
5861 FT_UInt glyph_index;
5862 DWORD width, height, pitch, needed = 0;
5863 FT_Bitmap ft_bitmap;
5864 FT_Error err;
5865 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5866 FT_Angle angle = 0;
5867 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5868 double widthRatio = 1.0;
5869 FT_Matrix transMat = identityMat;
5870 FT_Matrix transMatUnrotated;
5871 BOOL needsTransform = FALSE;
5872 BOOL tategaki = (font->GSUB_Table != NULL);
5873 UINT original_index;
5875 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5876 buflen, buf, lpmat);
5878 TRACE("font transform %f %f %f %f\n",
5879 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5880 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5882 if(format & GGO_GLYPH_INDEX) {
5883 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5884 original_index = glyph;
5885 format &= ~GGO_GLYPH_INDEX;
5886 } else {
5887 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5888 ft_face = font->ft_face;
5889 original_index = glyph_index;
5892 if(format & GGO_UNHINTED) {
5893 load_flags |= FT_LOAD_NO_HINTING;
5894 format &= ~GGO_UNHINTED;
5897 /* tategaki never appears to happen to lower glyph index */
5898 if (glyph_index < TATEGAKI_LOWER_BOUND )
5899 tategaki = FALSE;
5901 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5902 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5903 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5904 font->gmsize * sizeof(GM*));
5905 } else {
5906 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5907 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5909 *lpgm = FONT_GM(font,original_index)->gm;
5910 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5911 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5912 lpgm->gmCellIncX, lpgm->gmCellIncY);
5913 return 1; /* FIXME */
5917 if (!font->gm[original_index / GM_BLOCK_SIZE])
5918 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5920 /* Scaling factor */
5921 if (font->aveWidth)
5923 TEXTMETRICW tm;
5925 get_text_metrics(font, &tm);
5927 widthRatio = (double)font->aveWidth;
5928 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5930 else
5931 widthRatio = font->scale_y;
5933 /* Scaling transform */
5934 if (widthRatio != 1.0 || font->scale_y != 1.0)
5936 FT_Matrix scaleMat;
5937 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5938 scaleMat.xy = 0;
5939 scaleMat.yx = 0;
5940 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5942 pFT_Matrix_Multiply(&scaleMat, &transMat);
5943 needsTransform = TRUE;
5946 /* Slant transform */
5947 if (font->fake_italic) {
5948 FT_Matrix slantMat;
5950 slantMat.xx = (1 << 16);
5951 slantMat.xy = ((1 << 16) >> 2);
5952 slantMat.yx = 0;
5953 slantMat.yy = (1 << 16);
5954 pFT_Matrix_Multiply(&slantMat, &transMat);
5955 needsTransform = TRUE;
5958 /* Rotation transform */
5959 transMatUnrotated = transMat;
5960 if(font->orientation && !tategaki) {
5961 FT_Matrix rotationMat;
5962 FT_Vector vecAngle;
5963 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5964 pFT_Vector_Unit(&vecAngle, angle);
5965 rotationMat.xx = vecAngle.x;
5966 rotationMat.xy = -vecAngle.y;
5967 rotationMat.yx = -rotationMat.xy;
5968 rotationMat.yy = rotationMat.xx;
5970 pFT_Matrix_Multiply(&rotationMat, &transMat);
5971 needsTransform = TRUE;
5974 /* World transform */
5975 if (!is_identity_FMAT2(&font->font_desc.matrix))
5977 FT_Matrix worldMat;
5978 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5979 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5980 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5981 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5982 pFT_Matrix_Multiply(&worldMat, &transMat);
5983 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5984 needsTransform = TRUE;
5987 /* Extra transformation specified by caller */
5988 if (!is_identity_MAT2(lpmat))
5990 FT_Matrix extraMat;
5991 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5992 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5993 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5994 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5995 pFT_Matrix_Multiply(&extraMat, &transMat);
5996 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5997 needsTransform = TRUE;
6000 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
6001 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
6002 format == GGO_GRAY8_BITMAP))
6004 load_flags |= FT_LOAD_NO_BITMAP;
6007 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6009 if(err) {
6010 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6011 return GDI_ERROR;
6014 if(!needsTransform) {
6015 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
6016 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
6017 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
6019 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
6020 bottom = (ft_face->glyph->metrics.horiBearingY -
6021 ft_face->glyph->metrics.height) & -64;
6022 lpgm->gmCellIncX = adv;
6023 lpgm->gmCellIncY = 0;
6024 } else {
6025 INT xc, yc;
6026 FT_Vector vec;
6028 left = right = 0;
6030 for(xc = 0; xc < 2; xc++) {
6031 for(yc = 0; yc < 2; yc++) {
6032 vec.x = (ft_face->glyph->metrics.horiBearingX +
6033 xc * ft_face->glyph->metrics.width);
6034 vec.y = ft_face->glyph->metrics.horiBearingY -
6035 yc * ft_face->glyph->metrics.height;
6036 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6037 pFT_Vector_Transform(&vec, &transMat);
6038 if(xc == 0 && yc == 0) {
6039 left = right = vec.x;
6040 top = bottom = vec.y;
6041 } else {
6042 if(vec.x < left) left = vec.x;
6043 else if(vec.x > right) right = vec.x;
6044 if(vec.y < bottom) bottom = vec.y;
6045 else if(vec.y > top) top = vec.y;
6049 left = left & -64;
6050 right = (right + 63) & -64;
6051 bottom = bottom & -64;
6052 top = (top + 63) & -64;
6054 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6055 vec.x = ft_face->glyph->metrics.horiAdvance;
6056 vec.y = 0;
6057 pFT_Vector_Transform(&vec, &transMat);
6058 lpgm->gmCellIncX = (vec.x+63) >> 6;
6059 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6061 vec.x = ft_face->glyph->metrics.horiAdvance;
6062 vec.y = 0;
6063 pFT_Vector_Transform(&vec, &transMatUnrotated);
6064 adv = (vec.x+63) >> 6;
6067 lsb = left >> 6;
6068 bbx = (right - left) >> 6;
6069 lpgm->gmBlackBoxX = (right - left) >> 6;
6070 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6071 lpgm->gmptGlyphOrigin.x = left >> 6;
6072 lpgm->gmptGlyphOrigin.y = top >> 6;
6074 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6075 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6076 lpgm->gmCellIncX, lpgm->gmCellIncY);
6078 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6079 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6081 FONT_GM(font,original_index)->gm = *lpgm;
6082 FONT_GM(font,original_index)->adv = adv;
6083 FONT_GM(font,original_index)->lsb = lsb;
6084 FONT_GM(font,original_index)->bbx = bbx;
6085 FONT_GM(font,original_index)->init = TRUE;
6088 if(format == GGO_METRICS)
6090 return 1; /* FIXME */
6093 if(ft_face->glyph->format != ft_glyph_format_outline &&
6094 (format == GGO_NATIVE || format == GGO_BEZIER))
6096 TRACE("loaded a bitmap\n");
6097 return GDI_ERROR;
6100 switch(format) {
6101 case GGO_BITMAP:
6102 width = lpgm->gmBlackBoxX;
6103 height = lpgm->gmBlackBoxY;
6104 pitch = ((width + 31) >> 5) << 2;
6105 needed = pitch * height;
6107 if(!buf || !buflen) break;
6109 switch(ft_face->glyph->format) {
6110 case ft_glyph_format_bitmap:
6112 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6113 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
6114 INT h = ft_face->glyph->bitmap.rows;
6115 while(h--) {
6116 memcpy(dst, src, w);
6117 src += ft_face->glyph->bitmap.pitch;
6118 dst += pitch;
6120 break;
6123 case ft_glyph_format_outline:
6124 ft_bitmap.width = width;
6125 ft_bitmap.rows = height;
6126 ft_bitmap.pitch = pitch;
6127 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6128 ft_bitmap.buffer = buf;
6130 if(needsTransform)
6131 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6133 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6135 /* Note: FreeType will only set 'black' bits for us. */
6136 memset(buf, 0, needed);
6137 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6138 break;
6140 default:
6141 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6142 return GDI_ERROR;
6144 break;
6146 case GGO_GRAY2_BITMAP:
6147 case GGO_GRAY4_BITMAP:
6148 case GGO_GRAY8_BITMAP:
6149 case WINE_GGO_GRAY16_BITMAP:
6151 unsigned int max_level, row, col;
6152 BYTE *start, *ptr;
6154 width = lpgm->gmBlackBoxX;
6155 height = lpgm->gmBlackBoxY;
6156 pitch = (width + 3) / 4 * 4;
6157 needed = pitch * height;
6159 if(!buf || !buflen) break;
6161 max_level = get_max_level( format );
6163 switch(ft_face->glyph->format) {
6164 case ft_glyph_format_bitmap:
6166 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6167 INT h = ft_face->glyph->bitmap.rows;
6168 INT x;
6169 memset( buf, 0, needed );
6170 while(h--) {
6171 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6172 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6173 src += ft_face->glyph->bitmap.pitch;
6174 dst += pitch;
6176 return needed;
6178 case ft_glyph_format_outline:
6180 ft_bitmap.width = width;
6181 ft_bitmap.rows = height;
6182 ft_bitmap.pitch = pitch;
6183 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6184 ft_bitmap.buffer = buf;
6186 if(needsTransform)
6187 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6189 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6191 memset(ft_bitmap.buffer, 0, buflen);
6193 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6195 if (max_level != 255)
6197 for (row = 0, start = buf; row < height; row++)
6199 for (col = 0, ptr = start; col < width; col++, ptr++)
6200 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6201 start += pitch;
6204 return needed;
6207 default:
6208 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6209 return GDI_ERROR;
6211 break;
6214 case WINE_GGO_HRGB_BITMAP:
6215 case WINE_GGO_HBGR_BITMAP:
6216 case WINE_GGO_VRGB_BITMAP:
6217 case WINE_GGO_VBGR_BITMAP:
6218 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6220 switch (ft_face->glyph->format)
6222 case FT_GLYPH_FORMAT_BITMAP:
6224 BYTE *src, *dst;
6225 INT src_pitch, x;
6227 width = lpgm->gmBlackBoxX;
6228 height = lpgm->gmBlackBoxY;
6229 pitch = width * 4;
6230 needed = pitch * height;
6232 if (!buf || !buflen) break;
6234 memset(buf, 0, buflen);
6235 dst = buf;
6236 src = ft_face->glyph->bitmap.buffer;
6237 src_pitch = ft_face->glyph->bitmap.pitch;
6239 height = min( height, ft_face->glyph->bitmap.rows );
6240 while ( height-- )
6242 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6244 if ( src[x / 8] & masks[x % 8] )
6245 ((unsigned int *)dst)[x] = ~0u;
6247 src += src_pitch;
6248 dst += pitch;
6251 break;
6254 case FT_GLYPH_FORMAT_OUTLINE:
6256 unsigned int *dst;
6257 BYTE *src;
6258 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6259 INT x_shift, y_shift;
6260 BOOL rgb;
6261 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6262 FT_Render_Mode render_mode =
6263 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6264 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6266 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6268 if ( render_mode == FT_RENDER_MODE_LCD)
6270 lpgm->gmBlackBoxX += 2;
6271 lpgm->gmptGlyphOrigin.x -= 1;
6273 else
6275 lpgm->gmBlackBoxY += 2;
6276 lpgm->gmptGlyphOrigin.y += 1;
6280 width = lpgm->gmBlackBoxX;
6281 height = lpgm->gmBlackBoxY;
6282 pitch = width * 4;
6283 needed = pitch * height;
6285 if (!buf || !buflen) break;
6287 memset(buf, 0, buflen);
6288 dst = buf;
6289 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6291 if ( needsTransform )
6292 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6294 if ( pFT_Library_SetLcdFilter )
6295 pFT_Library_SetLcdFilter( library, lcdfilter );
6296 pFT_Render_Glyph (ft_face->glyph, render_mode);
6298 src = ft_face->glyph->bitmap.buffer;
6299 src_pitch = ft_face->glyph->bitmap.pitch;
6300 src_width = ft_face->glyph->bitmap.width;
6301 src_height = ft_face->glyph->bitmap.rows;
6303 if ( render_mode == FT_RENDER_MODE_LCD)
6305 rgb_interval = 1;
6306 hmul = 3;
6307 vmul = 1;
6309 else
6311 rgb_interval = src_pitch;
6312 hmul = 1;
6313 vmul = 3;
6316 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6317 if ( x_shift < 0 ) x_shift = 0;
6318 if ( x_shift + (src_width / hmul) > width )
6319 x_shift = width - (src_width / hmul);
6321 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6322 if ( y_shift < 0 ) y_shift = 0;
6323 if ( y_shift + (src_height / vmul) > height )
6324 y_shift = height - (src_height / vmul);
6326 dst += x_shift + y_shift * ( pitch / 4 );
6327 while ( src_height )
6329 for ( x = 0; x < src_width / hmul; x++ )
6331 if ( rgb )
6333 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6334 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6335 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6336 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6338 else
6340 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6341 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6342 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6343 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6346 src += src_pitch * vmul;
6347 dst += pitch / 4;
6348 src_height -= vmul;
6351 break;
6354 default:
6355 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6356 return GDI_ERROR;
6359 break;
6361 #else
6362 return GDI_ERROR;
6363 #endif
6365 case GGO_NATIVE:
6367 int contour, point = 0, first_pt;
6368 FT_Outline *outline = &ft_face->glyph->outline;
6369 TTPOLYGONHEADER *pph;
6370 TTPOLYCURVE *ppc;
6371 DWORD pph_start, cpfx, type;
6373 if(buflen == 0) buf = NULL;
6375 if (needsTransform && buf) {
6376 pFT_Outline_Transform(outline, &transMat);
6379 for(contour = 0; contour < outline->n_contours; contour++) {
6380 pph_start = needed;
6381 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6382 first_pt = point;
6383 if(buf) {
6384 pph->dwType = TT_POLYGON_TYPE;
6385 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6387 needed += sizeof(*pph);
6388 point++;
6389 while(point <= outline->contours[contour]) {
6390 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6391 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6392 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6393 cpfx = 0;
6394 do {
6395 if(buf)
6396 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6397 cpfx++;
6398 point++;
6399 } while(point <= outline->contours[contour] &&
6400 (outline->tags[point] & FT_Curve_Tag_On) ==
6401 (outline->tags[point-1] & FT_Curve_Tag_On));
6402 /* At the end of a contour Windows adds the start point, but
6403 only for Beziers */
6404 if(point > outline->contours[contour] &&
6405 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6406 if(buf)
6407 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6408 cpfx++;
6409 } else if(point <= outline->contours[contour] &&
6410 outline->tags[point] & FT_Curve_Tag_On) {
6411 /* add closing pt for bezier */
6412 if(buf)
6413 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6414 cpfx++;
6415 point++;
6417 if(buf) {
6418 ppc->wType = type;
6419 ppc->cpfx = cpfx;
6421 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6423 if(buf)
6424 pph->cb = needed - pph_start;
6426 break;
6428 case GGO_BEZIER:
6430 /* Convert the quadratic Beziers to cubic Beziers.
6431 The parametric eqn for a cubic Bezier is, from PLRM:
6432 r(t) = at^3 + bt^2 + ct + r0
6433 with the control points:
6434 r1 = r0 + c/3
6435 r2 = r1 + (c + b)/3
6436 r3 = r0 + c + b + a
6438 A quadratic Bezier has the form:
6439 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6441 So equating powers of t leads to:
6442 r1 = 2/3 p1 + 1/3 p0
6443 r2 = 2/3 p1 + 1/3 p2
6444 and of course r0 = p0, r3 = p2
6447 int contour, point = 0, first_pt;
6448 FT_Outline *outline = &ft_face->glyph->outline;
6449 TTPOLYGONHEADER *pph;
6450 TTPOLYCURVE *ppc;
6451 DWORD pph_start, cpfx, type;
6452 FT_Vector cubic_control[4];
6453 if(buflen == 0) buf = NULL;
6455 if (needsTransform && buf) {
6456 pFT_Outline_Transform(outline, &transMat);
6459 for(contour = 0; contour < outline->n_contours; contour++) {
6460 pph_start = needed;
6461 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6462 first_pt = point;
6463 if(buf) {
6464 pph->dwType = TT_POLYGON_TYPE;
6465 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6467 needed += sizeof(*pph);
6468 point++;
6469 while(point <= outline->contours[contour]) {
6470 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6471 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6472 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6473 cpfx = 0;
6474 do {
6475 if(type == TT_PRIM_LINE) {
6476 if(buf)
6477 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6478 cpfx++;
6479 point++;
6480 } else {
6481 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6482 so cpfx = 3n */
6484 /* FIXME: Possible optimization in endpoint calculation
6485 if there are two consecutive curves */
6486 cubic_control[0] = outline->points[point-1];
6487 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6488 cubic_control[0].x += outline->points[point].x + 1;
6489 cubic_control[0].y += outline->points[point].y + 1;
6490 cubic_control[0].x >>= 1;
6491 cubic_control[0].y >>= 1;
6493 if(point+1 > outline->contours[contour])
6494 cubic_control[3] = outline->points[first_pt];
6495 else {
6496 cubic_control[3] = outline->points[point+1];
6497 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6498 cubic_control[3].x += outline->points[point].x + 1;
6499 cubic_control[3].y += outline->points[point].y + 1;
6500 cubic_control[3].x >>= 1;
6501 cubic_control[3].y >>= 1;
6504 /* r1 = 1/3 p0 + 2/3 p1
6505 r2 = 1/3 p2 + 2/3 p1 */
6506 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6507 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6508 cubic_control[2] = cubic_control[1];
6509 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6510 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6511 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6512 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6513 if(buf) {
6514 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6515 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6516 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6518 cpfx += 3;
6519 point++;
6521 } while(point <= outline->contours[contour] &&
6522 (outline->tags[point] & FT_Curve_Tag_On) ==
6523 (outline->tags[point-1] & FT_Curve_Tag_On));
6524 /* At the end of a contour Windows adds the start point,
6525 but only for Beziers and we've already done that.
6527 if(point <= outline->contours[contour] &&
6528 outline->tags[point] & FT_Curve_Tag_On) {
6529 /* This is the closing pt of a bezier, but we've already
6530 added it, so just inc point and carry on */
6531 point++;
6533 if(buf) {
6534 ppc->wType = type;
6535 ppc->cpfx = cpfx;
6537 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6539 if(buf)
6540 pph->cb = needed - pph_start;
6542 break;
6545 default:
6546 FIXME("Unsupported format %d\n", format);
6547 return GDI_ERROR;
6549 return needed;
6552 static BOOL get_bitmap_text_metrics(GdiFont *font)
6554 FT_Face ft_face = font->ft_face;
6555 FT_WinFNT_HeaderRec winfnt_header;
6556 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6557 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6558 font->potm->otmSize = size;
6560 #define TM font->potm->otmTextMetrics
6561 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6563 TM.tmHeight = winfnt_header.pixel_height;
6564 TM.tmAscent = winfnt_header.ascent;
6565 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6566 TM.tmInternalLeading = winfnt_header.internal_leading;
6567 TM.tmExternalLeading = winfnt_header.external_leading;
6568 TM.tmAveCharWidth = winfnt_header.avg_width;
6569 TM.tmMaxCharWidth = winfnt_header.max_width;
6570 TM.tmWeight = winfnt_header.weight;
6571 TM.tmOverhang = 0;
6572 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6573 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6574 TM.tmFirstChar = winfnt_header.first_char;
6575 TM.tmLastChar = winfnt_header.last_char;
6576 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6577 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6578 TM.tmItalic = winfnt_header.italic;
6579 TM.tmUnderlined = font->underline;
6580 TM.tmStruckOut = font->strikeout;
6581 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6582 TM.tmCharSet = winfnt_header.charset;
6584 else
6586 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6587 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6588 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6589 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6590 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6591 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6592 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6593 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6594 TM.tmOverhang = 0;
6595 TM.tmDigitizedAspectX = 96; /* FIXME */
6596 TM.tmDigitizedAspectY = 96; /* FIXME */
6597 TM.tmFirstChar = 1;
6598 TM.tmLastChar = 255;
6599 TM.tmDefaultChar = 32;
6600 TM.tmBreakChar = 32;
6601 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6602 TM.tmUnderlined = font->underline;
6603 TM.tmStruckOut = font->strikeout;
6604 /* NB inverted meaning of TMPF_FIXED_PITCH */
6605 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6606 TM.tmCharSet = font->charset;
6608 #undef TM
6610 return TRUE;
6614 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6616 double scale_x, scale_y;
6618 if (font->aveWidth)
6620 scale_x = (double)font->aveWidth;
6621 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6623 else
6624 scale_x = font->scale_y;
6626 scale_x *= fabs(font->font_desc.matrix.eM11);
6627 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6629 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6630 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6632 SCALE_Y(ptm->tmHeight);
6633 SCALE_Y(ptm->tmAscent);
6634 SCALE_Y(ptm->tmDescent);
6635 SCALE_Y(ptm->tmInternalLeading);
6636 SCALE_Y(ptm->tmExternalLeading);
6637 SCALE_Y(ptm->tmOverhang);
6639 SCALE_X(ptm->tmAveCharWidth);
6640 SCALE_X(ptm->tmMaxCharWidth);
6642 #undef SCALE_X
6643 #undef SCALE_Y
6646 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6648 double scale_x, scale_y;
6650 if (font->aveWidth)
6652 scale_x = (double)font->aveWidth;
6653 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6655 else
6656 scale_x = font->scale_y;
6658 scale_x *= fabs(font->font_desc.matrix.eM11);
6659 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6661 scale_font_metrics(font, &potm->otmTextMetrics);
6663 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6664 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6666 SCALE_Y(potm->otmAscent);
6667 SCALE_Y(potm->otmDescent);
6668 SCALE_Y(potm->otmLineGap);
6669 SCALE_Y(potm->otmsCapEmHeight);
6670 SCALE_Y(potm->otmsXHeight);
6671 SCALE_Y(potm->otmrcFontBox.top);
6672 SCALE_Y(potm->otmrcFontBox.bottom);
6673 SCALE_X(potm->otmrcFontBox.left);
6674 SCALE_X(potm->otmrcFontBox.right);
6675 SCALE_Y(potm->otmMacAscent);
6676 SCALE_Y(potm->otmMacDescent);
6677 SCALE_Y(potm->otmMacLineGap);
6678 SCALE_X(potm->otmptSubscriptSize.x);
6679 SCALE_Y(potm->otmptSubscriptSize.y);
6680 SCALE_X(potm->otmptSubscriptOffset.x);
6681 SCALE_Y(potm->otmptSubscriptOffset.y);
6682 SCALE_X(potm->otmptSuperscriptSize.x);
6683 SCALE_Y(potm->otmptSuperscriptSize.y);
6684 SCALE_X(potm->otmptSuperscriptOffset.x);
6685 SCALE_Y(potm->otmptSuperscriptOffset.y);
6686 SCALE_Y(potm->otmsStrikeoutSize);
6687 SCALE_Y(potm->otmsStrikeoutPosition);
6688 SCALE_Y(potm->otmsUnderscoreSize);
6689 SCALE_Y(potm->otmsUnderscorePosition);
6691 #undef SCALE_X
6692 #undef SCALE_Y
6695 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6697 if(!font->potm)
6699 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6701 /* Make sure that the font has sane width/height ratio */
6702 if (font->aveWidth)
6704 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6706 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6707 font->aveWidth = 0;
6711 *ptm = font->potm->otmTextMetrics;
6712 scale_font_metrics(font, ptm);
6713 return TRUE;
6716 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6718 int i;
6720 for(i = 0; i < ft_face->num_charmaps; i++)
6722 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6723 return TRUE;
6725 return FALSE;
6728 static BOOL get_outline_text_metrics(GdiFont *font)
6730 BOOL ret = FALSE;
6731 FT_Face ft_face = font->ft_face;
6732 UINT needed, lenfam, lensty, lenface, lenfull;
6733 TT_OS2 *pOS2;
6734 TT_HoriHeader *pHori;
6735 TT_Postscript *pPost;
6736 FT_Fixed x_scale, y_scale;
6737 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6738 char *cp;
6739 INT ascent, descent;
6741 TRACE("font=%p\n", font);
6743 if(!FT_IS_SCALABLE(ft_face))
6744 return FALSE;
6746 needed = sizeof(*font->potm);
6748 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6749 family_nameW = strdupW(font->name);
6751 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6752 if (!style_nameW)
6753 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6754 if (!style_nameW)
6756 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6757 style_nameW = towstr( CP_ACP, ft_face->style_name );
6759 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6761 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6762 if (!face_nameW)
6763 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6764 if (!face_nameW)
6766 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6767 face_nameW = strdupW(font->name);
6769 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6770 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6772 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6773 if (!full_nameW)
6774 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6775 if (!full_nameW)
6777 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6778 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6779 full_nameW = strdupW(fake_nameW);
6781 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6783 /* These names should be read from the TT name table */
6785 /* length of otmpFamilyName */
6786 needed += lenfam;
6788 /* length of otmpFaceName */
6789 needed += lenface;
6791 /* length of otmpStyleName */
6792 needed += lensty;
6794 /* length of otmpFullName */
6795 needed += lenfull;
6798 x_scale = ft_face->size->metrics.x_scale;
6799 y_scale = ft_face->size->metrics.y_scale;
6801 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6802 if(!pOS2) {
6803 FIXME("Can't find OS/2 table - not TT font?\n");
6804 goto end;
6807 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6808 if(!pHori) {
6809 FIXME("Can't find HHEA table - not TT font?\n");
6810 goto end;
6813 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6815 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6816 pOS2->usWinAscent, pOS2->usWinDescent,
6817 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6818 pOS2->xAvgCharWidth,
6819 ft_face->ascender, ft_face->descender, ft_face->height,
6820 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6821 ft_face->bbox.yMax, ft_face->bbox.yMin);
6823 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6824 font->potm->otmSize = needed;
6826 #define TM font->potm->otmTextMetrics
6828 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6829 ascent = pHori->Ascender;
6830 descent = -pHori->Descender;
6831 } else {
6832 ascent = pOS2->usWinAscent;
6833 descent = pOS2->usWinDescent;
6836 font->ntmCellHeight = ascent + descent;
6837 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6839 if(font->yMax) {
6840 TM.tmAscent = font->yMax;
6841 TM.tmDescent = -font->yMin;
6842 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6843 } else {
6844 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6845 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6846 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6847 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6850 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6852 /* MSDN says:
6853 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6855 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6856 ((ascent + descent) -
6857 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6859 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6860 if (TM.tmAveCharWidth == 0) {
6861 TM.tmAveCharWidth = 1;
6863 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6864 TM.tmWeight = FW_REGULAR;
6865 if (font->fake_bold)
6866 TM.tmWeight = FW_BOLD;
6867 else
6869 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6871 if (pOS2->usWeightClass > FW_MEDIUM)
6872 TM.tmWeight = pOS2->usWeightClass;
6874 else if (pOS2->usWeightClass <= FW_MEDIUM)
6875 TM.tmWeight = pOS2->usWeightClass;
6877 TM.tmOverhang = 0;
6878 TM.tmDigitizedAspectX = 96; /* FIXME */
6879 TM.tmDigitizedAspectY = 96; /* FIXME */
6880 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6881 * symbol range to 0 - f0ff
6884 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6886 TM.tmFirstChar = 0;
6887 switch(GetACP())
6889 case 1257: /* Baltic */
6890 TM.tmLastChar = 0xf8fd;
6891 break;
6892 default:
6893 TM.tmLastChar = 0xf0ff;
6895 TM.tmBreakChar = 0x20;
6896 TM.tmDefaultChar = 0x1f;
6898 else
6900 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6901 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6903 if(pOS2->usFirstCharIndex <= 1)
6904 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6905 else if (pOS2->usFirstCharIndex > 0xff)
6906 TM.tmBreakChar = 0x20;
6907 else
6908 TM.tmBreakChar = pOS2->usFirstCharIndex;
6909 TM.tmDefaultChar = TM.tmBreakChar - 1;
6911 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6912 TM.tmUnderlined = font->underline;
6913 TM.tmStruckOut = font->strikeout;
6915 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6916 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6917 (pOS2->version == 0xFFFFU ||
6918 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6919 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6920 else
6921 TM.tmPitchAndFamily = 0;
6923 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6925 case PAN_FAMILY_SCRIPT:
6926 TM.tmPitchAndFamily |= FF_SCRIPT;
6927 break;
6929 case PAN_FAMILY_DECORATIVE:
6930 TM.tmPitchAndFamily |= FF_DECORATIVE;
6931 break;
6933 case PAN_ANY:
6934 case PAN_NO_FIT:
6935 case PAN_FAMILY_TEXT_DISPLAY:
6936 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6937 /* which is clearly not what the panose spec says. */
6938 default:
6939 if(TM.tmPitchAndFamily == 0 || /* fixed */
6940 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6941 TM.tmPitchAndFamily = FF_MODERN;
6942 else
6944 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6946 case PAN_ANY:
6947 case PAN_NO_FIT:
6948 default:
6949 TM.tmPitchAndFamily |= FF_DONTCARE;
6950 break;
6952 case PAN_SERIF_COVE:
6953 case PAN_SERIF_OBTUSE_COVE:
6954 case PAN_SERIF_SQUARE_COVE:
6955 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6956 case PAN_SERIF_SQUARE:
6957 case PAN_SERIF_THIN:
6958 case PAN_SERIF_BONE:
6959 case PAN_SERIF_EXAGGERATED:
6960 case PAN_SERIF_TRIANGLE:
6961 TM.tmPitchAndFamily |= FF_ROMAN;
6962 break;
6964 case PAN_SERIF_NORMAL_SANS:
6965 case PAN_SERIF_OBTUSE_SANS:
6966 case PAN_SERIF_PERP_SANS:
6967 case PAN_SERIF_FLARED:
6968 case PAN_SERIF_ROUNDED:
6969 TM.tmPitchAndFamily |= FF_SWISS;
6970 break;
6973 break;
6976 if(FT_IS_SCALABLE(ft_face))
6977 TM.tmPitchAndFamily |= TMPF_VECTOR;
6979 if(FT_IS_SFNT(ft_face))
6981 if (font->ntmFlags & NTM_PS_OPENTYPE)
6982 TM.tmPitchAndFamily |= TMPF_DEVICE;
6983 else
6984 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6987 TM.tmCharSet = font->charset;
6989 font->potm->otmFiller = 0;
6990 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6991 font->potm->otmfsSelection = pOS2->fsSelection;
6992 font->potm->otmfsType = pOS2->fsType;
6993 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6994 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6995 font->potm->otmItalicAngle = 0; /* POST table */
6996 font->potm->otmEMSquare = ft_face->units_per_EM;
6997 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6998 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6999 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
7000 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
7001 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
7002 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
7003 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
7004 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
7005 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
7006 font->potm->otmMacAscent = TM.tmAscent;
7007 font->potm->otmMacDescent = -TM.tmDescent;
7008 font->potm->otmMacLineGap = font->potm->otmLineGap;
7009 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7010 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
7011 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
7012 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
7013 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
7014 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
7015 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
7016 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
7017 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
7018 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
7019 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
7020 if(!pPost) {
7021 font->potm->otmsUnderscoreSize = 0;
7022 font->potm->otmsUnderscorePosition = 0;
7023 } else {
7024 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
7025 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
7027 #undef TM
7029 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7030 cp = (char*)font->potm + sizeof(*font->potm);
7031 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7032 strcpyW((WCHAR*)cp, family_nameW);
7033 cp += lenfam;
7034 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7035 strcpyW((WCHAR*)cp, style_nameW);
7036 cp += lensty;
7037 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7038 strcpyW((WCHAR*)cp, face_nameW);
7039 cp += lenface;
7040 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7041 strcpyW((WCHAR*)cp, full_nameW);
7042 ret = TRUE;
7044 end:
7045 HeapFree(GetProcessHeap(), 0, style_nameW);
7046 HeapFree(GetProcessHeap(), 0, family_nameW);
7047 HeapFree(GetProcessHeap(), 0, face_nameW);
7048 HeapFree(GetProcessHeap(), 0, full_nameW);
7049 return ret;
7052 /*************************************************************
7053 * freetype_GetGlyphOutline
7055 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7056 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7058 struct freetype_physdev *physdev = get_freetype_dev( dev );
7059 DWORD ret;
7061 if (!physdev->font)
7063 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7064 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7067 GDI_CheckNotLock();
7068 EnterCriticalSection( &freetype_cs );
7069 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
7070 LeaveCriticalSection( &freetype_cs );
7071 return ret;
7074 /*************************************************************
7075 * freetype_GetTextMetrics
7077 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7079 struct freetype_physdev *physdev = get_freetype_dev( dev );
7080 BOOL ret;
7082 if (!physdev->font)
7084 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7085 return dev->funcs->pGetTextMetrics( dev, metrics );
7088 GDI_CheckNotLock();
7089 EnterCriticalSection( &freetype_cs );
7090 ret = get_text_metrics( physdev->font, metrics );
7091 LeaveCriticalSection( &freetype_cs );
7092 return ret;
7095 /*************************************************************
7096 * freetype_GetOutlineTextMetrics
7098 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7100 struct freetype_physdev *physdev = get_freetype_dev( dev );
7101 UINT ret = 0;
7103 if (!physdev->font)
7105 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7106 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7109 TRACE("font=%p\n", physdev->font);
7111 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7113 GDI_CheckNotLock();
7114 EnterCriticalSection( &freetype_cs );
7116 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7118 if(cbSize >= physdev->font->potm->otmSize)
7120 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7121 scale_outline_font_metrics(physdev->font, potm);
7123 ret = physdev->font->potm->otmSize;
7125 LeaveCriticalSection( &freetype_cs );
7126 return ret;
7129 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7131 HFONTLIST *hfontlist;
7132 child->font = alloc_font();
7133 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7134 if(!child->font->ft_face)
7136 free_font(child->font);
7137 child->font = NULL;
7138 return FALSE;
7141 child->font->font_desc = font->font_desc;
7142 child->font->ntmFlags = child->face->ntmFlags;
7143 child->font->orientation = font->orientation;
7144 child->font->scale_y = font->scale_y;
7145 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
7146 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
7147 child->font->name = strdupW(child->face->family->FamilyName);
7148 list_add_head(&child->font->hfontlist, &hfontlist->entry);
7149 child->font->base_font = font;
7150 list_add_head(&child_font_list, &child->font->entry);
7151 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
7152 return TRUE;
7155 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7157 FT_UInt g;
7158 CHILD_FONT *child_font;
7160 if(font->base_font)
7161 font = font->base_font;
7163 *linked_font = font;
7165 if((*glyph = get_glyph_index(font, c)))
7167 *glyph = get_GSUB_vert_glyph(font, *glyph);
7168 return TRUE;
7171 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7173 if(!child_font->font)
7174 if(!load_child_font(font, child_font))
7175 continue;
7177 if(!child_font->font->ft_face)
7178 continue;
7179 g = get_glyph_index(child_font->font, c);
7180 g = get_GSUB_vert_glyph(child_font->font, g);
7181 if(g)
7183 *glyph = g;
7184 *linked_font = child_font->font;
7185 return TRUE;
7188 return FALSE;
7191 /*************************************************************
7192 * freetype_GetCharWidth
7194 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7196 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7197 UINT c;
7198 GLYPHMETRICS gm;
7199 FT_UInt glyph_index;
7200 GdiFont *linked_font;
7201 struct freetype_physdev *physdev = get_freetype_dev( dev );
7203 if (!physdev->font)
7205 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7206 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7209 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7211 GDI_CheckNotLock();
7212 EnterCriticalSection( &freetype_cs );
7213 for(c = firstChar; c <= lastChar; c++) {
7214 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7215 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7216 &gm, 0, NULL, &identity);
7217 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7219 LeaveCriticalSection( &freetype_cs );
7220 return TRUE;
7223 /*************************************************************
7224 * freetype_GetCharABCWidths
7226 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7228 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7229 UINT c;
7230 GLYPHMETRICS gm;
7231 FT_UInt glyph_index;
7232 GdiFont *linked_font;
7233 struct freetype_physdev *physdev = get_freetype_dev( dev );
7235 if (!physdev->font)
7237 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7238 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7241 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7243 GDI_CheckNotLock();
7244 EnterCriticalSection( &freetype_cs );
7246 for(c = firstChar; c <= lastChar; c++) {
7247 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7248 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7249 &gm, 0, NULL, &identity);
7250 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7251 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7252 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7253 FONT_GM(linked_font,glyph_index)->bbx;
7255 LeaveCriticalSection( &freetype_cs );
7256 return TRUE;
7259 /*************************************************************
7260 * freetype_GetCharABCWidthsI
7262 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7264 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7265 UINT c;
7266 GLYPHMETRICS gm;
7267 FT_UInt glyph_index;
7268 GdiFont *linked_font;
7269 struct freetype_physdev *physdev = get_freetype_dev( dev );
7271 if (!physdev->font)
7273 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7274 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7277 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7278 return FALSE;
7280 GDI_CheckNotLock();
7281 EnterCriticalSection( &freetype_cs );
7283 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7284 if (!pgi)
7285 for(c = firstChar; c < firstChar+count; c++) {
7286 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7287 &gm, 0, NULL, &identity);
7288 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7289 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7290 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7291 - FONT_GM(linked_font,c)->bbx;
7293 else
7294 for(c = 0; c < count; c++) {
7295 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7296 &gm, 0, NULL, &identity);
7297 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7298 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7299 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7300 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7303 LeaveCriticalSection( &freetype_cs );
7304 return TRUE;
7307 /*************************************************************
7308 * freetype_GetTextExtentExPoint
7310 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7311 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7313 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7314 INT idx;
7315 INT nfit = 0, ext;
7316 GLYPHMETRICS gm;
7317 TEXTMETRICW tm;
7318 FT_UInt glyph_index;
7319 GdiFont *linked_font;
7320 struct freetype_physdev *physdev = get_freetype_dev( dev );
7322 if (!physdev->font)
7324 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7325 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7328 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7330 GDI_CheckNotLock();
7331 EnterCriticalSection( &freetype_cs );
7333 size->cx = 0;
7334 get_text_metrics( physdev->font, &tm );
7335 size->cy = tm.tmHeight;
7337 for(idx = 0; idx < count; idx++) {
7338 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7339 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7340 &gm, 0, NULL, &identity);
7341 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7342 ext = size->cx;
7343 if (! pnfit || ext <= max_ext) {
7344 ++nfit;
7345 if (dxs)
7346 dxs[idx] = ext;
7350 if (pnfit)
7351 *pnfit = nfit;
7353 LeaveCriticalSection( &freetype_cs );
7354 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7355 return TRUE;
7358 /*************************************************************
7359 * freetype_GetTextExtentExPointI
7361 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7362 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7364 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7365 INT idx;
7366 INT nfit = 0, ext;
7367 GLYPHMETRICS gm;
7368 TEXTMETRICW tm;
7369 struct freetype_physdev *physdev = get_freetype_dev( dev );
7371 if (!physdev->font)
7373 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7374 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7377 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7379 GDI_CheckNotLock();
7380 EnterCriticalSection( &freetype_cs );
7382 size->cx = 0;
7383 get_text_metrics(physdev->font, &tm);
7384 size->cy = tm.tmHeight;
7386 for(idx = 0; idx < count; idx++) {
7387 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7388 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7389 ext = size->cx;
7390 if (! pnfit || ext <= max_ext) {
7391 ++nfit;
7392 if (dxs)
7393 dxs[idx] = ext;
7397 if (pnfit)
7398 *pnfit = nfit;
7400 LeaveCriticalSection( &freetype_cs );
7401 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7402 return TRUE;
7405 /*************************************************************
7406 * freetype_GetFontData
7408 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7410 struct freetype_physdev *physdev = get_freetype_dev( dev );
7412 if (!physdev->font)
7414 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7415 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7418 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7419 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7420 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7422 return get_font_data( physdev->font, table, offset, buf, cbData );
7425 /*************************************************************
7426 * freetype_GetTextFace
7428 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7430 INT n;
7431 struct freetype_physdev *physdev = get_freetype_dev( dev );
7433 if (!physdev->font)
7435 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7436 return dev->funcs->pGetTextFace( dev, count, str );
7439 n = strlenW(physdev->font->name) + 1;
7440 if (str)
7442 lstrcpynW(str, physdev->font->name, count);
7443 n = min(count, n);
7445 return n;
7448 /*************************************************************
7449 * freetype_GetTextCharsetInfo
7451 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7453 struct freetype_physdev *physdev = get_freetype_dev( dev );
7455 if (!physdev->font)
7457 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7458 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7460 if (fs) *fs = physdev->font->fs;
7461 return physdev->font->charset;
7464 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7466 GdiFont *font = dc->gdiFont, *linked_font;
7467 struct list *first_hfont;
7468 BOOL ret;
7470 GDI_CheckNotLock();
7471 EnterCriticalSection( &freetype_cs );
7472 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7473 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7474 if(font == linked_font)
7475 *new_hfont = dc->hFont;
7476 else
7478 first_hfont = list_head(&linked_font->hfontlist);
7479 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7481 LeaveCriticalSection( &freetype_cs );
7482 return ret;
7485 /* Retrieve a list of supported Unicode ranges for a given font.
7486 * Can be called with NULL gs to calculate the buffer size. Returns
7487 * the number of ranges found.
7489 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7491 DWORD num_ranges = 0;
7493 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7495 FT_UInt glyph_code;
7496 FT_ULong char_code, char_code_prev;
7498 glyph_code = 0;
7499 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7501 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7502 face->num_glyphs, glyph_code, char_code);
7504 if (!glyph_code) return 0;
7506 if (gs)
7508 gs->ranges[0].wcLow = (USHORT)char_code;
7509 gs->ranges[0].cGlyphs = 0;
7510 gs->cGlyphsSupported = 0;
7513 num_ranges = 1;
7514 while (glyph_code)
7516 if (char_code < char_code_prev)
7518 ERR("expected increasing char code from FT_Get_Next_Char\n");
7519 return 0;
7521 if (char_code - char_code_prev > 1)
7523 num_ranges++;
7524 if (gs)
7526 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7527 gs->ranges[num_ranges - 1].cGlyphs = 1;
7528 gs->cGlyphsSupported++;
7531 else if (gs)
7533 gs->ranges[num_ranges - 1].cGlyphs++;
7534 gs->cGlyphsSupported++;
7536 char_code_prev = char_code;
7537 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7540 else
7541 FIXME("encoding %u not supported\n", face->charmap->encoding);
7543 return num_ranges;
7546 /*************************************************************
7547 * freetype_GetFontUnicodeRanges
7549 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7551 struct freetype_physdev *physdev = get_freetype_dev( dev );
7552 DWORD size, num_ranges;
7554 if (!physdev->font)
7556 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7557 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7560 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7561 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7562 if (glyphset)
7564 glyphset->cbThis = size;
7565 glyphset->cRanges = num_ranges;
7566 glyphset->flAccel = 0;
7568 return size;
7571 /*************************************************************
7572 * freetype_FontIsLinked
7574 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7576 struct freetype_physdev *physdev = get_freetype_dev( dev );
7577 BOOL ret;
7579 if (!physdev->font)
7581 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7582 return dev->funcs->pFontIsLinked( dev );
7585 GDI_CheckNotLock();
7586 EnterCriticalSection( &freetype_cs );
7587 ret = !list_empty(&physdev->font->child_fonts);
7588 LeaveCriticalSection( &freetype_cs );
7589 return ret;
7592 /*************************************************************************
7593 * GetRasterizerCaps (GDI32.@)
7595 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7597 lprs->nSize = sizeof(RASTERIZER_STATUS);
7598 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7599 lprs->nLanguageID = 0;
7600 return TRUE;
7603 /*************************************************************
7604 * freetype_GdiRealizationInfo
7606 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7608 struct freetype_physdev *physdev = get_freetype_dev( dev );
7609 realization_info_t *info = ptr;
7611 if (!physdev->font)
7613 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7614 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7617 FIXME("(%p, %p): stub!\n", physdev->font, info);
7619 info->flags = 1;
7620 if(FT_IS_SCALABLE(physdev->font->ft_face))
7621 info->flags |= 2;
7623 info->cache_num = physdev->font->cache_num;
7624 info->unknown2 = -1;
7625 return TRUE;
7628 /*************************************************************************
7629 * Kerning support for TrueType fonts
7631 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7633 struct TT_kern_table
7635 USHORT version;
7636 USHORT nTables;
7639 struct TT_kern_subtable
7641 USHORT version;
7642 USHORT length;
7643 union
7645 USHORT word;
7646 struct
7648 USHORT horizontal : 1;
7649 USHORT minimum : 1;
7650 USHORT cross_stream: 1;
7651 USHORT override : 1;
7652 USHORT reserved1 : 4;
7653 USHORT format : 8;
7654 } bits;
7655 } coverage;
7658 struct TT_format0_kern_subtable
7660 USHORT nPairs;
7661 USHORT searchRange;
7662 USHORT entrySelector;
7663 USHORT rangeShift;
7666 struct TT_kern_pair
7668 USHORT left;
7669 USHORT right;
7670 short value;
7673 static DWORD parse_format0_kern_subtable(GdiFont *font,
7674 const struct TT_format0_kern_subtable *tt_f0_ks,
7675 const USHORT *glyph_to_char,
7676 KERNINGPAIR *kern_pair, DWORD cPairs)
7678 USHORT i, nPairs;
7679 const struct TT_kern_pair *tt_kern_pair;
7681 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7683 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7685 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7686 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7687 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7689 if (!kern_pair || !cPairs)
7690 return nPairs;
7692 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7694 nPairs = min(nPairs, cPairs);
7696 for (i = 0; i < nPairs; i++)
7698 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7699 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7700 /* this algorithm appears to better match what Windows does */
7701 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7702 if (kern_pair->iKernAmount < 0)
7704 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7705 kern_pair->iKernAmount -= font->ppem;
7707 else if (kern_pair->iKernAmount > 0)
7709 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7710 kern_pair->iKernAmount += font->ppem;
7712 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7714 TRACE("left %u right %u value %d\n",
7715 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7717 kern_pair++;
7719 TRACE("copied %u entries\n", nPairs);
7720 return nPairs;
7723 /*************************************************************
7724 * freetype_GetKerningPairs
7726 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7728 DWORD length;
7729 void *buf;
7730 const struct TT_kern_table *tt_kern_table;
7731 const struct TT_kern_subtable *tt_kern_subtable;
7732 USHORT i, nTables;
7733 USHORT *glyph_to_char;
7734 GdiFont *font;
7735 struct freetype_physdev *physdev = get_freetype_dev( dev );
7737 if (!(font = physdev->font))
7739 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7740 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7743 GDI_CheckNotLock();
7744 EnterCriticalSection( &freetype_cs );
7745 if (font->total_kern_pairs != (DWORD)-1)
7747 if (cPairs && kern_pair)
7749 cPairs = min(cPairs, font->total_kern_pairs);
7750 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7752 else cPairs = font->total_kern_pairs;
7754 LeaveCriticalSection( &freetype_cs );
7755 return cPairs;
7758 font->total_kern_pairs = 0;
7760 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7762 if (length == GDI_ERROR)
7764 TRACE("no kerning data in the font\n");
7765 LeaveCriticalSection( &freetype_cs );
7766 return 0;
7769 buf = HeapAlloc(GetProcessHeap(), 0, length);
7770 if (!buf)
7772 WARN("Out of memory\n");
7773 LeaveCriticalSection( &freetype_cs );
7774 return 0;
7777 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7779 /* build a glyph index to char code map */
7780 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7781 if (!glyph_to_char)
7783 WARN("Out of memory allocating a glyph index to char code map\n");
7784 HeapFree(GetProcessHeap(), 0, buf);
7785 LeaveCriticalSection( &freetype_cs );
7786 return 0;
7789 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7791 FT_UInt glyph_code;
7792 FT_ULong char_code;
7794 glyph_code = 0;
7795 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7797 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7798 font->ft_face->num_glyphs, glyph_code, char_code);
7800 while (glyph_code)
7802 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7804 /* FIXME: This doesn't match what Windows does: it does some fancy
7805 * things with duplicate glyph index to char code mappings, while
7806 * we just avoid overriding existing entries.
7808 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7809 glyph_to_char[glyph_code] = (USHORT)char_code;
7811 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7814 else
7816 ULONG n;
7818 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7819 for (n = 0; n <= 65535; n++)
7820 glyph_to_char[n] = (USHORT)n;
7823 tt_kern_table = buf;
7824 nTables = GET_BE_WORD(tt_kern_table->nTables);
7825 TRACE("version %u, nTables %u\n",
7826 GET_BE_WORD(tt_kern_table->version), nTables);
7828 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7830 for (i = 0; i < nTables; i++)
7832 struct TT_kern_subtable tt_kern_subtable_copy;
7834 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7835 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7836 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7838 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7839 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7840 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7842 /* According to the TrueType specification this is the only format
7843 * that will be properly interpreted by Windows and OS/2
7845 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7847 DWORD new_chunk, old_total = font->total_kern_pairs;
7849 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7850 glyph_to_char, NULL, 0);
7851 font->total_kern_pairs += new_chunk;
7853 if (!font->kern_pairs)
7854 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7855 font->total_kern_pairs * sizeof(*font->kern_pairs));
7856 else
7857 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7858 font->total_kern_pairs * sizeof(*font->kern_pairs));
7860 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7861 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7863 else
7864 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7866 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7869 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7870 HeapFree(GetProcessHeap(), 0, buf);
7872 if (cPairs && kern_pair)
7874 cPairs = min(cPairs, font->total_kern_pairs);
7875 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7877 else cPairs = font->total_kern_pairs;
7879 LeaveCriticalSection( &freetype_cs );
7880 return cPairs;
7883 static const struct gdi_dc_funcs freetype_funcs =
7885 NULL, /* pAbortDoc */
7886 NULL, /* pAbortPath */
7887 NULL, /* pAlphaBlend */
7888 NULL, /* pAngleArc */
7889 NULL, /* pArc */
7890 NULL, /* pArcTo */
7891 NULL, /* pBeginPath */
7892 NULL, /* pBlendImage */
7893 NULL, /* pChord */
7894 NULL, /* pCloseFigure */
7895 NULL, /* pCreateCompatibleDC */
7896 freetype_CreateDC, /* pCreateDC */
7897 freetype_DeleteDC, /* pDeleteDC */
7898 NULL, /* pDeleteObject */
7899 NULL, /* pDeviceCapabilities */
7900 NULL, /* pEllipse */
7901 NULL, /* pEndDoc */
7902 NULL, /* pEndPage */
7903 NULL, /* pEndPath */
7904 freetype_EnumFonts, /* pEnumFonts */
7905 NULL, /* pEnumICMProfiles */
7906 NULL, /* pExcludeClipRect */
7907 NULL, /* pExtDeviceMode */
7908 NULL, /* pExtEscape */
7909 NULL, /* pExtFloodFill */
7910 NULL, /* pExtSelectClipRgn */
7911 NULL, /* pExtTextOut */
7912 NULL, /* pFillPath */
7913 NULL, /* pFillRgn */
7914 NULL, /* pFlattenPath */
7915 freetype_FontIsLinked, /* pFontIsLinked */
7916 NULL, /* pFrameRgn */
7917 NULL, /* pGdiComment */
7918 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7919 NULL, /* pGetBoundsRect */
7920 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7921 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7922 freetype_GetCharWidth, /* pGetCharWidth */
7923 NULL, /* pGetDeviceCaps */
7924 NULL, /* pGetDeviceGammaRamp */
7925 freetype_GetFontData, /* pGetFontData */
7926 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7927 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7928 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7929 NULL, /* pGetICMProfile */
7930 NULL, /* pGetImage */
7931 freetype_GetKerningPairs, /* pGetKerningPairs */
7932 NULL, /* pGetNearestColor */
7933 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7934 NULL, /* pGetPixel */
7935 NULL, /* pGetSystemPaletteEntries */
7936 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7937 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7938 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7939 freetype_GetTextFace, /* pGetTextFace */
7940 freetype_GetTextMetrics, /* pGetTextMetrics */
7941 NULL, /* pGradientFill */
7942 NULL, /* pIntersectClipRect */
7943 NULL, /* pInvertRgn */
7944 NULL, /* pLineTo */
7945 NULL, /* pModifyWorldTransform */
7946 NULL, /* pMoveTo */
7947 NULL, /* pOffsetClipRgn */
7948 NULL, /* pOffsetViewportOrg */
7949 NULL, /* pOffsetWindowOrg */
7950 NULL, /* pPaintRgn */
7951 NULL, /* pPatBlt */
7952 NULL, /* pPie */
7953 NULL, /* pPolyBezier */
7954 NULL, /* pPolyBezierTo */
7955 NULL, /* pPolyDraw */
7956 NULL, /* pPolyPolygon */
7957 NULL, /* pPolyPolyline */
7958 NULL, /* pPolygon */
7959 NULL, /* pPolyline */
7960 NULL, /* pPolylineTo */
7961 NULL, /* pPutImage */
7962 NULL, /* pRealizeDefaultPalette */
7963 NULL, /* pRealizePalette */
7964 NULL, /* pRectangle */
7965 NULL, /* pResetDC */
7966 NULL, /* pRestoreDC */
7967 NULL, /* pRoundRect */
7968 NULL, /* pSaveDC */
7969 NULL, /* pScaleViewportExt */
7970 NULL, /* pScaleWindowExt */
7971 NULL, /* pSelectBitmap */
7972 NULL, /* pSelectBrush */
7973 NULL, /* pSelectClipPath */
7974 freetype_SelectFont, /* pSelectFont */
7975 NULL, /* pSelectPalette */
7976 NULL, /* pSelectPen */
7977 NULL, /* pSetArcDirection */
7978 NULL, /* pSetBkColor */
7979 NULL, /* pSetBkMode */
7980 NULL, /* pSetDCBrushColor */
7981 NULL, /* pSetDCPenColor */
7982 NULL, /* pSetDIBColorTable */
7983 NULL, /* pSetDIBitsToDevice */
7984 NULL, /* pSetDeviceClipping */
7985 NULL, /* pSetDeviceGammaRamp */
7986 NULL, /* pSetLayout */
7987 NULL, /* pSetMapMode */
7988 NULL, /* pSetMapperFlags */
7989 NULL, /* pSetPixel */
7990 NULL, /* pSetPolyFillMode */
7991 NULL, /* pSetROP2 */
7992 NULL, /* pSetRelAbs */
7993 NULL, /* pSetStretchBltMode */
7994 NULL, /* pSetTextAlign */
7995 NULL, /* pSetTextCharacterExtra */
7996 NULL, /* pSetTextColor */
7997 NULL, /* pSetTextJustification */
7998 NULL, /* pSetViewportExt */
7999 NULL, /* pSetViewportOrg */
8000 NULL, /* pSetWindowExt */
8001 NULL, /* pSetWindowOrg */
8002 NULL, /* pSetWorldTransform */
8003 NULL, /* pStartDoc */
8004 NULL, /* pStartPage */
8005 NULL, /* pStretchBlt */
8006 NULL, /* pStretchDIBits */
8007 NULL, /* pStrokeAndFillPath */
8008 NULL, /* pStrokePath */
8009 NULL, /* pUnrealizePalette */
8010 NULL, /* pWidenPath */
8011 NULL, /* wine_get_wgl_driver */
8012 GDI_PRIORITY_FONT_DRV /* priority */
8015 #else /* HAVE_FREETYPE */
8017 /*************************************************************************/
8019 BOOL WineEngInit(void)
8021 return FALSE;
8023 BOOL WineEngDestroyFontInstance(HFONT hfont)
8025 return FALSE;
8028 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8030 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8031 return 1;
8034 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8036 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8037 return TRUE;
8040 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8042 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8043 return NULL;
8046 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8047 LPCWSTR font_file, LPCWSTR font_path )
8049 FIXME("stub\n");
8050 return FALSE;
8053 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
8055 return FALSE;
8058 /*************************************************************************
8059 * GetRasterizerCaps (GDI32.@)
8061 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8063 lprs->nSize = sizeof(RASTERIZER_STATUS);
8064 lprs->wFlags = 0;
8065 lprs->nLanguageID = 0;
8066 return TRUE;
8069 #endif /* HAVE_FREETYPE */