gdi32: Implement GetCharABCWidthsI as a standard driver entry point.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobfa3f72b051ae482205433f65d8ec86b7ad94eb09
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 WINE_DEFAULT_DEBUG_CHANNEL(font);
94 #ifdef HAVE_FREETYPE
96 #ifdef HAVE_FT2BUILD_H
97 #include <ft2build.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
101 #endif
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
104 #endif
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
110 #endif
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
113 #endif
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
116 #endif
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
119 #endif
120 #ifdef HAVE_FREETYPE_FTTRIGON_H
121 #include <freetype/fttrigon.h>
122 #endif
123 #ifdef HAVE_FREETYPE_FTWINFNT_H
124 #include <freetype/ftwinfnt.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTMODAPI_H
127 #include <freetype/ftmodapi.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTLCDFIL_H
130 #include <freetype/ftlcdfil.h>
131 #endif
133 #ifndef HAVE_FT_TRUETYPEENGINETYPE
134 typedef enum
136 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
137 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
138 FT_TRUETYPE_ENGINE_TYPE_PATENTED
139 } FT_TrueTypeEngineType;
140 #endif
142 static FT_Library library = 0;
143 typedef struct
145 FT_Int major;
146 FT_Int minor;
147 FT_Int patch;
148 } FT_Version_t;
149 static FT_Version_t FT_Version;
150 static DWORD FT_SimpleVersion;
152 static void *ft_handle = NULL;
154 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
155 MAKE_FUNCPTR(FT_Done_Face);
156 MAKE_FUNCPTR(FT_Get_Char_Index);
157 MAKE_FUNCPTR(FT_Get_First_Char);
158 MAKE_FUNCPTR(FT_Get_Module);
159 MAKE_FUNCPTR(FT_Get_Next_Char);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Library_Version);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
168 MAKE_FUNCPTR(FT_Matrix_Multiply);
169 #ifdef FT_MULFIX_INLINED
170 #define pFT_MulFix FT_MULFIX_INLINED
171 #else
172 MAKE_FUNCPTR(FT_MulFix);
173 #endif
174 MAKE_FUNCPTR(FT_New_Face);
175 MAKE_FUNCPTR(FT_New_Memory_Face);
176 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
177 MAKE_FUNCPTR(FT_Outline_Transform);
178 MAKE_FUNCPTR(FT_Outline_Translate);
179 MAKE_FUNCPTR(FT_Render_Glyph);
180 MAKE_FUNCPTR(FT_Select_Charmap);
181 MAKE_FUNCPTR(FT_Set_Charmap);
182 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
183 MAKE_FUNCPTR(FT_Vector_Transform);
184 MAKE_FUNCPTR(FT_Vector_Unit);
185 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
186 #ifdef HAVE_FREETYPE_FTLCDFIL_H
187 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
188 #endif
190 #ifdef SONAME_LIBFONTCONFIG
191 #include <fontconfig/fontconfig.h>
192 MAKE_FUNCPTR(FcConfigGetCurrent);
193 MAKE_FUNCPTR(FcFontList);
194 MAKE_FUNCPTR(FcFontSetDestroy);
195 MAKE_FUNCPTR(FcInit);
196 MAKE_FUNCPTR(FcObjectSetAdd);
197 MAKE_FUNCPTR(FcObjectSetCreate);
198 MAKE_FUNCPTR(FcObjectSetDestroy);
199 MAKE_FUNCPTR(FcPatternCreate);
200 MAKE_FUNCPTR(FcPatternDestroy);
201 MAKE_FUNCPTR(FcPatternGetBool);
202 MAKE_FUNCPTR(FcPatternGetString);
203 #endif
205 #undef MAKE_FUNCPTR
207 #ifndef FT_MAKE_TAG
208 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
209 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
210 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
211 #endif
213 #ifndef ft_encoding_none
214 #define FT_ENCODING_NONE ft_encoding_none
215 #endif
216 #ifndef ft_encoding_ms_symbol
217 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
218 #endif
219 #ifndef ft_encoding_unicode
220 #define FT_ENCODING_UNICODE ft_encoding_unicode
221 #endif
222 #ifndef ft_encoding_apple_roman
223 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
224 #endif
226 #ifdef WORDS_BIGENDIAN
227 #define GET_BE_WORD(x) (x)
228 #else
229 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
230 #endif
232 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
233 typedef struct {
234 FT_Short height;
235 FT_Short width;
236 FT_Pos size;
237 FT_Pos x_ppem;
238 FT_Pos y_ppem;
239 FT_Short internal_leading;
240 } Bitmap_Size;
242 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
243 So to let this compile on older versions of FreeType we'll define the
244 new structure here. */
245 typedef struct {
246 FT_Short height, width;
247 FT_Pos size, x_ppem, y_ppem;
248 } My_FT_Bitmap_Size;
250 struct enum_data
252 ENUMLOGFONTEXW elf;
253 NEWTEXTMETRICEXW ntm;
254 DWORD type;
257 typedef struct tagFace {
258 struct list entry;
259 WCHAR *StyleName;
260 WCHAR *FullName;
261 char *file;
262 void *font_data_ptr;
263 DWORD font_data_size;
264 FT_Long face_index;
265 FONTSIGNATURE fs;
266 FONTSIGNATURE fs_links;
267 DWORD ntmFlags;
268 FT_Fixed font_version;
269 BOOL scalable;
270 Bitmap_Size size; /* set if face is a bitmap */
271 BOOL external; /* TRUE if we should manually add this font to the registry */
272 struct tagFamily *family;
273 /* Cached data for Enum */
274 struct enum_data *cached_enum_data;
275 } Face;
277 typedef struct tagFamily {
278 struct list entry;
279 const WCHAR *FamilyName;
280 const WCHAR *EnglishName;
281 struct list faces;
282 } Family;
284 typedef struct {
285 GLYPHMETRICS gm;
286 INT adv; /* These three hold to widths of the unrotated chars */
287 INT lsb;
288 INT bbx;
289 BOOL init;
290 } GM;
292 typedef struct {
293 FLOAT eM11, eM12;
294 FLOAT eM21, eM22;
295 } FMAT2;
297 typedef struct {
298 DWORD hash;
299 LOGFONTW lf;
300 FMAT2 matrix;
301 BOOL can_use_bitmap;
302 } FONT_DESC;
304 typedef struct tagHFONTLIST {
305 struct list entry;
306 HFONT hfont;
307 } HFONTLIST;
309 typedef struct {
310 struct list entry;
311 Face *face;
312 GdiFont *font;
313 } CHILD_FONT;
315 struct tagGdiFont {
316 struct list entry;
317 GM **gm;
318 DWORD gmsize;
319 struct list hfontlist;
320 OUTLINETEXTMETRICW *potm;
321 DWORD total_kern_pairs;
322 KERNINGPAIR *kern_pairs;
323 struct list child_fonts;
325 /* the following members can be accessed without locking, they are never modified after creation */
326 FT_Face ft_face;
327 struct font_mapping *mapping;
328 LPWSTR name;
329 int charset;
330 int codepage;
331 BOOL fake_italic;
332 BOOL fake_bold;
333 BYTE underline;
334 BYTE strikeout;
335 INT orientation;
336 FONT_DESC font_desc;
337 LONG aveWidth, ppem;
338 double scale_y;
339 SHORT yMax;
340 SHORT yMin;
341 DWORD ntmFlags;
342 FONTSIGNATURE fs;
343 GdiFont *base_font;
344 VOID *GSUB_Table;
345 DWORD cache_num;
348 typedef struct {
349 struct list entry;
350 const WCHAR *font_name;
351 struct list links;
352 } SYSTEM_LINKS;
354 struct enum_charset_element {
355 DWORD mask;
356 DWORD charset;
357 LPCWSTR name;
360 struct enum_charset_list {
361 DWORD total;
362 struct enum_charset_element element[32];
365 #define GM_BLOCK_SIZE 128
366 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
368 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
369 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
370 #define UNUSED_CACHE_SIZE 10
371 static struct list child_font_list = LIST_INIT(child_font_list);
372 static struct list system_links = LIST_INIT(system_links);
374 static struct list font_subst_list = LIST_INIT(font_subst_list);
376 static struct list font_list = LIST_INIT(font_list);
378 struct freetype_physdev
380 struct gdi_physdev dev;
381 GdiFont *font;
384 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
386 return (struct freetype_physdev *)dev;
389 static const struct gdi_dc_funcs freetype_funcs;
391 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
392 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
393 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
395 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
396 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
397 'W','i','n','d','o','w','s','\\',
398 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
399 'F','o','n','t','s','\0'};
401 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
402 'W','i','n','d','o','w','s',' ','N','T','\\',
403 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
404 'F','o','n','t','s','\0'};
406 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
407 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
408 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
409 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
411 static const WCHAR * const SystemFontValues[4] = {
412 System_Value,
413 OEMFont_Value,
414 FixedSys_Value,
415 NULL
418 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
419 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
421 /* Interesting and well-known (frequently-assumed!) font names */
422 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
423 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 };
424 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
425 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
426 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
427 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
428 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
429 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
431 static const WCHAR arial[] = {'A','r','i','a','l',0};
432 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
433 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};
434 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};
435 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
436 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
437 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
438 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
439 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
441 static const WCHAR *default_serif_list[] =
443 times_new_roman,
444 liberation_serif,
445 bitstream_vera_serif,
446 NULL
449 static const WCHAR *default_fixed_list[] =
451 courier_new,
452 liberation_mono,
453 bitstream_vera_sans_mono,
454 NULL
457 static const WCHAR *default_sans_list[] =
459 arial,
460 liberation_sans,
461 bitstream_vera_sans,
462 NULL
466 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
467 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
468 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
469 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
470 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
471 'E','u','r','o','p','e','a','n','\0'};
472 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
473 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
474 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
475 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
476 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
477 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
478 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
479 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
480 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
481 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
482 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
483 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
485 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
486 WesternW, /*00*/
487 Central_EuropeanW,
488 CyrillicW,
489 GreekW,
490 TurkishW,
491 HebrewW,
492 ArabicW,
493 BalticW,
494 VietnameseW, /*08*/
495 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
496 ThaiW,
497 JapaneseW,
498 CHINESE_GB2312W,
499 HangulW,
500 CHINESE_BIG5W,
501 Hangul_Johab_W,
502 NULL, NULL, /*23*/
503 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
504 SymbolW /*31*/
507 typedef struct {
508 WCHAR *name;
509 INT charset;
510 } NameCs;
512 typedef struct tagFontSubst {
513 struct list entry;
514 NameCs from;
515 NameCs to;
516 } FontSubst;
518 /* Registry font cache key and value names */
519 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
520 'F','o','n','t','s',0};
521 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
522 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
523 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
524 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
525 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
526 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
527 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
528 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
529 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
530 static const WCHAR face_size_value[] = {'S','i','z','e',0};
531 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
532 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
533 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
534 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
535 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
538 struct font_mapping
540 struct list entry;
541 int refcount;
542 dev_t dev;
543 ino_t ino;
544 void *data;
545 size_t size;
548 static struct list mappings_list = LIST_INIT( mappings_list );
550 static CRITICAL_SECTION freetype_cs;
551 static CRITICAL_SECTION_DEBUG critsect_debug =
553 0, 0, &freetype_cs,
554 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
555 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
557 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
559 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
561 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
562 static BOOL use_default_fallback = FALSE;
564 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
565 static BOOL get_outline_text_metrics(GdiFont *font);
566 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
568 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
569 'W','i','n','d','o','w','s',' ','N','T','\\',
570 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
571 'S','y','s','t','e','m','L','i','n','k',0};
573 /****************************************
574 * Notes on .fon files
576 * The fonts System, FixedSys and Terminal are special. There are typically multiple
577 * versions installed for different resolutions and codepages. Windows stores which one to use
578 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
579 * Key Meaning
580 * FIXEDFON.FON FixedSys
581 * FONTS.FON System
582 * OEMFONT.FON Terminal
583 * LogPixels Current dpi set by the display control panel applet
584 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
585 * also has a LogPixels value that appears to mirror this)
587 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
588 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
589 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
590 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
591 * so that makes sense.
593 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
594 * to be mapped into the registry on Windows 2000 at least).
595 * I have
596 * woafont=app850.fon
597 * ega80woa.fon=ega80850.fon
598 * ega40woa.fon=ega40850.fon
599 * cga80woa.fon=cga80850.fon
600 * cga40woa.fon=cga40850.fon
603 /* These are all structures needed for the GSUB table */
605 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
606 #define TATEGAKI_LOWER_BOUND 0x02F1
608 typedef struct {
609 DWORD version;
610 WORD ScriptList;
611 WORD FeatureList;
612 WORD LookupList;
613 } GSUB_Header;
615 typedef struct {
616 CHAR ScriptTag[4];
617 WORD Script;
618 } GSUB_ScriptRecord;
620 typedef struct {
621 WORD ScriptCount;
622 GSUB_ScriptRecord ScriptRecord[1];
623 } GSUB_ScriptList;
625 typedef struct {
626 CHAR LangSysTag[4];
627 WORD LangSys;
628 } GSUB_LangSysRecord;
630 typedef struct {
631 WORD DefaultLangSys;
632 WORD LangSysCount;
633 GSUB_LangSysRecord LangSysRecord[1];
634 } GSUB_Script;
636 typedef struct {
637 WORD LookupOrder; /* Reserved */
638 WORD ReqFeatureIndex;
639 WORD FeatureCount;
640 WORD FeatureIndex[1];
641 } GSUB_LangSys;
643 typedef struct {
644 CHAR FeatureTag[4];
645 WORD Feature;
646 } GSUB_FeatureRecord;
648 typedef struct {
649 WORD FeatureCount;
650 GSUB_FeatureRecord FeatureRecord[1];
651 } GSUB_FeatureList;
653 typedef struct {
654 WORD FeatureParams; /* Reserved */
655 WORD LookupCount;
656 WORD LookupListIndex[1];
657 } GSUB_Feature;
659 typedef struct {
660 WORD LookupCount;
661 WORD Lookup[1];
662 } GSUB_LookupList;
664 typedef struct {
665 WORD LookupType;
666 WORD LookupFlag;
667 WORD SubTableCount;
668 WORD SubTable[1];
669 } GSUB_LookupTable;
671 typedef struct {
672 WORD CoverageFormat;
673 WORD GlyphCount;
674 WORD GlyphArray[1];
675 } GSUB_CoverageFormat1;
677 typedef struct {
678 WORD Start;
679 WORD End;
680 WORD StartCoverageIndex;
681 } GSUB_RangeRecord;
683 typedef struct {
684 WORD CoverageFormat;
685 WORD RangeCount;
686 GSUB_RangeRecord RangeRecord[1];
687 } GSUB_CoverageFormat2;
689 typedef struct {
690 WORD SubstFormat; /* = 1 */
691 WORD Coverage;
692 WORD DeltaGlyphID;
693 } GSUB_SingleSubstFormat1;
695 typedef struct {
696 WORD SubstFormat; /* = 2 */
697 WORD Coverage;
698 WORD GlyphCount;
699 WORD Substitute[1];
700 }GSUB_SingleSubstFormat2;
702 #ifdef HAVE_CARBON_CARBON_H
703 static char *find_cache_dir(void)
705 FSRef ref;
706 OSErr err;
707 static char cached_path[MAX_PATH];
708 static const char *wine = "/Wine", *fonts = "/Fonts";
710 if(*cached_path) return cached_path;
712 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
713 if(err != noErr)
715 WARN("can't create cached data folder\n");
716 return NULL;
718 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
719 if(err != noErr)
721 WARN("can't create cached data path\n");
722 *cached_path = '\0';
723 return NULL;
725 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
727 ERR("Could not create full path\n");
728 *cached_path = '\0';
729 return NULL;
731 strcat(cached_path, wine);
733 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
735 WARN("Couldn't mkdir %s\n", cached_path);
736 *cached_path = '\0';
737 return NULL;
739 strcat(cached_path, fonts);
740 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
742 WARN("Couldn't mkdir %s\n", cached_path);
743 *cached_path = '\0';
744 return NULL;
746 return cached_path;
749 /******************************************************************
750 * expand_mac_font
752 * Extracts individual TrueType font files from a Mac suitcase font
753 * and saves them into the user's caches directory (see
754 * find_cache_dir()).
755 * Returns a NULL terminated array of filenames.
757 * We do this because they are apps that try to read ttf files
758 * themselves and they don't like Mac suitcase files.
760 static char **expand_mac_font(const char *path)
762 FSRef ref;
763 SInt16 res_ref;
764 OSStatus s;
765 unsigned int idx;
766 const char *out_dir;
767 const char *filename;
768 int output_len;
769 struct {
770 char **array;
771 unsigned int size, max_size;
772 } ret;
774 TRACE("path %s\n", path);
776 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
777 if(s != noErr)
779 WARN("failed to get ref\n");
780 return NULL;
783 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
784 if(s != noErr)
786 TRACE("no data fork, so trying resource fork\n");
787 res_ref = FSOpenResFile(&ref, fsRdPerm);
788 if(res_ref == -1)
790 TRACE("unable to open resource fork\n");
791 return NULL;
795 ret.size = 0;
796 ret.max_size = 10;
797 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
798 if(!ret.array)
800 CloseResFile(res_ref);
801 return NULL;
804 out_dir = find_cache_dir();
806 filename = strrchr(path, '/');
807 if(!filename) filename = path;
808 else filename++;
810 /* output filename has the form out_dir/filename_%04x.ttf */
811 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
813 UseResFile(res_ref);
814 idx = 1;
815 while(1)
817 FamRec *fam_rec;
818 unsigned short *num_faces_ptr, num_faces, face;
819 AsscEntry *assoc;
820 Handle fond;
821 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
823 fond = Get1IndResource(fond_res, idx);
824 if(!fond) break;
825 TRACE("got fond resource %d\n", idx);
826 HLock(fond);
828 fam_rec = *(FamRec**)fond;
829 num_faces_ptr = (unsigned short *)(fam_rec + 1);
830 num_faces = GET_BE_WORD(*num_faces_ptr);
831 num_faces++;
832 assoc = (AsscEntry*)(num_faces_ptr + 1);
833 TRACE("num faces %04x\n", num_faces);
834 for(face = 0; face < num_faces; face++, assoc++)
836 Handle sfnt;
837 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
838 unsigned short size, font_id;
839 char *output;
841 size = GET_BE_WORD(assoc->fontSize);
842 font_id = GET_BE_WORD(assoc->fontID);
843 if(size != 0)
845 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
846 continue;
849 TRACE("trying to load sfnt id %04x\n", font_id);
850 sfnt = GetResource(sfnt_res, font_id);
851 if(!sfnt)
853 TRACE("can't get sfnt resource %04x\n", font_id);
854 continue;
857 output = HeapAlloc(GetProcessHeap(), 0, output_len);
858 if(output)
860 int fd;
862 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
864 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
865 if(fd != -1 || errno == EEXIST)
867 if(fd != -1)
869 unsigned char *sfnt_data;
871 HLock(sfnt);
872 sfnt_data = *(unsigned char**)sfnt;
873 write(fd, sfnt_data, GetHandleSize(sfnt));
874 HUnlock(sfnt);
875 close(fd);
877 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
879 ret.max_size *= 2;
880 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
882 ret.array[ret.size++] = output;
884 else
886 WARN("unable to create %s\n", output);
887 HeapFree(GetProcessHeap(), 0, output);
890 ReleaseResource(sfnt);
892 HUnlock(fond);
893 ReleaseResource(fond);
894 idx++;
896 CloseResFile(res_ref);
898 return ret.array;
901 #endif /* HAVE_CARBON_CARBON_H */
903 static inline BOOL is_win9x(void)
905 return GetVersion() & 0x80000000;
908 This function builds an FT_Fixed from a double. It fails if the absolute
909 value of the float number is greater than 32768.
911 static inline FT_Fixed FT_FixedFromFloat(double f)
913 return f * 0x10000;
917 This function builds an FT_Fixed from a FIXED. It simply put f.value
918 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
920 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
922 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
926 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
928 Family *family;
929 Face *face;
930 const char *file;
931 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
932 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
934 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
935 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
937 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
939 if(face_name && strcmpiW(face_name, family->FamilyName))
940 continue;
941 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
943 if (!face->file)
944 continue;
945 file = strrchr(face->file, '/');
946 if(!file)
947 file = face->file;
948 else
949 file++;
950 if(!strcasecmp(file, file_nameA))
952 HeapFree(GetProcessHeap(), 0, file_nameA);
953 return face;
957 HeapFree(GetProcessHeap(), 0, file_nameA);
958 return NULL;
961 static Family *find_family_from_name(const WCHAR *name)
963 Family *family;
965 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
967 if(!strcmpiW(family->FamilyName, name))
968 return family;
971 return NULL;
974 static void DumpSubstList(void)
976 FontSubst *psub;
978 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
980 if(psub->from.charset != -1 || psub->to.charset != -1)
981 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
982 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
983 else
984 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
985 debugstr_w(psub->to.name));
987 return;
990 static LPWSTR strdupW(LPCWSTR p)
992 LPWSTR ret;
993 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
994 ret = HeapAlloc(GetProcessHeap(), 0, len);
995 memcpy(ret, p, len);
996 return ret;
999 static LPSTR strdupA(LPCSTR p)
1001 LPSTR ret;
1002 DWORD len = (strlen(p) + 1);
1003 ret = HeapAlloc(GetProcessHeap(), 0, len);
1004 memcpy(ret, p, len);
1005 return ret;
1008 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1009 INT from_charset)
1011 FontSubst *element;
1013 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1015 if(!strcmpiW(element->from.name, from_name) &&
1016 (element->from.charset == from_charset ||
1017 element->from.charset == -1))
1018 return element;
1021 return NULL;
1024 #define ADD_FONT_SUBST_FORCE 1
1026 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1028 FontSubst *from_exist, *to_exist;
1030 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1032 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1034 list_remove(&from_exist->entry);
1035 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1036 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1037 HeapFree(GetProcessHeap(), 0, from_exist);
1038 from_exist = NULL;
1041 if(!from_exist)
1043 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1045 if(to_exist)
1047 HeapFree(GetProcessHeap(), 0, subst->to.name);
1048 subst->to.name = strdupW(to_exist->to.name);
1051 list_add_tail(subst_list, &subst->entry);
1053 return TRUE;
1056 HeapFree(GetProcessHeap(), 0, subst->from.name);
1057 HeapFree(GetProcessHeap(), 0, subst->to.name);
1058 HeapFree(GetProcessHeap(), 0, subst);
1059 return FALSE;
1062 static void split_subst_info(NameCs *nc, LPSTR str)
1064 CHAR *p = strrchr(str, ',');
1065 DWORD len;
1067 nc->charset = -1;
1068 if(p && *(p+1)) {
1069 nc->charset = strtol(p+1, NULL, 10);
1070 *p = '\0';
1072 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1073 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1074 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1077 static void LoadSubstList(void)
1079 FontSubst *psub;
1080 HKEY hkey;
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1082 LPSTR value;
1083 LPVOID data;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 dlen = datalen;
1097 vlen = valuelen;
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1113 } else {
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1117 dlen = datalen;
1118 vlen = valuelen;
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1122 RegCloseKey(hkey);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_SfntName name;
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1155 return TRUE;
1160 req->string = NULL;
1161 req->string_len = 0;
1162 return FALSE;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1167 WCHAR *ret = NULL;
1168 FT_SfntName name;
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1177 FT_UInt i;
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1186 ret[i] = 0;
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1190 return ret;
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1195 DWORD type, needed;
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1209 DWORD needed;
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1216 DWORD italic, bold;
1217 Face *face;
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1227 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1229 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1230 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1231 face->FullName = fullName;
1233 else
1234 face->FullName = NULL;
1236 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1237 reg_load_dword(hkey_face, face_italic_value, &italic);
1238 reg_load_dword(hkey_face, face_bold_value, &bold);
1239 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1240 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1242 needed = sizeof(face->fs);
1243 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1244 memset(&face->fs_links, 0, sizeof(face->fs_links));
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1251 else
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1265 face->ntmFlags = 0;
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1277 else
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1295 HKEY hkey_strike;
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1307 WCHAR *family_name;
1308 DWORD family_index = 0;
1309 Family *family;
1310 HKEY hkey_family;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1322 WCHAR *face_name;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 list_add_tail(&font_list, &family->entry);
1339 if(english_family)
1341 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1342 subst->from.name = strdupW(english_family);
1343 subst->from.charset = -1;
1344 subst->to.name = strdupW(family_name);
1345 subst->to.charset = -1;
1346 add_font_subst(&font_subst_list, subst, 0);
1349 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1350 NULL, NULL, NULL, NULL);
1352 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1353 size = max_face_key_len + 1;
1354 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1355 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1357 HKEY hkey_face;
1359 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1360 load_face(hkey_face, face_name, family);
1361 RegCloseKey(hkey_face);
1362 size = max_face_key_len + 1;
1364 HeapFree(GetProcessHeap(), 0, face_name);
1365 RegCloseKey(hkey_family);
1366 size = max_family_key_len + 1;
1369 HeapFree(GetProcessHeap(), 0, family_name);
1372 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1374 LONG ret;
1375 HKEY hkey_wine_fonts;
1377 /* We don't want to create the fonts key as volatile, so open this first */
1378 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1379 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1380 if(ret != ERROR_SUCCESS)
1382 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1383 return ret;
1386 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1387 KEY_ALL_ACCESS, NULL, hkey, disposition);
1388 RegCloseKey(hkey_wine_fonts);
1389 return ret;
1392 static void add_face_to_cache(Face *face)
1394 HKEY hkey_font_cache, hkey_family, hkey_face;
1395 WCHAR *face_key_name;
1397 create_font_cache_key(&hkey_font_cache, NULL);
1399 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1400 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1401 if(face->family->EnglishName)
1402 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1403 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1405 if(face->scalable)
1406 face_key_name = face->StyleName;
1407 else
1409 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1410 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1411 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1413 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1414 &hkey_face, NULL);
1415 if(!face->scalable)
1416 HeapFree(GetProcessHeap(), 0, face_key_name);
1418 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1419 if (face->FullName)
1420 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1421 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1423 reg_save_dword(hkey_face, face_index_value, face->face_index);
1424 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1425 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1426 reg_save_dword(hkey_face, face_version_value, face->font_version);
1427 reg_save_dword(hkey_face, face_external_value, face->external);
1429 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1431 if(!face->scalable)
1433 reg_save_dword(hkey_face, face_height_value, face->size.height);
1434 reg_save_dword(hkey_face, face_width_value, face->size.width);
1435 reg_save_dword(hkey_face, face_size_value, face->size.size);
1436 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1437 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1438 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1440 RegCloseKey(hkey_face);
1441 RegCloseKey(hkey_family);
1442 RegCloseKey(hkey_font_cache);
1445 static inline int TestStyles(DWORD flags, DWORD styles)
1447 return (flags & styles) == styles;
1450 static int StyleOrdering(Face *face)
1452 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1453 return 3;
1454 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1455 return 2;
1456 if (TestStyles(face->ntmFlags, NTM_BOLD))
1457 return 1;
1458 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1459 return 0;
1461 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1462 debugstr_w(face->family->FamilyName),
1463 debugstr_w(face->StyleName),
1464 face->ntmFlags);
1466 return 9999;
1469 /* Add a style of face to a font family using an ordering of the list such
1470 that regular fonts come before bold and italic, and single styles come
1471 before compound styles. */
1472 static void AddFaceToFamily(Face *face, Family *family)
1474 struct list *entry;
1476 LIST_FOR_EACH( entry, &family->faces )
1478 Face *ent = LIST_ENTRY(entry, Face, entry);
1479 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1481 list_add_before( entry, &face->entry );
1484 #define ADDFONT_EXTERNAL_FONT 0x01
1485 #define ADDFONT_FORCE_BITMAP 0x02
1486 #define ADDFONT_ADD_TO_CACHE 0x04
1488 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1490 FT_Face ft_face;
1491 TT_OS2 *pOS2;
1492 TT_Header *pHeader = NULL;
1493 WCHAR *english_family, *localised_family, *StyleW;
1494 DWORD len;
1495 Family *family;
1496 Face *face;
1497 struct list *family_elem_ptr, *face_elem_ptr;
1498 FT_Error err;
1499 FT_Long face_index = 0, num_faces;
1500 FT_WinFNT_HeaderRec winfnt_header;
1501 int i, bitmap_num, internal_leading;
1502 FONTSIGNATURE fs;
1504 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1505 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1507 #ifdef HAVE_CARBON_CARBON_H
1508 if(file && !fake_family)
1510 char **mac_list = expand_mac_font(file);
1511 if(mac_list)
1513 BOOL had_one = FALSE;
1514 char **cursor;
1515 for(cursor = mac_list; *cursor; cursor++)
1517 had_one = TRUE;
1518 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1519 HeapFree(GetProcessHeap(), 0, *cursor);
1521 HeapFree(GetProcessHeap(), 0, mac_list);
1522 if(had_one)
1523 return 1;
1526 #endif /* HAVE_CARBON_CARBON_H */
1528 do {
1529 char *family_name = fake_family;
1531 if (file)
1533 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1534 err = pFT_New_Face(library, file, face_index, &ft_face);
1535 } else
1537 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1538 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1541 if(err != 0) {
1542 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1543 return 0;
1546 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*/
1547 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1548 pFT_Done_Face(ft_face);
1549 return 0;
1552 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1553 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1554 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1555 pFT_Done_Face(ft_face);
1556 return 0;
1559 if(FT_IS_SFNT(ft_face))
1561 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1562 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1563 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1565 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1566 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1567 pFT_Done_Face(ft_face);
1568 return 0;
1571 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1572 we don't want to load these. */
1573 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1575 FT_ULong len = 0;
1577 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1579 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1580 pFT_Done_Face(ft_face);
1581 return 0;
1586 if(!ft_face->family_name || !ft_face->style_name) {
1587 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1588 pFT_Done_Face(ft_face);
1589 return 0;
1592 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1594 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1595 pFT_Done_Face(ft_face);
1596 return 0;
1599 if (target_family)
1601 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1602 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1604 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1605 HeapFree(GetProcessHeap(), 0, localised_family);
1606 num_faces = ft_face->num_faces;
1607 pFT_Done_Face(ft_face);
1608 continue;
1610 HeapFree(GetProcessHeap(), 0, localised_family);
1613 if(!family_name)
1614 family_name = ft_face->family_name;
1616 bitmap_num = 0;
1617 do {
1618 My_FT_Bitmap_Size *size = NULL;
1619 FT_ULong tmp_size;
1621 if(!FT_IS_SCALABLE(ft_face))
1622 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1624 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1625 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1626 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1628 localised_family = NULL;
1629 if(!fake_family) {
1630 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1631 if(localised_family && !strcmpiW(localised_family, english_family)) {
1632 HeapFree(GetProcessHeap(), 0, localised_family);
1633 localised_family = NULL;
1637 family = NULL;
1638 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1639 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1640 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1641 break;
1642 family = NULL;
1644 if(!family) {
1645 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1646 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1647 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1648 list_init(&family->faces);
1649 list_add_tail(&font_list, &family->entry);
1651 if(localised_family) {
1652 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1653 subst->from.name = strdupW(english_family);
1654 subst->from.charset = -1;
1655 subst->to.name = strdupW(localised_family);
1656 subst->to.charset = -1;
1657 add_font_subst(&font_subst_list, subst, 0);
1660 HeapFree(GetProcessHeap(), 0, localised_family);
1661 HeapFree(GetProcessHeap(), 0, english_family);
1663 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1664 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1665 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1667 internal_leading = 0;
1668 memset(&fs, 0, sizeof(fs));
1670 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1671 if(pOS2) {
1672 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1673 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1674 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1675 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1676 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1677 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1678 if(pOS2->version == 0) {
1679 FT_UInt dummy;
1681 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1682 fs.fsCsb[0] |= FS_LATIN1;
1683 else
1684 fs.fsCsb[0] |= FS_SYMBOL;
1687 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1688 CHARSETINFO csi;
1689 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1690 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1691 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1692 fs = csi.fs;
1693 internal_leading = winfnt_header.internal_leading;
1696 face_elem_ptr = list_head(&family->faces);
1697 while(face_elem_ptr) {
1698 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1699 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1700 if(!strcmpiW(face->StyleName, StyleW) &&
1701 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1702 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1703 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1704 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1706 if(fake_family) {
1707 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1708 HeapFree(GetProcessHeap(), 0, StyleW);
1709 pFT_Done_Face(ft_face);
1710 return 1;
1712 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1713 TRACE("Original font is newer so skipping this one\n");
1714 HeapFree(GetProcessHeap(), 0, StyleW);
1715 pFT_Done_Face(ft_face);
1716 return 1;
1717 } else {
1718 TRACE("Replacing original with this one\n");
1719 list_remove(&face->entry);
1720 HeapFree(GetProcessHeap(), 0, face->file);
1721 HeapFree(GetProcessHeap(), 0, face->StyleName);
1722 HeapFree(GetProcessHeap(), 0, face->FullName);
1723 HeapFree(GetProcessHeap(), 0, face);
1724 break;
1728 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1729 face->cached_enum_data = NULL;
1730 face->StyleName = StyleW;
1731 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1732 if (file)
1734 face->file = strdupA(file);
1735 face->font_data_ptr = NULL;
1736 face->font_data_size = 0;
1738 else
1740 face->file = NULL;
1741 face->font_data_ptr = font_data_ptr;
1742 face->font_data_size = font_data_size;
1744 face->face_index = face_index;
1745 face->ntmFlags = 0;
1746 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1747 face->ntmFlags |= NTM_ITALIC;
1748 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1749 face->ntmFlags |= NTM_BOLD;
1750 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1751 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1752 face->family = family;
1753 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1754 face->fs = fs;
1755 memset(&face->fs_links, 0, sizeof(face->fs_links));
1757 if(FT_IS_SCALABLE(ft_face)) {
1758 memset(&face->size, 0, sizeof(face->size));
1759 face->scalable = TRUE;
1760 } else {
1761 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1762 size->height, size->width, size->size >> 6,
1763 size->x_ppem >> 6, size->y_ppem >> 6);
1764 face->size.height = size->height;
1765 face->size.width = size->width;
1766 face->size.size = size->size;
1767 face->size.x_ppem = size->x_ppem;
1768 face->size.y_ppem = size->y_ppem;
1769 face->size.internal_leading = internal_leading;
1770 face->scalable = FALSE;
1773 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1774 tmp_size = 0;
1775 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1777 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1778 face->ntmFlags |= NTM_PS_OPENTYPE;
1781 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1782 face->fs.fsCsb[0], face->fs.fsCsb[1],
1783 face->fs.fsUsb[0], face->fs.fsUsb[1],
1784 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1787 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1788 for(i = 0; i < ft_face->num_charmaps; i++) {
1789 switch(ft_face->charmaps[i]->encoding) {
1790 case FT_ENCODING_UNICODE:
1791 case FT_ENCODING_APPLE_ROMAN:
1792 face->fs.fsCsb[0] |= FS_LATIN1;
1793 break;
1794 case FT_ENCODING_MS_SYMBOL:
1795 face->fs.fsCsb[0] |= FS_SYMBOL;
1796 break;
1797 default:
1798 break;
1803 if(flags & ADDFONT_ADD_TO_CACHE)
1804 add_face_to_cache(face);
1806 AddFaceToFamily(face, family);
1808 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1810 num_faces = ft_face->num_faces;
1811 pFT_Done_Face(ft_face);
1812 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1813 debugstr_w(StyleW));
1814 } while(num_faces > ++face_index);
1815 return num_faces;
1818 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1820 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1823 static void DumpFontList(void)
1825 Family *family;
1826 Face *face;
1827 struct list *family_elem_ptr, *face_elem_ptr;
1829 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1830 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1831 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1832 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1833 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1834 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1835 if(!face->scalable)
1836 TRACE(" %d", face->size.height);
1837 TRACE("\n");
1840 return;
1843 /***********************************************************
1844 * The replacement list is a way to map an entire font
1845 * family onto another family. For example adding
1847 * [HKCU\Software\Wine\Fonts\Replacements]
1848 * "Wingdings"="Winedings"
1850 * would enumerate the Winedings font both as Winedings and
1851 * Wingdings. However if a real Wingdings font is present the
1852 * replacement does not take place.
1855 static void LoadReplaceList(void)
1857 HKEY hkey;
1858 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1859 LPWSTR value;
1860 LPVOID data;
1861 Family *family;
1862 Face *face;
1863 struct list *family_elem_ptr, *face_elem_ptr;
1864 CHAR familyA[400];
1866 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1867 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1869 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1870 &valuelen, &datalen, NULL, NULL);
1872 valuelen++; /* returned value doesn't include room for '\0' */
1873 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1874 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1876 dlen = datalen;
1877 vlen = valuelen;
1878 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1879 &dlen) == ERROR_SUCCESS) {
1880 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1881 /* "NewName"="Oldname" */
1882 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1884 if(!find_family_from_name(value))
1886 /* Find the old family and hence all of the font files
1887 in that family */
1888 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1889 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1890 if(!strcmpiW(family->FamilyName, data)) {
1891 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1892 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1893 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1894 debugstr_w(face->StyleName), familyA);
1895 /* Now add a new entry with the new family name */
1896 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1897 familyA, family->FamilyName,
1898 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1900 break;
1904 /* reset dlen and vlen */
1905 dlen = datalen;
1906 vlen = valuelen;
1908 HeapFree(GetProcessHeap(), 0, data);
1909 HeapFree(GetProcessHeap(), 0, value);
1910 RegCloseKey(hkey);
1914 /*************************************************************
1915 * init_system_links
1917 static BOOL init_system_links(void)
1919 HKEY hkey;
1920 BOOL ret = FALSE;
1921 DWORD type, max_val, max_data, val_len, data_len, index;
1922 WCHAR *value, *data;
1923 WCHAR *entry, *next;
1924 SYSTEM_LINKS *font_link, *system_font_link;
1925 CHILD_FONT *child_font;
1926 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1927 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1928 FONTSIGNATURE fs;
1929 Family *family;
1930 Face *face;
1931 FontSubst *psub;
1933 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1935 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1936 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1937 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1938 val_len = max_val + 1;
1939 data_len = max_data;
1940 index = 0;
1941 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1943 memset(&fs, 0, sizeof(fs));
1944 psub = get_font_subst(&font_subst_list, value, -1);
1945 /* Don't store fonts that are only substitutes for other fonts */
1946 if(psub)
1948 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1949 goto next;
1951 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1952 font_link->font_name = strdupW(value);
1953 list_init(&font_link->links);
1954 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1956 WCHAR *face_name;
1957 CHILD_FONT *child_font;
1959 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1961 next = entry + strlenW(entry) + 1;
1963 face_name = strchrW(entry, ',');
1964 if(face_name)
1966 *face_name++ = 0;
1967 while(isspaceW(*face_name))
1968 face_name++;
1970 psub = get_font_subst(&font_subst_list, face_name, -1);
1971 if(psub)
1972 face_name = psub->to.name;
1974 face = find_face_from_filename(entry, face_name);
1975 if(!face)
1977 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1978 continue;
1981 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1982 child_font->face = face;
1983 child_font->font = NULL;
1984 fs.fsCsb[0] |= face->fs.fsCsb[0];
1985 fs.fsCsb[1] |= face->fs.fsCsb[1];
1986 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1987 list_add_tail(&font_link->links, &child_font->entry);
1989 family = find_family_from_name(font_link->font_name);
1990 if(family)
1992 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1994 face->fs_links = fs;
1997 list_add_tail(&system_links, &font_link->entry);
1998 next:
1999 val_len = max_val + 1;
2000 data_len = max_data;
2003 HeapFree(GetProcessHeap(), 0, value);
2004 HeapFree(GetProcessHeap(), 0, data);
2005 RegCloseKey(hkey);
2008 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2009 that Tahoma has */
2011 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2012 system_font_link->font_name = strdupW(System);
2013 list_init(&system_font_link->links);
2015 face = find_face_from_filename(tahoma_ttf, Tahoma);
2016 if(face)
2018 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2019 child_font->face = face;
2020 child_font->font = NULL;
2021 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2022 list_add_tail(&system_font_link->links, &child_font->entry);
2024 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2026 if(!strcmpiW(font_link->font_name, Tahoma))
2028 CHILD_FONT *font_link_entry;
2029 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2031 CHILD_FONT *new_child;
2032 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2033 new_child->face = font_link_entry->face;
2034 new_child->font = NULL;
2035 list_add_tail(&system_font_link->links, &new_child->entry);
2037 break;
2040 list_add_tail(&system_links, &system_font_link->entry);
2041 return ret;
2044 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2046 DIR *dir;
2047 struct dirent *dent;
2048 char path[MAX_PATH];
2050 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2052 dir = opendir(dirname);
2053 if(!dir) {
2054 WARN("Can't open directory %s\n", debugstr_a(dirname));
2055 return FALSE;
2057 while((dent = readdir(dir)) != NULL) {
2058 struct stat statbuf;
2060 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2061 continue;
2063 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2065 sprintf(path, "%s/%s", dirname, dent->d_name);
2067 if(stat(path, &statbuf) == -1)
2069 WARN("Can't stat %s\n", debugstr_a(path));
2070 continue;
2072 if(S_ISDIR(statbuf.st_mode))
2073 ReadFontDir(path, external_fonts);
2074 else
2076 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2077 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2078 AddFontFileToList(path, NULL, NULL, addfont_flags);
2081 closedir(dir);
2082 return TRUE;
2085 static void load_fontconfig_fonts(void)
2087 #ifdef SONAME_LIBFONTCONFIG
2088 void *fc_handle = NULL;
2089 FcConfig *config;
2090 FcPattern *pat;
2091 FcObjectSet *os;
2092 FcFontSet *fontset;
2093 int i, len;
2094 char *file;
2095 const char *ext;
2097 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2098 if(!fc_handle) {
2099 TRACE("Wine cannot find the fontconfig library (%s).\n",
2100 SONAME_LIBFONTCONFIG);
2101 return;
2103 #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;}
2104 LOAD_FUNCPTR(FcConfigGetCurrent);
2105 LOAD_FUNCPTR(FcFontList);
2106 LOAD_FUNCPTR(FcFontSetDestroy);
2107 LOAD_FUNCPTR(FcInit);
2108 LOAD_FUNCPTR(FcObjectSetAdd);
2109 LOAD_FUNCPTR(FcObjectSetCreate);
2110 LOAD_FUNCPTR(FcObjectSetDestroy);
2111 LOAD_FUNCPTR(FcPatternCreate);
2112 LOAD_FUNCPTR(FcPatternDestroy);
2113 LOAD_FUNCPTR(FcPatternGetBool);
2114 LOAD_FUNCPTR(FcPatternGetString);
2115 #undef LOAD_FUNCPTR
2117 if(!pFcInit()) return;
2119 config = pFcConfigGetCurrent();
2120 pat = pFcPatternCreate();
2121 os = pFcObjectSetCreate();
2122 pFcObjectSetAdd(os, FC_FILE);
2123 pFcObjectSetAdd(os, FC_SCALABLE);
2124 fontset = pFcFontList(config, pat, os);
2125 if(!fontset) return;
2126 for(i = 0; i < fontset->nfont; i++) {
2127 FcBool scalable;
2129 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2130 continue;
2131 TRACE("fontconfig: %s\n", file);
2133 /* We're just interested in OT/TT fonts for now, so this hack just
2134 picks up the scalable fonts without extensions .pf[ab] to save time
2135 loading every other font */
2137 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2139 TRACE("not scalable\n");
2140 continue;
2143 len = strlen( file );
2144 if(len < 4) continue;
2145 ext = &file[ len - 3 ];
2146 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2147 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2149 pFcFontSetDestroy(fontset);
2150 pFcObjectSetDestroy(os);
2151 pFcPatternDestroy(pat);
2152 sym_not_found:
2153 #endif
2154 return;
2157 static BOOL load_font_from_data_dir(LPCWSTR file)
2159 BOOL ret = FALSE;
2160 const char *data_dir = wine_get_data_dir();
2162 if (!data_dir) data_dir = wine_get_build_dir();
2164 if (data_dir)
2166 INT len;
2167 char *unix_name;
2169 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2171 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2173 strcpy(unix_name, data_dir);
2174 strcat(unix_name, "/fonts/");
2176 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2178 EnterCriticalSection( &freetype_cs );
2179 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2180 LeaveCriticalSection( &freetype_cs );
2181 HeapFree(GetProcessHeap(), 0, unix_name);
2183 return ret;
2186 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2188 static const WCHAR slashW[] = {'\\','\0'};
2189 BOOL ret = FALSE;
2190 WCHAR windowsdir[MAX_PATH];
2191 char *unixname;
2193 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2194 strcatW(windowsdir, fontsW);
2195 strcatW(windowsdir, slashW);
2196 strcatW(windowsdir, file);
2197 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2198 EnterCriticalSection( &freetype_cs );
2199 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2200 LeaveCriticalSection( &freetype_cs );
2201 HeapFree(GetProcessHeap(), 0, unixname);
2203 return ret;
2206 static void load_system_fonts(void)
2208 HKEY hkey;
2209 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2210 const WCHAR * const *value;
2211 DWORD dlen, type;
2212 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2213 char *unixname;
2215 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2216 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2217 strcatW(windowsdir, fontsW);
2218 for(value = SystemFontValues; *value; value++) {
2219 dlen = sizeof(data);
2220 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2221 type == REG_SZ) {
2222 BOOL added = FALSE;
2224 sprintfW(pathW, fmtW, windowsdir, data);
2225 if((unixname = wine_get_unix_file_name(pathW))) {
2226 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2227 HeapFree(GetProcessHeap(), 0, unixname);
2229 if (!added)
2230 load_font_from_data_dir(data);
2233 RegCloseKey(hkey);
2237 /*************************************************************
2239 * This adds registry entries for any externally loaded fonts
2240 * (fonts from fontconfig or FontDirs). It also deletes entries
2241 * of no longer existing fonts.
2244 static void update_reg_entries(void)
2246 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2247 LPWSTR valueW;
2248 DWORD len, len_fam;
2249 Family *family;
2250 Face *face;
2251 struct list *family_elem_ptr, *face_elem_ptr;
2252 WCHAR *file;
2253 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2254 static const WCHAR spaceW[] = {' ', '\0'};
2255 char *path;
2257 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2258 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2259 ERR("Can't create Windows font reg key\n");
2260 goto end;
2263 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2264 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2265 ERR("Can't create Windows font reg key\n");
2266 goto end;
2269 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2270 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2271 ERR("Can't create external font reg key\n");
2272 goto end;
2275 /* enumerate the fonts and add external ones to the two keys */
2277 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2278 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2279 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2280 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2281 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2282 if(!face->external) continue;
2283 len = len_fam;
2284 if (!(face->ntmFlags & NTM_REGULAR))
2285 len = len_fam + strlenW(face->StyleName) + 1;
2286 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2287 strcpyW(valueW, family->FamilyName);
2288 if(len != len_fam) {
2289 strcatW(valueW, spaceW);
2290 strcatW(valueW, face->StyleName);
2292 strcatW(valueW, TrueType);
2294 file = wine_get_dos_file_name(face->file);
2295 if(file)
2296 len = strlenW(file) + 1;
2297 else
2299 if((path = strrchr(face->file, '/')) == NULL)
2300 path = face->file;
2301 else
2302 path++;
2303 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2305 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2306 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2308 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2309 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2310 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2312 HeapFree(GetProcessHeap(), 0, file);
2313 HeapFree(GetProcessHeap(), 0, valueW);
2316 end:
2317 if(external_key) RegCloseKey(external_key);
2318 if(win9x_key) RegCloseKey(win9x_key);
2319 if(winnt_key) RegCloseKey(winnt_key);
2320 return;
2323 static void delete_external_font_keys(void)
2325 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2326 DWORD dlen, vlen, datalen, valuelen, i, type;
2327 LPWSTR valueW;
2328 LPVOID data;
2330 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2331 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2332 ERR("Can't create Windows font reg key\n");
2333 goto end;
2336 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2337 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2338 ERR("Can't create Windows font reg key\n");
2339 goto end;
2342 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2343 ERR("Can't create external font reg key\n");
2344 goto end;
2347 /* Delete all external fonts added last time */
2349 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2350 &valuelen, &datalen, NULL, NULL);
2351 valuelen++; /* returned value doesn't include room for '\0' */
2352 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2353 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2355 dlen = datalen * sizeof(WCHAR);
2356 vlen = valuelen;
2357 i = 0;
2358 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2359 &dlen) == ERROR_SUCCESS) {
2361 RegDeleteValueW(winnt_key, valueW);
2362 RegDeleteValueW(win9x_key, valueW);
2363 /* reset dlen and vlen */
2364 dlen = datalen;
2365 vlen = valuelen;
2367 HeapFree(GetProcessHeap(), 0, data);
2368 HeapFree(GetProcessHeap(), 0, valueW);
2370 /* Delete the old external fonts key */
2371 RegCloseKey(external_key);
2372 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2374 end:
2375 if(win9x_key) RegCloseKey(win9x_key);
2376 if(winnt_key) RegCloseKey(winnt_key);
2379 /*************************************************************
2380 * WineEngAddFontResourceEx
2383 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2385 INT ret = 0;
2387 GDI_CheckNotLock();
2389 if (ft_handle) /* do it only if we have freetype up and running */
2391 char *unixname;
2393 if(flags)
2394 FIXME("Ignoring flags %x\n", flags);
2396 if((unixname = wine_get_unix_file_name(file)))
2398 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2400 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2401 EnterCriticalSection( &freetype_cs );
2402 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2403 LeaveCriticalSection( &freetype_cs );
2404 HeapFree(GetProcessHeap(), 0, unixname);
2406 if (!ret && !strchrW(file, '\\')) {
2407 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2408 ret = load_font_from_winfonts_dir(file);
2409 if (!ret) {
2410 /* Try in datadir/fonts (or builddir/fonts),
2411 * needed for Magic the Gathering Online
2413 ret = load_font_from_data_dir(file);
2417 return ret;
2420 /*************************************************************
2421 * WineEngAddFontMemResourceEx
2424 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2426 GDI_CheckNotLock();
2428 if (ft_handle) /* do it only if we have freetype up and running */
2430 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2432 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2433 memcpy(pFontCopy, pbFont, cbFont);
2435 EnterCriticalSection( &freetype_cs );
2436 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2437 LeaveCriticalSection( &freetype_cs );
2439 if (*pcFonts == 0)
2441 TRACE("AddFontToList failed\n");
2442 HeapFree(GetProcessHeap(), 0, pFontCopy);
2443 return 0;
2445 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2446 * For now return something unique but quite random
2448 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2449 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2452 *pcFonts = 0;
2453 return 0;
2456 /*************************************************************
2457 * WineEngRemoveFontResourceEx
2460 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2462 GDI_CheckNotLock();
2463 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2464 return TRUE;
2467 static const struct nls_update_font_list
2469 UINT ansi_cp, oem_cp;
2470 const char *oem, *fixed, *system;
2471 const char *courier, *serif, *small, *sserif;
2472 /* these are for font substitutes */
2473 const char *shelldlg, *tmsrmn;
2474 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2475 *helv_0, *tmsrmn_0;
2476 const struct subst
2478 const char *from, *to;
2479 } arial_0, courier_new_0, times_new_roman_0;
2480 } nls_update_font_list[] =
2482 /* Latin 1 (United States) */
2483 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2484 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2485 "Tahoma","Times New Roman",
2486 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2487 { 0 }, { 0 }, { 0 }
2489 /* Latin 1 (Multilingual) */
2490 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2491 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2492 "Tahoma","Times New Roman", /* FIXME unverified */
2493 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2494 { 0 }, { 0 }, { 0 }
2496 /* Eastern Europe */
2497 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2498 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2499 "Tahoma","Times New Roman", /* FIXME unverified */
2500 "Fixedsys,238", "System,238",
2501 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2502 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2503 { "Arial CE,0", "Arial,238" },
2504 { "Courier New CE,0", "Courier New,238" },
2505 { "Times New Roman CE,0", "Times New Roman,238" }
2507 /* Cyrillic */
2508 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2509 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2510 "Tahoma","Times New Roman", /* FIXME unverified */
2511 "Fixedsys,204", "System,204",
2512 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2513 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2514 { "Arial Cyr,0", "Arial,204" },
2515 { "Courier New Cyr,0", "Courier New,204" },
2516 { "Times New Roman Cyr,0", "Times New Roman,204" }
2518 /* Greek */
2519 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2520 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2521 "Tahoma","Times New Roman", /* FIXME unverified */
2522 "Fixedsys,161", "System,161",
2523 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2524 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2525 { "Arial Greek,0", "Arial,161" },
2526 { "Courier New Greek,0", "Courier New,161" },
2527 { "Times New Roman Greek,0", "Times New Roman,161" }
2529 /* Turkish */
2530 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2531 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2532 "Tahoma","Times New Roman", /* FIXME unverified */
2533 "Fixedsys,162", "System,162",
2534 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2535 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2536 { "Arial Tur,0", "Arial,162" },
2537 { "Courier New Tur,0", "Courier New,162" },
2538 { "Times New Roman Tur,0", "Times New Roman,162" }
2540 /* Hebrew */
2541 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2542 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2543 "Tahoma","Times New Roman", /* FIXME unverified */
2544 "Fixedsys,177", "System,177",
2545 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2546 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2547 { 0 }, { 0 }, { 0 }
2549 /* Arabic */
2550 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2551 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2552 "Tahoma","Times New Roman", /* FIXME unverified */
2553 "Fixedsys,178", "System,178",
2554 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2555 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2556 { 0 }, { 0 }, { 0 }
2558 /* Baltic */
2559 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2560 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2561 "Tahoma","Times New Roman", /* FIXME unverified */
2562 "Fixedsys,186", "System,186",
2563 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2564 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2565 { "Arial Baltic,0", "Arial,186" },
2566 { "Courier New Baltic,0", "Courier New,186" },
2567 { "Times New Roman Baltic,0", "Times New Roman,186" }
2569 /* Vietnamese */
2570 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2571 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2572 "Tahoma","Times New Roman", /* FIXME unverified */
2573 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2574 { 0 }, { 0 }, { 0 }
2576 /* Thai */
2577 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2578 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2579 "Tahoma","Times New Roman", /* FIXME unverified */
2580 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2581 { 0 }, { 0 }, { 0 }
2583 /* Japanese */
2584 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2585 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2586 "MS UI Gothic","MS Serif",
2587 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2588 { 0 }, { 0 }, { 0 }
2590 /* Chinese Simplified */
2591 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2592 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2593 "SimSun", "NSimSun",
2594 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2595 { 0 }, { 0 }, { 0 }
2597 /* Korean */
2598 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2599 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2600 "Gulim", "Batang",
2601 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2602 { 0 }, { 0 }, { 0 }
2604 /* Chinese Traditional */
2605 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2606 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2607 "PMingLiU", "MingLiU",
2608 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2609 { 0 }, { 0 }, { 0 }
2613 static const WCHAR *font_links_list[] =
2615 Lucida_Sans_Unicode,
2616 Microsoft_Sans_Serif,
2617 Tahoma
2620 static const struct font_links_defaults_list
2622 /* Keyed off substitution for "MS Shell Dlg" */
2623 const WCHAR *shelldlg;
2624 /* Maximum of four substitutes, plus terminating NULL pointer */
2625 const WCHAR *substitutes[5];
2626 } font_links_defaults_list[] =
2628 /* Non East-Asian */
2629 { Tahoma, /* FIXME unverified ordering */
2630 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2632 /* Below lists are courtesy of
2633 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2635 /* Japanese */
2636 { MS_UI_Gothic,
2637 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2639 /* Chinese Simplified */
2640 { SimSun,
2641 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2643 /* Korean */
2644 { Gulim,
2645 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2647 /* Chinese Traditional */
2648 { PMingLiU,
2649 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2653 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2655 return ( ansi_cp == 932 /* CP932 for Japanese */
2656 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2657 || ansi_cp == 949 /* CP949 for Korean */
2658 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2661 static inline HKEY create_fonts_NT_registry_key(void)
2663 HKEY hkey = 0;
2665 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2666 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2667 return hkey;
2670 static inline HKEY create_fonts_9x_registry_key(void)
2672 HKEY hkey = 0;
2674 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2675 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2676 return hkey;
2679 static inline HKEY create_config_fonts_registry_key(void)
2681 HKEY hkey = 0;
2683 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2684 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2685 return hkey;
2688 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2690 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2691 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2692 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2693 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2696 static void set_value_key(HKEY hkey, const char *name, const char *value)
2698 if (value)
2699 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2700 else if (name)
2701 RegDeleteValueA(hkey, name);
2704 static void update_font_info(void)
2706 char buf[40], cpbuf[40];
2707 DWORD len, type;
2708 HKEY hkey = 0;
2709 UINT i, ansi_cp = 0, oem_cp = 0;
2710 BOOL done = FALSE;
2712 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2713 return;
2715 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2716 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2717 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2718 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2719 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2721 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2722 if (is_dbcs_ansi_cp(ansi_cp))
2723 use_default_fallback = TRUE;
2725 len = sizeof(buf);
2726 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2728 if (!strcmp( buf, cpbuf )) /* already set correctly */
2730 RegCloseKey(hkey);
2731 return;
2733 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2735 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2737 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2738 RegCloseKey(hkey);
2740 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2742 HKEY hkey;
2744 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2745 nls_update_font_list[i].oem_cp == oem_cp)
2747 hkey = create_config_fonts_registry_key();
2748 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2749 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2750 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2751 RegCloseKey(hkey);
2753 hkey = create_fonts_NT_registry_key();
2754 add_font_list(hkey, &nls_update_font_list[i]);
2755 RegCloseKey(hkey);
2757 hkey = create_fonts_9x_registry_key();
2758 add_font_list(hkey, &nls_update_font_list[i]);
2759 RegCloseKey(hkey);
2761 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2763 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2764 strlen(nls_update_font_list[i].shelldlg)+1);
2765 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2766 strlen(nls_update_font_list[i].tmsrmn)+1);
2768 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2769 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2770 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2771 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2772 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2773 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2774 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2775 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2777 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2778 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2779 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2781 RegCloseKey(hkey);
2783 done = TRUE;
2785 else
2787 /* Delete the FontSubstitutes from other locales */
2788 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2790 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2791 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2792 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2793 RegCloseKey(hkey);
2797 if (!done)
2798 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2800 /* Clear out system links */
2801 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2804 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2806 const WCHAR *value;
2807 int i;
2808 FontSubst *psub;
2809 Family *family;
2810 Face *face;
2811 const char *file;
2812 WCHAR *fileW;
2813 int fileLen;
2814 WCHAR buff[MAX_PATH];
2815 WCHAR *data;
2816 int entryLen;
2818 static const WCHAR comma[] = {',',0};
2820 RegDeleteValueW(hkey, name);
2821 if (values)
2823 data = buff;
2824 data[0] = '\0';
2825 for (i = 0; values[i] != NULL; i++)
2827 value = values[i];
2828 if (!strcmpiW(name,value))
2829 continue;
2830 psub = get_font_subst(&font_subst_list, value, -1);
2831 if(psub)
2832 value = psub->to.name;
2833 family = find_family_from_name(value);
2834 if (!family)
2835 continue;
2836 file = NULL;
2837 /* Use first extant filename for this Family */
2838 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2840 if (!face->file)
2841 continue;
2842 file = strrchr(face->file, '/');
2843 if (!file)
2844 file = face->file;
2845 else
2846 file++;
2847 break;
2849 if (!file)
2850 continue;
2851 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2852 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2853 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2854 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2855 if (sizeof(buff)-(data-buff) < entryLen + 1)
2857 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2858 HeapFree(GetProcessHeap(), 0, fileW);
2859 break;
2861 strcpyW(data, fileW);
2862 strcatW(data, comma);
2863 strcatW(data, value);
2864 data += entryLen;
2865 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2866 HeapFree(GetProcessHeap(), 0, fileW);
2868 if (data != buff)
2870 *data='\0';
2871 data++;
2872 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2873 } else
2874 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2875 } else
2876 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2879 static void update_system_links(void)
2881 HKEY hkey = 0;
2882 UINT i, j;
2883 BOOL done = FALSE;
2884 DWORD disposition;
2885 FontSubst *psub;
2887 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2889 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2891 if (disposition == REG_OPENED_EXISTING_KEY)
2893 TRACE("SystemLink key already exists, doing nothing\n");
2894 RegCloseKey(hkey);
2895 return;
2898 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2899 if (!psub) {
2900 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2901 RegCloseKey(hkey);
2902 return;
2905 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2907 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2909 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2910 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2912 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2913 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2914 done = TRUE;
2916 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2918 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2921 RegCloseKey(hkey);
2922 if (!done)
2923 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2924 } else
2925 WARN("failed to create SystemLink key\n");
2929 static BOOL init_freetype(void)
2931 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2932 if(!ft_handle) {
2933 WINE_MESSAGE(
2934 "Wine cannot find the FreeType font library. To enable Wine to\n"
2935 "use TrueType fonts please install a version of FreeType greater than\n"
2936 "or equal to 2.0.5.\n"
2937 "http://www.freetype.org\n");
2938 return FALSE;
2941 #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;}
2943 LOAD_FUNCPTR(FT_Done_Face)
2944 LOAD_FUNCPTR(FT_Get_Char_Index)
2945 LOAD_FUNCPTR(FT_Get_First_Char)
2946 LOAD_FUNCPTR(FT_Get_Module)
2947 LOAD_FUNCPTR(FT_Get_Next_Char)
2948 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2949 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2950 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2951 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2952 LOAD_FUNCPTR(FT_Init_FreeType)
2953 LOAD_FUNCPTR(FT_Library_Version)
2954 LOAD_FUNCPTR(FT_Load_Glyph)
2955 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2956 LOAD_FUNCPTR(FT_Matrix_Multiply)
2957 #ifndef FT_MULFIX_INLINED
2958 LOAD_FUNCPTR(FT_MulFix)
2959 #endif
2960 LOAD_FUNCPTR(FT_New_Face)
2961 LOAD_FUNCPTR(FT_New_Memory_Face)
2962 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2963 LOAD_FUNCPTR(FT_Outline_Transform)
2964 LOAD_FUNCPTR(FT_Outline_Translate)
2965 LOAD_FUNCPTR(FT_Render_Glyph)
2966 LOAD_FUNCPTR(FT_Select_Charmap)
2967 LOAD_FUNCPTR(FT_Set_Charmap)
2968 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2969 LOAD_FUNCPTR(FT_Vector_Transform)
2970 LOAD_FUNCPTR(FT_Vector_Unit)
2971 #undef LOAD_FUNCPTR
2972 /* Don't warn if these ones are missing */
2973 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2974 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2975 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2976 #endif
2978 if(pFT_Init_FreeType(&library) != 0) {
2979 ERR("Can't init FreeType library\n");
2980 wine_dlclose(ft_handle, NULL, 0);
2981 ft_handle = NULL;
2982 return FALSE;
2984 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2986 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2987 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2988 ((FT_Version.minor << 8) & 0x00ff00) |
2989 ((FT_Version.patch ) & 0x0000ff);
2991 font_driver = &freetype_funcs;
2992 return TRUE;
2994 sym_not_found:
2995 WINE_MESSAGE(
2996 "Wine cannot find certain functions that it needs inside the FreeType\n"
2997 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2998 "FreeType to at least version 2.1.4.\n"
2999 "http://www.freetype.org\n");
3000 wine_dlclose(ft_handle, NULL, 0);
3001 ft_handle = NULL;
3002 return FALSE;
3005 static void init_font_list(void)
3007 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3008 static const WCHAR pathW[] = {'P','a','t','h',0};
3009 HKEY hkey;
3010 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3011 WCHAR windowsdir[MAX_PATH];
3012 char *unixname;
3013 const char *data_dir;
3015 delete_external_font_keys();
3017 /* load the system bitmap fonts */
3018 load_system_fonts();
3020 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3021 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3022 strcatW(windowsdir, fontsW);
3023 if((unixname = wine_get_unix_file_name(windowsdir)))
3025 ReadFontDir(unixname, FALSE);
3026 HeapFree(GetProcessHeap(), 0, unixname);
3029 /* load the system truetype fonts */
3030 data_dir = wine_get_data_dir();
3031 if (!data_dir) data_dir = wine_get_build_dir();
3032 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3034 strcpy(unixname, data_dir);
3035 strcat(unixname, "/fonts/");
3036 ReadFontDir(unixname, TRUE);
3037 HeapFree(GetProcessHeap(), 0, unixname);
3040 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3041 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3042 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3043 will skip these. */
3044 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3045 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3046 &hkey) == ERROR_SUCCESS)
3048 LPWSTR data, valueW;
3049 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3050 &valuelen, &datalen, NULL, NULL);
3052 valuelen++; /* returned value doesn't include room for '\0' */
3053 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3054 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3055 if (valueW && data)
3057 dlen = datalen * sizeof(WCHAR);
3058 vlen = valuelen;
3059 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3060 &dlen) == ERROR_SUCCESS)
3062 if(data[0] && (data[1] == ':'))
3064 if((unixname = wine_get_unix_file_name(data)))
3066 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3067 HeapFree(GetProcessHeap(), 0, unixname);
3070 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3072 WCHAR pathW[MAX_PATH];
3073 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3074 BOOL added = FALSE;
3076 sprintfW(pathW, fmtW, windowsdir, data);
3077 if((unixname = wine_get_unix_file_name(pathW)))
3079 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3080 HeapFree(GetProcessHeap(), 0, unixname);
3082 if (!added)
3083 load_font_from_data_dir(data);
3085 /* reset dlen and vlen */
3086 dlen = datalen;
3087 vlen = valuelen;
3090 HeapFree(GetProcessHeap(), 0, data);
3091 HeapFree(GetProcessHeap(), 0, valueW);
3092 RegCloseKey(hkey);
3095 load_fontconfig_fonts();
3097 /* then look in any directories that we've specified in the config file */
3098 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3099 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3101 DWORD len;
3102 LPWSTR valueW;
3103 LPSTR valueA, ptr;
3105 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3107 len += sizeof(WCHAR);
3108 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3109 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3111 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3112 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3113 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3114 TRACE( "got font path %s\n", debugstr_a(valueA) );
3115 ptr = valueA;
3116 while (ptr)
3118 LPSTR next = strchr( ptr, ':' );
3119 if (next) *next++ = 0;
3120 ReadFontDir( ptr, TRUE );
3121 ptr = next;
3123 HeapFree( GetProcessHeap(), 0, valueA );
3125 HeapFree( GetProcessHeap(), 0, valueW );
3127 RegCloseKey(hkey);
3131 static BOOL move_to_front(const WCHAR *name)
3133 Family *family, *cursor2;
3134 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3136 if(!strcmpiW(family->FamilyName, name))
3138 list_remove(&family->entry);
3139 list_add_head(&font_list, &family->entry);
3140 return TRUE;
3143 return FALSE;
3146 static BOOL set_default(const WCHAR **name_list)
3148 while (*name_list)
3150 if (move_to_front(*name_list)) return TRUE;
3151 name_list++;
3154 return FALSE;
3157 static void reorder_font_list(void)
3159 set_default( default_serif_list );
3160 set_default( default_fixed_list );
3161 set_default( default_sans_list );
3164 /*************************************************************
3165 * WineEngInit
3167 * Initialize FreeType library and create a list of available faces
3169 BOOL WineEngInit(void)
3171 HKEY hkey_font_cache;
3172 DWORD disposition;
3173 HANDLE font_mutex;
3175 /* update locale dependent font info in registry */
3176 update_font_info();
3178 if(!init_freetype()) return FALSE;
3180 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3182 ERR("Failed to create font mutex\n");
3183 return FALSE;
3185 WaitForSingleObject(font_mutex, INFINITE);
3187 create_font_cache_key(&hkey_font_cache, &disposition);
3189 if(disposition == REG_CREATED_NEW_KEY)
3190 init_font_list();
3191 else
3192 load_font_list_from_cache(hkey_font_cache);
3194 RegCloseKey(hkey_font_cache);
3196 reorder_font_list();
3198 DumpFontList();
3199 LoadSubstList();
3200 DumpSubstList();
3201 LoadReplaceList();
3203 if(disposition == REG_CREATED_NEW_KEY)
3204 update_reg_entries();
3206 update_system_links();
3207 init_system_links();
3209 ReleaseMutex(font_mutex);
3210 return TRUE;
3214 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3216 TT_OS2 *pOS2;
3217 TT_HoriHeader *pHori;
3219 LONG ppem;
3221 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3222 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3224 if(height == 0) height = 16;
3226 /* Calc. height of EM square:
3228 * For +ve lfHeight we have
3229 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3230 * Re-arranging gives:
3231 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3233 * For -ve lfHeight we have
3234 * |lfHeight| = ppem
3235 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3236 * with il = winAscent + winDescent - units_per_em]
3240 if(height > 0) {
3241 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3242 ppem = MulDiv(ft_face->units_per_EM, height,
3243 pHori->Ascender - pHori->Descender);
3244 else
3245 ppem = MulDiv(ft_face->units_per_EM, height,
3246 pOS2->usWinAscent + pOS2->usWinDescent);
3248 else
3249 ppem = -height;
3251 return ppem;
3254 static struct font_mapping *map_font_file( const char *name )
3256 struct font_mapping *mapping;
3257 struct stat st;
3258 int fd;
3260 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3261 if (fstat( fd, &st ) == -1) goto error;
3263 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3265 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3267 mapping->refcount++;
3268 close( fd );
3269 return mapping;
3272 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3273 goto error;
3275 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3276 close( fd );
3278 if (mapping->data == MAP_FAILED)
3280 HeapFree( GetProcessHeap(), 0, mapping );
3281 return NULL;
3283 mapping->refcount = 1;
3284 mapping->dev = st.st_dev;
3285 mapping->ino = st.st_ino;
3286 mapping->size = st.st_size;
3287 list_add_tail( &mappings_list, &mapping->entry );
3288 return mapping;
3290 error:
3291 close( fd );
3292 return NULL;
3295 static void unmap_font_file( struct font_mapping *mapping )
3297 if (!--mapping->refcount)
3299 list_remove( &mapping->entry );
3300 munmap( mapping->data, mapping->size );
3301 HeapFree( GetProcessHeap(), 0, mapping );
3305 static LONG load_VDMX(GdiFont*, LONG);
3307 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3309 FT_Error err;
3310 FT_Face ft_face;
3311 void *data_ptr;
3312 DWORD data_size;
3314 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3316 if (face->file)
3318 if (!(font->mapping = map_font_file( face->file )))
3320 WARN("failed to map %s\n", debugstr_a(face->file));
3321 return 0;
3323 data_ptr = font->mapping->data;
3324 data_size = font->mapping->size;
3326 else
3328 data_ptr = face->font_data_ptr;
3329 data_size = face->font_data_size;
3332 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3333 if(err) {
3334 ERR("FT_New_Face rets %d\n", err);
3335 return 0;
3338 /* set it here, as load_VDMX needs it */
3339 font->ft_face = ft_face;
3341 if(FT_IS_SCALABLE(ft_face)) {
3342 /* load the VDMX table if we have one */
3343 font->ppem = load_VDMX(font, height);
3344 if(font->ppem == 0)
3345 font->ppem = calc_ppem_for_height(ft_face, height);
3346 TRACE("height %d => ppem %d\n", height, font->ppem);
3348 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3349 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3350 } else {
3351 font->ppem = height;
3352 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3353 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3355 return ft_face;
3359 static int get_nearest_charset(Face *face, int *cp)
3361 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3362 a single face with the requested charset. The idea is to check if
3363 the selected font supports the current ANSI codepage, if it does
3364 return the corresponding charset, else return the first charset */
3366 CHARSETINFO csi;
3367 int acp = GetACP(), i;
3368 DWORD fs0;
3370 *cp = acp;
3371 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3372 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3373 return csi.ciCharset;
3375 for(i = 0; i < 32; i++) {
3376 fs0 = 1L << i;
3377 if(face->fs.fsCsb[0] & fs0) {
3378 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3379 *cp = csi.ciACP;
3380 return csi.ciCharset;
3382 else
3383 FIXME("TCI failing on %x\n", fs0);
3387 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3388 face->fs.fsCsb[0], face->file);
3389 *cp = acp;
3390 return DEFAULT_CHARSET;
3393 static GdiFont *alloc_font(void)
3395 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3396 ret->gmsize = 1;
3397 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3398 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3399 ret->potm = NULL;
3400 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3401 ret->total_kern_pairs = (DWORD)-1;
3402 ret->kern_pairs = NULL;
3403 list_init(&ret->hfontlist);
3404 list_init(&ret->child_fonts);
3405 return ret;
3408 static void free_font(GdiFont *font)
3410 struct list *cursor, *cursor2;
3411 DWORD i;
3413 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3415 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3416 list_remove(cursor);
3417 if(child->font)
3418 free_font(child->font);
3419 HeapFree(GetProcessHeap(), 0, child);
3422 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3424 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3425 DeleteObject(hfontlist->hfont);
3426 list_remove(&hfontlist->entry);
3427 HeapFree(GetProcessHeap(), 0, hfontlist);
3430 if (font->ft_face) pFT_Done_Face(font->ft_face);
3431 if (font->mapping) unmap_font_file( font->mapping );
3432 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3433 HeapFree(GetProcessHeap(), 0, font->potm);
3434 HeapFree(GetProcessHeap(), 0, font->name);
3435 for (i = 0; i < font->gmsize; i++)
3436 HeapFree(GetProcessHeap(),0,font->gm[i]);
3437 HeapFree(GetProcessHeap(), 0, font->gm);
3438 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3439 HeapFree(GetProcessHeap(), 0, font);
3443 /*************************************************************
3444 * load_VDMX
3446 * load the vdmx entry for the specified height
3449 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3450 ( ( (FT_ULong)_x4 << 24 ) | \
3451 ( (FT_ULong)_x3 << 16 ) | \
3452 ( (FT_ULong)_x2 << 8 ) | \
3453 (FT_ULong)_x1 )
3455 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3457 typedef struct {
3458 BYTE bCharSet;
3459 BYTE xRatio;
3460 BYTE yStartRatio;
3461 BYTE yEndRatio;
3462 } Ratios;
3464 typedef struct {
3465 WORD recs;
3466 BYTE startsz;
3467 BYTE endsz;
3468 } VDMX_group;
3470 static LONG load_VDMX(GdiFont *font, LONG height)
3472 WORD hdr[3], tmp;
3473 VDMX_group group;
3474 BYTE devXRatio, devYRatio;
3475 USHORT numRecs, numRatios;
3476 DWORD result, offset = -1;
3477 LONG ppem = 0;
3478 int i;
3480 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3482 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3483 return ppem;
3485 /* FIXME: need the real device aspect ratio */
3486 devXRatio = 1;
3487 devYRatio = 1;
3489 numRecs = GET_BE_WORD(hdr[1]);
3490 numRatios = GET_BE_WORD(hdr[2]);
3492 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3493 for(i = 0; i < numRatios; i++) {
3494 Ratios ratio;
3496 offset = (3 * 2) + (i * sizeof(Ratios));
3497 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3498 offset = -1;
3500 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3502 if((ratio.xRatio == 0 &&
3503 ratio.yStartRatio == 0 &&
3504 ratio.yEndRatio == 0) ||
3505 (devXRatio == ratio.xRatio &&
3506 devYRatio >= ratio.yStartRatio &&
3507 devYRatio <= ratio.yEndRatio))
3509 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3510 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3511 offset = GET_BE_WORD(tmp);
3512 break;
3516 if(offset == -1) {
3517 FIXME("No suitable ratio found\n");
3518 return ppem;
3521 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3522 USHORT recs;
3523 BYTE startsz, endsz;
3524 WORD *vTable;
3526 recs = GET_BE_WORD(group.recs);
3527 startsz = group.startsz;
3528 endsz = group.endsz;
3530 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3532 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3533 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3534 if(result == GDI_ERROR) {
3535 FIXME("Failed to retrieve vTable\n");
3536 goto end;
3539 if(height > 0) {
3540 for(i = 0; i < recs; i++) {
3541 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3542 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3543 ppem = GET_BE_WORD(vTable[i * 3]);
3545 if(yMax + -yMin == height) {
3546 font->yMax = yMax;
3547 font->yMin = yMin;
3548 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3549 break;
3551 if(yMax + -yMin > height) {
3552 if(--i < 0) {
3553 ppem = 0;
3554 goto end; /* failed */
3556 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3557 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3558 ppem = GET_BE_WORD(vTable[i * 3]);
3559 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3560 break;
3563 if(!font->yMax) {
3564 ppem = 0;
3565 TRACE("ppem not found for height %d\n", height);
3568 end:
3569 HeapFree(GetProcessHeap(), 0, vTable);
3572 return ppem;
3575 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3577 if(font->font_desc.hash != fd->hash) return TRUE;
3578 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3579 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3580 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3581 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3584 static void calc_hash(FONT_DESC *pfd)
3586 DWORD hash = 0, *ptr, two_chars;
3587 WORD *pwc;
3588 unsigned int i;
3590 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3591 hash ^= *ptr;
3592 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3593 hash ^= *ptr;
3594 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3595 two_chars = *ptr;
3596 pwc = (WCHAR *)&two_chars;
3597 if(!*pwc) break;
3598 *pwc = toupperW(*pwc);
3599 pwc++;
3600 *pwc = toupperW(*pwc);
3601 hash ^= two_chars;
3602 if(!*pwc) break;
3604 hash ^= !pfd->can_use_bitmap;
3605 pfd->hash = hash;
3606 return;
3609 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3611 GdiFont *ret;
3612 FONT_DESC fd;
3613 HFONTLIST *hflist;
3614 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3616 fd.lf = *plf;
3617 fd.matrix = *pmat;
3618 fd.can_use_bitmap = can_use_bitmap;
3619 calc_hash(&fd);
3621 /* try the child list */
3622 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3623 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3624 if(!fontcmp(ret, &fd)) {
3625 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3626 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3627 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3628 if(hflist->hfont == hfont)
3629 return ret;
3634 /* try the in-use list */
3635 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3636 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3637 if(!fontcmp(ret, &fd)) {
3638 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3639 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3640 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3641 if(hflist->hfont == hfont)
3642 return ret;
3644 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3645 hflist->hfont = hfont;
3646 list_add_head(&ret->hfontlist, &hflist->entry);
3647 return ret;
3651 /* then the unused list */
3652 font_elem_ptr = list_head(&unused_gdi_font_list);
3653 while(font_elem_ptr) {
3654 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3655 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3656 if(!fontcmp(ret, &fd)) {
3657 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3658 assert(list_empty(&ret->hfontlist));
3659 TRACE("Found %p in unused list\n", ret);
3660 list_remove(&ret->entry);
3661 list_add_head(&gdi_font_list, &ret->entry);
3662 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3663 hflist->hfont = hfont;
3664 list_add_head(&ret->hfontlist, &hflist->entry);
3665 return ret;
3668 return NULL;
3671 static void add_to_cache(GdiFont *font)
3673 static DWORD cache_num = 1;
3675 font->cache_num = cache_num++;
3676 list_add_head(&gdi_font_list, &font->entry);
3679 /*************************************************************
3680 * create_child_font_list
3682 static BOOL create_child_font_list(GdiFont *font)
3684 BOOL ret = FALSE;
3685 SYSTEM_LINKS *font_link;
3686 CHILD_FONT *font_link_entry, *new_child;
3687 FontSubst *psub;
3688 WCHAR* font_name;
3690 psub = get_font_subst(&font_subst_list, font->name, -1);
3691 font_name = psub ? psub->to.name : font->name;
3692 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3694 if(!strcmpiW(font_link->font_name, font_name))
3696 TRACE("found entry in system list\n");
3697 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3699 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3700 new_child->face = font_link_entry->face;
3701 new_child->font = NULL;
3702 list_add_tail(&font->child_fonts, &new_child->entry);
3703 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3705 ret = TRUE;
3706 break;
3710 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3711 * Sans Serif. This is how asian windows get default fallbacks for fonts
3713 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3714 font->charset != OEM_CHARSET &&
3715 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3716 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3718 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3720 TRACE("found entry in default fallback list\n");
3721 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3723 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3724 new_child->face = font_link_entry->face;
3725 new_child->font = NULL;
3726 list_add_tail(&font->child_fonts, &new_child->entry);
3727 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3729 ret = TRUE;
3730 break;
3734 return ret;
3737 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3739 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3741 if (pFT_Set_Charmap)
3743 FT_Int i;
3744 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3746 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3748 for (i = 0; i < ft_face->num_charmaps; i++)
3750 if (ft_face->charmaps[i]->encoding == encoding)
3752 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3753 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3755 switch (ft_face->charmaps[i]->platform_id)
3757 default:
3758 cmap_def = ft_face->charmaps[i];
3759 break;
3760 case 0: /* Apple Unicode */
3761 cmap0 = ft_face->charmaps[i];
3762 break;
3763 case 1: /* Macintosh */
3764 cmap1 = ft_face->charmaps[i];
3765 break;
3766 case 2: /* ISO */
3767 cmap2 = ft_face->charmaps[i];
3768 break;
3769 case 3: /* Microsoft */
3770 cmap3 = ft_face->charmaps[i];
3771 break;
3775 if (cmap3) /* prefer Microsoft cmap table */
3776 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3777 else if (cmap1)
3778 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3779 else if (cmap2)
3780 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3781 else if (cmap0)
3782 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3783 else if (cmap_def)
3784 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3786 return ft_err == FT_Err_Ok;
3789 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3793 /*************************************************************
3794 * freetype_CreateDC
3796 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3797 LPCWSTR output, const DEVMODEW *devmode )
3799 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3801 if (!physdev) return FALSE;
3802 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3803 return TRUE;
3807 /*************************************************************
3808 * freetype_DeleteDC
3810 static BOOL freetype_DeleteDC( PHYSDEV dev )
3812 struct freetype_physdev *physdev = get_freetype_dev( dev );
3813 HeapFree( GetProcessHeap(), 0, physdev );
3814 return TRUE;
3818 /*************************************************************
3819 * freetype_SelectFont
3821 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3823 struct freetype_physdev *physdev = get_freetype_dev( dev );
3824 GdiFont *ret;
3825 Face *face, *best, *best_bitmap;
3826 Family *family, *last_resort_family;
3827 struct list *family_elem_ptr, *face_elem_ptr;
3828 INT height, width = 0;
3829 unsigned int score = 0, new_score;
3830 signed int diff = 0, newdiff;
3831 BOOL bd, it, can_use_bitmap;
3832 LOGFONTW lf;
3833 CHARSETINFO csi;
3834 HFONTLIST *hflist;
3835 FMAT2 dcmat;
3836 FontSubst *psub = NULL;
3837 DC *dc = get_dc_ptr( dev->hdc );
3839 if (!hfont) /* notification that the font has been changed by another driver */
3841 dc->gdiFont = NULL;
3842 physdev->font = NULL;
3843 release_dc_ptr( dc );
3844 return 0;
3847 GetObjectW( hfont, sizeof(lf), &lf );
3848 lf.lfWidth = abs(lf.lfWidth);
3850 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3852 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3853 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3854 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3855 lf.lfEscapement);
3857 if(dc->GraphicsMode == GM_ADVANCED)
3858 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3859 else
3861 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3862 font scaling abilities. */
3863 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3864 dcmat.eM21 = dcmat.eM12 = 0;
3867 /* Try to avoid not necessary glyph transformations */
3868 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3870 lf.lfHeight *= fabs(dcmat.eM11);
3871 lf.lfWidth *= fabs(dcmat.eM11);
3872 dcmat.eM11 = dcmat.eM22 = 1.0;
3875 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3876 dcmat.eM21, dcmat.eM22);
3878 GDI_CheckNotLock();
3879 EnterCriticalSection( &freetype_cs );
3881 /* check the cache first */
3882 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3883 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3884 goto done;
3887 if(list_empty(&font_list)) /* No fonts installed */
3889 TRACE("No fonts installed\n");
3890 goto done;
3893 TRACE("not in cache\n");
3894 ret = alloc_font();
3896 ret->font_desc.matrix = dcmat;
3897 ret->font_desc.lf = lf;
3898 ret->font_desc.can_use_bitmap = can_use_bitmap;
3899 calc_hash(&ret->font_desc);
3900 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3901 hflist->hfont = hfont;
3902 list_add_head(&ret->hfontlist, &hflist->entry);
3904 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3905 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3906 original value lfCharSet. Note this is a special case for
3907 Symbol and doesn't happen at least for "Wingdings*" */
3909 if(!strcmpiW(lf.lfFaceName, SymbolW))
3910 lf.lfCharSet = SYMBOL_CHARSET;
3912 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3913 switch(lf.lfCharSet) {
3914 case DEFAULT_CHARSET:
3915 csi.fs.fsCsb[0] = 0;
3916 break;
3917 default:
3918 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3919 csi.fs.fsCsb[0] = 0;
3920 break;
3924 family = NULL;
3925 if(lf.lfFaceName[0] != '\0') {
3926 SYSTEM_LINKS *font_link;
3927 CHILD_FONT *font_link_entry;
3928 LPWSTR FaceName = lf.lfFaceName;
3931 * Check for a leading '@' this signals that the font is being
3932 * requested in tategaki mode (vertical writing substitution) but
3933 * does not affect the fontface that is to be selected.
3935 if (lf.lfFaceName[0]=='@')
3936 FaceName = &lf.lfFaceName[1];
3938 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3940 if(psub) {
3941 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3942 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3943 if (psub->to.charset != -1)
3944 lf.lfCharSet = psub->to.charset;
3947 /* We want a match on name and charset or just name if
3948 charset was DEFAULT_CHARSET. If the latter then
3949 we fixup the returned charset later in get_nearest_charset
3950 where we'll either use the charset of the current ansi codepage
3951 or if that's unavailable the first charset that the font supports.
3953 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3954 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3955 if (!strcmpiW(family->FamilyName, FaceName) ||
3956 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3958 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3959 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3960 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3961 if(face->scalable || can_use_bitmap)
3962 goto found;
3967 /* Search by full face name. */
3968 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3969 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3970 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3971 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3972 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3973 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3975 if(face->scalable || can_use_bitmap)
3976 goto found_face;
3982 * Try check the SystemLink list first for a replacement font.
3983 * We may find good replacements there.
3985 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3987 if(!strcmpiW(font_link->font_name, FaceName) ||
3988 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3990 TRACE("found entry in system list\n");
3991 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3993 face = font_link_entry->face;
3994 family = face->family;
3995 if(csi.fs.fsCsb[0] &
3996 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3998 if(face->scalable || can_use_bitmap)
3999 goto found;
4006 psub = NULL; /* substitution is no more relevant */
4008 /* If requested charset was DEFAULT_CHARSET then try using charset
4009 corresponding to the current ansi codepage */
4010 if (!csi.fs.fsCsb[0])
4012 INT acp = GetACP();
4013 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4014 FIXME("TCI failed on codepage %d\n", acp);
4015 csi.fs.fsCsb[0] = 0;
4016 } else
4017 lf.lfCharSet = csi.ciCharset;
4020 /* Face families are in the top 4 bits of lfPitchAndFamily,
4021 so mask with 0xF0 before testing */
4023 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4024 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4025 strcpyW(lf.lfFaceName, defFixed);
4026 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4027 strcpyW(lf.lfFaceName, defSerif);
4028 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4029 strcpyW(lf.lfFaceName, defSans);
4030 else
4031 strcpyW(lf.lfFaceName, defSans);
4032 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4033 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4034 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4035 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4036 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4037 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4038 if(face->scalable || can_use_bitmap)
4039 goto found;
4044 last_resort_family = NULL;
4045 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4046 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4047 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4048 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4049 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4050 if(face->scalable)
4051 goto found;
4052 if(can_use_bitmap && !last_resort_family)
4053 last_resort_family = family;
4058 if(last_resort_family) {
4059 family = last_resort_family;
4060 csi.fs.fsCsb[0] = 0;
4061 goto found;
4064 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4065 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4066 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4067 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4068 if(face->scalable) {
4069 csi.fs.fsCsb[0] = 0;
4070 WARN("just using first face for now\n");
4071 goto found;
4073 if(can_use_bitmap && !last_resort_family)
4074 last_resort_family = family;
4077 if(!last_resort_family) {
4078 FIXME("can't find a single appropriate font - bailing\n");
4079 free_font(ret);
4080 ret = NULL;
4081 goto done;
4084 WARN("could only find a bitmap font - this will probably look awful!\n");
4085 family = last_resort_family;
4086 csi.fs.fsCsb[0] = 0;
4088 found:
4089 it = lf.lfItalic ? 1 : 0;
4090 bd = lf.lfWeight > 550 ? 1 : 0;
4092 height = lf.lfHeight;
4094 face = best = best_bitmap = NULL;
4095 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4097 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4099 BOOL italic, bold;
4101 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4102 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4103 new_score = (italic ^ it) + (bold ^ bd);
4104 if(!best || new_score <= score)
4106 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4107 italic, bold, it, bd);
4108 score = new_score;
4109 best = face;
4110 if(best->scalable && score == 0) break;
4111 if(!best->scalable)
4113 if(height > 0)
4114 newdiff = height - (signed int)(best->size.height);
4115 else
4116 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4117 if(!best_bitmap || new_score < score ||
4118 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4120 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4121 diff = newdiff;
4122 best_bitmap = best;
4123 if(score == 0 && diff == 0) break;
4129 if(best)
4130 face = best->scalable ? best : best_bitmap;
4131 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4132 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4134 found_face:
4135 height = lf.lfHeight;
4137 ret->fs = face->fs;
4139 if(csi.fs.fsCsb[0]) {
4140 ret->charset = lf.lfCharSet;
4141 ret->codepage = csi.ciACP;
4143 else
4144 ret->charset = get_nearest_charset(face, &ret->codepage);
4146 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4147 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4149 ret->aveWidth = height ? lf.lfWidth : 0;
4151 if(!face->scalable) {
4152 /* Windows uses integer scaling factors for bitmap fonts */
4153 INT scale, scaled_height;
4154 GdiFont *cachedfont;
4156 /* FIXME: rotation of bitmap fonts is ignored */
4157 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4158 if (ret->aveWidth)
4159 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4160 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4161 dcmat.eM11 = dcmat.eM22 = 1.0;
4162 /* As we changed the matrix, we need to search the cache for the font again,
4163 * otherwise we might explode the cache. */
4164 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4165 TRACE("Found cached font after non-scalable matrix rescale!\n");
4166 free_font( ret );
4167 ret = cachedfont;
4168 goto done;
4170 calc_hash(&ret->font_desc);
4172 if (height != 0) height = diff;
4173 height += face->size.height;
4175 scale = (height + face->size.height - 1) / face->size.height;
4176 scaled_height = scale * face->size.height;
4177 /* Only jump to the next height if the difference <= 25% original height */
4178 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4179 /* The jump between unscaled and doubled is delayed by 1 */
4180 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4181 ret->scale_y = scale;
4183 width = face->size.x_ppem >> 6;
4184 height = face->size.y_ppem >> 6;
4186 else
4187 ret->scale_y = 1.0;
4188 TRACE("font scale y: %f\n", ret->scale_y);
4190 ret->ft_face = OpenFontFace(ret, face, width, height);
4192 if (!ret->ft_face)
4194 free_font( ret );
4195 ret = NULL;
4196 goto done;
4199 ret->ntmFlags = face->ntmFlags;
4201 if (ret->charset == SYMBOL_CHARSET &&
4202 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4203 /* No ops */
4205 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4206 /* No ops */
4208 else {
4209 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4212 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4213 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4214 ret->underline = lf.lfUnderline ? 0xff : 0;
4215 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4216 create_child_font_list(ret);
4218 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4220 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
4221 if (length != GDI_ERROR)
4223 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4224 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4225 TRACE("Loaded GSUB table of %i bytes\n",length);
4229 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4231 add_to_cache(ret);
4232 done:
4233 if (ret)
4235 dc->gdiFont = ret;
4236 physdev->font = ret;
4238 LeaveCriticalSection( &freetype_cs );
4239 release_dc_ptr( dc );
4240 return ret ? hfont : 0;
4243 static void dump_gdi_font_list(void)
4245 GdiFont *gdiFont;
4246 struct list *elem_ptr;
4248 TRACE("---------- gdiFont Cache ----------\n");
4249 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4250 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4251 TRACE("gdiFont=%p %s %d\n",
4252 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4255 TRACE("---------- Unused gdiFont Cache ----------\n");
4256 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4257 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4258 TRACE("gdiFont=%p %s %d\n",
4259 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4262 TRACE("---------- Child gdiFont Cache ----------\n");
4263 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4264 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4265 TRACE("gdiFont=%p %s %d\n",
4266 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4270 /*************************************************************
4271 * WineEngDestroyFontInstance
4273 * free the gdiFont associated with this handle
4276 BOOL WineEngDestroyFontInstance(HFONT handle)
4278 GdiFont *gdiFont;
4279 HFONTLIST *hflist;
4280 BOOL ret = FALSE;
4281 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4282 int i = 0;
4284 GDI_CheckNotLock();
4285 EnterCriticalSection( &freetype_cs );
4287 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4289 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4290 while(hfontlist_elem_ptr) {
4291 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4292 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4293 if(hflist->hfont == handle) {
4294 TRACE("removing child font %p from child list\n", gdiFont);
4295 list_remove(&gdiFont->entry);
4296 LeaveCriticalSection( &freetype_cs );
4297 return TRUE;
4302 TRACE("destroying hfont=%p\n", handle);
4303 if(TRACE_ON(font))
4304 dump_gdi_font_list();
4306 font_elem_ptr = list_head(&gdi_font_list);
4307 while(font_elem_ptr) {
4308 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4309 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4311 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4312 while(hfontlist_elem_ptr) {
4313 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4314 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4315 if(hflist->hfont == handle) {
4316 list_remove(&hflist->entry);
4317 HeapFree(GetProcessHeap(), 0, hflist);
4318 ret = TRUE;
4321 if(list_empty(&gdiFont->hfontlist)) {
4322 TRACE("Moving to Unused list\n");
4323 list_remove(&gdiFont->entry);
4324 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4329 font_elem_ptr = list_head(&unused_gdi_font_list);
4330 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4331 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4332 while(font_elem_ptr) {
4333 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4334 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4335 TRACE("freeing %p\n", gdiFont);
4336 list_remove(&gdiFont->entry);
4337 free_font(gdiFont);
4339 LeaveCriticalSection( &freetype_cs );
4340 return ret;
4343 /***************************************************
4344 * create_enum_charset_list
4346 * This function creates charset enumeration list because in DEFAULT_CHARSET
4347 * case, the ANSI codepage's charset takes precedence over other charsets.
4348 * This function works as a filter other than DEFAULT_CHARSET case.
4350 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4352 CHARSETINFO csi;
4353 DWORD n = 0;
4355 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4356 csi.fs.fsCsb[0] != 0) {
4357 list->element[n].mask = csi.fs.fsCsb[0];
4358 list->element[n].charset = csi.ciCharset;
4359 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4360 n++;
4362 else { /* charset is DEFAULT_CHARSET or invalid. */
4363 INT acp, i;
4365 /* Set the current codepage's charset as the first element. */
4366 acp = GetACP();
4367 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4368 csi.fs.fsCsb[0] != 0) {
4369 list->element[n].mask = csi.fs.fsCsb[0];
4370 list->element[n].charset = csi.ciCharset;
4371 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4372 n++;
4375 /* Fill out left elements. */
4376 for (i = 0; i < 32; i++) {
4377 FONTSIGNATURE fs;
4378 fs.fsCsb[0] = 1L << i;
4379 fs.fsCsb[1] = 0;
4380 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4381 continue; /* skip, already added. */
4382 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4383 continue; /* skip, this is an invalid fsCsb bit. */
4385 list->element[n].mask = fs.fsCsb[0];
4386 list->element[n].charset = csi.ciCharset;
4387 list->element[n].name = ElfScriptsW[i];
4388 n++;
4391 list->total = n;
4393 return n;
4396 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4397 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4399 GdiFont *font;
4400 LONG width, height;
4402 if (face->cached_enum_data)
4404 TRACE("Cached\n");
4405 *pelf = face->cached_enum_data->elf;
4406 *pntm = face->cached_enum_data->ntm;
4407 *ptype = face->cached_enum_data->type;
4408 return;
4411 font = alloc_font();
4413 if(face->scalable) {
4414 height = -2048; /* 2048 is the most common em size */
4415 width = 0;
4416 } else {
4417 height = face->size.y_ppem >> 6;
4418 width = face->size.x_ppem >> 6;
4420 font->scale_y = 1.0;
4422 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4424 free_font(font);
4425 return;
4428 font->name = strdupW(face->family->FamilyName);
4429 font->ntmFlags = face->ntmFlags;
4431 if (get_outline_text_metrics(font))
4433 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4435 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4437 lstrcpynW(pelf->elfLogFont.lfFaceName,
4438 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4439 LF_FACESIZE);
4440 lstrcpynW(pelf->elfFullName,
4441 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4442 LF_FULLFACESIZE);
4443 lstrcpynW(pelf->elfStyle,
4444 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4445 LF_FACESIZE);
4447 else
4449 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4451 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4453 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4454 if (face->FullName)
4455 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4456 else
4457 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4458 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4461 pntm->ntmTm.ntmFlags = face->ntmFlags;
4462 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4463 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4464 pntm->ntmFontSig = face->fs;
4466 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4468 pelf->elfLogFont.lfEscapement = 0;
4469 pelf->elfLogFont.lfOrientation = 0;
4470 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4471 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4472 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4473 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4474 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4475 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4476 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4477 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4478 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4479 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4480 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4482 *ptype = 0;
4483 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4484 *ptype |= TRUETYPE_FONTTYPE;
4485 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4486 *ptype |= DEVICE_FONTTYPE;
4487 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4488 *ptype |= RASTER_FONTTYPE;
4490 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4491 if (face->cached_enum_data)
4493 face->cached_enum_data->elf = *pelf;
4494 face->cached_enum_data->ntm = *pntm;
4495 face->cached_enum_data->type = *ptype;
4498 free_font(font);
4501 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4503 struct list *face_elem_ptr;
4505 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4507 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4509 static const WCHAR spaceW[] = { ' ',0 };
4510 WCHAR full_family_name[LF_FULLFACESIZE];
4511 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4513 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4515 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4516 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4517 continue;
4520 strcpyW(full_family_name, family->FamilyName);
4521 strcatW(full_family_name, spaceW);
4522 strcatW(full_family_name, face->StyleName);
4523 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4526 return FALSE;
4529 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4531 static const WCHAR spaceW[] = { ' ',0 };
4532 WCHAR full_family_name[LF_FULLFACESIZE];
4534 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4536 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4538 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4539 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4540 return FALSE;
4543 strcpyW(full_family_name, face->family->FamilyName);
4544 strcatW(full_family_name, spaceW);
4545 strcatW(full_family_name, face->StyleName);
4546 return !strcmpiW(lf->lfFaceName, full_family_name);
4549 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4550 FONTENUMPROCW proc, LPARAM lparam)
4552 ENUMLOGFONTEXW elf;
4553 NEWTEXTMETRICEXW ntm;
4554 DWORD type = 0;
4555 int i;
4557 GetEnumStructs(face, &elf, &ntm, &type);
4558 for(i = 0; i < list->total; i++) {
4559 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4560 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4561 strcpyW(elf.elfScript, OEM_DOSW);
4562 i = 32; /* break out of loop */
4563 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4564 continue;
4565 else {
4566 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4567 if(list->element[i].name)
4568 strcpyW(elf.elfScript, list->element[i].name);
4569 else
4570 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4572 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4573 debugstr_w(elf.elfLogFont.lfFaceName),
4574 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4575 list->element[i].charset, type, debugstr_w(elf.elfScript),
4576 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4577 ntm.ntmTm.ntmFlags);
4578 /* release section before callback (FIXME) */
4579 LeaveCriticalSection( &freetype_cs );
4580 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4581 EnterCriticalSection( &freetype_cs );
4583 return TRUE;
4586 /*************************************************************
4587 * freetype_EnumFonts
4589 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4591 Family *family;
4592 Face *face;
4593 struct list *family_elem_ptr, *face_elem_ptr;
4594 LOGFONTW lf;
4595 struct enum_charset_list enum_charsets;
4597 if (!plf)
4599 lf.lfCharSet = DEFAULT_CHARSET;
4600 lf.lfPitchAndFamily = 0;
4601 lf.lfFaceName[0] = 0;
4602 plf = &lf;
4605 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4607 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4609 GDI_CheckNotLock();
4610 EnterCriticalSection( &freetype_cs );
4611 if(plf->lfFaceName[0]) {
4612 FontSubst *psub;
4613 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4615 if(psub) {
4616 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4617 debugstr_w(psub->to.name));
4618 lf = *plf;
4619 strcpyW(lf.lfFaceName, psub->to.name);
4620 plf = &lf;
4623 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4624 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4625 if(family_matches(family, plf)) {
4626 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4627 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4628 if (!face_matches(face, plf)) continue;
4629 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4633 } else {
4634 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4635 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4636 face_elem_ptr = list_head(&family->faces);
4637 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4638 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4641 LeaveCriticalSection( &freetype_cs );
4642 return TRUE;
4645 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4647 pt->x.value = vec->x >> 6;
4648 pt->x.fract = (vec->x & 0x3f) << 10;
4649 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4650 pt->y.value = vec->y >> 6;
4651 pt->y.fract = (vec->y & 0x3f) << 10;
4652 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4653 return;
4656 /***************************************************
4657 * According to the MSDN documentation on WideCharToMultiByte,
4658 * certain codepages cannot set the default_used parameter.
4659 * This returns TRUE if the codepage can set that parameter, false else
4660 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4662 static BOOL codepage_sets_default_used(UINT codepage)
4664 switch (codepage)
4666 case CP_UTF7:
4667 case CP_UTF8:
4668 case CP_SYMBOL:
4669 return FALSE;
4670 default:
4671 return TRUE;
4676 * GSUB Table handling functions
4679 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4681 const GSUB_CoverageFormat1* cf1;
4683 cf1 = table;
4685 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4687 int count = GET_BE_WORD(cf1->GlyphCount);
4688 int i;
4689 TRACE("Coverage Format 1, %i glyphs\n",count);
4690 for (i = 0; i < count; i++)
4691 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4692 return i;
4693 return -1;
4695 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4697 const GSUB_CoverageFormat2* cf2;
4698 int i;
4699 int count;
4700 cf2 = (const GSUB_CoverageFormat2*)cf1;
4702 count = GET_BE_WORD(cf2->RangeCount);
4703 TRACE("Coverage Format 2, %i ranges\n",count);
4704 for (i = 0; i < count; i++)
4706 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4707 return -1;
4708 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4709 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4711 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4712 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4715 return -1;
4717 else
4718 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4720 return -1;
4723 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4725 const GSUB_ScriptList *script;
4726 const GSUB_Script *deflt = NULL;
4727 int i;
4728 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4730 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4731 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4733 const GSUB_Script *scr;
4734 int offset;
4736 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4737 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4739 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4740 return scr;
4741 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4742 deflt = scr;
4744 return deflt;
4747 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4749 int i;
4750 int offset;
4751 const GSUB_LangSys *Lang;
4753 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4755 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4757 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4758 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4760 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4761 return Lang;
4763 offset = GET_BE_WORD(script->DefaultLangSys);
4764 if (offset)
4766 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4767 return Lang;
4769 return NULL;
4772 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4774 int i;
4775 const GSUB_FeatureList *feature;
4776 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4778 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4779 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4781 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4782 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4784 const GSUB_Feature *feat;
4785 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4786 return feat;
4789 return NULL;
4792 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4794 int i;
4795 int offset;
4796 const GSUB_LookupList *lookup;
4797 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4799 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4800 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4802 const GSUB_LookupTable *look;
4803 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4804 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4805 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4806 if (GET_BE_WORD(look->LookupType) != 1)
4807 FIXME("We only handle SubType 1\n");
4808 else
4810 int j;
4812 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4814 const GSUB_SingleSubstFormat1 *ssf1;
4815 offset = GET_BE_WORD(look->SubTable[j]);
4816 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4817 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4819 int offset = GET_BE_WORD(ssf1->Coverage);
4820 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4821 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4823 TRACE(" Glyph 0x%x ->",glyph);
4824 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4825 TRACE(" 0x%x\n",glyph);
4828 else
4830 const GSUB_SingleSubstFormat2 *ssf2;
4831 INT index;
4832 INT offset;
4834 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4835 offset = GET_BE_WORD(ssf1->Coverage);
4836 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4837 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4838 TRACE(" Coverage index %i\n",index);
4839 if (index != -1)
4841 TRACE(" Glyph is 0x%x ->",glyph);
4842 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4843 TRACE("0x%x\n",glyph);
4849 return glyph;
4852 static const char* get_opentype_script(const GdiFont *font)
4855 * I am not sure if this is the correct way to generate our script tag
4858 switch (font->charset)
4860 case ANSI_CHARSET: return "latn";
4861 case BALTIC_CHARSET: return "latn"; /* ?? */
4862 case CHINESEBIG5_CHARSET: return "hani";
4863 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4864 case GB2312_CHARSET: return "hani";
4865 case GREEK_CHARSET: return "grek";
4866 case HANGUL_CHARSET: return "hang";
4867 case RUSSIAN_CHARSET: return "cyrl";
4868 case SHIFTJIS_CHARSET: return "kana";
4869 case TURKISH_CHARSET: return "latn"; /* ?? */
4870 case VIETNAMESE_CHARSET: return "latn";
4871 case JOHAB_CHARSET: return "latn"; /* ?? */
4872 case ARABIC_CHARSET: return "arab";
4873 case HEBREW_CHARSET: return "hebr";
4874 case THAI_CHARSET: return "thai";
4875 default: return "latn";
4879 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4881 const GSUB_Header *header;
4882 const GSUB_Script *script;
4883 const GSUB_LangSys *language;
4884 const GSUB_Feature *feature;
4886 if (!font->GSUB_Table)
4887 return glyph;
4889 header = font->GSUB_Table;
4891 script = GSUB_get_script_table(header, get_opentype_script(font));
4892 if (!script)
4894 TRACE("Script not found\n");
4895 return glyph;
4897 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4898 if (!language)
4900 TRACE("Language not found\n");
4901 return glyph;
4903 feature = GSUB_get_feature(header, language, "vrt2");
4904 if (!feature)
4905 feature = GSUB_get_feature(header, language, "vert");
4906 if (!feature)
4908 TRACE("vrt2/vert feature not found\n");
4909 return glyph;
4911 return GSUB_apply_feature(header, feature, glyph);
4914 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4916 FT_UInt glyphId;
4918 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4919 WCHAR wc = (WCHAR)glyph;
4920 BOOL default_used;
4921 BOOL *default_used_pointer;
4922 FT_UInt ret;
4923 char buf;
4924 default_used_pointer = NULL;
4925 default_used = FALSE;
4926 if (codepage_sets_default_used(font->codepage))
4927 default_used_pointer = &default_used;
4928 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4929 ret = 0;
4930 else
4931 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4932 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4933 return get_GSUB_vert_glyph(font,ret);
4936 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4938 if (glyph < 0x100) glyph += 0xf000;
4939 /* there is a number of old pre-Unicode "broken" TTFs, which
4940 do have symbols at U+00XX instead of U+f0XX */
4941 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4942 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4944 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4946 return get_GSUB_vert_glyph(font,glyphId);
4949 /*************************************************************
4950 * WineEngGetGlyphIndices
4953 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4954 LPWORD pgi, DWORD flags)
4956 int i;
4957 WORD default_char;
4958 BOOL got_default = FALSE;
4960 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4962 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4963 got_default = TRUE;
4966 GDI_CheckNotLock();
4967 EnterCriticalSection( &freetype_cs );
4969 for(i = 0; i < count; i++)
4971 pgi[i] = get_glyph_index(font, lpstr[i]);
4972 if (pgi[i] == 0)
4974 if (!got_default)
4976 if (FT_IS_SFNT(font->ft_face))
4978 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4979 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4981 else
4983 TEXTMETRICW textm;
4984 get_text_metrics(font, &textm);
4985 default_char = textm.tmDefaultChar;
4987 got_default = TRUE;
4989 pgi[i] = default_char;
4992 LeaveCriticalSection( &freetype_cs );
4993 return count;
4996 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4998 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4999 return !memcmp(matrix, &identity, sizeof(FMAT2));
5002 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5004 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5005 return !memcmp(matrix, &identity, sizeof(MAT2));
5008 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5009 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5010 const MAT2* lpmat)
5012 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5013 FT_Face ft_face = incoming_font->ft_face;
5014 GdiFont *font = incoming_font;
5015 FT_UInt glyph_index;
5016 DWORD width, height, pitch, needed = 0;
5017 FT_Bitmap ft_bitmap;
5018 FT_Error err;
5019 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5020 FT_Angle angle = 0;
5021 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5022 double widthRatio = 1.0;
5023 FT_Matrix transMat = identityMat;
5024 FT_Matrix transMatUnrotated;
5025 BOOL needsTransform = FALSE;
5026 BOOL tategaki = (font->GSUB_Table != NULL);
5027 UINT original_index;
5029 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5030 buflen, buf, lpmat);
5032 TRACE("font transform %f %f %f %f\n",
5033 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5034 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5036 if(format & GGO_GLYPH_INDEX) {
5037 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5038 original_index = glyph;
5039 format &= ~GGO_GLYPH_INDEX;
5040 } else {
5041 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5042 ft_face = font->ft_face;
5043 original_index = glyph_index;
5046 if(format & GGO_UNHINTED) {
5047 load_flags |= FT_LOAD_NO_HINTING;
5048 format &= ~GGO_UNHINTED;
5051 /* tategaki never appears to happen to lower glyph index */
5052 if (glyph_index < TATEGAKI_LOWER_BOUND )
5053 tategaki = FALSE;
5055 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5056 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5057 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5058 font->gmsize * sizeof(GM*));
5059 } else {
5060 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5061 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5063 *lpgm = FONT_GM(font,original_index)->gm;
5064 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5065 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5066 lpgm->gmCellIncX, lpgm->gmCellIncY);
5067 return 1; /* FIXME */
5071 if (!font->gm[original_index / GM_BLOCK_SIZE])
5072 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5074 /* Scaling factor */
5075 if (font->aveWidth)
5077 TEXTMETRICW tm;
5079 get_text_metrics(font, &tm);
5081 widthRatio = (double)font->aveWidth;
5082 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5084 else
5085 widthRatio = font->scale_y;
5087 /* Scaling transform */
5088 if (widthRatio != 1.0 || font->scale_y != 1.0)
5090 FT_Matrix scaleMat;
5091 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5092 scaleMat.xy = 0;
5093 scaleMat.yx = 0;
5094 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5096 pFT_Matrix_Multiply(&scaleMat, &transMat);
5097 needsTransform = TRUE;
5100 /* Slant transform */
5101 if (font->fake_italic) {
5102 FT_Matrix slantMat;
5104 slantMat.xx = (1 << 16);
5105 slantMat.xy = ((1 << 16) >> 2);
5106 slantMat.yx = 0;
5107 slantMat.yy = (1 << 16);
5108 pFT_Matrix_Multiply(&slantMat, &transMat);
5109 needsTransform = TRUE;
5112 /* Rotation transform */
5113 transMatUnrotated = transMat;
5114 if(font->orientation && !tategaki) {
5115 FT_Matrix rotationMat;
5116 FT_Vector vecAngle;
5117 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5118 pFT_Vector_Unit(&vecAngle, angle);
5119 rotationMat.xx = vecAngle.x;
5120 rotationMat.xy = -vecAngle.y;
5121 rotationMat.yx = -rotationMat.xy;
5122 rotationMat.yy = rotationMat.xx;
5124 pFT_Matrix_Multiply(&rotationMat, &transMat);
5125 needsTransform = TRUE;
5128 /* World transform */
5129 if (!is_identity_FMAT2(&font->font_desc.matrix))
5131 FT_Matrix worldMat;
5132 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5133 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5134 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5135 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5136 pFT_Matrix_Multiply(&worldMat, &transMat);
5137 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5138 needsTransform = TRUE;
5141 /* Extra transformation specified by caller */
5142 if (!is_identity_MAT2(lpmat))
5144 FT_Matrix extraMat;
5145 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5146 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5147 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5148 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5149 pFT_Matrix_Multiply(&extraMat, &transMat);
5150 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5151 needsTransform = TRUE;
5154 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5155 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5156 format == GGO_GRAY8_BITMAP))
5158 load_flags |= FT_LOAD_NO_BITMAP;
5161 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5163 if(err) {
5164 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5165 return GDI_ERROR;
5168 if(!needsTransform) {
5169 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5170 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5171 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5173 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5174 bottom = (ft_face->glyph->metrics.horiBearingY -
5175 ft_face->glyph->metrics.height) & -64;
5176 lpgm->gmCellIncX = adv;
5177 lpgm->gmCellIncY = 0;
5178 } else {
5179 INT xc, yc;
5180 FT_Vector vec;
5182 left = right = 0;
5184 for(xc = 0; xc < 2; xc++) {
5185 for(yc = 0; yc < 2; yc++) {
5186 vec.x = (ft_face->glyph->metrics.horiBearingX +
5187 xc * ft_face->glyph->metrics.width);
5188 vec.y = ft_face->glyph->metrics.horiBearingY -
5189 yc * ft_face->glyph->metrics.height;
5190 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5191 pFT_Vector_Transform(&vec, &transMat);
5192 if(xc == 0 && yc == 0) {
5193 left = right = vec.x;
5194 top = bottom = vec.y;
5195 } else {
5196 if(vec.x < left) left = vec.x;
5197 else if(vec.x > right) right = vec.x;
5198 if(vec.y < bottom) bottom = vec.y;
5199 else if(vec.y > top) top = vec.y;
5203 left = left & -64;
5204 right = (right + 63) & -64;
5205 bottom = bottom & -64;
5206 top = (top + 63) & -64;
5208 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5209 vec.x = ft_face->glyph->metrics.horiAdvance;
5210 vec.y = 0;
5211 pFT_Vector_Transform(&vec, &transMat);
5212 lpgm->gmCellIncX = (vec.x+63) >> 6;
5213 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5215 vec.x = ft_face->glyph->metrics.horiAdvance;
5216 vec.y = 0;
5217 pFT_Vector_Transform(&vec, &transMatUnrotated);
5218 adv = (vec.x+63) >> 6;
5221 lsb = left >> 6;
5222 bbx = (right - left) >> 6;
5223 lpgm->gmBlackBoxX = (right - left) >> 6;
5224 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5225 lpgm->gmptGlyphOrigin.x = left >> 6;
5226 lpgm->gmptGlyphOrigin.y = top >> 6;
5228 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5229 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5230 lpgm->gmCellIncX, lpgm->gmCellIncY);
5232 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5233 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5235 FONT_GM(font,original_index)->gm = *lpgm;
5236 FONT_GM(font,original_index)->adv = adv;
5237 FONT_GM(font,original_index)->lsb = lsb;
5238 FONT_GM(font,original_index)->bbx = bbx;
5239 FONT_GM(font,original_index)->init = TRUE;
5242 if(format == GGO_METRICS)
5244 return 1; /* FIXME */
5247 if(ft_face->glyph->format != ft_glyph_format_outline &&
5248 (format == GGO_NATIVE || format == GGO_BEZIER ||
5249 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5250 format == GGO_GRAY8_BITMAP))
5252 TRACE("loaded a bitmap\n");
5253 return GDI_ERROR;
5256 switch(format) {
5257 case GGO_BITMAP:
5258 width = lpgm->gmBlackBoxX;
5259 height = lpgm->gmBlackBoxY;
5260 pitch = ((width + 31) >> 5) << 2;
5261 needed = pitch * height;
5263 if(!buf || !buflen) break;
5265 switch(ft_face->glyph->format) {
5266 case ft_glyph_format_bitmap:
5268 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5269 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5270 INT h = ft_face->glyph->bitmap.rows;
5271 while(h--) {
5272 memcpy(dst, src, w);
5273 src += ft_face->glyph->bitmap.pitch;
5274 dst += pitch;
5276 break;
5279 case ft_glyph_format_outline:
5280 ft_bitmap.width = width;
5281 ft_bitmap.rows = height;
5282 ft_bitmap.pitch = pitch;
5283 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5284 ft_bitmap.buffer = buf;
5286 if(needsTransform)
5287 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5289 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5291 /* Note: FreeType will only set 'black' bits for us. */
5292 memset(buf, 0, needed);
5293 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5294 break;
5296 default:
5297 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5298 return GDI_ERROR;
5300 break;
5302 case GGO_GRAY2_BITMAP:
5303 case GGO_GRAY4_BITMAP:
5304 case GGO_GRAY8_BITMAP:
5305 case WINE_GGO_GRAY16_BITMAP:
5307 unsigned int mult, row, col;
5308 BYTE *start, *ptr;
5310 width = lpgm->gmBlackBoxX;
5311 height = lpgm->gmBlackBoxY;
5312 pitch = (width + 3) / 4 * 4;
5313 needed = pitch * height;
5315 if(!buf || !buflen) break;
5317 switch(ft_face->glyph->format) {
5318 case ft_glyph_format_bitmap:
5320 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5321 INT h = ft_face->glyph->bitmap.rows;
5322 INT x;
5323 memset( buf, 0, needed );
5324 while(h--) {
5325 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5326 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5327 src += ft_face->glyph->bitmap.pitch;
5328 dst += pitch;
5330 return needed;
5332 case ft_glyph_format_outline:
5334 ft_bitmap.width = width;
5335 ft_bitmap.rows = height;
5336 ft_bitmap.pitch = pitch;
5337 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5338 ft_bitmap.buffer = buf;
5340 if(needsTransform)
5341 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5343 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5345 memset(ft_bitmap.buffer, 0, buflen);
5347 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5349 if(format == GGO_GRAY2_BITMAP)
5350 mult = 4;
5351 else if(format == GGO_GRAY4_BITMAP)
5352 mult = 16;
5353 else if(format == GGO_GRAY8_BITMAP)
5354 mult = 64;
5355 else /* format == WINE_GGO_GRAY16_BITMAP */
5356 return needed;
5357 break;
5359 default:
5360 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5361 return GDI_ERROR;
5364 start = buf;
5365 for(row = 0; row < height; row++) {
5366 ptr = start;
5367 for(col = 0; col < width; col++, ptr++) {
5368 *ptr = (((int)*ptr) * mult + 128) / 256;
5370 start += pitch;
5372 break;
5375 case WINE_GGO_HRGB_BITMAP:
5376 case WINE_GGO_HBGR_BITMAP:
5377 case WINE_GGO_VRGB_BITMAP:
5378 case WINE_GGO_VBGR_BITMAP:
5379 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5381 switch (ft_face->glyph->format)
5383 case FT_GLYPH_FORMAT_BITMAP:
5385 BYTE *src, *dst;
5386 INT src_pitch, x;
5388 width = lpgm->gmBlackBoxX;
5389 height = lpgm->gmBlackBoxY;
5390 pitch = width * 4;
5391 needed = pitch * height;
5393 if (!buf || !buflen) break;
5395 memset(buf, 0, buflen);
5396 dst = buf;
5397 src = ft_face->glyph->bitmap.buffer;
5398 src_pitch = ft_face->glyph->bitmap.pitch;
5400 height = min( height, ft_face->glyph->bitmap.rows );
5401 while ( height-- )
5403 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5405 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5406 ((unsigned int *)dst)[x] = ~0u;
5408 src += src_pitch;
5409 dst += pitch;
5412 break;
5415 case FT_GLYPH_FORMAT_OUTLINE:
5417 unsigned int *dst;
5418 BYTE *src;
5419 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5420 INT x_shift, y_shift;
5421 BOOL rgb;
5422 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5423 FT_Render_Mode render_mode =
5424 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5425 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5427 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5429 if ( render_mode == FT_RENDER_MODE_LCD)
5431 lpgm->gmBlackBoxX += 2;
5432 lpgm->gmptGlyphOrigin.x -= 1;
5434 else
5436 lpgm->gmBlackBoxY += 2;
5437 lpgm->gmptGlyphOrigin.y += 1;
5441 width = lpgm->gmBlackBoxX;
5442 height = lpgm->gmBlackBoxY;
5443 pitch = width * 4;
5444 needed = pitch * height;
5446 if (!buf || !buflen) break;
5448 memset(buf, 0, buflen);
5449 dst = buf;
5450 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5452 if ( needsTransform )
5453 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5455 if ( pFT_Library_SetLcdFilter )
5456 pFT_Library_SetLcdFilter( library, lcdfilter );
5457 pFT_Render_Glyph (ft_face->glyph, render_mode);
5459 src = ft_face->glyph->bitmap.buffer;
5460 src_pitch = ft_face->glyph->bitmap.pitch;
5461 src_width = ft_face->glyph->bitmap.width;
5462 src_height = ft_face->glyph->bitmap.rows;
5464 if ( render_mode == FT_RENDER_MODE_LCD)
5466 rgb_interval = 1;
5467 hmul = 3;
5468 vmul = 1;
5470 else
5472 rgb_interval = src_pitch;
5473 hmul = 1;
5474 vmul = 3;
5477 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5478 if ( x_shift < 0 ) x_shift = 0;
5479 if ( x_shift + (src_width / hmul) > width )
5480 x_shift = width - (src_width / hmul);
5482 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5483 if ( y_shift < 0 ) y_shift = 0;
5484 if ( y_shift + (src_height / vmul) > height )
5485 y_shift = height - (src_height / vmul);
5487 dst += x_shift + y_shift * ( pitch / 4 );
5488 while ( src_height )
5490 for ( x = 0; x < src_width / hmul; x++ )
5492 if ( rgb )
5494 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5495 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5496 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5497 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5499 else
5501 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5502 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5503 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5504 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5507 src += src_pitch * vmul;
5508 dst += pitch / 4;
5509 src_height -= vmul;
5512 break;
5515 default:
5516 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5517 return GDI_ERROR;
5520 break;
5522 #else
5523 return GDI_ERROR;
5524 #endif
5526 case GGO_NATIVE:
5528 int contour, point = 0, first_pt;
5529 FT_Outline *outline = &ft_face->glyph->outline;
5530 TTPOLYGONHEADER *pph;
5531 TTPOLYCURVE *ppc;
5532 DWORD pph_start, cpfx, type;
5534 if(buflen == 0) buf = NULL;
5536 if (needsTransform && buf) {
5537 pFT_Outline_Transform(outline, &transMat);
5540 for(contour = 0; contour < outline->n_contours; contour++) {
5541 pph_start = needed;
5542 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5543 first_pt = point;
5544 if(buf) {
5545 pph->dwType = TT_POLYGON_TYPE;
5546 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5548 needed += sizeof(*pph);
5549 point++;
5550 while(point <= outline->contours[contour]) {
5551 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5552 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5553 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5554 cpfx = 0;
5555 do {
5556 if(buf)
5557 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5558 cpfx++;
5559 point++;
5560 } while(point <= outline->contours[contour] &&
5561 (outline->tags[point] & FT_Curve_Tag_On) ==
5562 (outline->tags[point-1] & FT_Curve_Tag_On));
5563 /* At the end of a contour Windows adds the start point, but
5564 only for Beziers */
5565 if(point > outline->contours[contour] &&
5566 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5567 if(buf)
5568 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5569 cpfx++;
5570 } else if(point <= outline->contours[contour] &&
5571 outline->tags[point] & FT_Curve_Tag_On) {
5572 /* add closing pt for bezier */
5573 if(buf)
5574 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5575 cpfx++;
5576 point++;
5578 if(buf) {
5579 ppc->wType = type;
5580 ppc->cpfx = cpfx;
5582 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5584 if(buf)
5585 pph->cb = needed - pph_start;
5587 break;
5589 case GGO_BEZIER:
5591 /* Convert the quadratic Beziers to cubic Beziers.
5592 The parametric eqn for a cubic Bezier is, from PLRM:
5593 r(t) = at^3 + bt^2 + ct + r0
5594 with the control points:
5595 r1 = r0 + c/3
5596 r2 = r1 + (c + b)/3
5597 r3 = r0 + c + b + a
5599 A quadratic Bezier has the form:
5600 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5602 So equating powers of t leads to:
5603 r1 = 2/3 p1 + 1/3 p0
5604 r2 = 2/3 p1 + 1/3 p2
5605 and of course r0 = p0, r3 = p2
5608 int contour, point = 0, first_pt;
5609 FT_Outline *outline = &ft_face->glyph->outline;
5610 TTPOLYGONHEADER *pph;
5611 TTPOLYCURVE *ppc;
5612 DWORD pph_start, cpfx, type;
5613 FT_Vector cubic_control[4];
5614 if(buflen == 0) buf = NULL;
5616 if (needsTransform && buf) {
5617 pFT_Outline_Transform(outline, &transMat);
5620 for(contour = 0; contour < outline->n_contours; contour++) {
5621 pph_start = needed;
5622 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5623 first_pt = point;
5624 if(buf) {
5625 pph->dwType = TT_POLYGON_TYPE;
5626 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5628 needed += sizeof(*pph);
5629 point++;
5630 while(point <= outline->contours[contour]) {
5631 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5632 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5633 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5634 cpfx = 0;
5635 do {
5636 if(type == TT_PRIM_LINE) {
5637 if(buf)
5638 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5639 cpfx++;
5640 point++;
5641 } else {
5642 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5643 so cpfx = 3n */
5645 /* FIXME: Possible optimization in endpoint calculation
5646 if there are two consecutive curves */
5647 cubic_control[0] = outline->points[point-1];
5648 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5649 cubic_control[0].x += outline->points[point].x + 1;
5650 cubic_control[0].y += outline->points[point].y + 1;
5651 cubic_control[0].x >>= 1;
5652 cubic_control[0].y >>= 1;
5654 if(point+1 > outline->contours[contour])
5655 cubic_control[3] = outline->points[first_pt];
5656 else {
5657 cubic_control[3] = outline->points[point+1];
5658 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5659 cubic_control[3].x += outline->points[point].x + 1;
5660 cubic_control[3].y += outline->points[point].y + 1;
5661 cubic_control[3].x >>= 1;
5662 cubic_control[3].y >>= 1;
5665 /* r1 = 1/3 p0 + 2/3 p1
5666 r2 = 1/3 p2 + 2/3 p1 */
5667 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5668 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5669 cubic_control[2] = cubic_control[1];
5670 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5671 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5672 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5673 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5674 if(buf) {
5675 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5676 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5677 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5679 cpfx += 3;
5680 point++;
5682 } while(point <= outline->contours[contour] &&
5683 (outline->tags[point] & FT_Curve_Tag_On) ==
5684 (outline->tags[point-1] & FT_Curve_Tag_On));
5685 /* At the end of a contour Windows adds the start point,
5686 but only for Beziers and we've already done that.
5688 if(point <= outline->contours[contour] &&
5689 outline->tags[point] & FT_Curve_Tag_On) {
5690 /* This is the closing pt of a bezier, but we've already
5691 added it, so just inc point and carry on */
5692 point++;
5694 if(buf) {
5695 ppc->wType = type;
5696 ppc->cpfx = cpfx;
5698 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5700 if(buf)
5701 pph->cb = needed - pph_start;
5703 break;
5706 default:
5707 FIXME("Unsupported format %d\n", format);
5708 return GDI_ERROR;
5710 return needed;
5713 static BOOL get_bitmap_text_metrics(GdiFont *font)
5715 FT_Face ft_face = font->ft_face;
5716 FT_WinFNT_HeaderRec winfnt_header;
5717 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5718 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5719 font->potm->otmSize = size;
5721 #define TM font->potm->otmTextMetrics
5722 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5724 TM.tmHeight = winfnt_header.pixel_height;
5725 TM.tmAscent = winfnt_header.ascent;
5726 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5727 TM.tmInternalLeading = winfnt_header.internal_leading;
5728 TM.tmExternalLeading = winfnt_header.external_leading;
5729 TM.tmAveCharWidth = winfnt_header.avg_width;
5730 TM.tmMaxCharWidth = winfnt_header.max_width;
5731 TM.tmWeight = winfnt_header.weight;
5732 TM.tmOverhang = 0;
5733 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5734 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5735 TM.tmFirstChar = winfnt_header.first_char;
5736 TM.tmLastChar = winfnt_header.last_char;
5737 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5738 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5739 TM.tmItalic = winfnt_header.italic;
5740 TM.tmUnderlined = font->underline;
5741 TM.tmStruckOut = font->strikeout;
5742 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5743 TM.tmCharSet = winfnt_header.charset;
5745 else
5747 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5748 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5749 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5750 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5751 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5752 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5753 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5754 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5755 TM.tmOverhang = 0;
5756 TM.tmDigitizedAspectX = 96; /* FIXME */
5757 TM.tmDigitizedAspectY = 96; /* FIXME */
5758 TM.tmFirstChar = 1;
5759 TM.tmLastChar = 255;
5760 TM.tmDefaultChar = 32;
5761 TM.tmBreakChar = 32;
5762 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5763 TM.tmUnderlined = font->underline;
5764 TM.tmStruckOut = font->strikeout;
5765 /* NB inverted meaning of TMPF_FIXED_PITCH */
5766 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5767 TM.tmCharSet = font->charset;
5769 #undef TM
5771 return TRUE;
5775 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5777 double scale_x, scale_y;
5779 if (font->aveWidth)
5781 scale_x = (double)font->aveWidth;
5782 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5784 else
5785 scale_x = font->scale_y;
5787 scale_x *= fabs(font->font_desc.matrix.eM11);
5788 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5790 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5791 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5793 SCALE_Y(ptm->tmHeight);
5794 SCALE_Y(ptm->tmAscent);
5795 SCALE_Y(ptm->tmDescent);
5796 SCALE_Y(ptm->tmInternalLeading);
5797 SCALE_Y(ptm->tmExternalLeading);
5798 SCALE_Y(ptm->tmOverhang);
5800 SCALE_X(ptm->tmAveCharWidth);
5801 SCALE_X(ptm->tmMaxCharWidth);
5803 #undef SCALE_X
5804 #undef SCALE_Y
5807 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5809 double scale_x, scale_y;
5811 if (font->aveWidth)
5813 scale_x = (double)font->aveWidth;
5814 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5816 else
5817 scale_x = font->scale_y;
5819 scale_x *= fabs(font->font_desc.matrix.eM11);
5820 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5822 scale_font_metrics(font, &potm->otmTextMetrics);
5824 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5825 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5827 SCALE_Y(potm->otmAscent);
5828 SCALE_Y(potm->otmDescent);
5829 SCALE_Y(potm->otmLineGap);
5830 SCALE_Y(potm->otmsCapEmHeight);
5831 SCALE_Y(potm->otmsXHeight);
5832 SCALE_Y(potm->otmrcFontBox.top);
5833 SCALE_Y(potm->otmrcFontBox.bottom);
5834 SCALE_X(potm->otmrcFontBox.left);
5835 SCALE_X(potm->otmrcFontBox.right);
5836 SCALE_Y(potm->otmMacAscent);
5837 SCALE_Y(potm->otmMacDescent);
5838 SCALE_Y(potm->otmMacLineGap);
5839 SCALE_X(potm->otmptSubscriptSize.x);
5840 SCALE_Y(potm->otmptSubscriptSize.y);
5841 SCALE_X(potm->otmptSubscriptOffset.x);
5842 SCALE_Y(potm->otmptSubscriptOffset.y);
5843 SCALE_X(potm->otmptSuperscriptSize.x);
5844 SCALE_Y(potm->otmptSuperscriptSize.y);
5845 SCALE_X(potm->otmptSuperscriptOffset.x);
5846 SCALE_Y(potm->otmptSuperscriptOffset.y);
5847 SCALE_Y(potm->otmsStrikeoutSize);
5848 SCALE_Y(potm->otmsStrikeoutPosition);
5849 SCALE_Y(potm->otmsUnderscoreSize);
5850 SCALE_Y(potm->otmsUnderscorePosition);
5852 #undef SCALE_X
5853 #undef SCALE_Y
5856 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5858 if(!font->potm)
5860 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5862 /* Make sure that the font has sane width/height ratio */
5863 if (font->aveWidth)
5865 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5867 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5868 font->aveWidth = 0;
5872 *ptm = font->potm->otmTextMetrics;
5873 scale_font_metrics(font, ptm);
5874 return TRUE;
5877 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5879 int i;
5881 for(i = 0; i < ft_face->num_charmaps; i++)
5883 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5884 return TRUE;
5886 return FALSE;
5889 static BOOL get_outline_text_metrics(GdiFont *font)
5891 BOOL ret = FALSE;
5892 FT_Face ft_face = font->ft_face;
5893 UINT needed, lenfam, lensty;
5894 TT_OS2 *pOS2;
5895 TT_HoriHeader *pHori;
5896 TT_Postscript *pPost;
5897 FT_Fixed x_scale, y_scale;
5898 WCHAR *family_nameW, *style_nameW;
5899 static const WCHAR spaceW[] = {' ', '\0'};
5900 char *cp;
5901 INT ascent, descent;
5903 TRACE("font=%p\n", font);
5905 if(!FT_IS_SCALABLE(ft_face))
5906 return FALSE;
5908 needed = sizeof(*font->potm);
5910 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5911 family_nameW = strdupW(font->name);
5913 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5914 * sizeof(WCHAR);
5915 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5916 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5917 style_nameW, lensty/sizeof(WCHAR));
5919 /* These names should be read from the TT name table */
5921 /* length of otmpFamilyName */
5922 needed += lenfam;
5924 /* length of otmpFaceName */
5925 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5926 needed += lenfam; /* just the family name */
5927 } else {
5928 needed += lenfam + lensty; /* family + " " + style */
5931 /* length of otmpStyleName */
5932 needed += lensty;
5934 /* length of otmpFullName */
5935 needed += lenfam + lensty;
5938 x_scale = ft_face->size->metrics.x_scale;
5939 y_scale = ft_face->size->metrics.y_scale;
5941 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5942 if(!pOS2) {
5943 FIXME("Can't find OS/2 table - not TT font?\n");
5944 goto end;
5947 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5948 if(!pHori) {
5949 FIXME("Can't find HHEA table - not TT font?\n");
5950 goto end;
5953 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5955 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",
5956 pOS2->usWinAscent, pOS2->usWinDescent,
5957 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5958 ft_face->ascender, ft_face->descender, ft_face->height,
5959 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5960 ft_face->bbox.yMax, ft_face->bbox.yMin);
5962 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5963 font->potm->otmSize = needed;
5965 #define TM font->potm->otmTextMetrics
5967 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5968 ascent = pHori->Ascender;
5969 descent = -pHori->Descender;
5970 } else {
5971 ascent = pOS2->usWinAscent;
5972 descent = pOS2->usWinDescent;
5975 if(font->yMax) {
5976 TM.tmAscent = font->yMax;
5977 TM.tmDescent = -font->yMin;
5978 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5979 } else {
5980 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5981 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5982 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5983 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5986 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5988 /* MSDN says:
5989 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5991 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5992 ((ascent + descent) -
5993 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5995 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5996 if (TM.tmAveCharWidth == 0) {
5997 TM.tmAveCharWidth = 1;
5999 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6000 TM.tmWeight = FW_REGULAR;
6001 if (font->fake_bold)
6002 TM.tmWeight = FW_BOLD;
6003 else
6005 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6007 if (pOS2->usWeightClass > FW_MEDIUM)
6008 TM.tmWeight = pOS2->usWeightClass;
6010 else if (pOS2->usWeightClass <= FW_MEDIUM)
6011 TM.tmWeight = pOS2->usWeightClass;
6013 TM.tmOverhang = 0;
6014 TM.tmDigitizedAspectX = 300;
6015 TM.tmDigitizedAspectY = 300;
6016 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6017 * symbol range to 0 - f0ff
6020 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6022 TM.tmFirstChar = 0;
6023 switch(GetACP())
6025 case 1257: /* Baltic */
6026 TM.tmLastChar = 0xf8fd;
6027 break;
6028 default:
6029 TM.tmLastChar = 0xf0ff;
6031 TM.tmBreakChar = 0x20;
6032 TM.tmDefaultChar = 0x1f;
6034 else
6036 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6037 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6039 if(pOS2->usFirstCharIndex <= 1)
6040 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6041 else if (pOS2->usFirstCharIndex > 0xff)
6042 TM.tmBreakChar = 0x20;
6043 else
6044 TM.tmBreakChar = pOS2->usFirstCharIndex;
6045 TM.tmDefaultChar = TM.tmBreakChar - 1;
6047 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6048 TM.tmUnderlined = font->underline;
6049 TM.tmStruckOut = font->strikeout;
6051 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6052 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6053 (pOS2->version == 0xFFFFU ||
6054 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6055 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6056 else
6057 TM.tmPitchAndFamily = 0;
6059 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6061 case PAN_FAMILY_SCRIPT:
6062 TM.tmPitchAndFamily |= FF_SCRIPT;
6063 break;
6065 case PAN_FAMILY_DECORATIVE:
6066 TM.tmPitchAndFamily |= FF_DECORATIVE;
6067 break;
6069 case PAN_ANY:
6070 case PAN_NO_FIT:
6071 case PAN_FAMILY_TEXT_DISPLAY:
6072 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6073 /* which is clearly not what the panose spec says. */
6074 default:
6075 if(TM.tmPitchAndFamily == 0 || /* fixed */
6076 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6077 TM.tmPitchAndFamily = FF_MODERN;
6078 else
6080 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6082 case PAN_ANY:
6083 case PAN_NO_FIT:
6084 default:
6085 TM.tmPitchAndFamily |= FF_DONTCARE;
6086 break;
6088 case PAN_SERIF_COVE:
6089 case PAN_SERIF_OBTUSE_COVE:
6090 case PAN_SERIF_SQUARE_COVE:
6091 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6092 case PAN_SERIF_SQUARE:
6093 case PAN_SERIF_THIN:
6094 case PAN_SERIF_BONE:
6095 case PAN_SERIF_EXAGGERATED:
6096 case PAN_SERIF_TRIANGLE:
6097 TM.tmPitchAndFamily |= FF_ROMAN;
6098 break;
6100 case PAN_SERIF_NORMAL_SANS:
6101 case PAN_SERIF_OBTUSE_SANS:
6102 case PAN_SERIF_PERP_SANS:
6103 case PAN_SERIF_FLARED:
6104 case PAN_SERIF_ROUNDED:
6105 TM.tmPitchAndFamily |= FF_SWISS;
6106 break;
6109 break;
6112 if(FT_IS_SCALABLE(ft_face))
6113 TM.tmPitchAndFamily |= TMPF_VECTOR;
6115 if(FT_IS_SFNT(ft_face))
6117 if (font->ntmFlags & NTM_PS_OPENTYPE)
6118 TM.tmPitchAndFamily |= TMPF_DEVICE;
6119 else
6120 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6123 TM.tmCharSet = font->charset;
6125 font->potm->otmFiller = 0;
6126 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6127 font->potm->otmfsSelection = pOS2->fsSelection;
6128 font->potm->otmfsType = pOS2->fsType;
6129 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6130 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6131 font->potm->otmItalicAngle = 0; /* POST table */
6132 font->potm->otmEMSquare = ft_face->units_per_EM;
6133 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6134 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6135 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6136 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6137 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6138 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6139 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6140 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6141 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6142 font->potm->otmMacAscent = TM.tmAscent;
6143 font->potm->otmMacDescent = -TM.tmDescent;
6144 font->potm->otmMacLineGap = font->potm->otmLineGap;
6145 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6146 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6147 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6148 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6149 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6150 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6151 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6152 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6153 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6154 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6155 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6156 if(!pPost) {
6157 font->potm->otmsUnderscoreSize = 0;
6158 font->potm->otmsUnderscorePosition = 0;
6159 } else {
6160 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6161 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6163 #undef TM
6165 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6166 cp = (char*)font->potm + sizeof(*font->potm);
6167 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6168 strcpyW((WCHAR*)cp, family_nameW);
6169 cp += lenfam;
6170 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6171 strcpyW((WCHAR*)cp, style_nameW);
6172 cp += lensty;
6173 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6174 strcpyW((WCHAR*)cp, family_nameW);
6175 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6176 strcatW((WCHAR*)cp, spaceW);
6177 strcatW((WCHAR*)cp, style_nameW);
6178 cp += lenfam + lensty;
6179 } else
6180 cp += lenfam;
6181 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6182 strcpyW((WCHAR*)cp, family_nameW);
6183 strcatW((WCHAR*)cp, spaceW);
6184 strcatW((WCHAR*)cp, style_nameW);
6185 ret = TRUE;
6187 end:
6188 HeapFree(GetProcessHeap(), 0, style_nameW);
6189 HeapFree(GetProcessHeap(), 0, family_nameW);
6190 return ret;
6193 /*************************************************************
6194 * WineEngGetGlyphOutline
6197 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6198 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6199 const MAT2* lpmat)
6201 DWORD ret;
6203 GDI_CheckNotLock();
6204 EnterCriticalSection( &freetype_cs );
6205 ret = get_glyph_outline( font, glyph, format, lpgm, buflen, buf, lpmat );
6206 LeaveCriticalSection( &freetype_cs );
6207 return ret;
6210 /*************************************************************
6211 * freetype_GetTextMetrics
6213 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6215 struct freetype_physdev *physdev = get_freetype_dev( dev );
6216 BOOL ret;
6218 if (!physdev->font)
6220 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6221 return dev->funcs->pGetTextMetrics( dev, metrics );
6224 GDI_CheckNotLock();
6225 EnterCriticalSection( &freetype_cs );
6226 ret = get_text_metrics( physdev->font, metrics );
6227 LeaveCriticalSection( &freetype_cs );
6228 return ret;
6231 /*************************************************************
6232 * WineEngGetOutlineTextMetrics
6235 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6236 OUTLINETEXTMETRICW *potm)
6238 UINT ret = 0;
6240 TRACE("font=%p\n", font);
6242 if (!FT_IS_SCALABLE( font->ft_face )) return 0;
6244 GDI_CheckNotLock();
6245 EnterCriticalSection( &freetype_cs );
6247 if (font->potm || get_outline_text_metrics( font ))
6249 if(cbSize >= font->potm->otmSize)
6251 memcpy(potm, font->potm, font->potm->otmSize);
6252 scale_outline_font_metrics(font, potm);
6254 ret = font->potm->otmSize;
6256 LeaveCriticalSection( &freetype_cs );
6257 return ret;
6260 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6262 HFONTLIST *hfontlist;
6263 child->font = alloc_font();
6264 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6265 if(!child->font->ft_face)
6267 free_font(child->font);
6268 child->font = NULL;
6269 return FALSE;
6272 child->font->font_desc = font->font_desc;
6273 child->font->ntmFlags = child->face->ntmFlags;
6274 child->font->orientation = font->orientation;
6275 child->font->scale_y = font->scale_y;
6276 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6277 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6278 child->font->name = strdupW(child->face->family->FamilyName);
6279 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6280 child->font->base_font = font;
6281 list_add_head(&child_font_list, &child->font->entry);
6282 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6283 return TRUE;
6286 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6288 FT_UInt g;
6289 CHILD_FONT *child_font;
6291 if(font->base_font)
6292 font = font->base_font;
6294 *linked_font = font;
6296 if((*glyph = get_glyph_index(font, c)))
6297 return TRUE;
6299 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6301 if(!child_font->font)
6302 if(!load_child_font(font, child_font))
6303 continue;
6305 if(!child_font->font->ft_face)
6306 continue;
6307 g = get_glyph_index(child_font->font, c);
6308 if(g)
6310 *glyph = g;
6311 *linked_font = child_font->font;
6312 return TRUE;
6315 return FALSE;
6318 /*************************************************************
6319 * freetype_GetCharWidth
6321 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6323 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6324 UINT c;
6325 GLYPHMETRICS gm;
6326 FT_UInt glyph_index;
6327 GdiFont *linked_font;
6328 struct freetype_physdev *physdev = get_freetype_dev( dev );
6330 if (!physdev->font)
6332 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6333 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6336 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6338 GDI_CheckNotLock();
6339 EnterCriticalSection( &freetype_cs );
6340 for(c = firstChar; c <= lastChar; c++) {
6341 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6342 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6343 &gm, 0, NULL, &identity);
6344 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6346 LeaveCriticalSection( &freetype_cs );
6347 return TRUE;
6350 /*************************************************************
6351 * freetype_GetCharABCWidths
6353 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6355 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6356 UINT c;
6357 GLYPHMETRICS gm;
6358 FT_UInt glyph_index;
6359 GdiFont *linked_font;
6360 struct freetype_physdev *physdev = get_freetype_dev( dev );
6362 if (!physdev->font)
6364 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6365 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6368 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6370 if(!FT_IS_SCALABLE(physdev->font->ft_face))
6371 return FALSE;
6373 GDI_CheckNotLock();
6374 EnterCriticalSection( &freetype_cs );
6376 for(c = firstChar; c <= lastChar; c++) {
6377 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6378 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6379 &gm, 0, NULL, &identity);
6380 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6381 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6382 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6383 FONT_GM(linked_font,glyph_index)->bbx;
6385 LeaveCriticalSection( &freetype_cs );
6386 return TRUE;
6389 /*************************************************************
6390 * WineEngGetCharABCWidthsFloat
6393 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6395 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6396 UINT c;
6397 GLYPHMETRICS gm;
6398 FT_UInt glyph_index;
6399 GdiFont *linked_font;
6401 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6403 GDI_CheckNotLock();
6404 EnterCriticalSection( &freetype_cs );
6406 for (c = first; c <= last; c++)
6408 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6409 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6410 &gm, 0, NULL, &identity);
6411 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6412 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6413 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6414 FONT_GM(linked_font, glyph_index)->lsb -
6415 FONT_GM(linked_font, glyph_index)->bbx;
6417 LeaveCriticalSection( &freetype_cs );
6418 return TRUE;
6421 /*************************************************************
6422 * freetype_GetCharABCWidthsI
6424 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6426 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6427 UINT c;
6428 GLYPHMETRICS gm;
6429 FT_UInt glyph_index;
6430 GdiFont *linked_font;
6431 struct freetype_physdev *physdev = get_freetype_dev( dev );
6433 if (!physdev->font)
6435 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6436 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6439 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6440 return FALSE;
6442 GDI_CheckNotLock();
6443 EnterCriticalSection( &freetype_cs );
6445 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6446 if (!pgi)
6447 for(c = firstChar; c < firstChar+count; c++) {
6448 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6449 &gm, 0, NULL, &identity);
6450 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6451 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6452 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6453 - FONT_GM(linked_font,c)->bbx;
6455 else
6456 for(c = 0; c < count; c++) {
6457 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6458 &gm, 0, NULL, &identity);
6459 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6460 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6461 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6462 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6465 LeaveCriticalSection( &freetype_cs );
6466 return TRUE;
6469 /*************************************************************
6470 * freetype_GetTextExtentExPoint
6472 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6473 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6475 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6476 INT idx;
6477 INT nfit = 0, ext;
6478 GLYPHMETRICS gm;
6479 TEXTMETRICW tm;
6480 FT_UInt glyph_index;
6481 GdiFont *linked_font;
6482 struct freetype_physdev *physdev = get_freetype_dev( dev );
6484 if (!physdev->font)
6486 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6487 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6490 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6492 GDI_CheckNotLock();
6493 EnterCriticalSection( &freetype_cs );
6495 size->cx = 0;
6496 get_text_metrics( physdev->font, &tm );
6497 size->cy = tm.tmHeight;
6499 for(idx = 0; idx < count; idx++) {
6500 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6501 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6502 &gm, 0, NULL, &identity);
6503 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6504 ext = size->cx;
6505 if (! pnfit || ext <= max_ext) {
6506 ++nfit;
6507 if (dxs)
6508 dxs[idx] = ext;
6512 if (pnfit)
6513 *pnfit = nfit;
6515 LeaveCriticalSection( &freetype_cs );
6516 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6517 return TRUE;
6520 /*************************************************************
6521 * WineEngGetTextExtentExPointI
6524 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6525 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6527 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6528 INT idx;
6529 INT nfit = 0, ext;
6530 GLYPHMETRICS gm;
6531 TEXTMETRICW tm;
6533 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6535 GDI_CheckNotLock();
6536 EnterCriticalSection( &freetype_cs );
6538 size->cx = 0;
6539 get_text_metrics(font, &tm);
6540 size->cy = tm.tmHeight;
6542 for(idx = 0; idx < count; idx++) {
6543 get_glyph_outline(font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6544 size->cx += FONT_GM(font,indices[idx])->adv;
6545 ext = size->cx;
6546 if (! pnfit || ext <= max_ext) {
6547 ++nfit;
6548 if (dxs)
6549 dxs[idx] = ext;
6553 if (pnfit)
6554 *pnfit = nfit;
6556 LeaveCriticalSection( &freetype_cs );
6557 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6558 return TRUE;
6561 /*************************************************************
6562 * WineEngGetFontData
6565 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6566 DWORD cbData)
6568 FT_Face ft_face = font->ft_face;
6569 FT_ULong len;
6570 FT_Error err;
6572 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6573 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6574 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6576 if(!FT_IS_SFNT(ft_face))
6577 return GDI_ERROR;
6579 if(!buf)
6580 len = 0;
6581 else
6582 len = cbData;
6584 if(table) { /* MS tags differ in endianness from FT ones */
6585 table = table >> 24 | table << 24 |
6586 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6589 /* make sure value of len is the value freetype says it needs */
6590 if(buf && len)
6592 FT_ULong needed = 0;
6593 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
6594 if( !err && needed < len) len = needed;
6596 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
6598 if(err) {
6599 TRACE("Can't find table %c%c%c%c\n",
6600 /* bytes were reversed */
6601 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6602 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6603 return GDI_ERROR;
6605 return len;
6608 /*************************************************************
6609 * WineEngGetTextFace
6612 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6614 INT n = strlenW(font->name) + 1;
6615 if(str) {
6616 lstrcpynW(str, font->name, count);
6617 return min(count, n);
6618 } else
6619 return n;
6622 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6624 if (fs) *fs = font->fs;
6625 return font->charset;
6628 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6630 GdiFont *font = dc->gdiFont, *linked_font;
6631 struct list *first_hfont;
6632 BOOL ret;
6634 GDI_CheckNotLock();
6635 EnterCriticalSection( &freetype_cs );
6636 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6637 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6638 if(font == linked_font)
6639 *new_hfont = dc->hFont;
6640 else
6642 first_hfont = list_head(&linked_font->hfontlist);
6643 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6645 LeaveCriticalSection( &freetype_cs );
6646 return ret;
6649 /* Retrieve a list of supported Unicode ranges for a given font.
6650 * Can be called with NULL gs to calculate the buffer size. Returns
6651 * the number of ranges found.
6653 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6655 DWORD num_ranges = 0;
6657 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6659 FT_UInt glyph_code;
6660 FT_ULong char_code, char_code_prev;
6662 glyph_code = 0;
6663 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6665 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6666 face->num_glyphs, glyph_code, char_code);
6668 if (!glyph_code) return 0;
6670 if (gs)
6672 gs->ranges[0].wcLow = (USHORT)char_code;
6673 gs->ranges[0].cGlyphs = 0;
6674 gs->cGlyphsSupported = 0;
6677 num_ranges = 1;
6678 while (glyph_code)
6680 if (char_code < char_code_prev)
6682 ERR("expected increasing char code from FT_Get_Next_Char\n");
6683 return 0;
6685 if (char_code - char_code_prev > 1)
6687 num_ranges++;
6688 if (gs)
6690 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6691 gs->ranges[num_ranges - 1].cGlyphs = 1;
6692 gs->cGlyphsSupported++;
6695 else if (gs)
6697 gs->ranges[num_ranges - 1].cGlyphs++;
6698 gs->cGlyphsSupported++;
6700 char_code_prev = char_code;
6701 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6704 else
6705 FIXME("encoding %u not supported\n", face->charmap->encoding);
6707 return num_ranges;
6710 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6712 DWORD size = 0;
6713 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6715 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6716 if (glyphset)
6718 glyphset->cbThis = size;
6719 glyphset->cRanges = num_ranges;
6720 glyphset->flAccel = 0;
6722 return size;
6725 /*************************************************************
6726 * FontIsLinked
6728 BOOL WineEngFontIsLinked(GdiFont *font)
6730 BOOL ret;
6731 GDI_CheckNotLock();
6732 EnterCriticalSection( &freetype_cs );
6733 ret = !list_empty(&font->child_fonts);
6734 LeaveCriticalSection( &freetype_cs );
6735 return ret;
6738 static BOOL is_hinting_enabled(void)
6740 /* Use the >= 2.2.0 function if available */
6741 if(pFT_Get_TrueType_Engine_Type)
6743 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6744 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6746 #ifdef FT_DRIVER_HAS_HINTER
6747 else
6749 FT_Module mod;
6751 /* otherwise if we've been compiled with < 2.2.0 headers
6752 use the internal macro */
6753 mod = pFT_Get_Module(library, "truetype");
6754 if(mod && FT_DRIVER_HAS_HINTER(mod))
6755 return TRUE;
6757 #endif
6759 return FALSE;
6762 static BOOL is_subpixel_rendering_enabled( void )
6764 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6765 return pFT_Library_SetLcdFilter &&
6766 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6767 #else
6768 return FALSE;
6769 #endif
6772 /*************************************************************************
6773 * GetRasterizerCaps (GDI32.@)
6775 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6777 static int hinting = -1;
6778 static int subpixel = -1;
6780 if(hinting == -1)
6782 hinting = is_hinting_enabled();
6783 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6786 if ( subpixel == -1 )
6788 subpixel = is_subpixel_rendering_enabled();
6789 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6792 lprs->nSize = sizeof(RASTERIZER_STATUS);
6793 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6794 if ( subpixel )
6795 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6796 lprs->nLanguageID = 0;
6797 return TRUE;
6800 /*************************************************************
6801 * WineEngRealizationInfo
6803 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6805 FIXME("(%p, %p): stub!\n", font, info);
6807 info->flags = 1;
6808 if(FT_IS_SCALABLE(font->ft_face))
6809 info->flags |= 2;
6811 info->cache_num = font->cache_num;
6812 info->unknown2 = -1;
6813 return TRUE;
6816 /*************************************************************************
6817 * Kerning support for TrueType fonts
6819 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6821 struct TT_kern_table
6823 USHORT version;
6824 USHORT nTables;
6827 struct TT_kern_subtable
6829 USHORT version;
6830 USHORT length;
6831 union
6833 USHORT word;
6834 struct
6836 USHORT horizontal : 1;
6837 USHORT minimum : 1;
6838 USHORT cross_stream: 1;
6839 USHORT override : 1;
6840 USHORT reserved1 : 4;
6841 USHORT format : 8;
6842 } bits;
6843 } coverage;
6846 struct TT_format0_kern_subtable
6848 USHORT nPairs;
6849 USHORT searchRange;
6850 USHORT entrySelector;
6851 USHORT rangeShift;
6854 struct TT_kern_pair
6856 USHORT left;
6857 USHORT right;
6858 short value;
6861 static DWORD parse_format0_kern_subtable(GdiFont *font,
6862 const struct TT_format0_kern_subtable *tt_f0_ks,
6863 const USHORT *glyph_to_char,
6864 KERNINGPAIR *kern_pair, DWORD cPairs)
6866 USHORT i, nPairs;
6867 const struct TT_kern_pair *tt_kern_pair;
6869 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6871 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6873 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6874 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6875 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6877 if (!kern_pair || !cPairs)
6878 return nPairs;
6880 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6882 nPairs = min(nPairs, cPairs);
6884 for (i = 0; i < nPairs; i++)
6886 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6887 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6888 /* this algorithm appears to better match what Windows does */
6889 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6890 if (kern_pair->iKernAmount < 0)
6892 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6893 kern_pair->iKernAmount -= font->ppem;
6895 else if (kern_pair->iKernAmount > 0)
6897 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6898 kern_pair->iKernAmount += font->ppem;
6900 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6902 TRACE("left %u right %u value %d\n",
6903 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6905 kern_pair++;
6907 TRACE("copied %u entries\n", nPairs);
6908 return nPairs;
6911 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6913 DWORD length;
6914 void *buf;
6915 const struct TT_kern_table *tt_kern_table;
6916 const struct TT_kern_subtable *tt_kern_subtable;
6917 USHORT i, nTables;
6918 USHORT *glyph_to_char;
6920 GDI_CheckNotLock();
6921 EnterCriticalSection( &freetype_cs );
6922 if (font->total_kern_pairs != (DWORD)-1)
6924 if (cPairs && kern_pair)
6926 cPairs = min(cPairs, font->total_kern_pairs);
6927 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6928 LeaveCriticalSection( &freetype_cs );
6929 return cPairs;
6931 LeaveCriticalSection( &freetype_cs );
6932 return font->total_kern_pairs;
6935 font->total_kern_pairs = 0;
6937 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6939 if (length == GDI_ERROR)
6941 TRACE("no kerning data in the font\n");
6942 LeaveCriticalSection( &freetype_cs );
6943 return 0;
6946 buf = HeapAlloc(GetProcessHeap(), 0, length);
6947 if (!buf)
6949 WARN("Out of memory\n");
6950 LeaveCriticalSection( &freetype_cs );
6951 return 0;
6954 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6956 /* build a glyph index to char code map */
6957 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6958 if (!glyph_to_char)
6960 WARN("Out of memory allocating a glyph index to char code map\n");
6961 HeapFree(GetProcessHeap(), 0, buf);
6962 LeaveCriticalSection( &freetype_cs );
6963 return 0;
6966 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
6968 FT_UInt glyph_code;
6969 FT_ULong char_code;
6971 glyph_code = 0;
6972 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6974 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6975 font->ft_face->num_glyphs, glyph_code, char_code);
6977 while (glyph_code)
6979 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6981 /* FIXME: This doesn't match what Windows does: it does some fancy
6982 * things with duplicate glyph index to char code mappings, while
6983 * we just avoid overriding existing entries.
6985 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6986 glyph_to_char[glyph_code] = (USHORT)char_code;
6988 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6991 else
6993 ULONG n;
6995 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6996 for (n = 0; n <= 65535; n++)
6997 glyph_to_char[n] = (USHORT)n;
7000 tt_kern_table = buf;
7001 nTables = GET_BE_WORD(tt_kern_table->nTables);
7002 TRACE("version %u, nTables %u\n",
7003 GET_BE_WORD(tt_kern_table->version), nTables);
7005 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7007 for (i = 0; i < nTables; i++)
7009 struct TT_kern_subtable tt_kern_subtable_copy;
7011 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7012 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7013 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7015 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7016 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7017 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7019 /* According to the TrueType specification this is the only format
7020 * that will be properly interpreted by Windows and OS/2
7022 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7024 DWORD new_chunk, old_total = font->total_kern_pairs;
7026 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7027 glyph_to_char, NULL, 0);
7028 font->total_kern_pairs += new_chunk;
7030 if (!font->kern_pairs)
7031 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7032 font->total_kern_pairs * sizeof(*font->kern_pairs));
7033 else
7034 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7035 font->total_kern_pairs * sizeof(*font->kern_pairs));
7037 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7038 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7040 else
7041 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7043 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7046 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7047 HeapFree(GetProcessHeap(), 0, buf);
7049 if (cPairs && kern_pair)
7051 cPairs = min(cPairs, font->total_kern_pairs);
7052 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7053 LeaveCriticalSection( &freetype_cs );
7054 return cPairs;
7056 LeaveCriticalSection( &freetype_cs );
7057 return font->total_kern_pairs;
7060 static const struct gdi_dc_funcs freetype_funcs =
7062 NULL, /* pAbortDoc */
7063 NULL, /* pAbortPath */
7064 NULL, /* pAlphaBlend */
7065 NULL, /* pAngleArc */
7066 NULL, /* pArc */
7067 NULL, /* pArcTo */
7068 NULL, /* pBeginPath */
7069 NULL, /* pBlendImage */
7070 NULL, /* pChoosePixelFormat */
7071 NULL, /* pChord */
7072 NULL, /* pCloseFigure */
7073 NULL, /* pCreateBitmap */
7074 NULL, /* pCreateCompatibleDC */
7075 freetype_CreateDC, /* pCreateDC */
7076 NULL, /* pCreateDIBSection */
7077 NULL, /* pDeleteBitmap */
7078 freetype_DeleteDC, /* pDeleteDC */
7079 NULL, /* pDeleteObject */
7080 NULL, /* pDescribePixelFormat */
7081 NULL, /* pDeviceCapabilities */
7082 NULL, /* pEllipse */
7083 NULL, /* pEndDoc */
7084 NULL, /* pEndPage */
7085 NULL, /* pEndPath */
7086 freetype_EnumFonts, /* pEnumFonts */
7087 NULL, /* pEnumICMProfiles */
7088 NULL, /* pExcludeClipRect */
7089 NULL, /* pExtDeviceMode */
7090 NULL, /* pExtEscape */
7091 NULL, /* pExtFloodFill */
7092 NULL, /* pExtSelectClipRgn */
7093 NULL, /* pExtTextOut */
7094 NULL, /* pFillPath */
7095 NULL, /* pFillRgn */
7096 NULL, /* pFlattenPath */
7097 NULL, /* pFontIsLinked */
7098 NULL, /* pFrameRgn */
7099 NULL, /* pGdiComment */
7100 NULL, /* pGdiRealizationInfo */
7101 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7102 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7103 freetype_GetCharWidth, /* pGetCharWidth */
7104 NULL, /* pGetDeviceCaps */
7105 NULL, /* pGetDeviceGammaRamp */
7106 NULL, /* pGetFontData */
7107 NULL, /* pGetFontUnicodeRanges */
7108 NULL, /* pGetGlyphIndices */
7109 NULL, /* pGetGlyphOutline */
7110 NULL, /* pGetICMProfile */
7111 NULL, /* pGetImage */
7112 NULL, /* pGetKerningPairs */
7113 NULL, /* pGetNearestColor */
7114 NULL, /* pGetOutlineTextMetrics */
7115 NULL, /* pGetPixel */
7116 NULL, /* pGetPixelFormat */
7117 NULL, /* pGetSystemPaletteEntries */
7118 NULL, /* pGetTextCharsetInfo */
7119 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7120 NULL, /* pGetTextExtentExPointI */
7121 NULL, /* pGetTextFace */
7122 freetype_GetTextMetrics, /* pGetTextMetrics */
7123 NULL, /* pIntersectClipRect */
7124 NULL, /* pInvertRgn */
7125 NULL, /* pLineTo */
7126 NULL, /* pModifyWorldTransform */
7127 NULL, /* pMoveTo */
7128 NULL, /* pOffsetClipRgn */
7129 NULL, /* pOffsetViewportOrg */
7130 NULL, /* pOffsetWindowOrg */
7131 NULL, /* pPaintRgn */
7132 NULL, /* pPatBlt */
7133 NULL, /* pPie */
7134 NULL, /* pPolyBezier */
7135 NULL, /* pPolyBezierTo */
7136 NULL, /* pPolyDraw */
7137 NULL, /* pPolyPolygon */
7138 NULL, /* pPolyPolyline */
7139 NULL, /* pPolygon */
7140 NULL, /* pPolyline */
7141 NULL, /* pPolylineTo */
7142 NULL, /* pPutImage */
7143 NULL, /* pRealizeDefaultPalette */
7144 NULL, /* pRealizePalette */
7145 NULL, /* pRectangle */
7146 NULL, /* pResetDC */
7147 NULL, /* pRestoreDC */
7148 NULL, /* pRoundRect */
7149 NULL, /* pSaveDC */
7150 NULL, /* pScaleViewportExt */
7151 NULL, /* pScaleWindowExt */
7152 NULL, /* pSelectBitmap */
7153 NULL, /* pSelectBrush */
7154 NULL, /* pSelectClipPath */
7155 freetype_SelectFont, /* pSelectFont */
7156 NULL, /* pSelectPalette */
7157 NULL, /* pSelectPen */
7158 NULL, /* pSetArcDirection */
7159 NULL, /* pSetBkColor */
7160 NULL, /* pSetBkMode */
7161 NULL, /* pSetDCBrushColor */
7162 NULL, /* pSetDCPenColor */
7163 NULL, /* pSetDIBColorTable */
7164 NULL, /* pSetDIBitsToDevice */
7165 NULL, /* pSetDeviceClipping */
7166 NULL, /* pSetDeviceGammaRamp */
7167 NULL, /* pSetLayout */
7168 NULL, /* pSetMapMode */
7169 NULL, /* pSetMapperFlags */
7170 NULL, /* pSetPixel */
7171 NULL, /* pSetPixelFormat */
7172 NULL, /* pSetPolyFillMode */
7173 NULL, /* pSetROP2 */
7174 NULL, /* pSetRelAbs */
7175 NULL, /* pSetStretchBltMode */
7176 NULL, /* pSetTextAlign */
7177 NULL, /* pSetTextCharacterExtra */
7178 NULL, /* pSetTextColor */
7179 NULL, /* pSetTextJustification */
7180 NULL, /* pSetViewportExt */
7181 NULL, /* pSetViewportOrg */
7182 NULL, /* pSetWindowExt */
7183 NULL, /* pSetWindowOrg */
7184 NULL, /* pSetWorldTransform */
7185 NULL, /* pStartDoc */
7186 NULL, /* pStartPage */
7187 NULL, /* pStretchBlt */
7188 NULL, /* pStretchDIBits */
7189 NULL, /* pStrokeAndFillPath */
7190 NULL, /* pStrokePath */
7191 NULL, /* pSwapBuffers */
7192 NULL, /* pUnrealizePalette */
7193 NULL, /* pWidenPath */
7194 /* OpenGL not supported */
7197 #else /* HAVE_FREETYPE */
7199 /*************************************************************************/
7201 BOOL WineEngInit(void)
7203 return FALSE;
7205 BOOL WineEngDestroyFontInstance(HFONT hfont)
7207 return FALSE;
7210 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
7211 LPWORD pgi, DWORD flags)
7213 return GDI_ERROR;
7216 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
7217 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
7218 const MAT2* lpmat)
7220 ERR("called but we don't have FreeType\n");
7221 return GDI_ERROR;
7224 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
7225 OUTLINETEXTMETRICW *potm)
7227 ERR("called but we don't have FreeType\n");
7228 return 0;
7231 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
7233 ERR("called but we don't have FreeType\n");
7234 return FALSE;
7237 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
7238 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7240 ERR("called but we don't have FreeType\n");
7241 return FALSE;
7244 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
7245 DWORD cbData)
7247 ERR("called but we don't have FreeType\n");
7248 return GDI_ERROR;
7251 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
7253 ERR("called but we don't have FreeType\n");
7254 return 0;
7257 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7259 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7260 return 1;
7263 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7265 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7266 return TRUE;
7269 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7271 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7272 return NULL;
7275 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
7277 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
7278 return DEFAULT_CHARSET;
7281 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7283 return FALSE;
7286 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
7288 FIXME("(%p, %p): stub\n", font, glyphset);
7289 return 0;
7292 BOOL WineEngFontIsLinked(GdiFont *font)
7294 return FALSE;
7297 /*************************************************************************
7298 * GetRasterizerCaps (GDI32.@)
7300 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7302 lprs->nSize = sizeof(RASTERIZER_STATUS);
7303 lprs->wFlags = 0;
7304 lprs->nLanguageID = 0;
7305 return TRUE;
7308 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
7310 ERR("called but we don't have FreeType\n");
7311 return 0;
7314 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
7316 ERR("called but we don't have FreeType\n");
7317 return FALSE;
7320 #endif /* HAVE_FREETYPE */