gdi32: Fixed loop end setting (Coverity).
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob06350be955514b6d79435d80b1a6c2276502c60c
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(FcConfigGetCurrent);
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(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 FONTSIGNATURE fs_links;
269 DWORD ntmFlags;
270 FT_Fixed font_version;
271 BOOL scalable;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
283 struct list faces;
284 } Family;
286 typedef struct {
287 GLYPHMETRICS gm;
288 INT adv; /* These three hold to widths of the unrotated chars */
289 INT lsb;
290 INT bbx;
291 BOOL init;
292 } GM;
294 typedef struct {
295 FLOAT eM11, eM12;
296 FLOAT eM21, eM22;
297 } FMAT2;
299 typedef struct {
300 DWORD hash;
301 LOGFONTW lf;
302 FMAT2 matrix;
303 BOOL can_use_bitmap;
304 } FONT_DESC;
306 typedef struct tagHFONTLIST {
307 struct list entry;
308 HFONT hfont;
309 } HFONTLIST;
311 typedef struct {
312 struct list entry;
313 Face *face;
314 GdiFont *font;
315 } CHILD_FONT;
317 struct tagGdiFont {
318 struct list entry;
319 GM **gm;
320 DWORD gmsize;
321 struct list hfontlist;
322 OUTLINETEXTMETRICW *potm;
323 DWORD total_kern_pairs;
324 KERNINGPAIR *kern_pairs;
325 struct list child_fonts;
327 /* the following members can be accessed without locking, they are never modified after creation */
328 FT_Face ft_face;
329 struct font_mapping *mapping;
330 LPWSTR name;
331 int charset;
332 int codepage;
333 BOOL fake_italic;
334 BOOL fake_bold;
335 BYTE underline;
336 BYTE strikeout;
337 INT orientation;
338 FONT_DESC font_desc;
339 LONG aveWidth, ppem;
340 double scale_y;
341 SHORT yMax;
342 SHORT yMin;
343 DWORD ntmFlags;
344 FONTSIGNATURE fs;
345 GdiFont *base_font;
346 VOID *GSUB_Table;
347 DWORD cache_num;
350 typedef struct {
351 struct list entry;
352 const WCHAR *font_name;
353 struct list links;
354 } SYSTEM_LINKS;
356 struct enum_charset_element {
357 DWORD mask;
358 DWORD charset;
359 WCHAR name[LF_FACESIZE];
362 struct enum_charset_list {
363 DWORD total;
364 struct enum_charset_element element[32];
367 #define GM_BLOCK_SIZE 128
368 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
370 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
371 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
372 #define UNUSED_CACHE_SIZE 10
373 static struct list child_font_list = LIST_INIT(child_font_list);
374 static struct list system_links = LIST_INIT(system_links);
376 static struct list font_subst_list = LIST_INIT(font_subst_list);
378 static struct list font_list = LIST_INIT(font_list);
380 struct freetype_physdev
382 struct gdi_physdev dev;
383 GdiFont *font;
386 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
388 return (struct freetype_physdev *)dev;
391 static const struct gdi_dc_funcs freetype_funcs;
393 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
394 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
395 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
397 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
398 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
399 'W','i','n','d','o','w','s','\\',
400 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
401 'F','o','n','t','s','\0'};
403 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
404 'W','i','n','d','o','w','s',' ','N','T','\\',
405 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
406 'F','o','n','t','s','\0'};
408 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
409 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
410 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
411 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
413 static const WCHAR * const SystemFontValues[4] = {
414 System_Value,
415 OEMFont_Value,
416 FixedSys_Value,
417 NULL
420 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
421 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
423 /* Interesting and well-known (frequently-assumed!) font names */
424 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
425 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 };
426 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
427 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
428 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
429 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
430 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
431 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
433 static const WCHAR arial[] = {'A','r','i','a','l',0};
434 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
435 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};
436 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};
437 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
438 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
439 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
440 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
441 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
442 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
444 static const WCHAR *default_serif_list[] =
446 times_new_roman,
447 liberation_serif,
448 bitstream_vera_serif,
449 NULL
452 static const WCHAR *default_fixed_list[] =
454 courier_new,
455 liberation_mono,
456 bitstream_vera_sans_mono,
457 NULL
460 static const WCHAR *default_sans_list[] =
462 arial,
463 liberation_sans,
464 bitstream_vera_sans,
465 NULL
468 typedef struct {
469 WCHAR *name;
470 INT charset;
471 } NameCs;
473 typedef struct tagFontSubst {
474 struct list entry;
475 NameCs from;
476 NameCs to;
477 } FontSubst;
479 /* Registry font cache key and value names */
480 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
481 'F','o','n','t','s',0};
482 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
483 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
484 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
485 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
486 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
487 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
488 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
489 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
490 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
491 static const WCHAR face_size_value[] = {'S','i','z','e',0};
492 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
493 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
494 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
495 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
496 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
499 struct font_mapping
501 struct list entry;
502 int refcount;
503 dev_t dev;
504 ino_t ino;
505 void *data;
506 size_t size;
509 static struct list mappings_list = LIST_INIT( mappings_list );
511 static CRITICAL_SECTION freetype_cs;
512 static CRITICAL_SECTION_DEBUG critsect_debug =
514 0, 0, &freetype_cs,
515 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
516 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
518 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
520 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
522 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
523 static BOOL use_default_fallback = FALSE;
525 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
526 static BOOL get_outline_text_metrics(GdiFont *font);
527 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
529 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
530 'W','i','n','d','o','w','s',' ','N','T','\\',
531 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
532 'S','y','s','t','e','m','L','i','n','k',0};
534 /****************************************
535 * Notes on .fon files
537 * The fonts System, FixedSys and Terminal are special. There are typically multiple
538 * versions installed for different resolutions and codepages. Windows stores which one to use
539 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
540 * Key Meaning
541 * FIXEDFON.FON FixedSys
542 * FONTS.FON System
543 * OEMFONT.FON Terminal
544 * LogPixels Current dpi set by the display control panel applet
545 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
546 * also has a LogPixels value that appears to mirror this)
548 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
549 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
550 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
551 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
552 * so that makes sense.
554 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
555 * to be mapped into the registry on Windows 2000 at least).
556 * I have
557 * woafont=app850.fon
558 * ega80woa.fon=ega80850.fon
559 * ega40woa.fon=ega40850.fon
560 * cga80woa.fon=cga80850.fon
561 * cga40woa.fon=cga40850.fon
564 /* These are all structures needed for the GSUB table */
566 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
567 #define TATEGAKI_LOWER_BOUND 0x02F1
569 typedef struct {
570 DWORD version;
571 WORD ScriptList;
572 WORD FeatureList;
573 WORD LookupList;
574 } GSUB_Header;
576 typedef struct {
577 CHAR ScriptTag[4];
578 WORD Script;
579 } GSUB_ScriptRecord;
581 typedef struct {
582 WORD ScriptCount;
583 GSUB_ScriptRecord ScriptRecord[1];
584 } GSUB_ScriptList;
586 typedef struct {
587 CHAR LangSysTag[4];
588 WORD LangSys;
589 } GSUB_LangSysRecord;
591 typedef struct {
592 WORD DefaultLangSys;
593 WORD LangSysCount;
594 GSUB_LangSysRecord LangSysRecord[1];
595 } GSUB_Script;
597 typedef struct {
598 WORD LookupOrder; /* Reserved */
599 WORD ReqFeatureIndex;
600 WORD FeatureCount;
601 WORD FeatureIndex[1];
602 } GSUB_LangSys;
604 typedef struct {
605 CHAR FeatureTag[4];
606 WORD Feature;
607 } GSUB_FeatureRecord;
609 typedef struct {
610 WORD FeatureCount;
611 GSUB_FeatureRecord FeatureRecord[1];
612 } GSUB_FeatureList;
614 typedef struct {
615 WORD FeatureParams; /* Reserved */
616 WORD LookupCount;
617 WORD LookupListIndex[1];
618 } GSUB_Feature;
620 typedef struct {
621 WORD LookupCount;
622 WORD Lookup[1];
623 } GSUB_LookupList;
625 typedef struct {
626 WORD LookupType;
627 WORD LookupFlag;
628 WORD SubTableCount;
629 WORD SubTable[1];
630 } GSUB_LookupTable;
632 typedef struct {
633 WORD CoverageFormat;
634 WORD GlyphCount;
635 WORD GlyphArray[1];
636 } GSUB_CoverageFormat1;
638 typedef struct {
639 WORD Start;
640 WORD End;
641 WORD StartCoverageIndex;
642 } GSUB_RangeRecord;
644 typedef struct {
645 WORD CoverageFormat;
646 WORD RangeCount;
647 GSUB_RangeRecord RangeRecord[1];
648 } GSUB_CoverageFormat2;
650 typedef struct {
651 WORD SubstFormat; /* = 1 */
652 WORD Coverage;
653 WORD DeltaGlyphID;
654 } GSUB_SingleSubstFormat1;
656 typedef struct {
657 WORD SubstFormat; /* = 2 */
658 WORD Coverage;
659 WORD GlyphCount;
660 WORD Substitute[1];
661 }GSUB_SingleSubstFormat2;
663 #ifdef HAVE_CARBON_CARBON_H
664 static char *find_cache_dir(void)
666 FSRef ref;
667 OSErr err;
668 static char cached_path[MAX_PATH];
669 static const char *wine = "/Wine", *fonts = "/Fonts";
671 if(*cached_path) return cached_path;
673 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
674 if(err != noErr)
676 WARN("can't create cached data folder\n");
677 return NULL;
679 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
680 if(err != noErr)
682 WARN("can't create cached data path\n");
683 *cached_path = '\0';
684 return NULL;
686 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
688 ERR("Could not create full path\n");
689 *cached_path = '\0';
690 return NULL;
692 strcat(cached_path, wine);
694 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
696 WARN("Couldn't mkdir %s\n", cached_path);
697 *cached_path = '\0';
698 return NULL;
700 strcat(cached_path, fonts);
701 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
703 WARN("Couldn't mkdir %s\n", cached_path);
704 *cached_path = '\0';
705 return NULL;
707 return cached_path;
710 /******************************************************************
711 * expand_mac_font
713 * Extracts individual TrueType font files from a Mac suitcase font
714 * and saves them into the user's caches directory (see
715 * find_cache_dir()).
716 * Returns a NULL terminated array of filenames.
718 * We do this because they are apps that try to read ttf files
719 * themselves and they don't like Mac suitcase files.
721 static char **expand_mac_font(const char *path)
723 FSRef ref;
724 SInt16 res_ref;
725 OSStatus s;
726 unsigned int idx;
727 const char *out_dir;
728 const char *filename;
729 int output_len;
730 struct {
731 char **array;
732 unsigned int size, max_size;
733 } ret;
735 TRACE("path %s\n", path);
737 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
738 if(s != noErr)
740 WARN("failed to get ref\n");
741 return NULL;
744 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
745 if(s != noErr)
747 TRACE("no data fork, so trying resource fork\n");
748 res_ref = FSOpenResFile(&ref, fsRdPerm);
749 if(res_ref == -1)
751 TRACE("unable to open resource fork\n");
752 return NULL;
756 ret.size = 0;
757 ret.max_size = 10;
758 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
759 if(!ret.array)
761 CloseResFile(res_ref);
762 return NULL;
765 out_dir = find_cache_dir();
767 filename = strrchr(path, '/');
768 if(!filename) filename = path;
769 else filename++;
771 /* output filename has the form out_dir/filename_%04x.ttf */
772 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
774 UseResFile(res_ref);
775 idx = 1;
776 while(1)
778 FamRec *fam_rec;
779 unsigned short *num_faces_ptr, num_faces, face;
780 AsscEntry *assoc;
781 Handle fond;
782 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
784 fond = Get1IndResource(fond_res, idx);
785 if(!fond) break;
786 TRACE("got fond resource %d\n", idx);
787 HLock(fond);
789 fam_rec = *(FamRec**)fond;
790 num_faces_ptr = (unsigned short *)(fam_rec + 1);
791 num_faces = GET_BE_WORD(*num_faces_ptr);
792 num_faces++;
793 assoc = (AsscEntry*)(num_faces_ptr + 1);
794 TRACE("num faces %04x\n", num_faces);
795 for(face = 0; face < num_faces; face++, assoc++)
797 Handle sfnt;
798 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
799 unsigned short size, font_id;
800 char *output;
802 size = GET_BE_WORD(assoc->fontSize);
803 font_id = GET_BE_WORD(assoc->fontID);
804 if(size != 0)
806 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
807 continue;
810 TRACE("trying to load sfnt id %04x\n", font_id);
811 sfnt = GetResource(sfnt_res, font_id);
812 if(!sfnt)
814 TRACE("can't get sfnt resource %04x\n", font_id);
815 continue;
818 output = HeapAlloc(GetProcessHeap(), 0, output_len);
819 if(output)
821 int fd;
823 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
825 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
826 if(fd != -1 || errno == EEXIST)
828 if(fd != -1)
830 unsigned char *sfnt_data;
832 HLock(sfnt);
833 sfnt_data = *(unsigned char**)sfnt;
834 write(fd, sfnt_data, GetHandleSize(sfnt));
835 HUnlock(sfnt);
836 close(fd);
838 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
840 ret.max_size *= 2;
841 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
843 ret.array[ret.size++] = output;
845 else
847 WARN("unable to create %s\n", output);
848 HeapFree(GetProcessHeap(), 0, output);
851 ReleaseResource(sfnt);
853 HUnlock(fond);
854 ReleaseResource(fond);
855 idx++;
857 CloseResFile(res_ref);
859 return ret.array;
862 #endif /* HAVE_CARBON_CARBON_H */
864 static inline BOOL is_win9x(void)
866 return GetVersion() & 0x80000000;
869 This function builds an FT_Fixed from a double. It fails if the absolute
870 value of the float number is greater than 32768.
872 static inline FT_Fixed FT_FixedFromFloat(double f)
874 return f * 0x10000;
878 This function builds an FT_Fixed from a FIXED. It simply put f.value
879 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
881 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
883 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
887 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
889 Family *family;
890 Face *face;
891 const char *file;
892 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
893 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
895 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
896 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
898 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
900 if(face_name && strcmpiW(face_name, family->FamilyName))
901 continue;
902 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
904 if (!face->file)
905 continue;
906 file = strrchr(face->file, '/');
907 if(!file)
908 file = face->file;
909 else
910 file++;
911 if(!strcasecmp(file, file_nameA))
913 HeapFree(GetProcessHeap(), 0, file_nameA);
914 return face;
918 HeapFree(GetProcessHeap(), 0, file_nameA);
919 return NULL;
922 static Family *find_family_from_name(const WCHAR *name)
924 Family *family;
926 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
928 if(!strcmpiW(family->FamilyName, name))
929 return family;
932 return NULL;
935 static void DumpSubstList(void)
937 FontSubst *psub;
939 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
941 if(psub->from.charset != -1 || psub->to.charset != -1)
942 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
943 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
944 else
945 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
946 debugstr_w(psub->to.name));
948 return;
951 static LPWSTR strdupW(LPCWSTR p)
953 LPWSTR ret;
954 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
955 ret = HeapAlloc(GetProcessHeap(), 0, len);
956 memcpy(ret, p, len);
957 return ret;
960 static LPSTR strdupA(LPCSTR p)
962 LPSTR ret;
963 DWORD len = (strlen(p) + 1);
964 ret = HeapAlloc(GetProcessHeap(), 0, len);
965 memcpy(ret, p, len);
966 return ret;
969 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
970 INT from_charset)
972 FontSubst *element;
974 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
976 if(!strcmpiW(element->from.name, from_name) &&
977 (element->from.charset == from_charset ||
978 element->from.charset == -1))
979 return element;
982 return NULL;
985 #define ADD_FONT_SUBST_FORCE 1
987 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
989 FontSubst *from_exist, *to_exist;
991 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
993 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
995 list_remove(&from_exist->entry);
996 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
997 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
998 HeapFree(GetProcessHeap(), 0, from_exist);
999 from_exist = NULL;
1002 if(!from_exist)
1004 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1006 if(to_exist)
1008 HeapFree(GetProcessHeap(), 0, subst->to.name);
1009 subst->to.name = strdupW(to_exist->to.name);
1012 list_add_tail(subst_list, &subst->entry);
1014 return TRUE;
1017 HeapFree(GetProcessHeap(), 0, subst->from.name);
1018 HeapFree(GetProcessHeap(), 0, subst->to.name);
1019 HeapFree(GetProcessHeap(), 0, subst);
1020 return FALSE;
1023 static void split_subst_info(NameCs *nc, LPSTR str)
1025 CHAR *p = strrchr(str, ',');
1026 DWORD len;
1028 nc->charset = -1;
1029 if(p && *(p+1)) {
1030 nc->charset = strtol(p+1, NULL, 10);
1031 *p = '\0';
1033 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1034 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1035 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1038 static void LoadSubstList(void)
1040 FontSubst *psub;
1041 HKEY hkey;
1042 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1043 LPSTR value;
1044 LPVOID data;
1046 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1047 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1048 &hkey) == ERROR_SUCCESS) {
1050 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1051 &valuelen, &datalen, NULL, NULL);
1053 valuelen++; /* returned value doesn't include room for '\0' */
1054 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1055 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1057 dlen = datalen;
1058 vlen = valuelen;
1059 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1060 &dlen) == ERROR_SUCCESS) {
1061 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1063 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1064 split_subst_info(&psub->from, value);
1065 split_subst_info(&psub->to, data);
1067 /* Win 2000 doesn't allow mapping between different charsets
1068 or mapping of DEFAULT_CHARSET */
1069 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1070 psub->to.charset == DEFAULT_CHARSET) {
1071 HeapFree(GetProcessHeap(), 0, psub->to.name);
1072 HeapFree(GetProcessHeap(), 0, psub->from.name);
1073 HeapFree(GetProcessHeap(), 0, psub);
1074 } else {
1075 add_font_subst(&font_subst_list, psub, 0);
1077 /* reset dlen and vlen */
1078 dlen = datalen;
1079 vlen = valuelen;
1081 HeapFree(GetProcessHeap(), 0, data);
1082 HeapFree(GetProcessHeap(), 0, value);
1083 RegCloseKey(hkey);
1088 /*****************************************************************
1089 * get_name_table_entry
1091 * Supply the platform, encoding, language and name ids in req
1092 * and if the name exists the function will fill in the string
1093 * and string_len members. The string is owned by FreeType so
1094 * don't free it. Returns TRUE if the name is found else FALSE.
1096 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1098 FT_SfntName name;
1099 FT_UInt num_names, name_index;
1101 if(FT_IS_SFNT(ft_face))
1103 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1105 for(name_index = 0; name_index < num_names; name_index++)
1107 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1109 if((name.platform_id == req->platform_id) &&
1110 (name.encoding_id == req->encoding_id) &&
1111 (name.language_id == req->language_id) &&
1112 (name.name_id == req->name_id))
1114 req->string = name.string;
1115 req->string_len = name.string_len;
1116 return TRUE;
1121 req->string = NULL;
1122 req->string_len = 0;
1123 return FALSE;
1126 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1128 WCHAR *ret = NULL;
1129 FT_SfntName name;
1131 name.platform_id = TT_PLATFORM_MICROSOFT;
1132 name.encoding_id = TT_MS_ID_UNICODE_CS;
1133 name.language_id = language_id;
1134 name.name_id = name_id;
1136 if(get_name_table_entry(ft_face, &name))
1138 FT_UInt i;
1140 /* String is not nul terminated and string_len is a byte length. */
1141 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1142 for(i = 0; i < name.string_len / 2; i++)
1144 WORD *tmp = (WORD *)&name.string[i * 2];
1145 ret[i] = GET_BE_WORD(*tmp);
1147 ret[i] = 0;
1148 TRACE("Got localised name %s\n", debugstr_w(ret));
1151 return ret;
1154 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1156 DWORD type, needed;
1157 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1158 if(r != ERROR_SUCCESS) return r;
1159 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1160 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1163 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1165 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1168 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1170 DWORD needed;
1171 DWORD num_strikes, max_strike_key_len;
1173 /* If we have a File Name key then this is a real font, not just the parent
1174 key of a bunch of non-scalable strikes */
1175 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1177 DWORD italic, bold;
1178 Face *face;
1179 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1180 face->cached_enum_data = NULL;
1182 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1183 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1185 face->StyleName = strdupW(face_name);
1186 face->family = family;
1188 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1190 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1191 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1192 face->FullName = fullName;
1194 else
1195 face->FullName = NULL;
1197 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1198 reg_load_dword(hkey_face, face_italic_value, &italic);
1199 reg_load_dword(hkey_face, face_bold_value, &bold);
1200 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1201 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1203 needed = sizeof(face->fs);
1204 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1205 memset(&face->fs_links, 0, sizeof(face->fs_links));
1207 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1209 face->scalable = TRUE;
1210 memset(&face->size, 0, sizeof(face->size));
1212 else
1214 face->scalable = FALSE;
1215 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1216 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1217 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1218 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1219 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1221 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1222 face->size.height, face->size.width, face->size.size >> 6,
1223 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1226 face->ntmFlags = 0;
1227 if (italic) face->ntmFlags |= NTM_ITALIC;
1228 if (bold) face->ntmFlags |= NTM_BOLD;
1229 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1231 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1232 face->fs.fsCsb[0], face->fs.fsCsb[1],
1233 face->fs.fsUsb[0], face->fs.fsUsb[1],
1234 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1236 if(!italic && !bold)
1237 list_add_head(&family->faces, &face->entry);
1238 else
1239 list_add_tail(&family->faces, &face->entry);
1241 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1244 /* do we have any bitmap strikes? */
1245 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1246 NULL, NULL, NULL, NULL);
1247 if(num_strikes != 0)
1249 WCHAR strike_name[10];
1250 DWORD strike_index = 0;
1252 needed = sizeof(strike_name) / sizeof(WCHAR);
1253 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1254 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1256 HKEY hkey_strike;
1257 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1258 load_face(hkey_strike, face_name, family);
1259 RegCloseKey(hkey_strike);
1260 needed = sizeof(strike_name) / sizeof(WCHAR);
1265 static void load_font_list_from_cache(HKEY hkey_font_cache)
1267 DWORD max_family_key_len, size;
1268 WCHAR *family_name;
1269 DWORD family_index = 0;
1270 Family *family;
1271 HKEY hkey_family;
1273 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1274 NULL, NULL, NULL, NULL);
1275 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1277 size = max_family_key_len + 1;
1278 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1279 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1281 WCHAR *english_family = NULL;
1282 DWORD face_index = 0;
1283 WCHAR *face_name;
1284 DWORD max_face_key_len;
1286 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1287 TRACE("opened family key %s\n", debugstr_w(family_name));
1288 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1290 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1291 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1294 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1295 family->FamilyName = strdupW(family_name);
1296 family->EnglishName = english_family;
1297 list_init(&family->faces);
1298 list_add_tail(&font_list, &family->entry);
1300 if(english_family)
1302 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1303 subst->from.name = strdupW(english_family);
1304 subst->from.charset = -1;
1305 subst->to.name = strdupW(family_name);
1306 subst->to.charset = -1;
1307 add_font_subst(&font_subst_list, subst, 0);
1310 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1311 NULL, NULL, NULL, NULL);
1313 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1314 size = max_face_key_len + 1;
1315 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1316 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1318 HKEY hkey_face;
1320 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1321 load_face(hkey_face, face_name, family);
1322 RegCloseKey(hkey_face);
1323 size = max_face_key_len + 1;
1325 HeapFree(GetProcessHeap(), 0, face_name);
1326 RegCloseKey(hkey_family);
1327 size = max_family_key_len + 1;
1330 HeapFree(GetProcessHeap(), 0, family_name);
1333 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1335 LONG ret;
1336 HKEY hkey_wine_fonts;
1338 /* We don't want to create the fonts key as volatile, so open this first */
1339 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1340 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1341 if(ret != ERROR_SUCCESS)
1343 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1344 return ret;
1347 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1348 KEY_ALL_ACCESS, NULL, hkey, disposition);
1349 RegCloseKey(hkey_wine_fonts);
1350 return ret;
1353 static void add_face_to_cache(Face *face)
1355 HKEY hkey_font_cache, hkey_family, hkey_face;
1356 WCHAR *face_key_name;
1358 create_font_cache_key(&hkey_font_cache, NULL);
1360 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1361 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1362 if(face->family->EnglishName)
1363 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1364 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1366 if(face->scalable)
1367 face_key_name = face->StyleName;
1368 else
1370 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1371 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1372 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1374 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1375 &hkey_face, NULL);
1376 if(!face->scalable)
1377 HeapFree(GetProcessHeap(), 0, face_key_name);
1379 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1380 if (face->FullName)
1381 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1382 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1384 reg_save_dword(hkey_face, face_index_value, face->face_index);
1385 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1386 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1387 reg_save_dword(hkey_face, face_version_value, face->font_version);
1388 reg_save_dword(hkey_face, face_external_value, face->external);
1390 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1392 if(!face->scalable)
1394 reg_save_dword(hkey_face, face_height_value, face->size.height);
1395 reg_save_dword(hkey_face, face_width_value, face->size.width);
1396 reg_save_dword(hkey_face, face_size_value, face->size.size);
1397 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1398 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1399 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1401 RegCloseKey(hkey_face);
1402 RegCloseKey(hkey_family);
1403 RegCloseKey(hkey_font_cache);
1406 static inline int TestStyles(DWORD flags, DWORD styles)
1408 return (flags & styles) == styles;
1411 static int StyleOrdering(Face *face)
1413 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1414 return 3;
1415 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1416 return 2;
1417 if (TestStyles(face->ntmFlags, NTM_BOLD))
1418 return 1;
1419 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1420 return 0;
1422 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1423 debugstr_w(face->family->FamilyName),
1424 debugstr_w(face->StyleName),
1425 face->ntmFlags);
1427 return 9999;
1430 /* Add a style of face to a font family using an ordering of the list such
1431 that regular fonts come before bold and italic, and single styles come
1432 before compound styles. */
1433 static void AddFaceToFamily(Face *face, Family *family)
1435 struct list *entry;
1437 LIST_FOR_EACH( entry, &family->faces )
1439 Face *ent = LIST_ENTRY(entry, Face, entry);
1440 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1442 list_add_before( entry, &face->entry );
1445 #define ADDFONT_EXTERNAL_FONT 0x01
1446 #define ADDFONT_FORCE_BITMAP 0x02
1447 #define ADDFONT_ADD_TO_CACHE 0x04
1449 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1451 FT_Face ft_face;
1452 TT_OS2 *pOS2;
1453 TT_Header *pHeader = NULL;
1454 WCHAR *english_family, *localised_family, *StyleW;
1455 DWORD len;
1456 Family *family;
1457 Face *face;
1458 struct list *family_elem_ptr, *face_elem_ptr;
1459 FT_Error err;
1460 FT_Long face_index = 0, num_faces;
1461 FT_WinFNT_HeaderRec winfnt_header;
1462 int i, bitmap_num, internal_leading;
1463 FONTSIGNATURE fs;
1465 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1466 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1468 #ifdef HAVE_CARBON_CARBON_H
1469 if(file && !fake_family)
1471 char **mac_list = expand_mac_font(file);
1472 if(mac_list)
1474 BOOL had_one = FALSE;
1475 char **cursor;
1476 for(cursor = mac_list; *cursor; cursor++)
1478 had_one = TRUE;
1479 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1480 HeapFree(GetProcessHeap(), 0, *cursor);
1482 HeapFree(GetProcessHeap(), 0, mac_list);
1483 if(had_one)
1484 return 1;
1487 #endif /* HAVE_CARBON_CARBON_H */
1489 do {
1490 char *family_name = fake_family;
1492 if (file)
1494 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1495 err = pFT_New_Face(library, file, face_index, &ft_face);
1496 } else
1498 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1499 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1502 if(err != 0) {
1503 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1504 return 0;
1507 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1508 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1509 pFT_Done_Face(ft_face);
1510 return 0;
1513 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1514 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1515 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1516 pFT_Done_Face(ft_face);
1517 return 0;
1520 if(FT_IS_SFNT(ft_face))
1522 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1523 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1524 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1526 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1527 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1528 pFT_Done_Face(ft_face);
1529 return 0;
1532 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1533 we don't want to load these. */
1534 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1536 FT_ULong len = 0;
1538 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1540 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1541 pFT_Done_Face(ft_face);
1542 return 0;
1547 if(!ft_face->family_name || !ft_face->style_name) {
1548 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1549 pFT_Done_Face(ft_face);
1550 return 0;
1553 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1555 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1556 pFT_Done_Face(ft_face);
1557 return 0;
1560 if (target_family)
1562 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1563 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1565 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1566 HeapFree(GetProcessHeap(), 0, localised_family);
1567 num_faces = ft_face->num_faces;
1568 pFT_Done_Face(ft_face);
1569 continue;
1571 HeapFree(GetProcessHeap(), 0, localised_family);
1574 if(!family_name)
1575 family_name = ft_face->family_name;
1577 bitmap_num = 0;
1578 do {
1579 My_FT_Bitmap_Size *size = NULL;
1580 FT_ULong tmp_size;
1582 if(!FT_IS_SCALABLE(ft_face))
1583 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1585 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1586 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1587 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1589 localised_family = NULL;
1590 if(!fake_family) {
1591 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1592 if(localised_family && !strcmpiW(localised_family, english_family)) {
1593 HeapFree(GetProcessHeap(), 0, localised_family);
1594 localised_family = NULL;
1598 family = NULL;
1599 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1600 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1601 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1602 break;
1603 family = NULL;
1605 if(!family) {
1606 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1607 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1608 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1609 list_init(&family->faces);
1610 list_add_tail(&font_list, &family->entry);
1612 if(localised_family) {
1613 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1614 subst->from.name = strdupW(english_family);
1615 subst->from.charset = -1;
1616 subst->to.name = strdupW(localised_family);
1617 subst->to.charset = -1;
1618 add_font_subst(&font_subst_list, subst, 0);
1621 HeapFree(GetProcessHeap(), 0, localised_family);
1622 HeapFree(GetProcessHeap(), 0, english_family);
1624 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1625 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1626 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1628 internal_leading = 0;
1629 memset(&fs, 0, sizeof(fs));
1631 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1632 if(pOS2) {
1633 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1634 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1635 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1636 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1637 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1638 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1639 if(pOS2->version == 0) {
1640 FT_UInt dummy;
1642 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1643 fs.fsCsb[0] |= FS_LATIN1;
1644 else
1645 fs.fsCsb[0] |= FS_SYMBOL;
1648 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1649 CHARSETINFO csi;
1650 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1651 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1652 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1653 fs = csi.fs;
1654 internal_leading = winfnt_header.internal_leading;
1657 face_elem_ptr = list_head(&family->faces);
1658 while(face_elem_ptr) {
1659 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1660 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1661 if(!strcmpiW(face->StyleName, StyleW) &&
1662 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1663 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1664 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1665 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1667 if(fake_family) {
1668 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1669 HeapFree(GetProcessHeap(), 0, StyleW);
1670 pFT_Done_Face(ft_face);
1671 return 1;
1673 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1674 TRACE("Original font is newer so skipping this one\n");
1675 HeapFree(GetProcessHeap(), 0, StyleW);
1676 pFT_Done_Face(ft_face);
1677 return 1;
1678 } else {
1679 TRACE("Replacing original with this one\n");
1680 list_remove(&face->entry);
1681 HeapFree(GetProcessHeap(), 0, face->file);
1682 HeapFree(GetProcessHeap(), 0, face->StyleName);
1683 HeapFree(GetProcessHeap(), 0, face->FullName);
1684 HeapFree(GetProcessHeap(), 0, face);
1685 break;
1689 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1690 face->cached_enum_data = NULL;
1691 face->StyleName = StyleW;
1692 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1693 if (file)
1695 face->file = strdupA(file);
1696 face->font_data_ptr = NULL;
1697 face->font_data_size = 0;
1699 else
1701 face->file = NULL;
1702 face->font_data_ptr = font_data_ptr;
1703 face->font_data_size = font_data_size;
1705 face->face_index = face_index;
1706 face->ntmFlags = 0;
1707 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1708 face->ntmFlags |= NTM_ITALIC;
1709 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1710 face->ntmFlags |= NTM_BOLD;
1711 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1712 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1713 face->family = family;
1714 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1715 face->fs = fs;
1716 memset(&face->fs_links, 0, sizeof(face->fs_links));
1718 if(FT_IS_SCALABLE(ft_face)) {
1719 memset(&face->size, 0, sizeof(face->size));
1720 face->scalable = TRUE;
1721 } else {
1722 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1723 size->height, size->width, size->size >> 6,
1724 size->x_ppem >> 6, size->y_ppem >> 6);
1725 face->size.height = size->height;
1726 face->size.width = size->width;
1727 face->size.size = size->size;
1728 face->size.x_ppem = size->x_ppem;
1729 face->size.y_ppem = size->y_ppem;
1730 face->size.internal_leading = internal_leading;
1731 face->scalable = FALSE;
1734 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1735 tmp_size = 0;
1736 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1738 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1739 face->ntmFlags |= NTM_PS_OPENTYPE;
1742 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1743 face->fs.fsCsb[0], face->fs.fsCsb[1],
1744 face->fs.fsUsb[0], face->fs.fsUsb[1],
1745 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1748 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1749 for(i = 0; i < ft_face->num_charmaps; i++) {
1750 switch(ft_face->charmaps[i]->encoding) {
1751 case FT_ENCODING_UNICODE:
1752 case FT_ENCODING_APPLE_ROMAN:
1753 face->fs.fsCsb[0] |= FS_LATIN1;
1754 break;
1755 case FT_ENCODING_MS_SYMBOL:
1756 face->fs.fsCsb[0] |= FS_SYMBOL;
1757 break;
1758 default:
1759 break;
1764 if(flags & ADDFONT_ADD_TO_CACHE)
1765 add_face_to_cache(face);
1767 AddFaceToFamily(face, family);
1769 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1771 num_faces = ft_face->num_faces;
1772 pFT_Done_Face(ft_face);
1773 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1774 debugstr_w(StyleW));
1775 } while(num_faces > ++face_index);
1776 return num_faces;
1779 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1781 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1784 static void DumpFontList(void)
1786 Family *family;
1787 Face *face;
1788 struct list *family_elem_ptr, *face_elem_ptr;
1790 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1791 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1792 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1793 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1794 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1795 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1796 if(!face->scalable)
1797 TRACE(" %d", face->size.height);
1798 TRACE("\n");
1801 return;
1804 /***********************************************************
1805 * The replacement list is a way to map an entire font
1806 * family onto another family. For example adding
1808 * [HKCU\Software\Wine\Fonts\Replacements]
1809 * "Wingdings"="Winedings"
1811 * would enumerate the Winedings font both as Winedings and
1812 * Wingdings. However if a real Wingdings font is present the
1813 * replacement does not take place.
1816 static void LoadReplaceList(void)
1818 HKEY hkey;
1819 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1820 LPWSTR value;
1821 LPVOID data;
1822 Family *family;
1823 Face *face;
1824 struct list *family_elem_ptr, *face_elem_ptr;
1825 CHAR familyA[400];
1827 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1828 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1830 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1831 &valuelen, &datalen, NULL, NULL);
1833 valuelen++; /* returned value doesn't include room for '\0' */
1834 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1835 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1837 dlen = datalen;
1838 vlen = valuelen;
1839 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1840 &dlen) == ERROR_SUCCESS) {
1841 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1842 /* "NewName"="Oldname" */
1843 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1845 if(!find_family_from_name(value))
1847 /* Find the old family and hence all of the font files
1848 in that family */
1849 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1850 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1851 if(!strcmpiW(family->FamilyName, data)) {
1852 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1853 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1854 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1855 debugstr_w(face->StyleName), familyA);
1856 /* Now add a new entry with the new family name */
1857 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1858 familyA, family->FamilyName,
1859 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1861 break;
1865 /* reset dlen and vlen */
1866 dlen = datalen;
1867 vlen = valuelen;
1869 HeapFree(GetProcessHeap(), 0, data);
1870 HeapFree(GetProcessHeap(), 0, value);
1871 RegCloseKey(hkey);
1875 /*************************************************************
1876 * init_system_links
1878 static BOOL init_system_links(void)
1880 HKEY hkey;
1881 BOOL ret = FALSE;
1882 DWORD type, max_val, max_data, val_len, data_len, index;
1883 WCHAR *value, *data;
1884 WCHAR *entry, *next;
1885 SYSTEM_LINKS *font_link, *system_font_link;
1886 CHILD_FONT *child_font;
1887 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1888 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1889 FONTSIGNATURE fs;
1890 Family *family;
1891 Face *face;
1892 FontSubst *psub;
1894 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1896 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1897 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1898 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1899 val_len = max_val + 1;
1900 data_len = max_data;
1901 index = 0;
1902 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1904 memset(&fs, 0, sizeof(fs));
1905 psub = get_font_subst(&font_subst_list, value, -1);
1906 /* Don't store fonts that are only substitutes for other fonts */
1907 if(psub)
1909 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1910 goto next;
1912 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1913 font_link->font_name = strdupW(value);
1914 list_init(&font_link->links);
1915 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1917 WCHAR *face_name;
1918 CHILD_FONT *child_font;
1920 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1922 next = entry + strlenW(entry) + 1;
1924 face_name = strchrW(entry, ',');
1925 if(face_name)
1927 *face_name++ = 0;
1928 while(isspaceW(*face_name))
1929 face_name++;
1931 psub = get_font_subst(&font_subst_list, face_name, -1);
1932 if(psub)
1933 face_name = psub->to.name;
1935 face = find_face_from_filename(entry, face_name);
1936 if(!face)
1938 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1939 continue;
1942 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1943 child_font->face = face;
1944 child_font->font = NULL;
1945 fs.fsCsb[0] |= face->fs.fsCsb[0];
1946 fs.fsCsb[1] |= face->fs.fsCsb[1];
1947 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1948 list_add_tail(&font_link->links, &child_font->entry);
1950 family = find_family_from_name(font_link->font_name);
1951 if(family)
1953 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1955 face->fs_links = fs;
1958 list_add_tail(&system_links, &font_link->entry);
1959 next:
1960 val_len = max_val + 1;
1961 data_len = max_data;
1964 HeapFree(GetProcessHeap(), 0, value);
1965 HeapFree(GetProcessHeap(), 0, data);
1966 RegCloseKey(hkey);
1969 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1970 that Tahoma has */
1972 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1973 system_font_link->font_name = strdupW(System);
1974 list_init(&system_font_link->links);
1976 face = find_face_from_filename(tahoma_ttf, Tahoma);
1977 if(face)
1979 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1980 child_font->face = face;
1981 child_font->font = NULL;
1982 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1983 list_add_tail(&system_font_link->links, &child_font->entry);
1985 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1987 if(!strcmpiW(font_link->font_name, Tahoma))
1989 CHILD_FONT *font_link_entry;
1990 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1992 CHILD_FONT *new_child;
1993 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1994 new_child->face = font_link_entry->face;
1995 new_child->font = NULL;
1996 list_add_tail(&system_font_link->links, &new_child->entry);
1998 break;
2001 list_add_tail(&system_links, &system_font_link->entry);
2002 return ret;
2005 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2007 DIR *dir;
2008 struct dirent *dent;
2009 char path[MAX_PATH];
2011 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2013 dir = opendir(dirname);
2014 if(!dir) {
2015 WARN("Can't open directory %s\n", debugstr_a(dirname));
2016 return FALSE;
2018 while((dent = readdir(dir)) != NULL) {
2019 struct stat statbuf;
2021 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2022 continue;
2024 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2026 sprintf(path, "%s/%s", dirname, dent->d_name);
2028 if(stat(path, &statbuf) == -1)
2030 WARN("Can't stat %s\n", debugstr_a(path));
2031 continue;
2033 if(S_ISDIR(statbuf.st_mode))
2034 ReadFontDir(path, external_fonts);
2035 else
2037 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2038 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2039 AddFontFileToList(path, NULL, NULL, addfont_flags);
2042 closedir(dir);
2043 return TRUE;
2046 static void load_fontconfig_fonts(void)
2048 #ifdef SONAME_LIBFONTCONFIG
2049 void *fc_handle = NULL;
2050 FcConfig *config;
2051 FcPattern *pat;
2052 FcObjectSet *os;
2053 FcFontSet *fontset;
2054 int i, len;
2055 char *file;
2056 const char *ext;
2058 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2059 if(!fc_handle) {
2060 TRACE("Wine cannot find the fontconfig library (%s).\n",
2061 SONAME_LIBFONTCONFIG);
2062 return;
2064 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2065 LOAD_FUNCPTR(FcConfigGetCurrent);
2066 LOAD_FUNCPTR(FcFontList);
2067 LOAD_FUNCPTR(FcFontSetDestroy);
2068 LOAD_FUNCPTR(FcInit);
2069 LOAD_FUNCPTR(FcObjectSetAdd);
2070 LOAD_FUNCPTR(FcObjectSetCreate);
2071 LOAD_FUNCPTR(FcObjectSetDestroy);
2072 LOAD_FUNCPTR(FcPatternCreate);
2073 LOAD_FUNCPTR(FcPatternDestroy);
2074 LOAD_FUNCPTR(FcPatternGetBool);
2075 LOAD_FUNCPTR(FcPatternGetString);
2076 #undef LOAD_FUNCPTR
2078 if(!pFcInit()) return;
2080 config = pFcConfigGetCurrent();
2081 pat = pFcPatternCreate();
2082 os = pFcObjectSetCreate();
2083 pFcObjectSetAdd(os, FC_FILE);
2084 pFcObjectSetAdd(os, FC_SCALABLE);
2085 fontset = pFcFontList(config, pat, os);
2086 if(!fontset) return;
2087 for(i = 0; i < fontset->nfont; i++) {
2088 FcBool scalable;
2090 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2091 continue;
2092 TRACE("fontconfig: %s\n", file);
2094 /* We're just interested in OT/TT fonts for now, so this hack just
2095 picks up the scalable fonts without extensions .pf[ab] to save time
2096 loading every other font */
2098 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2100 TRACE("not scalable\n");
2101 continue;
2104 len = strlen( file );
2105 if(len < 4) continue;
2106 ext = &file[ len - 3 ];
2107 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2108 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2110 pFcFontSetDestroy(fontset);
2111 pFcObjectSetDestroy(os);
2112 pFcPatternDestroy(pat);
2113 sym_not_found:
2114 #endif
2115 return;
2118 static BOOL load_font_from_data_dir(LPCWSTR file)
2120 BOOL ret = FALSE;
2121 const char *data_dir = wine_get_data_dir();
2123 if (!data_dir) data_dir = wine_get_build_dir();
2125 if (data_dir)
2127 INT len;
2128 char *unix_name;
2130 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2132 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2134 strcpy(unix_name, data_dir);
2135 strcat(unix_name, "/fonts/");
2137 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2139 EnterCriticalSection( &freetype_cs );
2140 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2141 LeaveCriticalSection( &freetype_cs );
2142 HeapFree(GetProcessHeap(), 0, unix_name);
2144 return ret;
2147 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2149 static const WCHAR slashW[] = {'\\','\0'};
2150 BOOL ret = FALSE;
2151 WCHAR windowsdir[MAX_PATH];
2152 char *unixname;
2154 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2155 strcatW(windowsdir, fontsW);
2156 strcatW(windowsdir, slashW);
2157 strcatW(windowsdir, file);
2158 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2159 EnterCriticalSection( &freetype_cs );
2160 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2161 LeaveCriticalSection( &freetype_cs );
2162 HeapFree(GetProcessHeap(), 0, unixname);
2164 return ret;
2167 static void load_system_fonts(void)
2169 HKEY hkey;
2170 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2171 const WCHAR * const *value;
2172 DWORD dlen, type;
2173 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2174 char *unixname;
2176 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2177 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2178 strcatW(windowsdir, fontsW);
2179 for(value = SystemFontValues; *value; value++) {
2180 dlen = sizeof(data);
2181 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2182 type == REG_SZ) {
2183 BOOL added = FALSE;
2185 sprintfW(pathW, fmtW, windowsdir, data);
2186 if((unixname = wine_get_unix_file_name(pathW))) {
2187 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2188 HeapFree(GetProcessHeap(), 0, unixname);
2190 if (!added)
2191 load_font_from_data_dir(data);
2194 RegCloseKey(hkey);
2198 /*************************************************************
2200 * This adds registry entries for any externally loaded fonts
2201 * (fonts from fontconfig or FontDirs). It also deletes entries
2202 * of no longer existing fonts.
2205 static void update_reg_entries(void)
2207 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2208 LPWSTR valueW;
2209 DWORD len, len_fam;
2210 Family *family;
2211 Face *face;
2212 struct list *family_elem_ptr, *face_elem_ptr;
2213 WCHAR *file;
2214 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2215 static const WCHAR spaceW[] = {' ', '\0'};
2216 char *path;
2218 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2219 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2220 ERR("Can't create Windows font reg key\n");
2221 goto end;
2224 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2225 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2226 ERR("Can't create Windows font reg key\n");
2227 goto end;
2230 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2231 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2232 ERR("Can't create external font reg key\n");
2233 goto end;
2236 /* enumerate the fonts and add external ones to the two keys */
2238 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2239 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2240 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2241 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2242 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2243 if(!face->external) continue;
2244 len = len_fam;
2245 if (!(face->ntmFlags & NTM_REGULAR))
2246 len = len_fam + strlenW(face->StyleName) + 1;
2247 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2248 strcpyW(valueW, family->FamilyName);
2249 if(len != len_fam) {
2250 strcatW(valueW, spaceW);
2251 strcatW(valueW, face->StyleName);
2253 strcatW(valueW, TrueType);
2255 file = wine_get_dos_file_name(face->file);
2256 if(file)
2257 len = strlenW(file) + 1;
2258 else
2260 if((path = strrchr(face->file, '/')) == NULL)
2261 path = face->file;
2262 else
2263 path++;
2264 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2266 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2267 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2269 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2270 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2271 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2273 HeapFree(GetProcessHeap(), 0, file);
2274 HeapFree(GetProcessHeap(), 0, valueW);
2277 end:
2278 if(external_key) RegCloseKey(external_key);
2279 if(win9x_key) RegCloseKey(win9x_key);
2280 if(winnt_key) RegCloseKey(winnt_key);
2281 return;
2284 static void delete_external_font_keys(void)
2286 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2287 DWORD dlen, vlen, datalen, valuelen, i, type;
2288 LPWSTR valueW;
2289 LPVOID data;
2291 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2292 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2293 ERR("Can't create Windows font reg key\n");
2294 goto end;
2297 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2298 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2299 ERR("Can't create Windows font reg key\n");
2300 goto end;
2303 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2304 ERR("Can't create external font reg key\n");
2305 goto end;
2308 /* Delete all external fonts added last time */
2310 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2311 &valuelen, &datalen, NULL, NULL);
2312 valuelen++; /* returned value doesn't include room for '\0' */
2313 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2314 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2316 dlen = datalen * sizeof(WCHAR);
2317 vlen = valuelen;
2318 i = 0;
2319 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2320 &dlen) == ERROR_SUCCESS) {
2322 RegDeleteValueW(winnt_key, valueW);
2323 RegDeleteValueW(win9x_key, valueW);
2324 /* reset dlen and vlen */
2325 dlen = datalen;
2326 vlen = valuelen;
2328 HeapFree(GetProcessHeap(), 0, data);
2329 HeapFree(GetProcessHeap(), 0, valueW);
2331 /* Delete the old external fonts key */
2332 RegCloseKey(external_key);
2333 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2335 end:
2336 if(win9x_key) RegCloseKey(win9x_key);
2337 if(winnt_key) RegCloseKey(winnt_key);
2340 /*************************************************************
2341 * WineEngAddFontResourceEx
2344 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2346 INT ret = 0;
2348 GDI_CheckNotLock();
2350 if (ft_handle) /* do it only if we have freetype up and running */
2352 char *unixname;
2354 if(flags)
2355 FIXME("Ignoring flags %x\n", flags);
2357 if((unixname = wine_get_unix_file_name(file)))
2359 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2361 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2362 EnterCriticalSection( &freetype_cs );
2363 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2364 LeaveCriticalSection( &freetype_cs );
2365 HeapFree(GetProcessHeap(), 0, unixname);
2367 if (!ret && !strchrW(file, '\\')) {
2368 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2369 ret = load_font_from_winfonts_dir(file);
2370 if (!ret) {
2371 /* Try in datadir/fonts (or builddir/fonts),
2372 * needed for Magic the Gathering Online
2374 ret = load_font_from_data_dir(file);
2378 return ret;
2381 /*************************************************************
2382 * WineEngAddFontMemResourceEx
2385 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2387 GDI_CheckNotLock();
2389 if (ft_handle) /* do it only if we have freetype up and running */
2391 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2393 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2394 memcpy(pFontCopy, pbFont, cbFont);
2396 EnterCriticalSection( &freetype_cs );
2397 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2398 LeaveCriticalSection( &freetype_cs );
2400 if (*pcFonts == 0)
2402 TRACE("AddFontToList failed\n");
2403 HeapFree(GetProcessHeap(), 0, pFontCopy);
2404 return 0;
2406 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2407 * For now return something unique but quite random
2409 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2410 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2413 *pcFonts = 0;
2414 return 0;
2417 /*************************************************************
2418 * WineEngRemoveFontResourceEx
2421 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2423 GDI_CheckNotLock();
2424 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2425 return TRUE;
2428 static const struct nls_update_font_list
2430 UINT ansi_cp, oem_cp;
2431 const char *oem, *fixed, *system;
2432 const char *courier, *serif, *small, *sserif;
2433 /* these are for font substitutes */
2434 const char *shelldlg, *tmsrmn;
2435 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2436 *helv_0, *tmsrmn_0;
2437 const struct subst
2439 const char *from, *to;
2440 } arial_0, courier_new_0, times_new_roman_0;
2441 } nls_update_font_list[] =
2443 /* Latin 1 (United States) */
2444 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2445 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2446 "Tahoma","Times New Roman",
2447 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2448 { 0 }, { 0 }, { 0 }
2450 /* Latin 1 (Multilingual) */
2451 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2452 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2453 "Tahoma","Times New Roman", /* FIXME unverified */
2454 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2455 { 0 }, { 0 }, { 0 }
2457 /* Eastern Europe */
2458 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2459 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2460 "Tahoma","Times New Roman", /* FIXME unverified */
2461 "Fixedsys,238", "System,238",
2462 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2463 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2464 { "Arial CE,0", "Arial,238" },
2465 { "Courier New CE,0", "Courier New,238" },
2466 { "Times New Roman CE,0", "Times New Roman,238" }
2468 /* Cyrillic */
2469 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2470 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2471 "Tahoma","Times New Roman", /* FIXME unverified */
2472 "Fixedsys,204", "System,204",
2473 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2474 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2475 { "Arial Cyr,0", "Arial,204" },
2476 { "Courier New Cyr,0", "Courier New,204" },
2477 { "Times New Roman Cyr,0", "Times New Roman,204" }
2479 /* Greek */
2480 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2481 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2482 "Tahoma","Times New Roman", /* FIXME unverified */
2483 "Fixedsys,161", "System,161",
2484 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2485 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2486 { "Arial Greek,0", "Arial,161" },
2487 { "Courier New Greek,0", "Courier New,161" },
2488 { "Times New Roman Greek,0", "Times New Roman,161" }
2490 /* Turkish */
2491 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2492 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2493 "Tahoma","Times New Roman", /* FIXME unverified */
2494 "Fixedsys,162", "System,162",
2495 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2496 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2497 { "Arial Tur,0", "Arial,162" },
2498 { "Courier New Tur,0", "Courier New,162" },
2499 { "Times New Roman Tur,0", "Times New Roman,162" }
2501 /* Hebrew */
2502 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2503 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2504 "Tahoma","Times New Roman", /* FIXME unverified */
2505 "Fixedsys,177", "System,177",
2506 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2507 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2508 { 0 }, { 0 }, { 0 }
2510 /* Arabic */
2511 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2512 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2513 "Tahoma","Times New Roman", /* FIXME unverified */
2514 "Fixedsys,178", "System,178",
2515 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2516 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2517 { 0 }, { 0 }, { 0 }
2519 /* Baltic */
2520 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2521 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2522 "Tahoma","Times New Roman", /* FIXME unverified */
2523 "Fixedsys,186", "System,186",
2524 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2525 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2526 { "Arial Baltic,0", "Arial,186" },
2527 { "Courier New Baltic,0", "Courier New,186" },
2528 { "Times New Roman Baltic,0", "Times New Roman,186" }
2530 /* Vietnamese */
2531 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2532 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2533 "Tahoma","Times New Roman", /* FIXME unverified */
2534 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2535 { 0 }, { 0 }, { 0 }
2537 /* Thai */
2538 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2539 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2540 "Tahoma","Times New Roman", /* FIXME unverified */
2541 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2542 { 0 }, { 0 }, { 0 }
2544 /* Japanese */
2545 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2546 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2547 "MS UI Gothic","MS Serif",
2548 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2549 { 0 }, { 0 }, { 0 }
2551 /* Chinese Simplified */
2552 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2553 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2554 "SimSun", "NSimSun",
2555 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2556 { 0 }, { 0 }, { 0 }
2558 /* Korean */
2559 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2560 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2561 "Gulim", "Batang",
2562 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2563 { 0 }, { 0 }, { 0 }
2565 /* Chinese Traditional */
2566 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2567 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2568 "PMingLiU", "MingLiU",
2569 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2570 { 0 }, { 0 }, { 0 }
2574 static const WCHAR *font_links_list[] =
2576 Lucida_Sans_Unicode,
2577 Microsoft_Sans_Serif,
2578 Tahoma
2581 static const struct font_links_defaults_list
2583 /* Keyed off substitution for "MS Shell Dlg" */
2584 const WCHAR *shelldlg;
2585 /* Maximum of four substitutes, plus terminating NULL pointer */
2586 const WCHAR *substitutes[5];
2587 } font_links_defaults_list[] =
2589 /* Non East-Asian */
2590 { Tahoma, /* FIXME unverified ordering */
2591 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2593 /* Below lists are courtesy of
2594 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2596 /* Japanese */
2597 { MS_UI_Gothic,
2598 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2600 /* Chinese Simplified */
2601 { SimSun,
2602 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2604 /* Korean */
2605 { Gulim,
2606 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2608 /* Chinese Traditional */
2609 { PMingLiU,
2610 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2614 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2616 return ( ansi_cp == 932 /* CP932 for Japanese */
2617 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2618 || ansi_cp == 949 /* CP949 for Korean */
2619 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2622 static inline HKEY create_fonts_NT_registry_key(void)
2624 HKEY hkey = 0;
2626 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2627 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2628 return hkey;
2631 static inline HKEY create_fonts_9x_registry_key(void)
2633 HKEY hkey = 0;
2635 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2636 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2637 return hkey;
2640 static inline HKEY create_config_fonts_registry_key(void)
2642 HKEY hkey = 0;
2644 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2645 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2646 return hkey;
2649 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2651 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2652 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2653 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2654 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2657 static void set_value_key(HKEY hkey, const char *name, const char *value)
2659 if (value)
2660 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2661 else if (name)
2662 RegDeleteValueA(hkey, name);
2665 static void update_font_info(void)
2667 char buf[40], cpbuf[40];
2668 DWORD len, type;
2669 HKEY hkey = 0;
2670 UINT i, ansi_cp = 0, oem_cp = 0;
2671 BOOL done = FALSE;
2673 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2674 return;
2676 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2677 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2678 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2679 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2680 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2682 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2683 if (is_dbcs_ansi_cp(ansi_cp))
2684 use_default_fallback = TRUE;
2686 len = sizeof(buf);
2687 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2689 if (!strcmp( buf, cpbuf )) /* already set correctly */
2691 RegCloseKey(hkey);
2692 return;
2694 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2696 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2698 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2699 RegCloseKey(hkey);
2701 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2703 HKEY hkey;
2705 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2706 nls_update_font_list[i].oem_cp == oem_cp)
2708 hkey = create_config_fonts_registry_key();
2709 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2710 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2711 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2712 RegCloseKey(hkey);
2714 hkey = create_fonts_NT_registry_key();
2715 add_font_list(hkey, &nls_update_font_list[i]);
2716 RegCloseKey(hkey);
2718 hkey = create_fonts_9x_registry_key();
2719 add_font_list(hkey, &nls_update_font_list[i]);
2720 RegCloseKey(hkey);
2722 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2724 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2725 strlen(nls_update_font_list[i].shelldlg)+1);
2726 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2727 strlen(nls_update_font_list[i].tmsrmn)+1);
2729 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2730 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2731 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2732 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2733 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2734 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2735 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2736 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2738 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2739 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2740 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2742 RegCloseKey(hkey);
2744 done = TRUE;
2746 else
2748 /* Delete the FontSubstitutes from other locales */
2749 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2751 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2752 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2753 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2754 RegCloseKey(hkey);
2758 if (!done)
2759 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2761 /* Clear out system links */
2762 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2765 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2767 const WCHAR *value;
2768 int i;
2769 FontSubst *psub;
2770 Family *family;
2771 Face *face;
2772 const char *file;
2773 WCHAR *fileW;
2774 int fileLen;
2775 WCHAR buff[MAX_PATH];
2776 WCHAR *data;
2777 int entryLen;
2779 static const WCHAR comma[] = {',',0};
2781 RegDeleteValueW(hkey, name);
2782 if (values)
2784 data = buff;
2785 data[0] = '\0';
2786 for (i = 0; values[i] != NULL; i++)
2788 value = values[i];
2789 if (!strcmpiW(name,value))
2790 continue;
2791 psub = get_font_subst(&font_subst_list, value, -1);
2792 if(psub)
2793 value = psub->to.name;
2794 family = find_family_from_name(value);
2795 if (!family)
2796 continue;
2797 file = NULL;
2798 /* Use first extant filename for this Family */
2799 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2801 if (!face->file)
2802 continue;
2803 file = strrchr(face->file, '/');
2804 if (!file)
2805 file = face->file;
2806 else
2807 file++;
2808 break;
2810 if (!file)
2811 continue;
2812 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2813 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2814 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2815 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2816 if (sizeof(buff)-(data-buff) < entryLen + 1)
2818 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2819 HeapFree(GetProcessHeap(), 0, fileW);
2820 break;
2822 strcpyW(data, fileW);
2823 strcatW(data, comma);
2824 strcatW(data, value);
2825 data += entryLen;
2826 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2827 HeapFree(GetProcessHeap(), 0, fileW);
2829 if (data != buff)
2831 *data='\0';
2832 data++;
2833 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2834 } else
2835 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2836 } else
2837 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2840 static void update_system_links(void)
2842 HKEY hkey = 0;
2843 UINT i, j;
2844 BOOL done = FALSE;
2845 DWORD disposition;
2846 FontSubst *psub;
2848 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2850 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2852 if (disposition == REG_OPENED_EXISTING_KEY)
2854 TRACE("SystemLink key already exists, doing nothing\n");
2855 RegCloseKey(hkey);
2856 return;
2859 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2860 if (!psub) {
2861 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2862 RegCloseKey(hkey);
2863 return;
2866 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2868 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2870 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2871 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2873 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2874 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2875 done = TRUE;
2877 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2879 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2882 RegCloseKey(hkey);
2883 if (!done)
2884 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2885 } else
2886 WARN("failed to create SystemLink key\n");
2890 static BOOL init_freetype(void)
2892 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2893 if(!ft_handle) {
2894 WINE_MESSAGE(
2895 "Wine cannot find the FreeType font library. To enable Wine to\n"
2896 "use TrueType fonts please install a version of FreeType greater than\n"
2897 "or equal to 2.0.5.\n"
2898 "http://www.freetype.org\n");
2899 return FALSE;
2902 #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;}
2904 LOAD_FUNCPTR(FT_Done_Face)
2905 LOAD_FUNCPTR(FT_Get_Char_Index)
2906 LOAD_FUNCPTR(FT_Get_First_Char)
2907 LOAD_FUNCPTR(FT_Get_Module)
2908 LOAD_FUNCPTR(FT_Get_Next_Char)
2909 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2910 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2911 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2912 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2913 LOAD_FUNCPTR(FT_Init_FreeType)
2914 LOAD_FUNCPTR(FT_Library_Version)
2915 LOAD_FUNCPTR(FT_Load_Glyph)
2916 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2917 LOAD_FUNCPTR(FT_Matrix_Multiply)
2918 #ifndef FT_MULFIX_INLINED
2919 LOAD_FUNCPTR(FT_MulFix)
2920 #endif
2921 LOAD_FUNCPTR(FT_New_Face)
2922 LOAD_FUNCPTR(FT_New_Memory_Face)
2923 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2924 LOAD_FUNCPTR(FT_Outline_Transform)
2925 LOAD_FUNCPTR(FT_Outline_Translate)
2926 LOAD_FUNCPTR(FT_Render_Glyph)
2927 LOAD_FUNCPTR(FT_Select_Charmap)
2928 LOAD_FUNCPTR(FT_Set_Charmap)
2929 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2930 LOAD_FUNCPTR(FT_Vector_Transform)
2931 LOAD_FUNCPTR(FT_Vector_Unit)
2932 #undef LOAD_FUNCPTR
2933 /* Don't warn if these ones are missing */
2934 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2935 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2936 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2937 #endif
2939 if(pFT_Init_FreeType(&library) != 0) {
2940 ERR("Can't init FreeType library\n");
2941 wine_dlclose(ft_handle, NULL, 0);
2942 ft_handle = NULL;
2943 return FALSE;
2945 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2947 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2948 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2949 ((FT_Version.minor << 8) & 0x00ff00) |
2950 ((FT_Version.patch ) & 0x0000ff);
2952 font_driver = &freetype_funcs;
2953 return TRUE;
2955 sym_not_found:
2956 WINE_MESSAGE(
2957 "Wine cannot find certain functions that it needs inside the FreeType\n"
2958 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2959 "FreeType to at least version 2.1.4.\n"
2960 "http://www.freetype.org\n");
2961 wine_dlclose(ft_handle, NULL, 0);
2962 ft_handle = NULL;
2963 return FALSE;
2966 static void init_font_list(void)
2968 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2969 static const WCHAR pathW[] = {'P','a','t','h',0};
2970 HKEY hkey;
2971 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2972 WCHAR windowsdir[MAX_PATH];
2973 char *unixname;
2974 const char *data_dir;
2976 delete_external_font_keys();
2978 /* load the system bitmap fonts */
2979 load_system_fonts();
2981 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2982 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2983 strcatW(windowsdir, fontsW);
2984 if((unixname = wine_get_unix_file_name(windowsdir)))
2986 ReadFontDir(unixname, FALSE);
2987 HeapFree(GetProcessHeap(), 0, unixname);
2990 /* load the system truetype fonts */
2991 data_dir = wine_get_data_dir();
2992 if (!data_dir) data_dir = wine_get_build_dir();
2993 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
2995 strcpy(unixname, data_dir);
2996 strcat(unixname, "/fonts/");
2997 ReadFontDir(unixname, TRUE);
2998 HeapFree(GetProcessHeap(), 0, unixname);
3001 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3002 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3003 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3004 will skip these. */
3005 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3006 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3007 &hkey) == ERROR_SUCCESS)
3009 LPWSTR data, valueW;
3010 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3011 &valuelen, &datalen, NULL, NULL);
3013 valuelen++; /* returned value doesn't include room for '\0' */
3014 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3015 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3016 if (valueW && data)
3018 dlen = datalen * sizeof(WCHAR);
3019 vlen = valuelen;
3020 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3021 &dlen) == ERROR_SUCCESS)
3023 if(data[0] && (data[1] == ':'))
3025 if((unixname = wine_get_unix_file_name(data)))
3027 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3028 HeapFree(GetProcessHeap(), 0, unixname);
3031 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3033 WCHAR pathW[MAX_PATH];
3034 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3035 BOOL added = FALSE;
3037 sprintfW(pathW, fmtW, windowsdir, data);
3038 if((unixname = wine_get_unix_file_name(pathW)))
3040 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3041 HeapFree(GetProcessHeap(), 0, unixname);
3043 if (!added)
3044 load_font_from_data_dir(data);
3046 /* reset dlen and vlen */
3047 dlen = datalen;
3048 vlen = valuelen;
3051 HeapFree(GetProcessHeap(), 0, data);
3052 HeapFree(GetProcessHeap(), 0, valueW);
3053 RegCloseKey(hkey);
3056 load_fontconfig_fonts();
3058 /* then look in any directories that we've specified in the config file */
3059 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3060 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3062 DWORD len;
3063 LPWSTR valueW;
3064 LPSTR valueA, ptr;
3066 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3068 len += sizeof(WCHAR);
3069 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3070 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3072 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3073 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3074 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3075 TRACE( "got font path %s\n", debugstr_a(valueA) );
3076 ptr = valueA;
3077 while (ptr)
3079 const char* home;
3080 LPSTR next = strchr( ptr, ':' );
3081 if (next) *next++ = 0;
3082 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3083 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3085 strcpy( unixname, home );
3086 strcat( unixname, ptr + 1 );
3087 ReadFontDir( unixname, TRUE );
3088 HeapFree( GetProcessHeap(), 0, unixname );
3090 else
3091 ReadFontDir( ptr, TRUE );
3092 ptr = next;
3094 HeapFree( GetProcessHeap(), 0, valueA );
3096 HeapFree( GetProcessHeap(), 0, valueW );
3098 RegCloseKey(hkey);
3102 static BOOL move_to_front(const WCHAR *name)
3104 Family *family, *cursor2;
3105 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3107 if(!strcmpiW(family->FamilyName, name))
3109 list_remove(&family->entry);
3110 list_add_head(&font_list, &family->entry);
3111 return TRUE;
3114 return FALSE;
3117 static BOOL set_default(const WCHAR **name_list)
3119 while (*name_list)
3121 if (move_to_front(*name_list)) return TRUE;
3122 name_list++;
3125 return FALSE;
3128 static void reorder_font_list(void)
3130 set_default( default_serif_list );
3131 set_default( default_fixed_list );
3132 set_default( default_sans_list );
3135 /*************************************************************
3136 * WineEngInit
3138 * Initialize FreeType library and create a list of available faces
3140 BOOL WineEngInit(void)
3142 HKEY hkey_font_cache;
3143 DWORD disposition;
3144 HANDLE font_mutex;
3146 /* update locale dependent font info in registry */
3147 update_font_info();
3149 if(!init_freetype()) return FALSE;
3151 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3153 ERR("Failed to create font mutex\n");
3154 return FALSE;
3156 WaitForSingleObject(font_mutex, INFINITE);
3158 create_font_cache_key(&hkey_font_cache, &disposition);
3160 if(disposition == REG_CREATED_NEW_KEY)
3161 init_font_list();
3162 else
3163 load_font_list_from_cache(hkey_font_cache);
3165 RegCloseKey(hkey_font_cache);
3167 reorder_font_list();
3169 DumpFontList();
3170 LoadSubstList();
3171 DumpSubstList();
3172 LoadReplaceList();
3174 if(disposition == REG_CREATED_NEW_KEY)
3175 update_reg_entries();
3177 update_system_links();
3178 init_system_links();
3180 ReleaseMutex(font_mutex);
3181 return TRUE;
3185 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3187 TT_OS2 *pOS2;
3188 TT_HoriHeader *pHori;
3190 LONG ppem;
3192 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3193 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3195 if(height == 0) height = 16;
3197 /* Calc. height of EM square:
3199 * For +ve lfHeight we have
3200 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3201 * Re-arranging gives:
3202 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3204 * For -ve lfHeight we have
3205 * |lfHeight| = ppem
3206 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3207 * with il = winAscent + winDescent - units_per_em]
3211 if(height > 0) {
3212 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3213 ppem = MulDiv(ft_face->units_per_EM, height,
3214 pHori->Ascender - pHori->Descender);
3215 else
3216 ppem = MulDiv(ft_face->units_per_EM, height,
3217 pOS2->usWinAscent + pOS2->usWinDescent);
3219 else
3220 ppem = -height;
3222 return ppem;
3225 static struct font_mapping *map_font_file( const char *name )
3227 struct font_mapping *mapping;
3228 struct stat st;
3229 int fd;
3231 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3232 if (fstat( fd, &st ) == -1) goto error;
3234 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3236 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3238 mapping->refcount++;
3239 close( fd );
3240 return mapping;
3243 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3244 goto error;
3246 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3247 close( fd );
3249 if (mapping->data == MAP_FAILED)
3251 HeapFree( GetProcessHeap(), 0, mapping );
3252 return NULL;
3254 mapping->refcount = 1;
3255 mapping->dev = st.st_dev;
3256 mapping->ino = st.st_ino;
3257 mapping->size = st.st_size;
3258 list_add_tail( &mappings_list, &mapping->entry );
3259 return mapping;
3261 error:
3262 close( fd );
3263 return NULL;
3266 static void unmap_font_file( struct font_mapping *mapping )
3268 if (!--mapping->refcount)
3270 list_remove( &mapping->entry );
3271 munmap( mapping->data, mapping->size );
3272 HeapFree( GetProcessHeap(), 0, mapping );
3276 static LONG load_VDMX(GdiFont*, LONG);
3278 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3280 FT_Error err;
3281 FT_Face ft_face;
3282 void *data_ptr;
3283 DWORD data_size;
3285 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3287 if (face->file)
3289 if (!(font->mapping = map_font_file( face->file )))
3291 WARN("failed to map %s\n", debugstr_a(face->file));
3292 return 0;
3294 data_ptr = font->mapping->data;
3295 data_size = font->mapping->size;
3297 else
3299 data_ptr = face->font_data_ptr;
3300 data_size = face->font_data_size;
3303 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3304 if(err) {
3305 ERR("FT_New_Face rets %d\n", err);
3306 return 0;
3309 /* set it here, as load_VDMX needs it */
3310 font->ft_face = ft_face;
3312 if(FT_IS_SCALABLE(ft_face)) {
3313 /* load the VDMX table if we have one */
3314 font->ppem = load_VDMX(font, height);
3315 if(font->ppem == 0)
3316 font->ppem = calc_ppem_for_height(ft_face, height);
3317 TRACE("height %d => ppem %d\n", height, font->ppem);
3319 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3320 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3321 } else {
3322 font->ppem = height;
3323 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3324 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3326 return ft_face;
3330 static int get_nearest_charset(Face *face, int *cp)
3332 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3333 a single face with the requested charset. The idea is to check if
3334 the selected font supports the current ANSI codepage, if it does
3335 return the corresponding charset, else return the first charset */
3337 CHARSETINFO csi;
3338 int acp = GetACP(), i;
3339 DWORD fs0;
3341 *cp = acp;
3342 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3343 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3344 return csi.ciCharset;
3346 for(i = 0; i < 32; i++) {
3347 fs0 = 1L << i;
3348 if(face->fs.fsCsb[0] & fs0) {
3349 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3350 *cp = csi.ciACP;
3351 return csi.ciCharset;
3353 else
3354 FIXME("TCI failing on %x\n", fs0);
3358 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3359 face->fs.fsCsb[0], face->file);
3360 *cp = acp;
3361 return DEFAULT_CHARSET;
3364 static GdiFont *alloc_font(void)
3366 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3367 ret->gmsize = 1;
3368 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3369 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3370 ret->potm = NULL;
3371 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3372 ret->total_kern_pairs = (DWORD)-1;
3373 ret->kern_pairs = NULL;
3374 list_init(&ret->hfontlist);
3375 list_init(&ret->child_fonts);
3376 return ret;
3379 static void free_font(GdiFont *font)
3381 struct list *cursor, *cursor2;
3382 DWORD i;
3384 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3386 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3387 list_remove(cursor);
3388 if(child->font)
3389 free_font(child->font);
3390 HeapFree(GetProcessHeap(), 0, child);
3393 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3395 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3396 DeleteObject(hfontlist->hfont);
3397 list_remove(&hfontlist->entry);
3398 HeapFree(GetProcessHeap(), 0, hfontlist);
3401 if (font->ft_face) pFT_Done_Face(font->ft_face);
3402 if (font->mapping) unmap_font_file( font->mapping );
3403 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3404 HeapFree(GetProcessHeap(), 0, font->potm);
3405 HeapFree(GetProcessHeap(), 0, font->name);
3406 for (i = 0; i < font->gmsize; i++)
3407 HeapFree(GetProcessHeap(),0,font->gm[i]);
3408 HeapFree(GetProcessHeap(), 0, font->gm);
3409 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3410 HeapFree(GetProcessHeap(), 0, font);
3414 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3416 FT_Face ft_face = font->ft_face;
3417 FT_ULong len;
3418 FT_Error err;
3420 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3422 if(!buf)
3423 len = 0;
3424 else
3425 len = cbData;
3427 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3429 /* make sure value of len is the value freetype says it needs */
3430 if (buf && len)
3432 FT_ULong needed = 0;
3433 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3434 if( !err && needed < len) len = needed;
3436 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3437 if (err)
3439 TRACE("Can't find table %c%c%c%c\n",
3440 /* bytes were reversed */
3441 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3442 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3443 return GDI_ERROR;
3445 return len;
3448 /*************************************************************
3449 * load_VDMX
3451 * load the vdmx entry for the specified height
3454 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3455 ( ( (FT_ULong)_x4 << 24 ) | \
3456 ( (FT_ULong)_x3 << 16 ) | \
3457 ( (FT_ULong)_x2 << 8 ) | \
3458 (FT_ULong)_x1 )
3460 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3462 typedef struct {
3463 BYTE bCharSet;
3464 BYTE xRatio;
3465 BYTE yStartRatio;
3466 BYTE yEndRatio;
3467 } Ratios;
3469 typedef struct {
3470 WORD recs;
3471 BYTE startsz;
3472 BYTE endsz;
3473 } VDMX_group;
3475 static LONG load_VDMX(GdiFont *font, LONG height)
3477 WORD hdr[3], tmp;
3478 VDMX_group group;
3479 BYTE devXRatio, devYRatio;
3480 USHORT numRecs, numRatios;
3481 DWORD result, offset = -1;
3482 LONG ppem = 0;
3483 int i;
3485 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3487 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3488 return ppem;
3490 /* FIXME: need the real device aspect ratio */
3491 devXRatio = 1;
3492 devYRatio = 1;
3494 numRecs = GET_BE_WORD(hdr[1]);
3495 numRatios = GET_BE_WORD(hdr[2]);
3497 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3498 for(i = 0; i < numRatios; i++) {
3499 Ratios ratio;
3501 offset = (3 * 2) + (i * sizeof(Ratios));
3502 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3503 offset = -1;
3505 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3507 if((ratio.xRatio == 0 &&
3508 ratio.yStartRatio == 0 &&
3509 ratio.yEndRatio == 0) ||
3510 (devXRatio == ratio.xRatio &&
3511 devYRatio >= ratio.yStartRatio &&
3512 devYRatio <= ratio.yEndRatio))
3514 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3515 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3516 offset = GET_BE_WORD(tmp);
3517 break;
3521 if(offset == -1) {
3522 FIXME("No suitable ratio found\n");
3523 return ppem;
3526 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3527 USHORT recs;
3528 BYTE startsz, endsz;
3529 WORD *vTable;
3531 recs = GET_BE_WORD(group.recs);
3532 startsz = group.startsz;
3533 endsz = group.endsz;
3535 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3537 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3538 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3539 if(result == GDI_ERROR) {
3540 FIXME("Failed to retrieve vTable\n");
3541 goto end;
3544 if(height > 0) {
3545 for(i = 0; i < recs; i++) {
3546 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3547 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3548 ppem = GET_BE_WORD(vTable[i * 3]);
3550 if(yMax + -yMin == height) {
3551 font->yMax = yMax;
3552 font->yMin = yMin;
3553 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3554 break;
3556 if(yMax + -yMin > height) {
3557 if(--i < 0) {
3558 ppem = 0;
3559 goto end; /* failed */
3561 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3562 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3563 ppem = GET_BE_WORD(vTable[i * 3]);
3564 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3565 break;
3568 if(!font->yMax) {
3569 ppem = 0;
3570 TRACE("ppem not found for height %d\n", height);
3573 end:
3574 HeapFree(GetProcessHeap(), 0, vTable);
3577 return ppem;
3580 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3582 if(font->font_desc.hash != fd->hash) return TRUE;
3583 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3584 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3585 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3586 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3589 static void calc_hash(FONT_DESC *pfd)
3591 DWORD hash = 0, *ptr, two_chars;
3592 WORD *pwc;
3593 unsigned int i;
3595 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3596 hash ^= *ptr;
3597 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3598 hash ^= *ptr;
3599 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3600 two_chars = *ptr;
3601 pwc = (WCHAR *)&two_chars;
3602 if(!*pwc) break;
3603 *pwc = toupperW(*pwc);
3604 pwc++;
3605 *pwc = toupperW(*pwc);
3606 hash ^= two_chars;
3607 if(!*pwc) break;
3609 hash ^= !pfd->can_use_bitmap;
3610 pfd->hash = hash;
3611 return;
3614 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3616 GdiFont *ret;
3617 FONT_DESC fd;
3618 HFONTLIST *hflist;
3619 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3621 fd.lf = *plf;
3622 fd.matrix = *pmat;
3623 fd.can_use_bitmap = can_use_bitmap;
3624 calc_hash(&fd);
3626 /* try the child list */
3627 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3628 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3629 if(!fontcmp(ret, &fd)) {
3630 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3631 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3632 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3633 if(hflist->hfont == hfont)
3634 return ret;
3639 /* try the in-use list */
3640 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3641 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3642 if(!fontcmp(ret, &fd)) {
3643 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3644 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3645 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3646 if(hflist->hfont == hfont)
3647 return ret;
3649 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3650 hflist->hfont = hfont;
3651 list_add_head(&ret->hfontlist, &hflist->entry);
3652 return ret;
3656 /* then the unused list */
3657 font_elem_ptr = list_head(&unused_gdi_font_list);
3658 while(font_elem_ptr) {
3659 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3660 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3661 if(!fontcmp(ret, &fd)) {
3662 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3663 assert(list_empty(&ret->hfontlist));
3664 TRACE("Found %p in unused list\n", ret);
3665 list_remove(&ret->entry);
3666 list_add_head(&gdi_font_list, &ret->entry);
3667 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3668 hflist->hfont = hfont;
3669 list_add_head(&ret->hfontlist, &hflist->entry);
3670 return ret;
3673 return NULL;
3676 static void add_to_cache(GdiFont *font)
3678 static DWORD cache_num = 1;
3680 font->cache_num = cache_num++;
3681 list_add_head(&gdi_font_list, &font->entry);
3684 /*************************************************************
3685 * create_child_font_list
3687 static BOOL create_child_font_list(GdiFont *font)
3689 BOOL ret = FALSE;
3690 SYSTEM_LINKS *font_link;
3691 CHILD_FONT *font_link_entry, *new_child;
3692 FontSubst *psub;
3693 WCHAR* font_name;
3695 psub = get_font_subst(&font_subst_list, font->name, -1);
3696 font_name = psub ? psub->to.name : font->name;
3697 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3699 if(!strcmpiW(font_link->font_name, font_name))
3701 TRACE("found entry in system list\n");
3702 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3704 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3705 new_child->face = font_link_entry->face;
3706 new_child->font = NULL;
3707 list_add_tail(&font->child_fonts, &new_child->entry);
3708 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3710 ret = TRUE;
3711 break;
3715 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3716 * Sans Serif. This is how asian windows get default fallbacks for fonts
3718 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3719 font->charset != OEM_CHARSET &&
3720 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3721 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3723 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3725 TRACE("found entry in default fallback list\n");
3726 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3728 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3729 new_child->face = font_link_entry->face;
3730 new_child->font = NULL;
3731 list_add_tail(&font->child_fonts, &new_child->entry);
3732 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3734 ret = TRUE;
3735 break;
3739 return ret;
3742 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3744 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3746 if (pFT_Set_Charmap)
3748 FT_Int i;
3749 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3751 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3753 for (i = 0; i < ft_face->num_charmaps; i++)
3755 if (ft_face->charmaps[i]->encoding == encoding)
3757 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3758 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3760 switch (ft_face->charmaps[i]->platform_id)
3762 default:
3763 cmap_def = ft_face->charmaps[i];
3764 break;
3765 case 0: /* Apple Unicode */
3766 cmap0 = ft_face->charmaps[i];
3767 break;
3768 case 1: /* Macintosh */
3769 cmap1 = ft_face->charmaps[i];
3770 break;
3771 case 2: /* ISO */
3772 cmap2 = ft_face->charmaps[i];
3773 break;
3774 case 3: /* Microsoft */
3775 cmap3 = ft_face->charmaps[i];
3776 break;
3780 if (cmap3) /* prefer Microsoft cmap table */
3781 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3782 else if (cmap1)
3783 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3784 else if (cmap2)
3785 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3786 else if (cmap0)
3787 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3788 else if (cmap_def)
3789 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3791 return ft_err == FT_Err_Ok;
3794 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3798 /*************************************************************
3799 * freetype_CreateDC
3801 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3802 LPCWSTR output, const DEVMODEW *devmode )
3804 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3806 if (!physdev) return FALSE;
3807 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3808 return TRUE;
3812 /*************************************************************
3813 * freetype_DeleteDC
3815 static BOOL freetype_DeleteDC( PHYSDEV dev )
3817 struct freetype_physdev *physdev = get_freetype_dev( dev );
3818 HeapFree( GetProcessHeap(), 0, physdev );
3819 return TRUE;
3823 /*************************************************************
3824 * freetype_SelectFont
3826 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3828 struct freetype_physdev *physdev = get_freetype_dev( dev );
3829 GdiFont *ret;
3830 Face *face, *best, *best_bitmap;
3831 Family *family, *last_resort_family;
3832 struct list *family_elem_ptr, *face_elem_ptr;
3833 INT height, width = 0;
3834 unsigned int score = 0, new_score;
3835 signed int diff = 0, newdiff;
3836 BOOL bd, it, can_use_bitmap;
3837 LOGFONTW lf;
3838 CHARSETINFO csi;
3839 HFONTLIST *hflist;
3840 FMAT2 dcmat;
3841 FontSubst *psub = NULL;
3842 DC *dc = get_dc_ptr( dev->hdc );
3844 if (!hfont) /* notification that the font has been changed by another driver */
3846 dc->gdiFont = NULL;
3847 physdev->font = NULL;
3848 release_dc_ptr( dc );
3849 return 0;
3852 GetObjectW( hfont, sizeof(lf), &lf );
3853 lf.lfWidth = abs(lf.lfWidth);
3855 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3857 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3858 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3859 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3860 lf.lfEscapement);
3862 if(dc->GraphicsMode == GM_ADVANCED)
3863 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3864 else
3866 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3867 font scaling abilities. */
3868 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3869 dcmat.eM21 = dcmat.eM12 = 0;
3872 /* Try to avoid not necessary glyph transformations */
3873 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3875 lf.lfHeight *= fabs(dcmat.eM11);
3876 lf.lfWidth *= fabs(dcmat.eM11);
3877 dcmat.eM11 = dcmat.eM22 = 1.0;
3880 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3881 dcmat.eM21, dcmat.eM22);
3883 GDI_CheckNotLock();
3884 EnterCriticalSection( &freetype_cs );
3886 /* check the cache first */
3887 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3888 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3889 goto done;
3892 if(list_empty(&font_list)) /* No fonts installed */
3894 TRACE("No fonts installed\n");
3895 goto done;
3898 TRACE("not in cache\n");
3899 ret = alloc_font();
3901 ret->font_desc.matrix = dcmat;
3902 ret->font_desc.lf = lf;
3903 ret->font_desc.can_use_bitmap = can_use_bitmap;
3904 calc_hash(&ret->font_desc);
3905 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3906 hflist->hfont = hfont;
3907 list_add_head(&ret->hfontlist, &hflist->entry);
3909 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3910 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3911 original value lfCharSet. Note this is a special case for
3912 Symbol and doesn't happen at least for "Wingdings*" */
3914 if(!strcmpiW(lf.lfFaceName, SymbolW))
3915 lf.lfCharSet = SYMBOL_CHARSET;
3917 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3918 switch(lf.lfCharSet) {
3919 case DEFAULT_CHARSET:
3920 csi.fs.fsCsb[0] = 0;
3921 break;
3922 default:
3923 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3924 csi.fs.fsCsb[0] = 0;
3925 break;
3929 family = NULL;
3930 if(lf.lfFaceName[0] != '\0') {
3931 SYSTEM_LINKS *font_link;
3932 CHILD_FONT *font_link_entry;
3933 LPWSTR FaceName = lf.lfFaceName;
3936 * Check for a leading '@' this signals that the font is being
3937 * requested in tategaki mode (vertical writing substitution) but
3938 * does not affect the fontface that is to be selected.
3940 if (lf.lfFaceName[0]=='@')
3941 FaceName = &lf.lfFaceName[1];
3943 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3945 if(psub) {
3946 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3947 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3948 if (psub->to.charset != -1)
3949 lf.lfCharSet = psub->to.charset;
3952 /* We want a match on name and charset or just name if
3953 charset was DEFAULT_CHARSET. If the latter then
3954 we fixup the returned charset later in get_nearest_charset
3955 where we'll either use the charset of the current ansi codepage
3956 or if that's unavailable the first charset that the font supports.
3958 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3959 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3960 if (!strcmpiW(family->FamilyName, FaceName) ||
3961 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3963 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3964 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3965 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3966 if(face->scalable || can_use_bitmap)
3967 goto found;
3972 /* Search by full face name. */
3973 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3974 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3975 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3976 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3977 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3978 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3980 if(face->scalable || can_use_bitmap)
3981 goto found_face;
3987 * Try check the SystemLink list first for a replacement font.
3988 * We may find good replacements there.
3990 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3992 if(!strcmpiW(font_link->font_name, FaceName) ||
3993 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3995 TRACE("found entry in system list\n");
3996 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3998 face = font_link_entry->face;
3999 family = face->family;
4000 if(csi.fs.fsCsb[0] &
4001 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4003 if(face->scalable || can_use_bitmap)
4004 goto found;
4011 psub = NULL; /* substitution is no more relevant */
4013 /* If requested charset was DEFAULT_CHARSET then try using charset
4014 corresponding to the current ansi codepage */
4015 if (!csi.fs.fsCsb[0])
4017 INT acp = GetACP();
4018 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4019 FIXME("TCI failed on codepage %d\n", acp);
4020 csi.fs.fsCsb[0] = 0;
4021 } else
4022 lf.lfCharSet = csi.ciCharset;
4025 /* Face families are in the top 4 bits of lfPitchAndFamily,
4026 so mask with 0xF0 before testing */
4028 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4029 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4030 strcpyW(lf.lfFaceName, defFixed);
4031 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4032 strcpyW(lf.lfFaceName, defSerif);
4033 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4034 strcpyW(lf.lfFaceName, defSans);
4035 else
4036 strcpyW(lf.lfFaceName, defSans);
4037 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4038 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4039 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4040 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4041 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4042 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4043 if(face->scalable || can_use_bitmap)
4044 goto found;
4049 last_resort_family = NULL;
4050 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4051 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4052 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4053 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4054 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4055 if(face->scalable)
4056 goto found;
4057 if(can_use_bitmap && !last_resort_family)
4058 last_resort_family = family;
4063 if(last_resort_family) {
4064 family = last_resort_family;
4065 csi.fs.fsCsb[0] = 0;
4066 goto found;
4069 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4070 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4071 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4072 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4073 if(face->scalable) {
4074 csi.fs.fsCsb[0] = 0;
4075 WARN("just using first face for now\n");
4076 goto found;
4078 if(can_use_bitmap && !last_resort_family)
4079 last_resort_family = family;
4082 if(!last_resort_family) {
4083 FIXME("can't find a single appropriate font - bailing\n");
4084 free_font(ret);
4085 ret = NULL;
4086 goto done;
4089 WARN("could only find a bitmap font - this will probably look awful!\n");
4090 family = last_resort_family;
4091 csi.fs.fsCsb[0] = 0;
4093 found:
4094 it = lf.lfItalic ? 1 : 0;
4095 bd = lf.lfWeight > 550 ? 1 : 0;
4097 height = lf.lfHeight;
4099 face = best = best_bitmap = NULL;
4100 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4102 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4104 BOOL italic, bold;
4106 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4107 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4108 new_score = (italic ^ it) + (bold ^ bd);
4109 if(!best || new_score <= score)
4111 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4112 italic, bold, it, bd);
4113 score = new_score;
4114 best = face;
4115 if(best->scalable && score == 0) break;
4116 if(!best->scalable)
4118 if(height > 0)
4119 newdiff = height - (signed int)(best->size.height);
4120 else
4121 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4122 if(!best_bitmap || new_score < score ||
4123 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4125 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4126 diff = newdiff;
4127 best_bitmap = best;
4128 if(score == 0 && diff == 0) break;
4134 if(best)
4135 face = best->scalable ? best : best_bitmap;
4136 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4137 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4139 found_face:
4140 height = lf.lfHeight;
4142 ret->fs = face->fs;
4144 if(csi.fs.fsCsb[0]) {
4145 ret->charset = lf.lfCharSet;
4146 ret->codepage = csi.ciACP;
4148 else
4149 ret->charset = get_nearest_charset(face, &ret->codepage);
4151 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4152 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4154 ret->aveWidth = height ? lf.lfWidth : 0;
4156 if(!face->scalable) {
4157 /* Windows uses integer scaling factors for bitmap fonts */
4158 INT scale, scaled_height;
4159 GdiFont *cachedfont;
4161 /* FIXME: rotation of bitmap fonts is ignored */
4162 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4163 if (ret->aveWidth)
4164 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4165 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4166 dcmat.eM11 = dcmat.eM22 = 1.0;
4167 /* As we changed the matrix, we need to search the cache for the font again,
4168 * otherwise we might explode the cache. */
4169 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4170 TRACE("Found cached font after non-scalable matrix rescale!\n");
4171 free_font( ret );
4172 ret = cachedfont;
4173 goto done;
4175 calc_hash(&ret->font_desc);
4177 if (height != 0) height = diff;
4178 height += face->size.height;
4180 scale = (height + face->size.height - 1) / face->size.height;
4181 scaled_height = scale * face->size.height;
4182 /* Only jump to the next height if the difference <= 25% original height */
4183 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4184 /* The jump between unscaled and doubled is delayed by 1 */
4185 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4186 ret->scale_y = scale;
4188 width = face->size.x_ppem >> 6;
4189 height = face->size.y_ppem >> 6;
4191 else
4192 ret->scale_y = 1.0;
4193 TRACE("font scale y: %f\n", ret->scale_y);
4195 ret->ft_face = OpenFontFace(ret, face, width, height);
4197 if (!ret->ft_face)
4199 free_font( ret );
4200 ret = NULL;
4201 goto done;
4204 ret->ntmFlags = face->ntmFlags;
4206 if (ret->charset == SYMBOL_CHARSET &&
4207 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4208 /* No ops */
4210 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4211 /* No ops */
4213 else {
4214 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4217 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4218 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4219 ret->underline = lf.lfUnderline ? 0xff : 0;
4220 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4221 create_child_font_list(ret);
4223 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4225 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4226 if (length != GDI_ERROR)
4228 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4229 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4230 TRACE("Loaded GSUB table of %i bytes\n",length);
4234 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4236 add_to_cache(ret);
4237 done:
4238 if (ret)
4240 dc->gdiFont = ret;
4241 physdev->font = ret;
4243 LeaveCriticalSection( &freetype_cs );
4244 release_dc_ptr( dc );
4245 return ret ? hfont : 0;
4248 static void dump_gdi_font_list(void)
4250 GdiFont *gdiFont;
4251 struct list *elem_ptr;
4253 TRACE("---------- gdiFont Cache ----------\n");
4254 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4255 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4256 TRACE("gdiFont=%p %s %d\n",
4257 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4260 TRACE("---------- Unused gdiFont Cache ----------\n");
4261 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4262 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4263 TRACE("gdiFont=%p %s %d\n",
4264 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4267 TRACE("---------- Child gdiFont Cache ----------\n");
4268 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4269 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4270 TRACE("gdiFont=%p %s %d\n",
4271 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4275 /*************************************************************
4276 * WineEngDestroyFontInstance
4278 * free the gdiFont associated with this handle
4281 BOOL WineEngDestroyFontInstance(HFONT handle)
4283 GdiFont *gdiFont;
4284 HFONTLIST *hflist;
4285 BOOL ret = FALSE;
4286 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4287 int i = 0;
4289 GDI_CheckNotLock();
4290 EnterCriticalSection( &freetype_cs );
4292 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4294 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4295 while(hfontlist_elem_ptr) {
4296 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4297 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4298 if(hflist->hfont == handle) {
4299 TRACE("removing child font %p from child list\n", gdiFont);
4300 list_remove(&gdiFont->entry);
4301 LeaveCriticalSection( &freetype_cs );
4302 return TRUE;
4307 TRACE("destroying hfont=%p\n", handle);
4308 if(TRACE_ON(font))
4309 dump_gdi_font_list();
4311 font_elem_ptr = list_head(&gdi_font_list);
4312 while(font_elem_ptr) {
4313 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4314 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4316 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4317 while(hfontlist_elem_ptr) {
4318 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4319 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4320 if(hflist->hfont == handle) {
4321 list_remove(&hflist->entry);
4322 HeapFree(GetProcessHeap(), 0, hflist);
4323 ret = TRUE;
4326 if(list_empty(&gdiFont->hfontlist)) {
4327 TRACE("Moving to Unused list\n");
4328 list_remove(&gdiFont->entry);
4329 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4334 font_elem_ptr = list_head(&unused_gdi_font_list);
4335 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4336 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4337 while(font_elem_ptr) {
4338 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4339 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4340 TRACE("freeing %p\n", gdiFont);
4341 list_remove(&gdiFont->entry);
4342 free_font(gdiFont);
4344 LeaveCriticalSection( &freetype_cs );
4345 return ret;
4348 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4350 HRSRC rsrc;
4351 HGLOBAL hMem;
4352 WCHAR *p;
4353 int i;
4355 id += IDS_FIRST_SCRIPT;
4356 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4357 if (!rsrc) return 0;
4358 hMem = LoadResource( gdi32_module, rsrc );
4359 if (!hMem) return 0;
4361 p = LockResource( hMem );
4362 id &= 0x000f;
4363 while (id--) p += *p + 1;
4365 i = min(LF_FACESIZE - 1, *p);
4366 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4367 buffer[i] = 0;
4368 return i;
4372 /***************************************************
4373 * create_enum_charset_list
4375 * This function creates charset enumeration list because in DEFAULT_CHARSET
4376 * case, the ANSI codepage's charset takes precedence over other charsets.
4377 * This function works as a filter other than DEFAULT_CHARSET case.
4379 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4381 CHARSETINFO csi;
4382 DWORD n = 0;
4384 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4385 csi.fs.fsCsb[0] != 0) {
4386 list->element[n].mask = csi.fs.fsCsb[0];
4387 list->element[n].charset = csi.ciCharset;
4388 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4389 n++;
4391 else { /* charset is DEFAULT_CHARSET or invalid. */
4392 INT acp, i;
4394 /* Set the current codepage's charset as the first element. */
4395 acp = GetACP();
4396 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4397 csi.fs.fsCsb[0] != 0) {
4398 list->element[n].mask = csi.fs.fsCsb[0];
4399 list->element[n].charset = csi.ciCharset;
4400 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4401 n++;
4404 /* Fill out left elements. */
4405 for (i = 0; i < 32; i++) {
4406 FONTSIGNATURE fs;
4407 fs.fsCsb[0] = 1L << i;
4408 fs.fsCsb[1] = 0;
4409 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4410 continue; /* skip, already added. */
4411 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4412 continue; /* skip, this is an invalid fsCsb bit. */
4414 list->element[n].mask = fs.fsCsb[0];
4415 list->element[n].charset = csi.ciCharset;
4416 load_script_name( i, list->element[n].name );
4417 n++;
4420 list->total = n;
4422 return n;
4425 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4426 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4428 GdiFont *font;
4429 LONG width, height;
4431 if (face->cached_enum_data)
4433 TRACE("Cached\n");
4434 *pelf = face->cached_enum_data->elf;
4435 *pntm = face->cached_enum_data->ntm;
4436 *ptype = face->cached_enum_data->type;
4437 return;
4440 font = alloc_font();
4442 if(face->scalable) {
4443 height = -2048; /* 2048 is the most common em size */
4444 width = 0;
4445 } else {
4446 height = face->size.y_ppem >> 6;
4447 width = face->size.x_ppem >> 6;
4449 font->scale_y = 1.0;
4451 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4453 free_font(font);
4454 return;
4457 font->name = strdupW(face->family->FamilyName);
4458 font->ntmFlags = face->ntmFlags;
4460 if (get_outline_text_metrics(font))
4462 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4464 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4466 lstrcpynW(pelf->elfLogFont.lfFaceName,
4467 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4468 LF_FACESIZE);
4469 lstrcpynW(pelf->elfFullName,
4470 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4471 LF_FULLFACESIZE);
4472 lstrcpynW(pelf->elfStyle,
4473 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4474 LF_FACESIZE);
4476 else
4478 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4480 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4482 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4483 if (face->FullName)
4484 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4485 else
4486 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4487 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4490 pntm->ntmTm.ntmFlags = face->ntmFlags;
4491 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4492 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4493 pntm->ntmFontSig = face->fs;
4495 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4497 pelf->elfLogFont.lfEscapement = 0;
4498 pelf->elfLogFont.lfOrientation = 0;
4499 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4500 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4501 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4502 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4503 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4504 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4505 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4506 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4507 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4508 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4509 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4511 *ptype = 0;
4512 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4513 *ptype |= TRUETYPE_FONTTYPE;
4514 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4515 *ptype |= DEVICE_FONTTYPE;
4516 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4517 *ptype |= RASTER_FONTTYPE;
4519 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4520 if (face->cached_enum_data)
4522 face->cached_enum_data->elf = *pelf;
4523 face->cached_enum_data->ntm = *pntm;
4524 face->cached_enum_data->type = *ptype;
4527 free_font(font);
4530 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4532 struct list *face_elem_ptr;
4534 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4536 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4538 static const WCHAR spaceW[] = { ' ',0 };
4539 WCHAR full_family_name[LF_FULLFACESIZE];
4540 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4542 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4544 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4545 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4546 continue;
4549 strcpyW(full_family_name, family->FamilyName);
4550 strcatW(full_family_name, spaceW);
4551 strcatW(full_family_name, face->StyleName);
4552 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4555 return FALSE;
4558 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4560 static const WCHAR spaceW[] = { ' ',0 };
4561 WCHAR full_family_name[LF_FULLFACESIZE];
4563 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4565 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4567 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4568 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4569 return FALSE;
4572 strcpyW(full_family_name, face->family->FamilyName);
4573 strcatW(full_family_name, spaceW);
4574 strcatW(full_family_name, face->StyleName);
4575 return !strcmpiW(lf->lfFaceName, full_family_name);
4578 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4579 FONTENUMPROCW proc, LPARAM lparam)
4581 ENUMLOGFONTEXW elf;
4582 NEWTEXTMETRICEXW ntm;
4583 DWORD type = 0;
4584 int i;
4586 GetEnumStructs(face, &elf, &ntm, &type);
4587 for(i = 0; i < list->total; i++) {
4588 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4589 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4590 load_script_name( IDS_OEM_DOS, elf.elfScript );
4591 i = list->total; /* break out of loop after enumeration */
4592 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4593 continue;
4594 else {
4595 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4596 strcpyW(elf.elfScript, list->element[i].name);
4597 if (!elf.elfScript[0])
4598 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4600 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4601 debugstr_w(elf.elfLogFont.lfFaceName),
4602 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4603 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4604 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4605 ntm.ntmTm.ntmFlags);
4606 /* release section before callback (FIXME) */
4607 LeaveCriticalSection( &freetype_cs );
4608 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4609 EnterCriticalSection( &freetype_cs );
4611 return TRUE;
4614 /*************************************************************
4615 * freetype_EnumFonts
4617 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4619 Family *family;
4620 Face *face;
4621 struct list *family_elem_ptr, *face_elem_ptr;
4622 LOGFONTW lf;
4623 struct enum_charset_list enum_charsets;
4625 if (!plf)
4627 lf.lfCharSet = DEFAULT_CHARSET;
4628 lf.lfPitchAndFamily = 0;
4629 lf.lfFaceName[0] = 0;
4630 plf = &lf;
4633 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4635 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4637 GDI_CheckNotLock();
4638 EnterCriticalSection( &freetype_cs );
4639 if(plf->lfFaceName[0]) {
4640 FontSubst *psub;
4641 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4643 if(psub) {
4644 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4645 debugstr_w(psub->to.name));
4646 lf = *plf;
4647 strcpyW(lf.lfFaceName, psub->to.name);
4648 plf = &lf;
4651 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4652 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4653 if(family_matches(family, plf)) {
4654 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4655 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4656 if (!face_matches(face, plf)) continue;
4657 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4661 } else {
4662 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4663 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4664 face_elem_ptr = list_head(&family->faces);
4665 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4666 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4669 LeaveCriticalSection( &freetype_cs );
4670 return TRUE;
4673 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4675 pt->x.value = vec->x >> 6;
4676 pt->x.fract = (vec->x & 0x3f) << 10;
4677 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4678 pt->y.value = vec->y >> 6;
4679 pt->y.fract = (vec->y & 0x3f) << 10;
4680 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4681 return;
4684 /***************************************************
4685 * According to the MSDN documentation on WideCharToMultiByte,
4686 * certain codepages cannot set the default_used parameter.
4687 * This returns TRUE if the codepage can set that parameter, false else
4688 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4690 static BOOL codepage_sets_default_used(UINT codepage)
4692 switch (codepage)
4694 case CP_UTF7:
4695 case CP_UTF8:
4696 case CP_SYMBOL:
4697 return FALSE;
4698 default:
4699 return TRUE;
4704 * GSUB Table handling functions
4707 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4709 const GSUB_CoverageFormat1* cf1;
4711 cf1 = table;
4713 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4715 int count = GET_BE_WORD(cf1->GlyphCount);
4716 int i;
4717 TRACE("Coverage Format 1, %i glyphs\n",count);
4718 for (i = 0; i < count; i++)
4719 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4720 return i;
4721 return -1;
4723 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4725 const GSUB_CoverageFormat2* cf2;
4726 int i;
4727 int count;
4728 cf2 = (const GSUB_CoverageFormat2*)cf1;
4730 count = GET_BE_WORD(cf2->RangeCount);
4731 TRACE("Coverage Format 2, %i ranges\n",count);
4732 for (i = 0; i < count; i++)
4734 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4735 return -1;
4736 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4737 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4739 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4740 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4743 return -1;
4745 else
4746 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4748 return -1;
4751 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4753 const GSUB_ScriptList *script;
4754 const GSUB_Script *deflt = NULL;
4755 int i;
4756 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4758 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4759 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4761 const GSUB_Script *scr;
4762 int offset;
4764 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4765 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4767 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4768 return scr;
4769 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4770 deflt = scr;
4772 return deflt;
4775 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4777 int i;
4778 int offset;
4779 const GSUB_LangSys *Lang;
4781 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4783 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4785 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4786 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4788 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4789 return Lang;
4791 offset = GET_BE_WORD(script->DefaultLangSys);
4792 if (offset)
4794 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4795 return Lang;
4797 return NULL;
4800 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4802 int i;
4803 const GSUB_FeatureList *feature;
4804 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4806 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4807 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4809 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4810 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4812 const GSUB_Feature *feat;
4813 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4814 return feat;
4817 return NULL;
4820 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4822 int i;
4823 int offset;
4824 const GSUB_LookupList *lookup;
4825 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4827 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4828 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4830 const GSUB_LookupTable *look;
4831 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4832 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4833 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4834 if (GET_BE_WORD(look->LookupType) != 1)
4835 FIXME("We only handle SubType 1\n");
4836 else
4838 int j;
4840 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4842 const GSUB_SingleSubstFormat1 *ssf1;
4843 offset = GET_BE_WORD(look->SubTable[j]);
4844 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4845 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4847 int offset = GET_BE_WORD(ssf1->Coverage);
4848 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4849 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4851 TRACE(" Glyph 0x%x ->",glyph);
4852 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4853 TRACE(" 0x%x\n",glyph);
4856 else
4858 const GSUB_SingleSubstFormat2 *ssf2;
4859 INT index;
4860 INT offset;
4862 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4863 offset = GET_BE_WORD(ssf1->Coverage);
4864 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4865 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4866 TRACE(" Coverage index %i\n",index);
4867 if (index != -1)
4869 TRACE(" Glyph is 0x%x ->",glyph);
4870 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4871 TRACE("0x%x\n",glyph);
4877 return glyph;
4880 static const char* get_opentype_script(const GdiFont *font)
4883 * I am not sure if this is the correct way to generate our script tag
4886 switch (font->charset)
4888 case ANSI_CHARSET: return "latn";
4889 case BALTIC_CHARSET: return "latn"; /* ?? */
4890 case CHINESEBIG5_CHARSET: return "hani";
4891 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4892 case GB2312_CHARSET: return "hani";
4893 case GREEK_CHARSET: return "grek";
4894 case HANGUL_CHARSET: return "hang";
4895 case RUSSIAN_CHARSET: return "cyrl";
4896 case SHIFTJIS_CHARSET: return "kana";
4897 case TURKISH_CHARSET: return "latn"; /* ?? */
4898 case VIETNAMESE_CHARSET: return "latn";
4899 case JOHAB_CHARSET: return "latn"; /* ?? */
4900 case ARABIC_CHARSET: return "arab";
4901 case HEBREW_CHARSET: return "hebr";
4902 case THAI_CHARSET: return "thai";
4903 default: return "latn";
4907 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4909 const GSUB_Header *header;
4910 const GSUB_Script *script;
4911 const GSUB_LangSys *language;
4912 const GSUB_Feature *feature;
4914 if (!font->GSUB_Table)
4915 return glyph;
4917 header = font->GSUB_Table;
4919 script = GSUB_get_script_table(header, get_opentype_script(font));
4920 if (!script)
4922 TRACE("Script not found\n");
4923 return glyph;
4925 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4926 if (!language)
4928 TRACE("Language not found\n");
4929 return glyph;
4931 feature = GSUB_get_feature(header, language, "vrt2");
4932 if (!feature)
4933 feature = GSUB_get_feature(header, language, "vert");
4934 if (!feature)
4936 TRACE("vrt2/vert feature not found\n");
4937 return glyph;
4939 return GSUB_apply_feature(header, feature, glyph);
4942 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4944 FT_UInt glyphId;
4946 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4947 WCHAR wc = (WCHAR)glyph;
4948 BOOL default_used;
4949 BOOL *default_used_pointer;
4950 FT_UInt ret;
4951 char buf;
4952 default_used_pointer = NULL;
4953 default_used = FALSE;
4954 if (codepage_sets_default_used(font->codepage))
4955 default_used_pointer = &default_used;
4956 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4957 ret = 0;
4958 else
4959 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4960 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4961 return get_GSUB_vert_glyph(font,ret);
4964 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4966 if (glyph < 0x100) glyph += 0xf000;
4967 /* there is a number of old pre-Unicode "broken" TTFs, which
4968 do have symbols at U+00XX instead of U+f0XX */
4969 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4970 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4972 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4974 return get_GSUB_vert_glyph(font,glyphId);
4977 /*************************************************************
4978 * freetype_GetGlyphIndices
4980 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
4982 struct freetype_physdev *physdev = get_freetype_dev( dev );
4983 int i;
4984 WORD default_char;
4985 BOOL got_default = FALSE;
4987 if (!physdev->font)
4989 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
4990 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
4993 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4995 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4996 got_default = TRUE;
4999 GDI_CheckNotLock();
5000 EnterCriticalSection( &freetype_cs );
5002 for(i = 0; i < count; i++)
5004 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5005 if (pgi[i] == 0)
5007 if (!got_default)
5009 if (FT_IS_SFNT(physdev->font->ft_face))
5011 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5012 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5014 else
5016 TEXTMETRICW textm;
5017 get_text_metrics(physdev->font, &textm);
5018 default_char = textm.tmDefaultChar;
5020 got_default = TRUE;
5022 pgi[i] = default_char;
5025 LeaveCriticalSection( &freetype_cs );
5026 return count;
5029 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5031 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5032 return !memcmp(matrix, &identity, sizeof(FMAT2));
5035 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5037 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5038 return !memcmp(matrix, &identity, sizeof(MAT2));
5041 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5042 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5043 const MAT2* lpmat)
5045 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5046 FT_Face ft_face = incoming_font->ft_face;
5047 GdiFont *font = incoming_font;
5048 FT_UInt glyph_index;
5049 DWORD width, height, pitch, needed = 0;
5050 FT_Bitmap ft_bitmap;
5051 FT_Error err;
5052 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5053 FT_Angle angle = 0;
5054 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5055 double widthRatio = 1.0;
5056 FT_Matrix transMat = identityMat;
5057 FT_Matrix transMatUnrotated;
5058 BOOL needsTransform = FALSE;
5059 BOOL tategaki = (font->GSUB_Table != NULL);
5060 UINT original_index;
5062 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5063 buflen, buf, lpmat);
5065 TRACE("font transform %f %f %f %f\n",
5066 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5067 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5069 if(format & GGO_GLYPH_INDEX) {
5070 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5071 original_index = glyph;
5072 format &= ~GGO_GLYPH_INDEX;
5073 } else {
5074 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5075 ft_face = font->ft_face;
5076 original_index = glyph_index;
5079 if(format & GGO_UNHINTED) {
5080 load_flags |= FT_LOAD_NO_HINTING;
5081 format &= ~GGO_UNHINTED;
5084 /* tategaki never appears to happen to lower glyph index */
5085 if (glyph_index < TATEGAKI_LOWER_BOUND )
5086 tategaki = FALSE;
5088 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5089 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5090 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5091 font->gmsize * sizeof(GM*));
5092 } else {
5093 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5094 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5096 *lpgm = FONT_GM(font,original_index)->gm;
5097 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5098 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5099 lpgm->gmCellIncX, lpgm->gmCellIncY);
5100 return 1; /* FIXME */
5104 if (!font->gm[original_index / GM_BLOCK_SIZE])
5105 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5107 /* Scaling factor */
5108 if (font->aveWidth)
5110 TEXTMETRICW tm;
5112 get_text_metrics(font, &tm);
5114 widthRatio = (double)font->aveWidth;
5115 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5117 else
5118 widthRatio = font->scale_y;
5120 /* Scaling transform */
5121 if (widthRatio != 1.0 || font->scale_y != 1.0)
5123 FT_Matrix scaleMat;
5124 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5125 scaleMat.xy = 0;
5126 scaleMat.yx = 0;
5127 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5129 pFT_Matrix_Multiply(&scaleMat, &transMat);
5130 needsTransform = TRUE;
5133 /* Slant transform */
5134 if (font->fake_italic) {
5135 FT_Matrix slantMat;
5137 slantMat.xx = (1 << 16);
5138 slantMat.xy = ((1 << 16) >> 2);
5139 slantMat.yx = 0;
5140 slantMat.yy = (1 << 16);
5141 pFT_Matrix_Multiply(&slantMat, &transMat);
5142 needsTransform = TRUE;
5145 /* Rotation transform */
5146 transMatUnrotated = transMat;
5147 if(font->orientation && !tategaki) {
5148 FT_Matrix rotationMat;
5149 FT_Vector vecAngle;
5150 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5151 pFT_Vector_Unit(&vecAngle, angle);
5152 rotationMat.xx = vecAngle.x;
5153 rotationMat.xy = -vecAngle.y;
5154 rotationMat.yx = -rotationMat.xy;
5155 rotationMat.yy = rotationMat.xx;
5157 pFT_Matrix_Multiply(&rotationMat, &transMat);
5158 needsTransform = TRUE;
5161 /* World transform */
5162 if (!is_identity_FMAT2(&font->font_desc.matrix))
5164 FT_Matrix worldMat;
5165 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5166 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5167 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5168 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5169 pFT_Matrix_Multiply(&worldMat, &transMat);
5170 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5171 needsTransform = TRUE;
5174 /* Extra transformation specified by caller */
5175 if (!is_identity_MAT2(lpmat))
5177 FT_Matrix extraMat;
5178 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5179 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5180 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5181 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5182 pFT_Matrix_Multiply(&extraMat, &transMat);
5183 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5184 needsTransform = TRUE;
5187 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5188 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5189 format == GGO_GRAY8_BITMAP))
5191 load_flags |= FT_LOAD_NO_BITMAP;
5194 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5196 if(err) {
5197 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5198 return GDI_ERROR;
5201 if(!needsTransform) {
5202 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5203 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5204 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5206 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5207 bottom = (ft_face->glyph->metrics.horiBearingY -
5208 ft_face->glyph->metrics.height) & -64;
5209 lpgm->gmCellIncX = adv;
5210 lpgm->gmCellIncY = 0;
5211 } else {
5212 INT xc, yc;
5213 FT_Vector vec;
5215 left = right = 0;
5217 for(xc = 0; xc < 2; xc++) {
5218 for(yc = 0; yc < 2; yc++) {
5219 vec.x = (ft_face->glyph->metrics.horiBearingX +
5220 xc * ft_face->glyph->metrics.width);
5221 vec.y = ft_face->glyph->metrics.horiBearingY -
5222 yc * ft_face->glyph->metrics.height;
5223 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5224 pFT_Vector_Transform(&vec, &transMat);
5225 if(xc == 0 && yc == 0) {
5226 left = right = vec.x;
5227 top = bottom = vec.y;
5228 } else {
5229 if(vec.x < left) left = vec.x;
5230 else if(vec.x > right) right = vec.x;
5231 if(vec.y < bottom) bottom = vec.y;
5232 else if(vec.y > top) top = vec.y;
5236 left = left & -64;
5237 right = (right + 63) & -64;
5238 bottom = bottom & -64;
5239 top = (top + 63) & -64;
5241 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5242 vec.x = ft_face->glyph->metrics.horiAdvance;
5243 vec.y = 0;
5244 pFT_Vector_Transform(&vec, &transMat);
5245 lpgm->gmCellIncX = (vec.x+63) >> 6;
5246 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5248 vec.x = ft_face->glyph->metrics.horiAdvance;
5249 vec.y = 0;
5250 pFT_Vector_Transform(&vec, &transMatUnrotated);
5251 adv = (vec.x+63) >> 6;
5254 lsb = left >> 6;
5255 bbx = (right - left) >> 6;
5256 lpgm->gmBlackBoxX = (right - left) >> 6;
5257 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5258 lpgm->gmptGlyphOrigin.x = left >> 6;
5259 lpgm->gmptGlyphOrigin.y = top >> 6;
5261 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5262 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5263 lpgm->gmCellIncX, lpgm->gmCellIncY);
5265 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5266 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5268 FONT_GM(font,original_index)->gm = *lpgm;
5269 FONT_GM(font,original_index)->adv = adv;
5270 FONT_GM(font,original_index)->lsb = lsb;
5271 FONT_GM(font,original_index)->bbx = bbx;
5272 FONT_GM(font,original_index)->init = TRUE;
5275 if(format == GGO_METRICS)
5277 return 1; /* FIXME */
5280 if(ft_face->glyph->format != ft_glyph_format_outline &&
5281 (format == GGO_NATIVE || format == GGO_BEZIER ||
5282 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5283 format == GGO_GRAY8_BITMAP))
5285 TRACE("loaded a bitmap\n");
5286 return GDI_ERROR;
5289 switch(format) {
5290 case GGO_BITMAP:
5291 width = lpgm->gmBlackBoxX;
5292 height = lpgm->gmBlackBoxY;
5293 pitch = ((width + 31) >> 5) << 2;
5294 needed = pitch * height;
5296 if(!buf || !buflen) break;
5298 switch(ft_face->glyph->format) {
5299 case ft_glyph_format_bitmap:
5301 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5302 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5303 INT h = ft_face->glyph->bitmap.rows;
5304 while(h--) {
5305 memcpy(dst, src, w);
5306 src += ft_face->glyph->bitmap.pitch;
5307 dst += pitch;
5309 break;
5312 case ft_glyph_format_outline:
5313 ft_bitmap.width = width;
5314 ft_bitmap.rows = height;
5315 ft_bitmap.pitch = pitch;
5316 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5317 ft_bitmap.buffer = buf;
5319 if(needsTransform)
5320 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5322 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5324 /* Note: FreeType will only set 'black' bits for us. */
5325 memset(buf, 0, needed);
5326 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5327 break;
5329 default:
5330 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5331 return GDI_ERROR;
5333 break;
5335 case GGO_GRAY2_BITMAP:
5336 case GGO_GRAY4_BITMAP:
5337 case GGO_GRAY8_BITMAP:
5338 case WINE_GGO_GRAY16_BITMAP:
5340 unsigned int mult, row, col;
5341 BYTE *start, *ptr;
5343 width = lpgm->gmBlackBoxX;
5344 height = lpgm->gmBlackBoxY;
5345 pitch = (width + 3) / 4 * 4;
5346 needed = pitch * height;
5348 if(!buf || !buflen) break;
5350 switch(ft_face->glyph->format) {
5351 case ft_glyph_format_bitmap:
5353 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5354 INT h = ft_face->glyph->bitmap.rows;
5355 INT x;
5356 memset( buf, 0, needed );
5357 while(h--) {
5358 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5359 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5360 src += ft_face->glyph->bitmap.pitch;
5361 dst += pitch;
5363 return needed;
5365 case ft_glyph_format_outline:
5367 ft_bitmap.width = width;
5368 ft_bitmap.rows = height;
5369 ft_bitmap.pitch = pitch;
5370 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5371 ft_bitmap.buffer = buf;
5373 if(needsTransform)
5374 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5376 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5378 memset(ft_bitmap.buffer, 0, buflen);
5380 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5382 if(format == GGO_GRAY2_BITMAP)
5383 mult = 4;
5384 else if(format == GGO_GRAY4_BITMAP)
5385 mult = 16;
5386 else if(format == GGO_GRAY8_BITMAP)
5387 mult = 64;
5388 else /* format == WINE_GGO_GRAY16_BITMAP */
5389 return needed;
5390 break;
5392 default:
5393 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5394 return GDI_ERROR;
5397 start = buf;
5398 for(row = 0; row < height; row++) {
5399 ptr = start;
5400 for(col = 0; col < width; col++, ptr++) {
5401 *ptr = (((int)*ptr) * mult + 128) / 256;
5403 start += pitch;
5405 break;
5408 case WINE_GGO_HRGB_BITMAP:
5409 case WINE_GGO_HBGR_BITMAP:
5410 case WINE_GGO_VRGB_BITMAP:
5411 case WINE_GGO_VBGR_BITMAP:
5412 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5414 switch (ft_face->glyph->format)
5416 case FT_GLYPH_FORMAT_BITMAP:
5418 BYTE *src, *dst;
5419 INT src_pitch, x;
5421 width = lpgm->gmBlackBoxX;
5422 height = lpgm->gmBlackBoxY;
5423 pitch = width * 4;
5424 needed = pitch * height;
5426 if (!buf || !buflen) break;
5428 memset(buf, 0, buflen);
5429 dst = buf;
5430 src = ft_face->glyph->bitmap.buffer;
5431 src_pitch = ft_face->glyph->bitmap.pitch;
5433 height = min( height, ft_face->glyph->bitmap.rows );
5434 while ( height-- )
5436 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5438 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5439 ((unsigned int *)dst)[x] = ~0u;
5441 src += src_pitch;
5442 dst += pitch;
5445 break;
5448 case FT_GLYPH_FORMAT_OUTLINE:
5450 unsigned int *dst;
5451 BYTE *src;
5452 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5453 INT x_shift, y_shift;
5454 BOOL rgb;
5455 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5456 FT_Render_Mode render_mode =
5457 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5458 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5460 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5462 if ( render_mode == FT_RENDER_MODE_LCD)
5464 lpgm->gmBlackBoxX += 2;
5465 lpgm->gmptGlyphOrigin.x -= 1;
5467 else
5469 lpgm->gmBlackBoxY += 2;
5470 lpgm->gmptGlyphOrigin.y += 1;
5474 width = lpgm->gmBlackBoxX;
5475 height = lpgm->gmBlackBoxY;
5476 pitch = width * 4;
5477 needed = pitch * height;
5479 if (!buf || !buflen) break;
5481 memset(buf, 0, buflen);
5482 dst = buf;
5483 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5485 if ( needsTransform )
5486 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5488 if ( pFT_Library_SetLcdFilter )
5489 pFT_Library_SetLcdFilter( library, lcdfilter );
5490 pFT_Render_Glyph (ft_face->glyph, render_mode);
5492 src = ft_face->glyph->bitmap.buffer;
5493 src_pitch = ft_face->glyph->bitmap.pitch;
5494 src_width = ft_face->glyph->bitmap.width;
5495 src_height = ft_face->glyph->bitmap.rows;
5497 if ( render_mode == FT_RENDER_MODE_LCD)
5499 rgb_interval = 1;
5500 hmul = 3;
5501 vmul = 1;
5503 else
5505 rgb_interval = src_pitch;
5506 hmul = 1;
5507 vmul = 3;
5510 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5511 if ( x_shift < 0 ) x_shift = 0;
5512 if ( x_shift + (src_width / hmul) > width )
5513 x_shift = width - (src_width / hmul);
5515 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5516 if ( y_shift < 0 ) y_shift = 0;
5517 if ( y_shift + (src_height / vmul) > height )
5518 y_shift = height - (src_height / vmul);
5520 dst += x_shift + y_shift * ( pitch / 4 );
5521 while ( src_height )
5523 for ( x = 0; x < src_width / hmul; x++ )
5525 if ( rgb )
5527 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5528 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5529 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5530 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5532 else
5534 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5535 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5536 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5537 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5540 src += src_pitch * vmul;
5541 dst += pitch / 4;
5542 src_height -= vmul;
5545 break;
5548 default:
5549 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5550 return GDI_ERROR;
5553 break;
5555 #else
5556 return GDI_ERROR;
5557 #endif
5559 case GGO_NATIVE:
5561 int contour, point = 0, first_pt;
5562 FT_Outline *outline = &ft_face->glyph->outline;
5563 TTPOLYGONHEADER *pph;
5564 TTPOLYCURVE *ppc;
5565 DWORD pph_start, cpfx, type;
5567 if(buflen == 0) buf = NULL;
5569 if (needsTransform && buf) {
5570 pFT_Outline_Transform(outline, &transMat);
5573 for(contour = 0; contour < outline->n_contours; contour++) {
5574 pph_start = needed;
5575 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5576 first_pt = point;
5577 if(buf) {
5578 pph->dwType = TT_POLYGON_TYPE;
5579 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5581 needed += sizeof(*pph);
5582 point++;
5583 while(point <= outline->contours[contour]) {
5584 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5585 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5586 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5587 cpfx = 0;
5588 do {
5589 if(buf)
5590 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5591 cpfx++;
5592 point++;
5593 } while(point <= outline->contours[contour] &&
5594 (outline->tags[point] & FT_Curve_Tag_On) ==
5595 (outline->tags[point-1] & FT_Curve_Tag_On));
5596 /* At the end of a contour Windows adds the start point, but
5597 only for Beziers */
5598 if(point > outline->contours[contour] &&
5599 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5600 if(buf)
5601 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5602 cpfx++;
5603 } else if(point <= outline->contours[contour] &&
5604 outline->tags[point] & FT_Curve_Tag_On) {
5605 /* add closing pt for bezier */
5606 if(buf)
5607 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5608 cpfx++;
5609 point++;
5611 if(buf) {
5612 ppc->wType = type;
5613 ppc->cpfx = cpfx;
5615 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5617 if(buf)
5618 pph->cb = needed - pph_start;
5620 break;
5622 case GGO_BEZIER:
5624 /* Convert the quadratic Beziers to cubic Beziers.
5625 The parametric eqn for a cubic Bezier is, from PLRM:
5626 r(t) = at^3 + bt^2 + ct + r0
5627 with the control points:
5628 r1 = r0 + c/3
5629 r2 = r1 + (c + b)/3
5630 r3 = r0 + c + b + a
5632 A quadratic Bezier has the form:
5633 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5635 So equating powers of t leads to:
5636 r1 = 2/3 p1 + 1/3 p0
5637 r2 = 2/3 p1 + 1/3 p2
5638 and of course r0 = p0, r3 = p2
5641 int contour, point = 0, first_pt;
5642 FT_Outline *outline = &ft_face->glyph->outline;
5643 TTPOLYGONHEADER *pph;
5644 TTPOLYCURVE *ppc;
5645 DWORD pph_start, cpfx, type;
5646 FT_Vector cubic_control[4];
5647 if(buflen == 0) buf = NULL;
5649 if (needsTransform && buf) {
5650 pFT_Outline_Transform(outline, &transMat);
5653 for(contour = 0; contour < outline->n_contours; contour++) {
5654 pph_start = needed;
5655 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5656 first_pt = point;
5657 if(buf) {
5658 pph->dwType = TT_POLYGON_TYPE;
5659 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5661 needed += sizeof(*pph);
5662 point++;
5663 while(point <= outline->contours[contour]) {
5664 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5665 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5666 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5667 cpfx = 0;
5668 do {
5669 if(type == TT_PRIM_LINE) {
5670 if(buf)
5671 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5672 cpfx++;
5673 point++;
5674 } else {
5675 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5676 so cpfx = 3n */
5678 /* FIXME: Possible optimization in endpoint calculation
5679 if there are two consecutive curves */
5680 cubic_control[0] = outline->points[point-1];
5681 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5682 cubic_control[0].x += outline->points[point].x + 1;
5683 cubic_control[0].y += outline->points[point].y + 1;
5684 cubic_control[0].x >>= 1;
5685 cubic_control[0].y >>= 1;
5687 if(point+1 > outline->contours[contour])
5688 cubic_control[3] = outline->points[first_pt];
5689 else {
5690 cubic_control[3] = outline->points[point+1];
5691 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5692 cubic_control[3].x += outline->points[point].x + 1;
5693 cubic_control[3].y += outline->points[point].y + 1;
5694 cubic_control[3].x >>= 1;
5695 cubic_control[3].y >>= 1;
5698 /* r1 = 1/3 p0 + 2/3 p1
5699 r2 = 1/3 p2 + 2/3 p1 */
5700 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5701 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5702 cubic_control[2] = cubic_control[1];
5703 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5704 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5705 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5706 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5707 if(buf) {
5708 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5709 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5710 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5712 cpfx += 3;
5713 point++;
5715 } while(point <= outline->contours[contour] &&
5716 (outline->tags[point] & FT_Curve_Tag_On) ==
5717 (outline->tags[point-1] & FT_Curve_Tag_On));
5718 /* At the end of a contour Windows adds the start point,
5719 but only for Beziers and we've already done that.
5721 if(point <= outline->contours[contour] &&
5722 outline->tags[point] & FT_Curve_Tag_On) {
5723 /* This is the closing pt of a bezier, but we've already
5724 added it, so just inc point and carry on */
5725 point++;
5727 if(buf) {
5728 ppc->wType = type;
5729 ppc->cpfx = cpfx;
5731 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5733 if(buf)
5734 pph->cb = needed - pph_start;
5736 break;
5739 default:
5740 FIXME("Unsupported format %d\n", format);
5741 return GDI_ERROR;
5743 return needed;
5746 static BOOL get_bitmap_text_metrics(GdiFont *font)
5748 FT_Face ft_face = font->ft_face;
5749 FT_WinFNT_HeaderRec winfnt_header;
5750 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5751 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5752 font->potm->otmSize = size;
5754 #define TM font->potm->otmTextMetrics
5755 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5757 TM.tmHeight = winfnt_header.pixel_height;
5758 TM.tmAscent = winfnt_header.ascent;
5759 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5760 TM.tmInternalLeading = winfnt_header.internal_leading;
5761 TM.tmExternalLeading = winfnt_header.external_leading;
5762 TM.tmAveCharWidth = winfnt_header.avg_width;
5763 TM.tmMaxCharWidth = winfnt_header.max_width;
5764 TM.tmWeight = winfnt_header.weight;
5765 TM.tmOverhang = 0;
5766 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5767 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5768 TM.tmFirstChar = winfnt_header.first_char;
5769 TM.tmLastChar = winfnt_header.last_char;
5770 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5771 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5772 TM.tmItalic = winfnt_header.italic;
5773 TM.tmUnderlined = font->underline;
5774 TM.tmStruckOut = font->strikeout;
5775 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5776 TM.tmCharSet = winfnt_header.charset;
5778 else
5780 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5781 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5782 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5783 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5784 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5785 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5786 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5787 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5788 TM.tmOverhang = 0;
5789 TM.tmDigitizedAspectX = 96; /* FIXME */
5790 TM.tmDigitizedAspectY = 96; /* FIXME */
5791 TM.tmFirstChar = 1;
5792 TM.tmLastChar = 255;
5793 TM.tmDefaultChar = 32;
5794 TM.tmBreakChar = 32;
5795 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5796 TM.tmUnderlined = font->underline;
5797 TM.tmStruckOut = font->strikeout;
5798 /* NB inverted meaning of TMPF_FIXED_PITCH */
5799 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5800 TM.tmCharSet = font->charset;
5802 #undef TM
5804 return TRUE;
5808 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5810 double scale_x, scale_y;
5812 if (font->aveWidth)
5814 scale_x = (double)font->aveWidth;
5815 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5817 else
5818 scale_x = font->scale_y;
5820 scale_x *= fabs(font->font_desc.matrix.eM11);
5821 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5823 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5824 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5826 SCALE_Y(ptm->tmHeight);
5827 SCALE_Y(ptm->tmAscent);
5828 SCALE_Y(ptm->tmDescent);
5829 SCALE_Y(ptm->tmInternalLeading);
5830 SCALE_Y(ptm->tmExternalLeading);
5831 SCALE_Y(ptm->tmOverhang);
5833 SCALE_X(ptm->tmAveCharWidth);
5834 SCALE_X(ptm->tmMaxCharWidth);
5836 #undef SCALE_X
5837 #undef SCALE_Y
5840 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5842 double scale_x, scale_y;
5844 if (font->aveWidth)
5846 scale_x = (double)font->aveWidth;
5847 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5849 else
5850 scale_x = font->scale_y;
5852 scale_x *= fabs(font->font_desc.matrix.eM11);
5853 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5855 scale_font_metrics(font, &potm->otmTextMetrics);
5857 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5858 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5860 SCALE_Y(potm->otmAscent);
5861 SCALE_Y(potm->otmDescent);
5862 SCALE_Y(potm->otmLineGap);
5863 SCALE_Y(potm->otmsCapEmHeight);
5864 SCALE_Y(potm->otmsXHeight);
5865 SCALE_Y(potm->otmrcFontBox.top);
5866 SCALE_Y(potm->otmrcFontBox.bottom);
5867 SCALE_X(potm->otmrcFontBox.left);
5868 SCALE_X(potm->otmrcFontBox.right);
5869 SCALE_Y(potm->otmMacAscent);
5870 SCALE_Y(potm->otmMacDescent);
5871 SCALE_Y(potm->otmMacLineGap);
5872 SCALE_X(potm->otmptSubscriptSize.x);
5873 SCALE_Y(potm->otmptSubscriptSize.y);
5874 SCALE_X(potm->otmptSubscriptOffset.x);
5875 SCALE_Y(potm->otmptSubscriptOffset.y);
5876 SCALE_X(potm->otmptSuperscriptSize.x);
5877 SCALE_Y(potm->otmptSuperscriptSize.y);
5878 SCALE_X(potm->otmptSuperscriptOffset.x);
5879 SCALE_Y(potm->otmptSuperscriptOffset.y);
5880 SCALE_Y(potm->otmsStrikeoutSize);
5881 SCALE_Y(potm->otmsStrikeoutPosition);
5882 SCALE_Y(potm->otmsUnderscoreSize);
5883 SCALE_Y(potm->otmsUnderscorePosition);
5885 #undef SCALE_X
5886 #undef SCALE_Y
5889 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5891 if(!font->potm)
5893 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5895 /* Make sure that the font has sane width/height ratio */
5896 if (font->aveWidth)
5898 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5900 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5901 font->aveWidth = 0;
5905 *ptm = font->potm->otmTextMetrics;
5906 scale_font_metrics(font, ptm);
5907 return TRUE;
5910 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5912 int i;
5914 for(i = 0; i < ft_face->num_charmaps; i++)
5916 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5917 return TRUE;
5919 return FALSE;
5922 static BOOL get_outline_text_metrics(GdiFont *font)
5924 BOOL ret = FALSE;
5925 FT_Face ft_face = font->ft_face;
5926 UINT needed, lenfam, lensty;
5927 TT_OS2 *pOS2;
5928 TT_HoriHeader *pHori;
5929 TT_Postscript *pPost;
5930 FT_Fixed x_scale, y_scale;
5931 WCHAR *family_nameW, *style_nameW;
5932 static const WCHAR spaceW[] = {' ', '\0'};
5933 char *cp;
5934 INT ascent, descent;
5936 TRACE("font=%p\n", font);
5938 if(!FT_IS_SCALABLE(ft_face))
5939 return FALSE;
5941 needed = sizeof(*font->potm);
5943 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5944 family_nameW = strdupW(font->name);
5946 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5947 * sizeof(WCHAR);
5948 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5949 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5950 style_nameW, lensty/sizeof(WCHAR));
5952 /* These names should be read from the TT name table */
5954 /* length of otmpFamilyName */
5955 needed += lenfam;
5957 /* length of otmpFaceName */
5958 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5959 needed += lenfam; /* just the family name */
5960 } else {
5961 needed += lenfam + lensty; /* family + " " + style */
5964 /* length of otmpStyleName */
5965 needed += lensty;
5967 /* length of otmpFullName */
5968 needed += lenfam + lensty;
5971 x_scale = ft_face->size->metrics.x_scale;
5972 y_scale = ft_face->size->metrics.y_scale;
5974 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5975 if(!pOS2) {
5976 FIXME("Can't find OS/2 table - not TT font?\n");
5977 goto end;
5980 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5981 if(!pHori) {
5982 FIXME("Can't find HHEA table - not TT font?\n");
5983 goto end;
5986 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5988 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
5989 pOS2->usWinAscent, pOS2->usWinDescent,
5990 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5991 ft_face->ascender, ft_face->descender, ft_face->height,
5992 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5993 ft_face->bbox.yMax, ft_face->bbox.yMin);
5995 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5996 font->potm->otmSize = needed;
5998 #define TM font->potm->otmTextMetrics
6000 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6001 ascent = pHori->Ascender;
6002 descent = -pHori->Descender;
6003 } else {
6004 ascent = pOS2->usWinAscent;
6005 descent = pOS2->usWinDescent;
6008 if(font->yMax) {
6009 TM.tmAscent = font->yMax;
6010 TM.tmDescent = -font->yMin;
6011 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6012 } else {
6013 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6014 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6015 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6016 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6019 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6021 /* MSDN says:
6022 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6024 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6025 ((ascent + descent) -
6026 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6028 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6029 if (TM.tmAveCharWidth == 0) {
6030 TM.tmAveCharWidth = 1;
6032 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6033 TM.tmWeight = FW_REGULAR;
6034 if (font->fake_bold)
6035 TM.tmWeight = FW_BOLD;
6036 else
6038 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6040 if (pOS2->usWeightClass > FW_MEDIUM)
6041 TM.tmWeight = pOS2->usWeightClass;
6043 else if (pOS2->usWeightClass <= FW_MEDIUM)
6044 TM.tmWeight = pOS2->usWeightClass;
6046 TM.tmOverhang = 0;
6047 TM.tmDigitizedAspectX = 300;
6048 TM.tmDigitizedAspectY = 300;
6049 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6050 * symbol range to 0 - f0ff
6053 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6055 TM.tmFirstChar = 0;
6056 switch(GetACP())
6058 case 1257: /* Baltic */
6059 TM.tmLastChar = 0xf8fd;
6060 break;
6061 default:
6062 TM.tmLastChar = 0xf0ff;
6064 TM.tmBreakChar = 0x20;
6065 TM.tmDefaultChar = 0x1f;
6067 else
6069 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6070 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6072 if(pOS2->usFirstCharIndex <= 1)
6073 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6074 else if (pOS2->usFirstCharIndex > 0xff)
6075 TM.tmBreakChar = 0x20;
6076 else
6077 TM.tmBreakChar = pOS2->usFirstCharIndex;
6078 TM.tmDefaultChar = TM.tmBreakChar - 1;
6080 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6081 TM.tmUnderlined = font->underline;
6082 TM.tmStruckOut = font->strikeout;
6084 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6085 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6086 (pOS2->version == 0xFFFFU ||
6087 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6088 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6089 else
6090 TM.tmPitchAndFamily = 0;
6092 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6094 case PAN_FAMILY_SCRIPT:
6095 TM.tmPitchAndFamily |= FF_SCRIPT;
6096 break;
6098 case PAN_FAMILY_DECORATIVE:
6099 TM.tmPitchAndFamily |= FF_DECORATIVE;
6100 break;
6102 case PAN_ANY:
6103 case PAN_NO_FIT:
6104 case PAN_FAMILY_TEXT_DISPLAY:
6105 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6106 /* which is clearly not what the panose spec says. */
6107 default:
6108 if(TM.tmPitchAndFamily == 0 || /* fixed */
6109 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6110 TM.tmPitchAndFamily = FF_MODERN;
6111 else
6113 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6115 case PAN_ANY:
6116 case PAN_NO_FIT:
6117 default:
6118 TM.tmPitchAndFamily |= FF_DONTCARE;
6119 break;
6121 case PAN_SERIF_COVE:
6122 case PAN_SERIF_OBTUSE_COVE:
6123 case PAN_SERIF_SQUARE_COVE:
6124 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6125 case PAN_SERIF_SQUARE:
6126 case PAN_SERIF_THIN:
6127 case PAN_SERIF_BONE:
6128 case PAN_SERIF_EXAGGERATED:
6129 case PAN_SERIF_TRIANGLE:
6130 TM.tmPitchAndFamily |= FF_ROMAN;
6131 break;
6133 case PAN_SERIF_NORMAL_SANS:
6134 case PAN_SERIF_OBTUSE_SANS:
6135 case PAN_SERIF_PERP_SANS:
6136 case PAN_SERIF_FLARED:
6137 case PAN_SERIF_ROUNDED:
6138 TM.tmPitchAndFamily |= FF_SWISS;
6139 break;
6142 break;
6145 if(FT_IS_SCALABLE(ft_face))
6146 TM.tmPitchAndFamily |= TMPF_VECTOR;
6148 if(FT_IS_SFNT(ft_face))
6150 if (font->ntmFlags & NTM_PS_OPENTYPE)
6151 TM.tmPitchAndFamily |= TMPF_DEVICE;
6152 else
6153 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6156 TM.tmCharSet = font->charset;
6158 font->potm->otmFiller = 0;
6159 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6160 font->potm->otmfsSelection = pOS2->fsSelection;
6161 font->potm->otmfsType = pOS2->fsType;
6162 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6163 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6164 font->potm->otmItalicAngle = 0; /* POST table */
6165 font->potm->otmEMSquare = ft_face->units_per_EM;
6166 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6167 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6168 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6169 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6170 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6171 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6172 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6173 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6174 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6175 font->potm->otmMacAscent = TM.tmAscent;
6176 font->potm->otmMacDescent = -TM.tmDescent;
6177 font->potm->otmMacLineGap = font->potm->otmLineGap;
6178 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6179 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6180 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6181 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6182 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6183 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6184 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6185 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6186 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6187 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6188 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6189 if(!pPost) {
6190 font->potm->otmsUnderscoreSize = 0;
6191 font->potm->otmsUnderscorePosition = 0;
6192 } else {
6193 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6194 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6196 #undef TM
6198 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6199 cp = (char*)font->potm + sizeof(*font->potm);
6200 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6201 strcpyW((WCHAR*)cp, family_nameW);
6202 cp += lenfam;
6203 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6204 strcpyW((WCHAR*)cp, style_nameW);
6205 cp += lensty;
6206 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6207 strcpyW((WCHAR*)cp, family_nameW);
6208 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6209 strcatW((WCHAR*)cp, spaceW);
6210 strcatW((WCHAR*)cp, style_nameW);
6211 cp += lenfam + lensty;
6212 } else
6213 cp += lenfam;
6214 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6215 strcpyW((WCHAR*)cp, family_nameW);
6216 strcatW((WCHAR*)cp, spaceW);
6217 strcatW((WCHAR*)cp, style_nameW);
6218 ret = TRUE;
6220 end:
6221 HeapFree(GetProcessHeap(), 0, style_nameW);
6222 HeapFree(GetProcessHeap(), 0, family_nameW);
6223 return ret;
6226 /*************************************************************
6227 * freetype_GetGlyphOutline
6229 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6230 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6232 struct freetype_physdev *physdev = get_freetype_dev( dev );
6233 DWORD ret;
6235 if (!physdev->font)
6237 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6238 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6241 GDI_CheckNotLock();
6242 EnterCriticalSection( &freetype_cs );
6243 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6244 LeaveCriticalSection( &freetype_cs );
6245 return ret;
6248 /*************************************************************
6249 * freetype_GetTextMetrics
6251 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6253 struct freetype_physdev *physdev = get_freetype_dev( dev );
6254 BOOL ret;
6256 if (!physdev->font)
6258 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6259 return dev->funcs->pGetTextMetrics( dev, metrics );
6262 GDI_CheckNotLock();
6263 EnterCriticalSection( &freetype_cs );
6264 ret = get_text_metrics( physdev->font, metrics );
6265 LeaveCriticalSection( &freetype_cs );
6266 return ret;
6269 /*************************************************************
6270 * freetype_GetOutlineTextMetrics
6272 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6274 struct freetype_physdev *physdev = get_freetype_dev( dev );
6275 UINT ret = 0;
6277 if (!physdev->font)
6279 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6280 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6283 TRACE("font=%p\n", physdev->font);
6285 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6287 GDI_CheckNotLock();
6288 EnterCriticalSection( &freetype_cs );
6290 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6292 if(cbSize >= physdev->font->potm->otmSize)
6294 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6295 scale_outline_font_metrics(physdev->font, potm);
6297 ret = physdev->font->potm->otmSize;
6299 LeaveCriticalSection( &freetype_cs );
6300 return ret;
6303 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6305 HFONTLIST *hfontlist;
6306 child->font = alloc_font();
6307 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6308 if(!child->font->ft_face)
6310 free_font(child->font);
6311 child->font = NULL;
6312 return FALSE;
6315 child->font->font_desc = font->font_desc;
6316 child->font->ntmFlags = child->face->ntmFlags;
6317 child->font->orientation = font->orientation;
6318 child->font->scale_y = font->scale_y;
6319 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6320 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6321 child->font->name = strdupW(child->face->family->FamilyName);
6322 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6323 child->font->base_font = font;
6324 list_add_head(&child_font_list, &child->font->entry);
6325 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6326 return TRUE;
6329 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6331 FT_UInt g;
6332 CHILD_FONT *child_font;
6334 if(font->base_font)
6335 font = font->base_font;
6337 *linked_font = font;
6339 if((*glyph = get_glyph_index(font, c)))
6340 return TRUE;
6342 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6344 if(!child_font->font)
6345 if(!load_child_font(font, child_font))
6346 continue;
6348 if(!child_font->font->ft_face)
6349 continue;
6350 g = get_glyph_index(child_font->font, c);
6351 if(g)
6353 *glyph = g;
6354 *linked_font = child_font->font;
6355 return TRUE;
6358 return FALSE;
6361 /*************************************************************
6362 * freetype_GetCharWidth
6364 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6366 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6367 UINT c;
6368 GLYPHMETRICS gm;
6369 FT_UInt glyph_index;
6370 GdiFont *linked_font;
6371 struct freetype_physdev *physdev = get_freetype_dev( dev );
6373 if (!physdev->font)
6375 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6376 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6379 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6381 GDI_CheckNotLock();
6382 EnterCriticalSection( &freetype_cs );
6383 for(c = firstChar; c <= lastChar; c++) {
6384 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6385 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6386 &gm, 0, NULL, &identity);
6387 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6389 LeaveCriticalSection( &freetype_cs );
6390 return TRUE;
6393 /*************************************************************
6394 * freetype_GetCharABCWidths
6396 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6398 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6399 UINT c;
6400 GLYPHMETRICS gm;
6401 FT_UInt glyph_index;
6402 GdiFont *linked_font;
6403 struct freetype_physdev *physdev = get_freetype_dev( dev );
6405 if (!physdev->font)
6407 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6408 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6411 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6413 if(!FT_IS_SCALABLE(physdev->font->ft_face))
6414 return FALSE;
6416 GDI_CheckNotLock();
6417 EnterCriticalSection( &freetype_cs );
6419 for(c = firstChar; c <= lastChar; c++) {
6420 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6421 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6422 &gm, 0, NULL, &identity);
6423 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6424 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6425 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6426 FONT_GM(linked_font,glyph_index)->bbx;
6428 LeaveCriticalSection( &freetype_cs );
6429 return TRUE;
6432 /*************************************************************
6433 * freetype_GetCharABCWidthsI
6435 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6437 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6438 UINT c;
6439 GLYPHMETRICS gm;
6440 FT_UInt glyph_index;
6441 GdiFont *linked_font;
6442 struct freetype_physdev *physdev = get_freetype_dev( dev );
6444 if (!physdev->font)
6446 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6447 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6450 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6451 return FALSE;
6453 GDI_CheckNotLock();
6454 EnterCriticalSection( &freetype_cs );
6456 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6457 if (!pgi)
6458 for(c = firstChar; c < firstChar+count; c++) {
6459 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6460 &gm, 0, NULL, &identity);
6461 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6462 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6463 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6464 - FONT_GM(linked_font,c)->bbx;
6466 else
6467 for(c = 0; c < count; c++) {
6468 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6469 &gm, 0, NULL, &identity);
6470 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6471 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6472 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6473 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6476 LeaveCriticalSection( &freetype_cs );
6477 return TRUE;
6480 /*************************************************************
6481 * freetype_GetTextExtentExPoint
6483 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6484 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6486 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6487 INT idx;
6488 INT nfit = 0, ext;
6489 GLYPHMETRICS gm;
6490 TEXTMETRICW tm;
6491 FT_UInt glyph_index;
6492 GdiFont *linked_font;
6493 struct freetype_physdev *physdev = get_freetype_dev( dev );
6495 if (!physdev->font)
6497 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6498 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6501 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6503 GDI_CheckNotLock();
6504 EnterCriticalSection( &freetype_cs );
6506 size->cx = 0;
6507 get_text_metrics( physdev->font, &tm );
6508 size->cy = tm.tmHeight;
6510 for(idx = 0; idx < count; idx++) {
6511 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6512 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6513 &gm, 0, NULL, &identity);
6514 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6515 ext = size->cx;
6516 if (! pnfit || ext <= max_ext) {
6517 ++nfit;
6518 if (dxs)
6519 dxs[idx] = ext;
6523 if (pnfit)
6524 *pnfit = nfit;
6526 LeaveCriticalSection( &freetype_cs );
6527 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6528 return TRUE;
6531 /*************************************************************
6532 * freetype_GetTextExtentExPointI
6534 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6535 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6537 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6538 INT idx;
6539 INT nfit = 0, ext;
6540 GLYPHMETRICS gm;
6541 TEXTMETRICW tm;
6542 struct freetype_physdev *physdev = get_freetype_dev( dev );
6544 if (!physdev->font)
6546 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6547 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6550 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6552 GDI_CheckNotLock();
6553 EnterCriticalSection( &freetype_cs );
6555 size->cx = 0;
6556 get_text_metrics(physdev->font, &tm);
6557 size->cy = tm.tmHeight;
6559 for(idx = 0; idx < count; idx++) {
6560 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6561 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6562 ext = size->cx;
6563 if (! pnfit || ext <= max_ext) {
6564 ++nfit;
6565 if (dxs)
6566 dxs[idx] = ext;
6570 if (pnfit)
6571 *pnfit = nfit;
6573 LeaveCriticalSection( &freetype_cs );
6574 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6575 return TRUE;
6578 /*************************************************************
6579 * freetype_GetFontData
6581 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6583 struct freetype_physdev *physdev = get_freetype_dev( dev );
6585 if (!physdev->font)
6587 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6588 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6591 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6592 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6593 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6595 return get_font_data( physdev->font, table, offset, buf, cbData );
6598 /*************************************************************
6599 * freetype_GetTextFace
6601 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6603 INT n;
6604 struct freetype_physdev *physdev = get_freetype_dev( dev );
6606 if (!physdev->font)
6608 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6609 return dev->funcs->pGetTextFace( dev, count, str );
6612 n = strlenW(physdev->font->name) + 1;
6613 if (str)
6615 lstrcpynW(str, physdev->font->name, count);
6616 n = min(count, n);
6618 return n;
6621 /*************************************************************
6622 * freetype_GetTextCharsetInfo
6624 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6626 struct freetype_physdev *physdev = get_freetype_dev( dev );
6628 if (!physdev->font)
6630 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6631 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6633 if (fs) *fs = physdev->font->fs;
6634 return physdev->font->charset;
6637 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6639 GdiFont *font = dc->gdiFont, *linked_font;
6640 struct list *first_hfont;
6641 BOOL ret;
6643 GDI_CheckNotLock();
6644 EnterCriticalSection( &freetype_cs );
6645 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6646 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6647 if(font == linked_font)
6648 *new_hfont = dc->hFont;
6649 else
6651 first_hfont = list_head(&linked_font->hfontlist);
6652 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6654 LeaveCriticalSection( &freetype_cs );
6655 return ret;
6658 /* Retrieve a list of supported Unicode ranges for a given font.
6659 * Can be called with NULL gs to calculate the buffer size. Returns
6660 * the number of ranges found.
6662 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6664 DWORD num_ranges = 0;
6666 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6668 FT_UInt glyph_code;
6669 FT_ULong char_code, char_code_prev;
6671 glyph_code = 0;
6672 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6674 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6675 face->num_glyphs, glyph_code, char_code);
6677 if (!glyph_code) return 0;
6679 if (gs)
6681 gs->ranges[0].wcLow = (USHORT)char_code;
6682 gs->ranges[0].cGlyphs = 0;
6683 gs->cGlyphsSupported = 0;
6686 num_ranges = 1;
6687 while (glyph_code)
6689 if (char_code < char_code_prev)
6691 ERR("expected increasing char code from FT_Get_Next_Char\n");
6692 return 0;
6694 if (char_code - char_code_prev > 1)
6696 num_ranges++;
6697 if (gs)
6699 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6700 gs->ranges[num_ranges - 1].cGlyphs = 1;
6701 gs->cGlyphsSupported++;
6704 else if (gs)
6706 gs->ranges[num_ranges - 1].cGlyphs++;
6707 gs->cGlyphsSupported++;
6709 char_code_prev = char_code;
6710 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6713 else
6714 FIXME("encoding %u not supported\n", face->charmap->encoding);
6716 return num_ranges;
6719 /*************************************************************
6720 * freetype_GetFontUnicodeRanges
6722 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6724 struct freetype_physdev *physdev = get_freetype_dev( dev );
6725 DWORD size, num_ranges;
6727 if (!physdev->font)
6729 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6730 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6733 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6734 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6735 if (glyphset)
6737 glyphset->cbThis = size;
6738 glyphset->cRanges = num_ranges;
6739 glyphset->flAccel = 0;
6741 return size;
6744 /*************************************************************
6745 * freetype_FontIsLinked
6747 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6749 struct freetype_physdev *physdev = get_freetype_dev( dev );
6750 BOOL ret;
6752 if (!physdev->font)
6754 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6755 return dev->funcs->pFontIsLinked( dev );
6758 GDI_CheckNotLock();
6759 EnterCriticalSection( &freetype_cs );
6760 ret = !list_empty(&physdev->font->child_fonts);
6761 LeaveCriticalSection( &freetype_cs );
6762 return ret;
6765 static BOOL is_hinting_enabled(void)
6767 /* Use the >= 2.2.0 function if available */
6768 if(pFT_Get_TrueType_Engine_Type)
6770 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6771 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6773 #ifdef FT_DRIVER_HAS_HINTER
6774 else
6776 FT_Module mod;
6778 /* otherwise if we've been compiled with < 2.2.0 headers
6779 use the internal macro */
6780 mod = pFT_Get_Module(library, "truetype");
6781 if(mod && FT_DRIVER_HAS_HINTER(mod))
6782 return TRUE;
6784 #endif
6786 return FALSE;
6789 static BOOL is_subpixel_rendering_enabled( void )
6791 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6792 return pFT_Library_SetLcdFilter &&
6793 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6794 #else
6795 return FALSE;
6796 #endif
6799 /*************************************************************************
6800 * GetRasterizerCaps (GDI32.@)
6802 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6804 static int hinting = -1;
6805 static int subpixel = -1;
6807 if(hinting == -1)
6809 hinting = is_hinting_enabled();
6810 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6813 if ( subpixel == -1 )
6815 subpixel = is_subpixel_rendering_enabled();
6816 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6819 lprs->nSize = sizeof(RASTERIZER_STATUS);
6820 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6821 if ( subpixel )
6822 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6823 lprs->nLanguageID = 0;
6824 return TRUE;
6827 /*************************************************************
6828 * freetype_GdiRealizationInfo
6830 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6832 struct freetype_physdev *physdev = get_freetype_dev( dev );
6833 realization_info_t *info = ptr;
6835 if (!physdev->font)
6837 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6838 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6841 FIXME("(%p, %p): stub!\n", physdev->font, info);
6843 info->flags = 1;
6844 if(FT_IS_SCALABLE(physdev->font->ft_face))
6845 info->flags |= 2;
6847 info->cache_num = physdev->font->cache_num;
6848 info->unknown2 = -1;
6849 return TRUE;
6852 /*************************************************************************
6853 * Kerning support for TrueType fonts
6855 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6857 struct TT_kern_table
6859 USHORT version;
6860 USHORT nTables;
6863 struct TT_kern_subtable
6865 USHORT version;
6866 USHORT length;
6867 union
6869 USHORT word;
6870 struct
6872 USHORT horizontal : 1;
6873 USHORT minimum : 1;
6874 USHORT cross_stream: 1;
6875 USHORT override : 1;
6876 USHORT reserved1 : 4;
6877 USHORT format : 8;
6878 } bits;
6879 } coverage;
6882 struct TT_format0_kern_subtable
6884 USHORT nPairs;
6885 USHORT searchRange;
6886 USHORT entrySelector;
6887 USHORT rangeShift;
6890 struct TT_kern_pair
6892 USHORT left;
6893 USHORT right;
6894 short value;
6897 static DWORD parse_format0_kern_subtable(GdiFont *font,
6898 const struct TT_format0_kern_subtable *tt_f0_ks,
6899 const USHORT *glyph_to_char,
6900 KERNINGPAIR *kern_pair, DWORD cPairs)
6902 USHORT i, nPairs;
6903 const struct TT_kern_pair *tt_kern_pair;
6905 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6907 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6909 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6910 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6911 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6913 if (!kern_pair || !cPairs)
6914 return nPairs;
6916 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6918 nPairs = min(nPairs, cPairs);
6920 for (i = 0; i < nPairs; i++)
6922 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6923 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6924 /* this algorithm appears to better match what Windows does */
6925 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6926 if (kern_pair->iKernAmount < 0)
6928 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6929 kern_pair->iKernAmount -= font->ppem;
6931 else if (kern_pair->iKernAmount > 0)
6933 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6934 kern_pair->iKernAmount += font->ppem;
6936 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6938 TRACE("left %u right %u value %d\n",
6939 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6941 kern_pair++;
6943 TRACE("copied %u entries\n", nPairs);
6944 return nPairs;
6947 /*************************************************************
6948 * freetype_GetKerningPairs
6950 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
6952 DWORD length;
6953 void *buf;
6954 const struct TT_kern_table *tt_kern_table;
6955 const struct TT_kern_subtable *tt_kern_subtable;
6956 USHORT i, nTables;
6957 USHORT *glyph_to_char;
6958 GdiFont *font;
6959 struct freetype_physdev *physdev = get_freetype_dev( dev );
6961 if (!(font = physdev->font))
6963 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
6964 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
6967 GDI_CheckNotLock();
6968 EnterCriticalSection( &freetype_cs );
6969 if (font->total_kern_pairs != (DWORD)-1)
6971 if (cPairs && kern_pair)
6973 cPairs = min(cPairs, font->total_kern_pairs);
6974 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6976 else cPairs = font->total_kern_pairs;
6978 LeaveCriticalSection( &freetype_cs );
6979 return cPairs;
6982 font->total_kern_pairs = 0;
6984 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
6986 if (length == GDI_ERROR)
6988 TRACE("no kerning data in the font\n");
6989 LeaveCriticalSection( &freetype_cs );
6990 return 0;
6993 buf = HeapAlloc(GetProcessHeap(), 0, length);
6994 if (!buf)
6996 WARN("Out of memory\n");
6997 LeaveCriticalSection( &freetype_cs );
6998 return 0;
7001 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7003 /* build a glyph index to char code map */
7004 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7005 if (!glyph_to_char)
7007 WARN("Out of memory allocating a glyph index to char code map\n");
7008 HeapFree(GetProcessHeap(), 0, buf);
7009 LeaveCriticalSection( &freetype_cs );
7010 return 0;
7013 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7015 FT_UInt glyph_code;
7016 FT_ULong char_code;
7018 glyph_code = 0;
7019 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7021 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7022 font->ft_face->num_glyphs, glyph_code, char_code);
7024 while (glyph_code)
7026 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7028 /* FIXME: This doesn't match what Windows does: it does some fancy
7029 * things with duplicate glyph index to char code mappings, while
7030 * we just avoid overriding existing entries.
7032 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7033 glyph_to_char[glyph_code] = (USHORT)char_code;
7035 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7038 else
7040 ULONG n;
7042 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7043 for (n = 0; n <= 65535; n++)
7044 glyph_to_char[n] = (USHORT)n;
7047 tt_kern_table = buf;
7048 nTables = GET_BE_WORD(tt_kern_table->nTables);
7049 TRACE("version %u, nTables %u\n",
7050 GET_BE_WORD(tt_kern_table->version), nTables);
7052 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7054 for (i = 0; i < nTables; i++)
7056 struct TT_kern_subtable tt_kern_subtable_copy;
7058 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7059 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7060 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7062 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7063 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7064 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7066 /* According to the TrueType specification this is the only format
7067 * that will be properly interpreted by Windows and OS/2
7069 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7071 DWORD new_chunk, old_total = font->total_kern_pairs;
7073 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7074 glyph_to_char, NULL, 0);
7075 font->total_kern_pairs += new_chunk;
7077 if (!font->kern_pairs)
7078 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7079 font->total_kern_pairs * sizeof(*font->kern_pairs));
7080 else
7081 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7082 font->total_kern_pairs * sizeof(*font->kern_pairs));
7084 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7085 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7087 else
7088 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7090 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7093 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7094 HeapFree(GetProcessHeap(), 0, buf);
7096 if (cPairs && kern_pair)
7098 cPairs = min(cPairs, font->total_kern_pairs);
7099 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7101 else cPairs = font->total_kern_pairs;
7103 LeaveCriticalSection( &freetype_cs );
7104 return cPairs;
7107 static const struct gdi_dc_funcs freetype_funcs =
7109 NULL, /* pAbortDoc */
7110 NULL, /* pAbortPath */
7111 NULL, /* pAlphaBlend */
7112 NULL, /* pAngleArc */
7113 NULL, /* pArc */
7114 NULL, /* pArcTo */
7115 NULL, /* pBeginPath */
7116 NULL, /* pBlendImage */
7117 NULL, /* pChoosePixelFormat */
7118 NULL, /* pChord */
7119 NULL, /* pCloseFigure */
7120 NULL, /* pCopyBitmap */
7121 NULL, /* pCreateBitmap */
7122 NULL, /* pCreateCompatibleDC */
7123 freetype_CreateDC, /* pCreateDC */
7124 NULL, /* pCreateDIBSection */
7125 NULL, /* pDeleteBitmap */
7126 freetype_DeleteDC, /* pDeleteDC */
7127 NULL, /* pDeleteObject */
7128 NULL, /* pDescribePixelFormat */
7129 NULL, /* pDeviceCapabilities */
7130 NULL, /* pEllipse */
7131 NULL, /* pEndDoc */
7132 NULL, /* pEndPage */
7133 NULL, /* pEndPath */
7134 freetype_EnumFonts, /* pEnumFonts */
7135 NULL, /* pEnumICMProfiles */
7136 NULL, /* pExcludeClipRect */
7137 NULL, /* pExtDeviceMode */
7138 NULL, /* pExtEscape */
7139 NULL, /* pExtFloodFill */
7140 NULL, /* pExtSelectClipRgn */
7141 NULL, /* pExtTextOut */
7142 NULL, /* pFillPath */
7143 NULL, /* pFillRgn */
7144 NULL, /* pFlattenPath */
7145 freetype_FontIsLinked, /* pFontIsLinked */
7146 NULL, /* pFrameRgn */
7147 NULL, /* pGdiComment */
7148 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7149 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7150 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7151 freetype_GetCharWidth, /* pGetCharWidth */
7152 NULL, /* pGetDeviceCaps */
7153 NULL, /* pGetDeviceGammaRamp */
7154 freetype_GetFontData, /* pGetFontData */
7155 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7156 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7157 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7158 NULL, /* pGetICMProfile */
7159 NULL, /* pGetImage */
7160 freetype_GetKerningPairs, /* pGetKerningPairs */
7161 NULL, /* pGetNearestColor */
7162 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7163 NULL, /* pGetPixel */
7164 NULL, /* pGetPixelFormat */
7165 NULL, /* pGetSystemPaletteEntries */
7166 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7167 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7168 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7169 freetype_GetTextFace, /* pGetTextFace */
7170 freetype_GetTextMetrics, /* pGetTextMetrics */
7171 NULL, /* pGradientFill */
7172 NULL, /* pIntersectClipRect */
7173 NULL, /* pInvertRgn */
7174 NULL, /* pLineTo */
7175 NULL, /* pModifyWorldTransform */
7176 NULL, /* pMoveTo */
7177 NULL, /* pOffsetClipRgn */
7178 NULL, /* pOffsetViewportOrg */
7179 NULL, /* pOffsetWindowOrg */
7180 NULL, /* pPaintRgn */
7181 NULL, /* pPatBlt */
7182 NULL, /* pPie */
7183 NULL, /* pPolyBezier */
7184 NULL, /* pPolyBezierTo */
7185 NULL, /* pPolyDraw */
7186 NULL, /* pPolyPolygon */
7187 NULL, /* pPolyPolyline */
7188 NULL, /* pPolygon */
7189 NULL, /* pPolyline */
7190 NULL, /* pPolylineTo */
7191 NULL, /* pPutImage */
7192 NULL, /* pRealizeDefaultPalette */
7193 NULL, /* pRealizePalette */
7194 NULL, /* pRectangle */
7195 NULL, /* pResetDC */
7196 NULL, /* pRestoreDC */
7197 NULL, /* pRoundRect */
7198 NULL, /* pSaveDC */
7199 NULL, /* pScaleViewportExt */
7200 NULL, /* pScaleWindowExt */
7201 NULL, /* pSelectBitmap */
7202 NULL, /* pSelectBrush */
7203 NULL, /* pSelectClipPath */
7204 freetype_SelectFont, /* pSelectFont */
7205 NULL, /* pSelectPalette */
7206 NULL, /* pSelectPen */
7207 NULL, /* pSetArcDirection */
7208 NULL, /* pSetBkColor */
7209 NULL, /* pSetBkMode */
7210 NULL, /* pSetDCBrushColor */
7211 NULL, /* pSetDCPenColor */
7212 NULL, /* pSetDIBColorTable */
7213 NULL, /* pSetDIBitsToDevice */
7214 NULL, /* pSetDeviceClipping */
7215 NULL, /* pSetDeviceGammaRamp */
7216 NULL, /* pSetLayout */
7217 NULL, /* pSetMapMode */
7218 NULL, /* pSetMapperFlags */
7219 NULL, /* pSetPixel */
7220 NULL, /* pSetPixelFormat */
7221 NULL, /* pSetPolyFillMode */
7222 NULL, /* pSetROP2 */
7223 NULL, /* pSetRelAbs */
7224 NULL, /* pSetStretchBltMode */
7225 NULL, /* pSetTextAlign */
7226 NULL, /* pSetTextCharacterExtra */
7227 NULL, /* pSetTextColor */
7228 NULL, /* pSetTextJustification */
7229 NULL, /* pSetViewportExt */
7230 NULL, /* pSetViewportOrg */
7231 NULL, /* pSetWindowExt */
7232 NULL, /* pSetWindowOrg */
7233 NULL, /* pSetWorldTransform */
7234 NULL, /* pStartDoc */
7235 NULL, /* pStartPage */
7236 NULL, /* pStretchBlt */
7237 NULL, /* pStretchDIBits */
7238 NULL, /* pStrokeAndFillPath */
7239 NULL, /* pStrokePath */
7240 NULL, /* pSwapBuffers */
7241 NULL, /* pUnrealizePalette */
7242 NULL, /* pWidenPath */
7243 /* OpenGL not supported */
7246 #else /* HAVE_FREETYPE */
7248 /*************************************************************************/
7250 BOOL WineEngInit(void)
7252 return FALSE;
7254 BOOL WineEngDestroyFontInstance(HFONT hfont)
7256 return FALSE;
7259 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7261 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7262 return 1;
7265 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7267 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7268 return TRUE;
7271 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7273 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7274 return NULL;
7277 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7279 return FALSE;
7282 /*************************************************************************
7283 * GetRasterizerCaps (GDI32.@)
7285 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7287 lprs->nSize = sizeof(RASTERIZER_STATUS);
7288 lprs->wFlags = 0;
7289 lprs->nLanguageID = 0;
7290 return TRUE;
7293 #endif /* HAVE_FREETYPE */