Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / gdi32 / freetype.c
blobbdcf8d6fc92ea23275b54fb0dfa9dc1f1ea9630d
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 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTSNAMES_H
106 #include <freetype/ftsnames.h>
107 #else
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
110 # endif
111 #endif
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
114 #endif
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
117 #endif
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
120 #endif
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
129 #endif
131 #ifndef SONAME_LIBFREETYPE
132 #define SONAME_LIBFREETYPE "libfreetype.so"
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 MAKE_FUNCPTR(FT_MulFix);
168 MAKE_FUNCPTR(FT_New_Face);
169 MAKE_FUNCPTR(FT_New_Memory_Face);
170 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
171 MAKE_FUNCPTR(FT_Outline_Transform);
172 MAKE_FUNCPTR(FT_Outline_Translate);
173 MAKE_FUNCPTR(FT_Select_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #ifndef SONAME_LIBFONTCONFIG
199 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
200 #endif
201 #endif
203 #undef MAKE_FUNCPTR
205 #ifndef ft_encoding_none
206 #define FT_ENCODING_NONE ft_encoding_none
207 #endif
208 #ifndef ft_encoding_ms_symbol
209 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
210 #endif
211 #ifndef ft_encoding_unicode
212 #define FT_ENCODING_UNICODE ft_encoding_unicode
213 #endif
214 #ifndef ft_encoding_apple_roman
215 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
216 #endif
218 #ifdef WORDS_BIGENDIAN
219 #define GET_BE_WORD(x) (x)
220 #else
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
222 #endif
224 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
225 typedef struct {
226 FT_Short height;
227 FT_Short width;
228 FT_Pos size;
229 FT_Pos x_ppem;
230 FT_Pos y_ppem;
231 FT_Short internal_leading;
232 } Bitmap_Size;
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
237 typedef struct {
238 FT_Short height, width;
239 FT_Pos size, x_ppem, y_ppem;
240 } My_FT_Bitmap_Size;
242 typedef struct tagFace {
243 struct list entry;
244 WCHAR *StyleName;
245 char *file;
246 FT_Long face_index;
247 BOOL Italic;
248 BOOL Bold;
249 FONTSIGNATURE fs;
250 FONTSIGNATURE fs_links;
251 FT_Fixed font_version;
252 BOOL scalable;
253 Bitmap_Size size; /* set if face is a bitmap */
254 BOOL external; /* TRUE if we should manually add this font to the registry */
255 struct tagFamily *family;
256 /* Cached data for Enum */
257 BOOL cache_valid;
258 ENUMLOGFONTEXW elf;
259 NEWTEXTMETRICEXW ntm;
260 DWORD type;
261 } Face;
263 typedef struct tagFamily {
264 struct list entry;
265 const WCHAR *FamilyName;
266 const WCHAR *EnglishName;
267 struct list faces;
268 } Family;
270 typedef struct {
271 GLYPHMETRICS gm;
272 INT adv; /* These three hold to widths of the unrotated chars */
273 INT lsb;
274 INT bbx;
275 BOOL init;
276 } GM;
278 typedef struct {
279 FLOAT eM11, eM12;
280 FLOAT eM21, eM22;
281 } FMAT2;
283 typedef struct {
284 DWORD hash;
285 LOGFONTW lf;
286 FMAT2 matrix;
287 BOOL can_use_bitmap;
288 } FONT_DESC;
290 typedef struct tagHFONTLIST {
291 struct list entry;
292 HFONT hfont;
293 } HFONTLIST;
295 typedef struct {
296 struct list entry;
297 char *file_name;
298 INT index;
299 GdiFont *font;
300 } CHILD_FONT;
302 struct tagGdiFont {
303 struct list entry;
304 FT_Face ft_face;
305 struct font_mapping *mapping;
306 LPWSTR name;
307 int charset;
308 int codepage;
309 BOOL fake_italic;
310 BOOL fake_bold;
311 BYTE underline;
312 BYTE strikeout;
313 INT orientation;
314 GM *gm;
315 DWORD gmsize;
316 struct list hfontlist;
317 FONT_DESC font_desc;
318 LONG aveWidth;
319 SHORT yMax;
320 SHORT yMin;
321 OUTLINETEXTMETRICW *potm;
322 DWORD total_kern_pairs;
323 KERNINGPAIR *kern_pairs;
324 FONTSIGNATURE fs;
325 GdiFont *base_font;
326 struct list child_fonts;
327 LONG ppem;
330 typedef struct {
331 struct list entry;
332 const WCHAR *font_name;
333 struct list links;
334 } SYSTEM_LINKS;
336 #define INIT_GM_SIZE 128
338 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
339 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
340 #define UNUSED_CACHE_SIZE 10
341 static struct list child_font_list = LIST_INIT(child_font_list);
342 static struct list system_links = LIST_INIT(system_links);
344 static struct list font_subst_list = LIST_INIT(font_subst_list);
346 static struct list font_list = LIST_INIT(font_list);
348 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
349 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
350 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
352 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
354 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
355 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
356 'W','i','n','d','o','w','s','\\',
357 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
358 'F','o','n','t','s','\0'};
360 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
361 'W','i','n','d','o','w','s',' ','N','T','\\',
362 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
363 'F','o','n','t','s','\0'};
365 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
366 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
367 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
368 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
370 static const WCHAR * const SystemFontValues[4] = {
371 System_Value,
372 OEMFont_Value,
373 FixedSys_Value,
374 NULL
377 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
378 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
380 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
381 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
382 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
383 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
384 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
385 'E','u','r','o','p','e','a','n','\0'};
386 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
387 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
388 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
389 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
390 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
391 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
392 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
393 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
394 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
395 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
396 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
397 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
399 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
400 WesternW, /*00*/
401 Central_EuropeanW,
402 CyrillicW,
403 GreekW,
404 TurkishW,
405 HebrewW,
406 ArabicW,
407 BalticW,
408 VietnameseW, /*08*/
409 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
410 ThaiW,
411 JapaneseW,
412 CHINESE_GB2312W,
413 HangulW,
414 CHINESE_BIG5W,
415 Hangul_Johab_W,
416 NULL, NULL, /*23*/
417 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
418 SymbolW /*31*/
421 typedef struct {
422 WCHAR *name;
423 INT charset;
424 } NameCs;
426 typedef struct tagFontSubst {
427 struct list entry;
428 NameCs from;
429 NameCs to;
430 } FontSubst;
432 /* Registry font cache key and value names */
433 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
434 'F','o','n','t','s',0};
435 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
436 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
437 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
438 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
439 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
440 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
441 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
442 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
443 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
444 static const WCHAR face_size_value[] = {'S','i','z','e',0};
445 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
446 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
447 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
448 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
451 struct font_mapping
453 struct list entry;
454 int refcount;
455 dev_t dev;
456 ino_t ino;
457 void *data;
458 size_t size;
461 static struct list mappings_list = LIST_INIT( mappings_list );
463 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
465 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
466 static HANDLE font_mutex;
469 /****************************************
470 * Notes on .fon files
472 * The fonts System, FixedSys and Terminal are special. There are typically multiple
473 * versions installed for different resolutions and codepages. Windows stores which one to use
474 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
475 * Key Meaning
476 * FIXEDFON.FON FixedSys
477 * FONTS.FON System
478 * OEMFONT.FON Terminal
479 * LogPixels Current dpi set by the display control panel applet
480 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
481 * also has a LogPixels value that appears to mirror this)
483 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
484 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
485 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
486 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
487 * so that makes sense.
489 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
490 * to be mapped into the registry on Windows 2000 at least).
491 * I have
492 * woafont=app850.fon
493 * ega80woa.fon=ega80850.fon
494 * ega40woa.fon=ega40850.fon
495 * cga80woa.fon=cga80850.fon
496 * cga40woa.fon=cga40850.fon
499 #ifdef HAVE_CARBON_CARBON_H
500 static char *find_cache_dir(void)
502 FSRef ref;
503 OSErr err;
504 static char cached_path[MAX_PATH];
505 static const char *wine = "/Wine", *fonts = "/Fonts";
507 if(*cached_path) return cached_path;
509 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
510 if(err != noErr)
512 WARN("can't create cached data folder\n");
513 return NULL;
515 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
516 if(err != noErr)
518 WARN("can't create cached data path\n");
519 *cached_path = '\0';
520 return NULL;
522 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
524 ERR("Could not create full path\n");
525 *cached_path = '\0';
526 return NULL;
528 strcat(cached_path, wine);
530 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
532 WARN("Couldn't mkdir %s\n", cached_path);
533 *cached_path = '\0';
534 return NULL;
536 strcat(cached_path, fonts);
537 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
539 WARN("Couldn't mkdir %s\n", cached_path);
540 *cached_path = '\0';
541 return NULL;
543 return cached_path;
546 /******************************************************************
547 * expand_mac_font
549 * Extracts individual TrueType font files from a Mac suitcase font
550 * and saves them into the user's caches directory (see
551 * find_cache_dir()).
552 * Returns a NULL terminated array of filenames.
554 * We do this because they are apps that try to read ttf files
555 * themselves and they don't like Mac suitcase files.
557 static char **expand_mac_font(const char *path)
559 FSRef ref;
560 SInt16 res_ref;
561 OSStatus s;
562 unsigned int idx;
563 const char *out_dir;
564 const char *filename;
565 int output_len;
566 struct {
567 char **array;
568 unsigned int size, max_size;
569 } ret;
571 TRACE("path %s\n", path);
573 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
574 if(s != noErr)
576 WARN("failed to get ref\n");
577 return NULL;
580 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
581 if(s != noErr)
583 TRACE("no data fork, so trying resource fork\n");
584 res_ref = FSOpenResFile(&ref, fsRdPerm);
585 if(res_ref == -1)
587 TRACE("unable to open resource fork\n");
588 return NULL;
592 ret.size = 0;
593 ret.max_size = 10;
594 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
595 if(!ret.array)
597 CloseResFile(res_ref);
598 return NULL;
601 out_dir = find_cache_dir();
603 filename = strrchr(path, '/');
604 if(!filename) filename = path;
605 else filename++;
607 /* output filename has the form out_dir/filename_%04x.ttf */
608 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
610 UseResFile(res_ref);
611 idx = 1;
612 while(1)
614 FamRec *fam_rec;
615 unsigned short *num_faces_ptr, num_faces, face;
616 AsscEntry *assoc;
617 Handle fond;
619 fond = Get1IndResource('FOND', idx);
620 if(!fond) break;
621 TRACE("got fond resource %d\n", idx);
622 HLock(fond);
624 fam_rec = *(FamRec**)fond;
625 num_faces_ptr = (unsigned short *)(fam_rec + 1);
626 num_faces = GET_BE_WORD(*num_faces_ptr);
627 num_faces++;
628 assoc = (AsscEntry*)(num_faces_ptr + 1);
629 TRACE("num faces %04x\n", num_faces);
630 for(face = 0; face < num_faces; face++, assoc++)
632 Handle sfnt;
633 unsigned short size, font_id;
634 char *output;
636 size = GET_BE_WORD(assoc->fontSize);
637 font_id = GET_BE_WORD(assoc->fontID);
638 if(size != 0)
640 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
641 continue;
644 TRACE("trying to load sfnt id %04x\n", font_id);
645 sfnt = GetResource('sfnt', font_id);
646 if(!sfnt)
648 TRACE("can't get sfnt resource %04x\n", font_id);
649 continue;
652 output = HeapAlloc(GetProcessHeap(), 0, output_len);
653 if(output)
655 int fd;
657 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
659 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
660 if(fd != -1 || errno == EEXIST)
662 if(fd != -1)
664 unsigned char *sfnt_data;
666 HLock(sfnt);
667 sfnt_data = *(unsigned char**)sfnt;
668 write(fd, sfnt_data, GetHandleSize(sfnt));
669 HUnlock(sfnt);
670 close(fd);
672 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
674 ret.max_size *= 2;
675 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
677 ret.array[ret.size++] = output;
679 else
681 WARN("unable to create %s\n", output);
682 HeapFree(GetProcessHeap(), 0, output);
685 ReleaseResource(sfnt);
687 HUnlock(fond);
688 ReleaseResource(fond);
689 idx++;
691 CloseResFile(res_ref);
693 return ret.array;
696 #endif /* HAVE_CARBON_CARBON_H */
698 static inline BOOL is_win9x(void)
700 return GetVersion() & 0x80000000;
703 This function builds an FT_Fixed from a float. It puts the integer part
704 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
705 It fails if the integer part of the float number is greater than SHORT_MAX.
707 static inline FT_Fixed FT_FixedFromFloat(float f)
709 short value = f;
710 unsigned short fract = (f - value) * 0xFFFF;
711 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
715 This function builds an FT_Fixed from a FIXED. It simply put f.value
716 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
718 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
720 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
724 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
726 Family *family;
727 Face *face;
728 const char *file;
729 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
730 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
732 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
733 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
735 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
737 if(face_name && strcmpiW(face_name, family->FamilyName))
738 continue;
739 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
741 file = strrchr(face->file, '/');
742 if(!file)
743 file = face->file;
744 else
745 file++;
746 if(!strcasecmp(file, file_nameA))
748 HeapFree(GetProcessHeap(), 0, file_nameA);
749 return face;
753 HeapFree(GetProcessHeap(), 0, file_nameA);
754 return NULL;
757 static Family *find_family_from_name(const WCHAR *name)
759 Family *family;
761 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
763 if(!strcmpiW(family->FamilyName, name))
764 return family;
767 return NULL;
770 static Face *find_face_from_path_index(const CHAR *file_name, const INT index)
772 Family *family;
773 Face *face;
775 TRACE("looking for file %s index %i\n", debugstr_a(file_name), index);
777 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
779 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
781 if(!strcasecmp(face->file, file_name) && face->face_index == index)
782 return face;
785 return NULL;
788 static void DumpSubstList(void)
790 FontSubst *psub;
792 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
794 if(psub->from.charset != -1 || psub->to.charset != -1)
795 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
796 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
797 else
798 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
799 debugstr_w(psub->to.name));
801 return;
804 static LPWSTR strdupW(LPCWSTR p)
806 LPWSTR ret;
807 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
808 ret = HeapAlloc(GetProcessHeap(), 0, len);
809 memcpy(ret, p, len);
810 return ret;
813 static LPSTR strdupA(LPCSTR p)
815 LPSTR ret;
816 DWORD len = (strlen(p) + 1);
817 ret = HeapAlloc(GetProcessHeap(), 0, len);
818 memcpy(ret, p, len);
819 return ret;
822 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
823 INT from_charset)
825 FontSubst *element;
827 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
829 if(!strcmpiW(element->from.name, from_name) &&
830 (element->from.charset == from_charset ||
831 element->from.charset == -1))
832 return element;
835 return NULL;
838 #define ADD_FONT_SUBST_FORCE 1
840 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
842 FontSubst *from_exist, *to_exist;
844 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
846 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
848 list_remove(&from_exist->entry);
849 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
850 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
851 HeapFree(GetProcessHeap(), 0, from_exist);
852 from_exist = NULL;
855 if(!from_exist)
857 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
859 if(to_exist)
861 HeapFree(GetProcessHeap(), 0, subst->to.name);
862 subst->to.name = strdupW(to_exist->to.name);
865 list_add_tail(subst_list, &subst->entry);
867 return TRUE;
870 HeapFree(GetProcessHeap(), 0, subst->from.name);
871 HeapFree(GetProcessHeap(), 0, subst->to.name);
872 HeapFree(GetProcessHeap(), 0, subst);
873 return FALSE;
876 static void split_subst_info(NameCs *nc, LPSTR str)
878 CHAR *p = strrchr(str, ',');
879 DWORD len;
881 nc->charset = -1;
882 if(p && *(p+1)) {
883 nc->charset = strtol(p+1, NULL, 10);
884 *p = '\0';
886 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
887 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
888 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
891 static void LoadSubstList(void)
893 FontSubst *psub;
894 HKEY hkey;
895 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
896 LPSTR value;
897 LPVOID data;
899 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
900 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
901 &hkey) == ERROR_SUCCESS) {
903 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
904 &valuelen, &datalen, NULL, NULL);
906 valuelen++; /* returned value doesn't include room for '\0' */
907 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
908 data = HeapAlloc(GetProcessHeap(), 0, datalen);
910 dlen = datalen;
911 vlen = valuelen;
912 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
913 &dlen) == ERROR_SUCCESS) {
914 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
916 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
917 split_subst_info(&psub->from, value);
918 split_subst_info(&psub->to, data);
920 /* Win 2000 doesn't allow mapping between different charsets
921 or mapping of DEFAULT_CHARSET */
922 if((psub->to.charset != psub->from.charset) ||
923 psub->to.charset == DEFAULT_CHARSET) {
924 HeapFree(GetProcessHeap(), 0, psub->to.name);
925 HeapFree(GetProcessHeap(), 0, psub->from.name);
926 HeapFree(GetProcessHeap(), 0, psub);
927 } else {
928 add_font_subst(&font_subst_list, psub, 0);
930 /* reset dlen and vlen */
931 dlen = datalen;
932 vlen = valuelen;
934 HeapFree(GetProcessHeap(), 0, data);
935 HeapFree(GetProcessHeap(), 0, value);
936 RegCloseKey(hkey);
940 static WCHAR *get_familyname(FT_Face ft_face)
942 WCHAR *family = NULL;
943 FT_SfntName name;
944 FT_UInt num_names, name_index, i;
946 if(FT_IS_SFNT(ft_face))
948 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
950 for(name_index = 0; name_index < num_names; name_index++)
952 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
954 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
955 (name.language_id == GetUserDefaultLCID()) &&
956 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
957 (name.encoding_id == TT_MS_ID_UNICODE_CS))
959 /* String is not nul terminated and string_len is a byte length. */
960 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
961 for(i = 0; i < name.string_len / 2; i++)
963 WORD *tmp = (WORD *)&name.string[i * 2];
964 family[i] = GET_BE_WORD(*tmp);
966 family[i] = 0;
968 TRACE("Got localised name %s\n", debugstr_w(family));
969 return family;
975 return NULL;
978 static HRESULT reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
980 DWORD type, needed;
981 HRESULT r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
982 if(FAILED(r)) return r;
983 if(type != REG_DWORD || needed != sizeof(DWORD)) return E_FAIL;
984 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
987 static inline HRESULT reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
989 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
992 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
994 DWORD needed;
995 DWORD num_strikes, max_strike_key_len;
997 /* If we have a File Name key then this is a real font, not just the parent
998 key of a bunch of non-scalable strikes */
999 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1001 Face *face;
1002 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1004 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1005 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1007 face->StyleName = strdupW(face_name);
1008 face->family = family;
1009 face->cache_valid = FALSE;
1011 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1012 reg_load_dword(hkey_face, face_italic_value, (DWORD*)&face->Italic);
1013 reg_load_dword(hkey_face, face_bold_value, (DWORD*)&face->Bold);
1014 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1015 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1017 needed = sizeof(face->fs);
1018 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1019 memset(&face->fs_links, 0, sizeof(face->fs_links));
1021 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1023 face->scalable = TRUE;
1024 memset(&face->size, 0, sizeof(face->size));
1026 else
1028 face->scalable = FALSE;
1029 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1030 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1031 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1032 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1033 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1035 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1036 face->size.height, face->size.width, face->size.size >> 6,
1037 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1040 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1041 face->fs.fsCsb[0], face->fs.fsCsb[1],
1042 face->fs.fsUsb[0], face->fs.fsUsb[1],
1043 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1045 if(!face->Italic && !face->Bold)
1046 list_add_head(&family->faces, &face->entry);
1047 else
1048 list_add_tail(&family->faces, &face->entry);
1050 if(face->fs.fsCsb[0] & ~(1L << 31))
1051 have_installed_roman_font = TRUE;
1053 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1056 /* do we have any bitmap strikes? */
1057 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1058 NULL, NULL, NULL, NULL);
1059 if(num_strikes != 0)
1061 WCHAR strike_name[10];
1062 DWORD strike_index = 0;
1064 needed = sizeof(strike_name) / sizeof(WCHAR);
1065 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1066 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1068 HKEY hkey_strike;
1069 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1070 load_face(hkey_strike, face_name, family);
1071 RegCloseKey(hkey_strike);
1072 needed = sizeof(strike_name) / sizeof(WCHAR);
1077 static void load_font_list_from_cache(HKEY hkey_font_cache)
1079 DWORD max_family_key_len, size;
1080 WCHAR *family_name;
1081 DWORD family_index = 0;
1082 Family *family;
1083 HKEY hkey_family;
1085 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1086 NULL, NULL, NULL, NULL);
1087 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1089 size = max_family_key_len + 1;
1090 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1091 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1093 WCHAR *english_family = NULL;
1094 DWORD face_index = 0;
1095 WCHAR *face_name;
1096 DWORD max_face_key_len;
1098 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1099 TRACE("opened family key %s\n", debugstr_w(family_name));
1100 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1102 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1103 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1106 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1107 family->FamilyName = strdupW(family_name);
1108 family->EnglishName = english_family;
1109 list_init(&family->faces);
1110 list_add_tail(&font_list, &family->entry);
1112 if(english_family)
1114 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1115 subst->from.name = strdupW(english_family);
1116 subst->from.charset = -1;
1117 subst->to.name = strdupW(family_name);
1118 subst->to.charset = -1;
1119 add_font_subst(&font_subst_list, subst, 0);
1122 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1123 NULL, NULL, NULL, NULL);
1125 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1126 size = max_face_key_len + 1;
1127 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1128 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1130 HKEY hkey_face;
1132 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1133 load_face(hkey_face, face_name, family);
1134 RegCloseKey(hkey_face);
1135 size = max_face_key_len + 1;
1137 HeapFree(GetProcessHeap(), 0, face_name);
1138 RegCloseKey(hkey_family);
1139 size = max_family_key_len + 1;
1142 HeapFree(GetProcessHeap(), 0, family_name);
1146 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1148 LONG ret;
1149 HKEY hkey_wine_fonts;
1151 /* We don't want to create the fonts key as volatile, so open this first */
1152 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1153 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1154 if(ret != ERROR_SUCCESS)
1156 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1157 return ret;
1160 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1161 KEY_ALL_ACCESS, NULL, hkey, disposition);
1162 RegCloseKey(hkey_wine_fonts);
1163 return ret;
1166 static void add_face_to_cache(Face *face)
1168 HKEY hkey_font_cache, hkey_family, hkey_face;
1169 WCHAR *face_key_name;
1171 create_font_cache_key(&hkey_font_cache, NULL);
1173 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1174 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1175 if(face->family->EnglishName)
1176 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1177 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1179 if(face->scalable)
1180 face_key_name = face->StyleName;
1181 else
1183 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1184 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1185 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1187 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1188 &hkey_face, NULL);
1189 if(!face->scalable)
1190 HeapFree(GetProcessHeap(), 0, face_key_name);
1192 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1194 reg_save_dword(hkey_face, face_index_value, face->face_index);
1195 reg_save_dword(hkey_face, face_italic_value, face->Italic);
1196 reg_save_dword(hkey_face, face_bold_value, face->Bold);
1197 reg_save_dword(hkey_face, face_version_value, face->font_version);
1198 reg_save_dword(hkey_face, face_external_value, face->external);
1200 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1202 if(!face->scalable)
1204 reg_save_dword(hkey_face, face_height_value, face->size.height);
1205 reg_save_dword(hkey_face, face_width_value, face->size.width);
1206 reg_save_dword(hkey_face, face_size_value, face->size.size);
1207 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1208 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1209 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1211 RegCloseKey(hkey_face);
1212 RegCloseKey(hkey_family);
1213 RegCloseKey(hkey_font_cache);
1216 #define ADDFONT_EXTERNAL_FONT 0x01
1217 #define ADDFONT_FORCE_BITMAP 0x02
1218 #define ADDFONT_ADD_TO_CACHE 0x04
1219 static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1221 FT_Face ft_face;
1222 TT_OS2 *pOS2;
1223 TT_Header *pHeader = NULL;
1224 WCHAR *english_family, *localised_family, *StyleW;
1225 DWORD len;
1226 Family *family;
1227 Face *face;
1228 struct list *family_elem_ptr, *face_elem_ptr;
1229 FT_Error err;
1230 FT_Long face_index = 0, num_faces;
1231 #ifdef HAVE_FREETYPE_FTWINFNT_H
1232 FT_WinFNT_HeaderRec winfnt_header;
1233 #endif
1234 int i, bitmap_num, internal_leading;
1235 FONTSIGNATURE fs;
1237 #ifdef HAVE_CARBON_CARBON_H
1238 if(!fake_family)
1240 char **mac_list = expand_mac_font(file);
1241 if(mac_list)
1243 BOOL had_one = FALSE;
1244 char **cursor;
1245 for(cursor = mac_list; *cursor; cursor++)
1247 had_one = TRUE;
1248 AddFontFileToList(*cursor, NULL, NULL, flags);
1249 HeapFree(GetProcessHeap(), 0, *cursor);
1251 HeapFree(GetProcessHeap(), 0, mac_list);
1252 if(had_one)
1253 return TRUE;
1256 #endif /* HAVE_CARBON_CARBON_H */
1258 do {
1259 char *family_name = fake_family;
1261 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1262 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
1263 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
1264 return FALSE;
1267 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*/
1268 WARN("Ignoring font %s\n", debugstr_a(file));
1269 pFT_Done_Face(ft_face);
1270 return FALSE;
1273 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1274 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1275 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1276 pFT_Done_Face(ft_face);
1277 return FALSE;
1280 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1281 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1282 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1283 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1284 "Skipping this font.\n", debugstr_a(file));
1285 pFT_Done_Face(ft_face);
1286 return FALSE;
1289 if(!ft_face->family_name || !ft_face->style_name) {
1290 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1291 pFT_Done_Face(ft_face);
1292 return FALSE;
1295 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1297 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1298 pFT_Done_Face(ft_face);
1299 return FALSE;
1302 if (target_family)
1304 localised_family = get_familyname(ft_face);
1305 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1307 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1308 HeapFree(GetProcessHeap(), 0, localised_family);
1309 num_faces = ft_face->num_faces;
1310 pFT_Done_Face(ft_face);
1311 continue;
1313 HeapFree(GetProcessHeap(), 0, localised_family);
1316 if(!family_name)
1317 family_name = ft_face->family_name;
1319 bitmap_num = 0;
1320 do {
1321 My_FT_Bitmap_Size *size = NULL;
1323 if(!FT_IS_SCALABLE(ft_face))
1324 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1326 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1327 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1328 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1330 localised_family = NULL;
1331 if(!fake_family) {
1332 localised_family = get_familyname(ft_face);
1333 if(localised_family && !strcmpW(localised_family, english_family)) {
1334 HeapFree(GetProcessHeap(), 0, localised_family);
1335 localised_family = NULL;
1339 family = NULL;
1340 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1341 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1342 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1343 break;
1344 family = NULL;
1346 if(!family) {
1347 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1348 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1349 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1351 list_init(&family->faces);
1352 list_add_tail(&font_list, &family->entry);
1354 if(localised_family) {
1355 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1356 subst->from.name = strdupW(english_family);
1357 subst->from.charset = -1;
1358 subst->to.name = strdupW(localised_family);
1359 subst->to.charset = -1;
1360 add_font_subst(&font_subst_list, subst, 0);
1363 HeapFree(GetProcessHeap(), 0, localised_family);
1364 HeapFree(GetProcessHeap(), 0, english_family);
1366 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1367 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1368 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1370 internal_leading = 0;
1371 memset(&fs, 0, sizeof(fs));
1373 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1374 if(pOS2) {
1375 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1376 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1377 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1378 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1379 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1380 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1381 if(pOS2->version == 0) {
1382 FT_UInt dummy;
1384 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1385 fs.fsCsb[0] |= 1;
1386 else
1387 fs.fsCsb[0] |= 1L << 31;
1390 #ifdef HAVE_FREETYPE_FTWINFNT_H
1391 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1392 CHARSETINFO csi;
1393 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1394 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1395 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1396 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1397 internal_leading = winfnt_header.internal_leading;
1399 #endif
1401 face_elem_ptr = list_head(&family->faces);
1402 while(face_elem_ptr) {
1403 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1404 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1405 if(!strcmpW(face->StyleName, StyleW) &&
1406 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1407 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1408 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1409 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1411 if(fake_family) {
1412 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1413 HeapFree(GetProcessHeap(), 0, StyleW);
1414 pFT_Done_Face(ft_face);
1415 return FALSE;
1417 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1418 TRACE("Original font is newer so skipping this one\n");
1419 HeapFree(GetProcessHeap(), 0, StyleW);
1420 pFT_Done_Face(ft_face);
1421 return FALSE;
1422 } else {
1423 TRACE("Replacing original with this one\n");
1424 list_remove(&face->entry);
1425 HeapFree(GetProcessHeap(), 0, face->file);
1426 HeapFree(GetProcessHeap(), 0, face->StyleName);
1427 HeapFree(GetProcessHeap(), 0, face);
1428 break;
1432 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1433 face->cache_valid = FALSE;
1434 face->StyleName = StyleW;
1435 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1436 strcpy(face->file, file);
1437 face->face_index = face_index;
1438 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1439 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1440 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1441 face->family = family;
1442 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1443 memcpy(&face->fs, &fs, sizeof(face->fs));
1444 memset(&face->fs_links, 0, sizeof(face->fs_links));
1446 if(FT_IS_SCALABLE(ft_face)) {
1447 memset(&face->size, 0, sizeof(face->size));
1448 face->scalable = TRUE;
1449 } else {
1450 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1451 size->height, size->width, size->size >> 6,
1452 size->x_ppem >> 6, size->y_ppem >> 6);
1453 face->size.height = size->height;
1454 face->size.width = size->width;
1455 face->size.size = size->size;
1456 face->size.x_ppem = size->x_ppem;
1457 face->size.y_ppem = size->y_ppem;
1458 face->size.internal_leading = internal_leading;
1459 face->scalable = FALSE;
1462 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1463 face->fs.fsCsb[0], face->fs.fsCsb[1],
1464 face->fs.fsUsb[0], face->fs.fsUsb[1],
1465 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1468 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1469 for(i = 0; i < ft_face->num_charmaps; i++) {
1470 switch(ft_face->charmaps[i]->encoding) {
1471 case FT_ENCODING_UNICODE:
1472 case FT_ENCODING_APPLE_ROMAN:
1473 face->fs.fsCsb[0] |= 1;
1474 break;
1475 case FT_ENCODING_MS_SYMBOL:
1476 face->fs.fsCsb[0] |= 1L << 31;
1477 break;
1478 default:
1479 break;
1484 if(!face->Italic && !face->Bold)
1485 list_add_head(&family->faces, &face->entry);
1486 else
1487 list_add_tail(&family->faces, &face->entry);
1489 if(flags & ADDFONT_ADD_TO_CACHE)
1490 add_face_to_cache(face);
1492 if(face->fs.fsCsb[0] & ~(1L << 31))
1493 have_installed_roman_font = TRUE;
1494 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1496 num_faces = ft_face->num_faces;
1497 pFT_Done_Face(ft_face);
1498 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1499 debugstr_w(StyleW));
1500 } while(num_faces > ++face_index);
1501 return TRUE;
1504 static void DumpFontList(void)
1506 Family *family;
1507 Face *face;
1508 struct list *family_elem_ptr, *face_elem_ptr;
1510 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1511 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1512 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1513 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1514 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1515 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1516 if(!face->scalable)
1517 TRACE(" %d", face->size.height);
1518 TRACE("\n");
1521 return;
1524 /***********************************************************
1525 * The replacement list is a way to map an entire font
1526 * family onto another family. For example adding
1528 * [HKCU\Software\Wine\Fonts\Replacements]
1529 * "Wingdings"="Winedings"
1531 * would enumerate the Winedings font both as Winedings and
1532 * Wingdings. However if a real Wingdings font is present the
1533 * replacement does not take place.
1536 static void LoadReplaceList(void)
1538 HKEY hkey;
1539 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1540 LPWSTR value;
1541 LPVOID data;
1542 Family *family;
1543 Face *face;
1544 struct list *family_elem_ptr, *face_elem_ptr;
1545 CHAR familyA[400];
1547 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1548 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1550 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1551 &valuelen, &datalen, NULL, NULL);
1553 valuelen++; /* returned value doesn't include room for '\0' */
1554 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1555 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1557 dlen = datalen;
1558 vlen = valuelen;
1559 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1560 &dlen) == ERROR_SUCCESS) {
1561 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1562 /* "NewName"="Oldname" */
1563 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1565 if(!find_family_from_name(value))
1567 /* Find the old family and hence all of the font files
1568 in that family */
1569 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1570 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1571 if(!strcmpiW(family->FamilyName, data)) {
1572 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1573 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1574 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1575 debugstr_w(face->StyleName), familyA);
1576 /* Now add a new entry with the new family name */
1577 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1579 break;
1583 /* reset dlen and vlen */
1584 dlen = datalen;
1585 vlen = valuelen;
1587 HeapFree(GetProcessHeap(), 0, data);
1588 HeapFree(GetProcessHeap(), 0, value);
1589 RegCloseKey(hkey);
1593 /*************************************************************
1594 * init_system_links
1596 static BOOL init_system_links(void)
1598 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1599 'W','i','n','d','o','w','s',' ','N','T','\\',
1600 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1601 'S','y','s','t','e','m','L','i','n','k',0};
1602 HKEY hkey;
1603 BOOL ret = FALSE;
1604 DWORD type, max_val, max_data, val_len, data_len, index;
1605 WCHAR *value, *data;
1606 WCHAR *entry, *next;
1607 SYSTEM_LINKS *font_link, *system_font_link;
1608 CHILD_FONT *child_font;
1609 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1610 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1611 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1612 FONTSIGNATURE fs;
1613 Family *family;
1614 Face *face;
1615 FontSubst *psub;
1617 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1619 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1620 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1621 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1622 val_len = max_val + 1;
1623 data_len = max_data;
1624 index = 0;
1625 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1627 TRACE("%s:\n", debugstr_w(value));
1629 memset(&fs, 0, sizeof(fs));
1630 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1631 psub = get_font_subst(&font_subst_list, value, -1);
1632 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1633 list_init(&font_link->links);
1634 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1636 WCHAR *face_name;
1637 CHILD_FONT *child_font;
1639 TRACE("\t%s\n", debugstr_w(entry));
1641 next = entry + strlenW(entry) + 1;
1643 face_name = strchrW(entry, ',');
1644 if(face_name)
1646 *face_name++ = 0;
1647 while(isspaceW(*face_name))
1648 face_name++;
1650 psub = get_font_subst(&font_subst_list, face_name, -1);
1651 if(psub)
1652 face_name = psub->to.name;
1654 face = find_face_from_filename(entry, face_name);
1655 if(!face)
1657 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1658 continue;
1661 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1662 child_font->file_name = strdupA(face->file);
1663 child_font->index = face->face_index;
1664 child_font->font = NULL;
1665 fs.fsCsb[0] |= face->fs.fsCsb[0];
1666 fs.fsCsb[1] |= face->fs.fsCsb[1];
1667 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1668 list_add_tail(&font_link->links, &child_font->entry);
1670 family = find_family_from_name(font_link->font_name);
1671 if(family)
1673 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1675 memcpy(&face->fs_links, &fs, sizeof(fs));
1678 list_add_tail(&system_links, &font_link->entry);
1679 val_len = max_val + 1;
1680 data_len = max_data;
1683 HeapFree(GetProcessHeap(), 0, value);
1684 HeapFree(GetProcessHeap(), 0, data);
1685 RegCloseKey(hkey);
1688 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1689 that Tahoma has */
1691 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1692 system_font_link->font_name = strdupW(System);
1693 list_init(&system_font_link->links);
1695 face = find_face_from_filename(tahoma_ttf, Tahoma);
1696 if(face)
1698 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1699 child_font->file_name = strdupA(face->file);
1700 child_font->index = face->face_index;
1701 child_font->font = NULL;
1702 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1703 list_add_tail(&system_font_link->links, &child_font->entry);
1705 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1707 if(!strcmpiW(font_link->font_name, Tahoma))
1709 CHILD_FONT *font_link_entry;
1710 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1712 CHILD_FONT *new_child;
1713 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1714 new_child->file_name = strdupA(font_link_entry->file_name);
1715 new_child->index = font_link_entry->index;
1716 new_child->font = NULL;
1717 list_add_tail(&system_font_link->links, &new_child->entry);
1719 break;
1722 list_add_tail(&system_links, &system_font_link->entry);
1723 return ret;
1726 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1728 DIR *dir;
1729 struct dirent *dent;
1730 char path[MAX_PATH];
1732 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1734 dir = opendir(dirname);
1735 if(!dir) {
1736 WARN("Can't open directory %s\n", debugstr_a(dirname));
1737 return FALSE;
1739 while((dent = readdir(dir)) != NULL) {
1740 struct stat statbuf;
1742 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1743 continue;
1745 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1747 sprintf(path, "%s/%s", dirname, dent->d_name);
1749 if(stat(path, &statbuf) == -1)
1751 WARN("Can't stat %s\n", debugstr_a(path));
1752 continue;
1754 if(S_ISDIR(statbuf.st_mode))
1755 ReadFontDir(path, external_fonts);
1756 else
1757 AddFontFileToList(path, NULL, NULL, (external_fonts ? ADDFONT_EXTERNAL_FONT : 0) | ADDFONT_ADD_TO_CACHE);
1759 closedir(dir);
1760 return TRUE;
1763 static void load_fontconfig_fonts(void)
1765 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1766 void *fc_handle = NULL;
1767 FcConfig *config;
1768 FcPattern *pat;
1769 FcObjectSet *os;
1770 FcFontSet *fontset;
1771 int i, len;
1772 char *file;
1773 const char *ext;
1775 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1776 if(!fc_handle) {
1777 TRACE("Wine cannot find the fontconfig library (%s).\n",
1778 SONAME_LIBFONTCONFIG);
1779 return;
1781 #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;}
1782 LOAD_FUNCPTR(FcConfigGetCurrent);
1783 LOAD_FUNCPTR(FcFontList);
1784 LOAD_FUNCPTR(FcFontSetDestroy);
1785 LOAD_FUNCPTR(FcInit);
1786 LOAD_FUNCPTR(FcObjectSetAdd);
1787 LOAD_FUNCPTR(FcObjectSetCreate);
1788 LOAD_FUNCPTR(FcObjectSetDestroy);
1789 LOAD_FUNCPTR(FcPatternCreate);
1790 LOAD_FUNCPTR(FcPatternDestroy);
1791 LOAD_FUNCPTR(FcPatternGetBool);
1792 LOAD_FUNCPTR(FcPatternGetString);
1793 #undef LOAD_FUNCPTR
1795 if(!pFcInit()) return;
1797 config = pFcConfigGetCurrent();
1798 pat = pFcPatternCreate();
1799 os = pFcObjectSetCreate();
1800 pFcObjectSetAdd(os, FC_FILE);
1801 pFcObjectSetAdd(os, FC_SCALABLE);
1802 fontset = pFcFontList(config, pat, os);
1803 if(!fontset) return;
1804 for(i = 0; i < fontset->nfont; i++) {
1805 FcBool scalable;
1807 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1808 continue;
1809 TRACE("fontconfig: %s\n", file);
1811 /* We're just interested in OT/TT fonts for now, so this hack just
1812 picks up the scalable fonts without extensions .pf[ab] to save time
1813 loading every other font */
1815 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1817 TRACE("not scalable\n");
1818 continue;
1821 len = strlen( file );
1822 if(len < 4) continue;
1823 ext = &file[ len - 3 ];
1824 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1825 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
1827 pFcFontSetDestroy(fontset);
1828 pFcObjectSetDestroy(os);
1829 pFcPatternDestroy(pat);
1830 sym_not_found:
1831 #endif
1832 return;
1835 static BOOL load_font_from_data_dir(LPCWSTR file)
1837 BOOL ret = FALSE;
1838 const char *data_dir = wine_get_data_dir();
1840 if (!data_dir) data_dir = wine_get_build_dir();
1842 if (data_dir)
1844 INT len;
1845 char *unix_name;
1847 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1849 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1851 strcpy(unix_name, data_dir);
1852 strcat(unix_name, "/fonts/");
1854 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1856 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
1857 HeapFree(GetProcessHeap(), 0, unix_name);
1859 return ret;
1862 static void load_system_fonts(void)
1864 HKEY hkey;
1865 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1866 const WCHAR * const *value;
1867 DWORD dlen, type;
1868 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1869 char *unixname;
1871 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1872 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1873 strcatW(windowsdir, fontsW);
1874 for(value = SystemFontValues; *value; value++) {
1875 dlen = sizeof(data);
1876 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1877 type == REG_SZ) {
1878 BOOL added = FALSE;
1880 sprintfW(pathW, fmtW, windowsdir, data);
1881 if((unixname = wine_get_unix_file_name(pathW))) {
1882 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
1883 HeapFree(GetProcessHeap(), 0, unixname);
1885 if (!added)
1886 load_font_from_data_dir(data);
1889 RegCloseKey(hkey);
1893 /*************************************************************
1895 * This adds registry entries for any externally loaded fonts
1896 * (fonts from fontconfig or FontDirs). It also deletes entries
1897 * of no longer existing fonts.
1900 static void update_reg_entries(void)
1902 HKEY winnt_key = 0, win9x_key, external_key = 0;
1903 LPWSTR valueW;
1904 DWORD len, len_fam;
1905 Family *family;
1906 Face *face;
1907 struct list *family_elem_ptr, *face_elem_ptr;
1908 WCHAR *file;
1909 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1910 static const WCHAR spaceW[] = {' ', '\0'};
1911 char *path;
1913 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1914 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1915 ERR("Can't create Windows font reg key\n");
1916 goto end;
1919 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1920 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1921 ERR("Can't create Windows font reg key\n");
1922 goto end;
1926 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1927 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1928 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1929 ERR("Can't create external font reg key\n");
1930 goto end;
1933 /* enumerate the fonts and add external ones to the two keys */
1935 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1936 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1937 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1938 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1939 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1940 if(!face->external) continue;
1941 len = len_fam;
1942 if(strcmpiW(face->StyleName, RegularW))
1943 len = len_fam + strlenW(face->StyleName) + 1;
1944 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1945 strcpyW(valueW, family->FamilyName);
1946 if(len != len_fam) {
1947 strcatW(valueW, spaceW);
1948 strcatW(valueW, face->StyleName);
1950 strcatW(valueW, TrueType);
1952 file = wine_get_dos_file_name(face->file);
1953 if(file)
1954 len = strlenW(file) + 1;
1955 else
1957 if((path = strrchr(face->file, '/')) == NULL)
1958 path = face->file;
1959 else
1960 path++;
1961 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1963 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1964 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1966 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1967 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1968 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1970 HeapFree(GetProcessHeap(), 0, file);
1971 HeapFree(GetProcessHeap(), 0, valueW);
1974 end:
1975 if(external_key) RegCloseKey(external_key);
1976 if(win9x_key) RegCloseKey(win9x_key);
1977 if(winnt_key) RegCloseKey(winnt_key);
1978 return;
1981 static void delete_external_font_keys(void)
1983 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1984 DWORD dlen, vlen, datalen, valuelen, i, type;
1985 LPWSTR valueW;
1986 LPVOID data;
1988 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1989 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1990 ERR("Can't create Windows font reg key\n");
1991 goto end;
1994 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1995 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1996 ERR("Can't create Windows font reg key\n");
1997 goto end;
2000 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
2001 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2002 ERR("Can't create external font reg key\n");
2003 goto end;
2006 /* Delete all external fonts added last time */
2008 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2009 &valuelen, &datalen, NULL, NULL);
2010 valuelen++; /* returned value doesn't include room for '\0' */
2011 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2012 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2014 dlen = datalen * sizeof(WCHAR);
2015 vlen = valuelen;
2016 i = 0;
2017 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2018 &dlen) == ERROR_SUCCESS) {
2020 RegDeleteValueW(winnt_key, valueW);
2021 RegDeleteValueW(win9x_key, valueW);
2022 /* reset dlen and vlen */
2023 dlen = datalen;
2024 vlen = valuelen;
2026 HeapFree(GetProcessHeap(), 0, data);
2027 HeapFree(GetProcessHeap(), 0, valueW);
2029 /* Delete the old external fonts key */
2030 RegCloseKey(external_key);
2031 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2033 end:
2034 if(win9x_key) RegCloseKey(win9x_key);
2035 if(winnt_key) RegCloseKey(winnt_key);
2038 /*************************************************************
2039 * WineEngAddFontResourceEx
2042 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2044 if (ft_handle) /* do it only if we have freetype up and running */
2046 char *unixname;
2048 if((unixname = wine_get_unix_file_name(file)))
2050 DWORD flags = ADDFONT_FORCE_BITMAP;
2052 if(!(flags & FR_PRIVATE)) flags |= ADDFONT_ADD_TO_CACHE;
2053 WaitForSingleObject(font_mutex, INFINITE);
2054 AddFontFileToList(unixname, NULL, NULL, flags);
2055 ReleaseMutex(font_mutex);
2056 HeapFree(GetProcessHeap(), 0, unixname);
2059 return 1;
2062 /*************************************************************
2063 * WineEngRemoveFontResourceEx
2066 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2068 FIXME(":stub\n");
2069 return TRUE;
2072 static const struct nls_update_font_list
2074 UINT ansi_cp, oem_cp;
2075 const char *oem, *fixed, *system;
2076 const char *courier, *serif, *small, *sserif;
2077 /* these are for font substitute */
2078 const char *shelldlg, *tmsrmn;
2079 } nls_update_font_list[] =
2081 /* Latin 1 (United States) */
2082 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2083 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2084 "Tahoma","Times New Roman",
2086 /* Latin 1 (Multilingual) */
2087 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2088 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2089 "Tahoma","Times New Roman", /* FIXME unverified */
2091 /* Eastern Europe */
2092 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2093 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2094 "Tahoma","Times New Roman", /* FIXME unverified */
2096 /* Cyrillic */
2097 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2098 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2099 "Tahoma","Times New Roman", /* FIXME unverified */
2101 /* Greek */
2102 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2103 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2104 "Tahoma","Times New Roman", /* FIXME unverified */
2106 /* Turkish */
2107 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2108 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2109 "Tahoma","Times New Roman", /* FIXME unverified */
2111 /* Hebrew */
2112 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2113 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2114 "Tahoma","Times New Roman", /* FIXME unverified */
2116 /* Arabic */
2117 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2118 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2119 "Tahoma","Times New Roman", /* FIXME unverified */
2121 /* Baltic */
2122 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2123 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2124 "Tahoma","Times New Roman", /* FIXME unverified */
2126 /* Vietnamese */
2127 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2128 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2129 "Tahoma","Times New Roman", /* FIXME unverified */
2131 /* Thai */
2132 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2133 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2134 "Tahoma","Times New Roman", /* FIXME unverified */
2136 /* Japanese */
2137 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2138 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2139 "MS UI Gothic","MS Serif",
2141 /* Chinese Simplified */
2142 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2143 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2144 "Tahoma", "Times New Roman", /* FIXME unverified */
2146 /* Korean */
2147 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2148 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2149 "Gulim", "Batang",
2151 /* Chinese Traditional */
2152 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2153 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2154 "Tahoma", "Times New Roman", /* FIXME unverified */
2158 static inline HKEY create_fonts_NT_registry_key(void)
2160 HKEY hkey = 0;
2162 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2163 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2164 return hkey;
2167 static inline HKEY create_fonts_9x_registry_key(void)
2169 HKEY hkey = 0;
2171 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2172 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2173 return hkey;
2176 static inline HKEY create_config_fonts_registry_key(void)
2178 HKEY hkey = 0;
2180 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2181 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2182 return hkey;
2185 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2187 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2188 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2189 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2190 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2193 static void update_font_info(void)
2195 char buf[40], cpbuf[40];
2196 DWORD len, type;
2197 HKEY hkey = 0;
2198 UINT i, ansi_cp = 0, oem_cp = 0;
2200 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2201 return;
2203 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2204 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2205 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2206 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2207 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2209 len = sizeof(buf);
2210 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2212 if (!strcmp( buf, cpbuf )) /* already set correctly */
2214 RegCloseKey(hkey);
2215 return;
2217 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2219 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2221 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2222 RegCloseKey(hkey);
2224 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2226 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2227 nls_update_font_list[i].oem_cp == oem_cp)
2229 HKEY hkey;
2231 hkey = create_config_fonts_registry_key();
2232 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2233 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2234 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2235 RegCloseKey(hkey);
2237 hkey = create_fonts_NT_registry_key();
2238 add_font_list(hkey, &nls_update_font_list[i]);
2239 RegCloseKey(hkey);
2241 hkey = create_fonts_9x_registry_key();
2242 add_font_list(hkey, &nls_update_font_list[i]);
2243 RegCloseKey(hkey);
2245 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2247 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2248 strlen(nls_update_font_list[i].shelldlg)+1);
2249 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2250 strlen(nls_update_font_list[i].tmsrmn)+1);
2251 RegCloseKey(hkey);
2253 return;
2256 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2259 static void init_font_list(void)
2261 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2262 static const WCHAR pathW[] = {'P','a','t','h',0};
2263 HKEY hkey;
2264 WCHAR windowsdir[MAX_PATH];
2265 char *unixname;
2266 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2267 LPVOID data;
2268 const char *data_dir;
2270 /* load the system bitmap fonts */
2271 load_system_fonts();
2273 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2274 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2275 strcatW(windowsdir, fontsW);
2276 if((unixname = wine_get_unix_file_name(windowsdir)))
2278 ReadFontDir(unixname, FALSE);
2279 HeapFree(GetProcessHeap(), 0, unixname);
2282 /* load the system truetype fonts */
2283 data_dir = wine_get_data_dir();
2284 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2285 strcpy(unixname, data_dir);
2286 strcat(unixname, "/fonts/");
2287 ReadFontDir(unixname, FALSE);
2288 HeapFree(GetProcessHeap(), 0, unixname);
2291 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2292 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2293 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2294 will skip these. */
2295 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2296 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2297 &hkey) == ERROR_SUCCESS) {
2298 LPWSTR valueW;
2299 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2300 &valuelen, &datalen, NULL, NULL);
2302 valuelen++; /* returned value doesn't include room for '\0' */
2303 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2304 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2305 if (valueW && data)
2307 dlen = datalen * sizeof(WCHAR);
2308 vlen = valuelen;
2309 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2310 &dlen) == ERROR_SUCCESS) {
2311 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2313 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2315 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2316 HeapFree(GetProcessHeap(), 0, unixname);
2319 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2321 WCHAR pathW[MAX_PATH];
2322 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2323 BOOL added = FALSE;
2325 sprintfW(pathW, fmtW, windowsdir, data);
2326 if((unixname = wine_get_unix_file_name(pathW)))
2328 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2329 HeapFree(GetProcessHeap(), 0, unixname);
2331 if (!added)
2332 load_font_from_data_dir(data);
2334 /* reset dlen and vlen */
2335 dlen = datalen;
2336 vlen = valuelen;
2339 HeapFree(GetProcessHeap(), 0, data);
2340 HeapFree(GetProcessHeap(), 0, valueW);
2341 RegCloseKey(hkey);
2344 load_fontconfig_fonts();
2346 /* then look in any directories that we've specified in the config file */
2347 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2348 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2350 DWORD len;
2351 LPWSTR valueW;
2352 LPSTR valueA, ptr;
2354 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2356 len += sizeof(WCHAR);
2357 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2358 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2360 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2361 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2362 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2363 TRACE( "got font path %s\n", debugstr_a(valueA) );
2364 ptr = valueA;
2365 while (ptr)
2367 LPSTR next = strchr( ptr, ':' );
2368 if (next) *next++ = 0;
2369 ReadFontDir( ptr, TRUE );
2370 ptr = next;
2372 HeapFree( GetProcessHeap(), 0, valueA );
2374 HeapFree( GetProcessHeap(), 0, valueW );
2376 RegCloseKey(hkey);
2380 static BOOL move_to_front(const WCHAR *name)
2382 Family *family, *cursor2;
2383 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
2385 if(!strcmpiW(family->FamilyName, name))
2387 list_remove(&family->entry);
2388 list_add_head(&font_list, &family->entry);
2389 return TRUE;
2392 return FALSE;
2395 static const WCHAR arial[] = {'A','r','i','a','l',0};
2396 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
2397 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};
2398 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};
2399 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
2400 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
2402 static void reorder_font_list(void)
2404 if(!move_to_front(times_new_roman))
2405 move_to_front(bitstream_vera_serif);
2407 if(!move_to_front(courier_new))
2408 move_to_front(bitstream_vera_sans_mono);
2410 if(!move_to_front(arial))
2411 move_to_front(bitstream_vera_sans);
2415 /*************************************************************
2416 * WineEngInit
2418 * Initialize FreeType library and create a list of available faces
2420 BOOL WineEngInit(void)
2422 static const WCHAR cx_hack_var[] = {'C','X','_','T','U','R','N','_','O','F','F','_','F','O','N','T','_',
2423 'R','E','P','L','A','C','E','M','E','N','T','S',0};
2424 WCHAR env_buf[20];
2425 HKEY hkey_font_cache;
2426 DWORD disposition;
2427 const char *ftname = "libcxfreetype.so";
2428 char freetypelib[MAX_PATH];
2429 LONG r;
2430 HKEY hkey;
2431 DWORD vlen, type;
2433 /* check if the config file specifies a freetype library */
2434 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2435 r = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts",
2436 &hkey);
2437 if( r == ERROR_SUCCESS )
2439 vlen = sizeof freetypelib;
2440 r = RegQueryValueExA( hkey, "FreeTypeLib", 0, &type,
2441 (LPBYTE)freetypelib, &vlen );
2442 if( ( ERROR_SUCCESS == r ) && ( type == REG_SZ ) )
2444 ftname = freetypelib;
2446 RegCloseKey( hkey );
2449 /* update locale dependent font info in registry */
2450 update_font_info();
2452 TRACE("Using freetype library %s\n",ftname);
2453 ft_handle = wine_dlopen(ftname, RTLD_NOW, NULL, 0);
2454 if(!ft_handle) {
2455 TRACE("Can't find freetype library %s, trying %s instead\n", ftname, SONAME_LIBFREETYPE);
2456 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2457 if(!ft_handle) {
2458 WINE_MESSAGE(
2459 "Wine cannot find the FreeType font library. To enable Wine to\n"
2460 "use TrueType fonts please install a version of FreeType greater than\n"
2461 "or equal to 2.0.5.\n"
2462 "http://www.freetype.org\n");
2463 return FALSE;
2467 #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;}
2469 LOAD_FUNCPTR(FT_Vector_Unit)
2470 LOAD_FUNCPTR(FT_Done_Face)
2471 LOAD_FUNCPTR(FT_Get_Char_Index)
2472 LOAD_FUNCPTR(FT_Get_Module)
2473 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2474 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2475 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2476 LOAD_FUNCPTR(FT_Init_FreeType)
2477 LOAD_FUNCPTR(FT_Load_Glyph)
2478 LOAD_FUNCPTR(FT_Matrix_Multiply)
2479 LOAD_FUNCPTR(FT_MulFix)
2480 LOAD_FUNCPTR(FT_New_Face)
2481 LOAD_FUNCPTR(FT_New_Memory_Face)
2482 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2483 LOAD_FUNCPTR(FT_Outline_Transform)
2484 LOAD_FUNCPTR(FT_Outline_Translate)
2485 LOAD_FUNCPTR(FT_Select_Charmap)
2486 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2487 LOAD_FUNCPTR(FT_Vector_Transform)
2489 #undef LOAD_FUNCPTR
2490 /* Don't warn if this one is missing */
2491 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2492 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2493 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2494 pFT_Get_Next_Char = wine_dlsym(ft_handle,"FT_Get_Next_Char", NULL, 0);
2495 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2496 #ifdef HAVE_FREETYPE_FTWINFNT_H
2497 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2498 #endif
2499 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2500 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2501 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2502 <= 2.0.3 has FT_Sqrt64 */
2503 goto sym_not_found;
2506 if(pFT_Init_FreeType(&library) != 0) {
2507 ERR("Can't init FreeType library\n");
2508 wine_dlclose(ft_handle, NULL, 0);
2509 ft_handle = NULL;
2510 return FALSE;
2512 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2513 if (pFT_Library_Version)
2515 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2517 if (FT_Version.major<=0)
2519 FT_Version.major=2;
2520 FT_Version.minor=0;
2521 FT_Version.patch=5;
2523 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2524 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2525 ((FT_Version.minor << 8) & 0x00ff00) |
2526 ((FT_Version.patch ) & 0x0000ff);
2528 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2529 ERR("Failed to create font mutex\n");
2530 return FALSE;
2532 WaitForSingleObject(font_mutex, INFINITE);
2534 create_font_cache_key(&hkey_font_cache, &disposition);
2536 if(disposition == REG_CREATED_NEW_KEY)
2538 delete_external_font_keys();
2539 init_font_list();
2541 else
2542 load_font_list_from_cache(hkey_font_cache);
2544 RegCloseKey(hkey_font_cache);
2546 reorder_font_list();
2548 DumpFontList();
2549 LoadSubstList();
2550 DumpSubstList();
2552 if(!GetEnvironmentVariableW(cx_hack_var, env_buf, sizeof(env_buf)/sizeof(WCHAR)))
2553 LoadReplaceList();
2555 if(disposition == REG_CREATED_NEW_KEY)
2556 update_reg_entries();
2558 init_system_links();
2560 ReleaseMutex(font_mutex);
2561 return TRUE;
2562 sym_not_found:
2563 WINE_MESSAGE(
2564 "Wine cannot find certain functions that it needs inside the FreeType\n"
2565 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2566 "FreeType to at least version 2.0.5.\n"
2567 "http://www.freetype.org\n");
2568 wine_dlclose(ft_handle, NULL, 0);
2569 ft_handle = NULL;
2570 return FALSE;
2574 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2576 TT_OS2 *pOS2;
2577 TT_HoriHeader *pHori;
2579 LONG ppem;
2581 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2582 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2584 if(height == 0) height = 16;
2586 /* Calc. height of EM square:
2588 * For +ve lfHeight we have
2589 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2590 * Re-arranging gives:
2591 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2593 * For -ve lfHeight we have
2594 * |lfHeight| = ppem
2595 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2596 * with il = winAscent + winDescent - units_per_em]
2600 if(height > 0) {
2601 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2602 ppem = ft_face->units_per_EM * height /
2603 (pHori->Ascender - pHori->Descender);
2604 else
2605 ppem = ft_face->units_per_EM * height /
2606 (pOS2->usWinAscent + pOS2->usWinDescent);
2608 else
2609 ppem = -height;
2611 return ppem;
2614 static struct font_mapping *map_font( const char *name )
2616 struct font_mapping *mapping;
2617 struct stat st;
2618 int fd;
2620 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2621 if (fstat( fd, &st ) == -1) goto error;
2623 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2625 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2627 mapping->refcount++;
2628 close( fd );
2629 return mapping;
2632 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2633 goto error;
2635 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2636 close( fd );
2638 if (mapping->data == MAP_FAILED)
2640 HeapFree( GetProcessHeap(), 0, mapping );
2641 return NULL;
2643 mapping->refcount = 1;
2644 mapping->dev = st.st_dev;
2645 mapping->ino = st.st_ino;
2646 mapping->size = st.st_size;
2647 list_add_tail( &mappings_list, &mapping->entry );
2648 return mapping;
2650 error:
2651 close( fd );
2652 return NULL;
2655 static void unmap_font( struct font_mapping *mapping )
2657 if (!--mapping->refcount)
2659 list_remove( &mapping->entry );
2660 munmap( mapping->data, mapping->size );
2661 HeapFree( GetProcessHeap(), 0, mapping );
2665 static LONG load_VDMX(GdiFont*, LONG);
2667 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2669 FT_Error err;
2670 FT_Face ft_face;
2672 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2674 if (!(font->mapping = map_font( file )))
2676 WARN("failed to map %s\n", debugstr_a(file));
2677 return 0;
2680 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2681 if(err) {
2682 ERR("FT_New_Face rets %d\n", err);
2683 return 0;
2686 /* set it here, as load_VDMX needs it */
2687 font->ft_face = ft_face;
2689 if(FT_IS_SCALABLE(ft_face)) {
2690 /* load the VDMX table if we have one */
2691 font->ppem = load_VDMX(font, height);
2692 if(font->ppem == 0)
2693 font->ppem = calc_ppem_for_height(ft_face, height);
2695 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2696 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2697 } else {
2698 font->ppem = height;
2699 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2700 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2702 return ft_face;
2706 static int get_nearest_charset(Face *face, int *cp)
2708 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2709 a single face with the requested charset. The idea is to check if
2710 the selected font supports the current ANSI codepage, if it does
2711 return the corresponding charset, else return the first charset */
2713 CHARSETINFO csi;
2714 int acp = GetACP(), i;
2715 DWORD fs0;
2717 *cp = acp;
2718 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2719 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2720 return csi.ciCharset;
2722 for(i = 0; i < 32; i++) {
2723 fs0 = 1L << i;
2724 if(face->fs.fsCsb[0] & fs0) {
2725 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2726 *cp = csi.ciACP;
2727 return csi.ciCharset;
2729 else
2730 FIXME("TCI failing on %x\n", fs0);
2734 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2735 face->fs.fsCsb[0], face->file);
2736 *cp = acp;
2737 return DEFAULT_CHARSET;
2740 static GdiFont *alloc_font(void)
2742 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2743 ret->gmsize = INIT_GM_SIZE;
2744 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2745 ret->gmsize * sizeof(*ret->gm));
2746 ret->potm = NULL;
2747 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2748 ret->total_kern_pairs = (DWORD)-1;
2749 ret->kern_pairs = NULL;
2750 list_init(&ret->hfontlist);
2751 list_init(&ret->child_fonts);
2752 return ret;
2755 static void free_font(GdiFont *font)
2757 struct list *cursor, *cursor2;
2759 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2761 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2762 struct list *first_hfont;
2763 HFONTLIST *hfontlist;
2764 list_remove(cursor);
2765 if(child->font)
2767 first_hfont = list_head(&child->font->hfontlist);
2768 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2769 DeleteObject(hfontlist->hfont);
2770 HeapFree(GetProcessHeap(), 0, hfontlist);
2771 free_font(child->font);
2773 HeapFree(GetProcessHeap(), 0, child->file_name);
2774 HeapFree(GetProcessHeap(), 0, child);
2777 if (font->ft_face) pFT_Done_Face(font->ft_face);
2778 if (font->mapping) unmap_font( font->mapping );
2779 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2780 HeapFree(GetProcessHeap(), 0, font->potm);
2781 HeapFree(GetProcessHeap(), 0, font->name);
2782 HeapFree(GetProcessHeap(), 0, font->gm);
2783 HeapFree(GetProcessHeap(), 0, font);
2787 /*************************************************************
2788 * load_VDMX
2790 * load the vdmx entry for the specified height
2793 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2794 ( ( (FT_ULong)_x4 << 24 ) | \
2795 ( (FT_ULong)_x3 << 16 ) | \
2796 ( (FT_ULong)_x2 << 8 ) | \
2797 (FT_ULong)_x1 )
2799 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2801 typedef struct {
2802 BYTE bCharSet;
2803 BYTE xRatio;
2804 BYTE yStartRatio;
2805 BYTE yEndRatio;
2806 } Ratios;
2808 typedef struct {
2809 WORD recs;
2810 BYTE startsz;
2811 BYTE endsz;
2812 } VDMX_group;
2814 static LONG load_VDMX(GdiFont *font, LONG height)
2816 WORD hdr[3], tmp;
2817 VDMX_group group;
2818 BYTE devXRatio, devYRatio;
2819 USHORT numRecs, numRatios;
2820 DWORD result, offset = -1;
2821 LONG ppem = 0;
2822 int i;
2824 /* For documentation on VDMX records, see
2825 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2828 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2830 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2831 return ppem;
2833 /* FIXME: need the real device aspect ratio */
2834 devXRatio = 1;
2835 devYRatio = 1;
2837 numRecs = GET_BE_WORD(hdr[1]);
2838 numRatios = GET_BE_WORD(hdr[2]);
2840 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2841 for(i = 0; i < numRatios; i++) {
2842 Ratios ratio;
2844 offset = (3 * 2) + (i * sizeof(Ratios));
2845 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2846 offset = -1;
2848 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2850 if((ratio.xRatio == 0 &&
2851 ratio.yStartRatio == 0 &&
2852 ratio.yEndRatio == 0) ||
2853 (devXRatio == ratio.xRatio &&
2854 devYRatio >= ratio.yStartRatio &&
2855 devYRatio <= ratio.yEndRatio))
2857 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2858 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2859 offset = GET_BE_WORD(tmp);
2860 break;
2864 if(offset == -1) {
2865 FIXME("No suitable ratio found\n");
2866 return ppem;
2869 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2870 USHORT recs;
2871 BYTE startsz, endsz;
2872 WORD *vTable;
2874 recs = GET_BE_WORD(group.recs);
2875 startsz = group.startsz;
2876 endsz = group.endsz;
2878 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2880 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2881 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2882 if(result == GDI_ERROR) {
2883 FIXME("Failed to retrieve vTable\n");
2884 goto end;
2887 if(height > 0) {
2888 for(i = 0; i < recs; i++) {
2889 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2890 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2891 ppem = GET_BE_WORD(vTable[i * 3]);
2893 if(yMax + -yMin == height) {
2894 font->yMax = yMax;
2895 font->yMin = yMin;
2896 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2897 break;
2899 if(yMax + -yMin > height) {
2900 if(--i < 0) {
2901 ppem = 0;
2902 goto end; /* failed */
2904 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2905 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2906 ppem = GET_BE_WORD(vTable[i * 3]);
2907 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2908 break;
2911 if(!font->yMax) {
2912 ppem = 0;
2913 TRACE("ppem not found for height %d\n", height);
2915 } else {
2916 ppem = -height;
2917 if(ppem < startsz || ppem > endsz)
2918 goto end;
2920 for(i = 0; i < recs; i++) {
2921 USHORT yPelHeight;
2922 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2924 if(yPelHeight > ppem)
2925 break; /* failed */
2927 if(yPelHeight == ppem) {
2928 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2929 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2930 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2931 break;
2935 end:
2936 HeapFree(GetProcessHeap(), 0, vTable);
2939 return ppem;
2942 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2944 if(font->font_desc.hash != fd->hash) return TRUE;
2945 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2946 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2947 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2948 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2951 static void calc_hash(FONT_DESC *pfd)
2953 DWORD hash = 0, *ptr, two_chars;
2954 WORD *pwc;
2955 unsigned int i;
2957 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2958 hash ^= *ptr;
2959 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2960 hash ^= *ptr;
2961 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2962 two_chars = *ptr;
2963 pwc = (WCHAR *)&two_chars;
2964 if(!*pwc) break;
2965 *pwc = toupperW(*pwc);
2966 pwc++;
2967 *pwc = toupperW(*pwc);
2968 hash ^= two_chars;
2969 if(!*pwc) break;
2971 hash ^= !pfd->can_use_bitmap;
2972 pfd->hash = hash;
2973 return;
2976 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2978 GdiFont *ret;
2979 FONT_DESC fd;
2980 HFONTLIST *hflist;
2981 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2983 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2984 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2985 fd.can_use_bitmap = can_use_bitmap;
2986 calc_hash(&fd);
2988 /* try the in-use list */
2989 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2990 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2991 if(!fontcmp(ret, &fd)) {
2992 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2993 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2994 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2995 if(hflist->hfont == hfont)
2996 return ret;
2998 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2999 hflist->hfont = hfont;
3000 list_add_head(&ret->hfontlist, &hflist->entry);
3001 return ret;
3005 /* then the unused list */
3006 font_elem_ptr = list_head(&unused_gdi_font_list);
3007 while(font_elem_ptr) {
3008 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3009 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3010 if(!fontcmp(ret, &fd)) {
3011 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3012 assert(list_empty(&ret->hfontlist));
3013 TRACE("Found %p in unused list\n", ret);
3014 list_remove(&ret->entry);
3015 list_add_head(&gdi_font_list, &ret->entry);
3016 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3017 hflist->hfont = hfont;
3018 list_add_head(&ret->hfontlist, &hflist->entry);
3019 return ret;
3022 return NULL;
3026 /*************************************************************
3027 * create_child_font_list
3029 static BOOL create_child_font_list(GdiFont *font)
3031 BOOL ret = FALSE;
3032 SYSTEM_LINKS *font_link;
3033 CHILD_FONT *font_link_entry, *new_child;
3035 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3037 if(!strcmpW(font_link->font_name, font->name))
3039 TRACE("found entry in system list\n");
3040 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3042 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3043 new_child->file_name = strdupA(font_link_entry->file_name);
3044 new_child->index = font_link_entry->index;
3045 new_child->font = NULL;
3046 list_add_tail(&font->child_fonts, &new_child->entry);
3047 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
3049 ret = TRUE;
3050 break;
3054 return ret;
3057 /*************************************************************
3058 * WineEngCreateFontInstance
3061 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3063 GdiFont *ret;
3064 Face *face, *best, *best_bitmap;
3065 Family *family, *last_resort_family;
3066 struct list *family_elem_ptr, *face_elem_ptr;
3067 INT height, width = 0;
3068 unsigned int score = 0, new_score;
3069 signed int diff = 0, newdiff;
3070 BOOL bd, it, can_use_bitmap;
3071 LOGFONTW lf;
3072 CHARSETINFO csi;
3073 HFONTLIST *hflist;
3075 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3077 struct list *first_hfont = list_head(&ret->hfontlist);
3078 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3079 if(hflist->hfont == hfont)
3080 return ret;
3083 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3084 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3086 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3087 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3088 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3089 lf.lfEscapement);
3091 /* check the cache first */
3092 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3093 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3094 return ret;
3097 TRACE("not in cache\n");
3098 if(list_empty(&font_list)) /* No fonts installed */
3100 TRACE("No fonts installed\n");
3101 return NULL;
3103 if(!have_installed_roman_font)
3105 TRACE("No roman font installed\n");
3106 return NULL;
3109 ret = alloc_font();
3111 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3112 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
3113 ret->font_desc.can_use_bitmap = can_use_bitmap;
3114 calc_hash(&ret->font_desc);
3115 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3116 hflist->hfont = hfont;
3117 list_add_head(&ret->hfontlist, &hflist->entry);
3120 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3121 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3122 original value lfCharSet. Note this is a special case for
3123 Symbol and doesn't happen at least for "Wingdings*" */
3125 if(!strcmpiW(lf.lfFaceName, SymbolW))
3126 lf.lfCharSet = SYMBOL_CHARSET;
3128 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3129 switch(lf.lfCharSet) {
3130 case DEFAULT_CHARSET:
3131 csi.fs.fsCsb[0] = 0;
3132 break;
3133 default:
3134 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3135 csi.fs.fsCsb[0] = 0;
3136 break;
3140 family = NULL;
3141 if(lf.lfFaceName[0] != '\0') {
3142 FontSubst *psub;
3143 SYSTEM_LINKS *font_link;
3144 CHILD_FONT *font_link_entry;
3146 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
3148 if(psub) {
3149 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
3150 debugstr_w(psub->to.name));
3151 strcpyW(lf.lfFaceName, psub->to.name);
3154 /* We want a match on name and charset or just name if
3155 charset was DEFAULT_CHARSET. If the latter then
3156 we fixup the returned charset later in get_nearest_charset
3157 where we'll either use the charset of the current ansi codepage
3158 or if that's unavailable the first charset that the font supports.
3160 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3161 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3162 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3163 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3164 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3165 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3166 if(face->scalable || can_use_bitmap)
3167 goto found;
3173 * Try check the SystemLink list first for a replacement font.
3174 * We may find good replacements there.
3176 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3178 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
3180 TRACE("found entry in system list\n");
3181 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3183 face = find_face_from_path_index(font_link_entry->file_name,
3184 font_link_entry->index);
3185 if (face)
3187 family = face->family;
3188 if(csi.fs.fsCsb[0] &
3189 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3191 if(face->scalable || can_use_bitmap)
3192 goto found;
3200 /* If requested charset was DEFAULT_CHARSET then try using charset
3201 corresponding to the current ansi codepage */
3202 if(!csi.fs.fsCsb[0]) {
3203 INT acp = GetACP();
3204 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3205 FIXME("TCI failed on codepage %d\n", acp);
3206 csi.fs.fsCsb[0] = 0;
3207 } else
3208 lf.lfCharSet = csi.ciCharset;
3211 /* Face families are in the top 4 bits of lfPitchAndFamily,
3212 so mask with 0xF0 before testing */
3214 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3215 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3216 strcpyW(lf.lfFaceName, defFixed);
3217 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3218 strcpyW(lf.lfFaceName, defSerif);
3219 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3220 strcpyW(lf.lfFaceName, defSans);
3221 else
3222 strcpyW(lf.lfFaceName, defSans);
3223 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3224 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3225 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3226 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3227 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3228 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3229 if(face->scalable || can_use_bitmap)
3230 goto found;
3235 last_resort_family = NULL;
3236 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3237 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3238 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3239 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3240 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3241 if(face->scalable)
3242 goto found;
3243 if(can_use_bitmap && !last_resort_family)
3244 last_resort_family = family;
3249 if(last_resort_family) {
3250 family = last_resort_family;
3251 csi.fs.fsCsb[0] = 0;
3252 goto found;
3255 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3256 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3257 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3258 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3259 if(face->scalable) {
3260 csi.fs.fsCsb[0] = 0;
3261 WARN("just using first face for now\n");
3262 goto found;
3264 if(can_use_bitmap && !last_resort_family)
3265 last_resort_family = family;
3268 if(!last_resort_family) {
3269 FIXME("can't find a single appropriate font - bailing\n");
3270 free_font(ret);
3271 return NULL;
3274 WARN("could only find a bitmap font - this will probably look awful!\n");
3275 family = last_resort_family;
3276 csi.fs.fsCsb[0] = 0;
3278 found:
3279 it = lf.lfItalic ? 1 : 0;
3280 bd = lf.lfWeight > 550 ? 1 : 0;
3282 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3283 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3285 face = best = best_bitmap = NULL;
3286 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3288 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3290 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3291 if(!best || new_score <= score)
3293 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3294 face->Italic, face->Bold, it, bd);
3295 score = new_score;
3296 best = face;
3297 if(best->scalable && score == 0) break;
3298 if(!best->scalable)
3300 if(height > 0)
3301 newdiff = height - (signed int)(best->size.height);
3302 else
3303 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3304 if(!best_bitmap || new_score < score ||
3305 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3307 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3308 diff = newdiff;
3309 best_bitmap = best;
3310 if(score == 0 && diff == 0) break;
3316 if(best)
3317 face = best->scalable ? best : best_bitmap;
3318 ret->fake_italic = (it && !face->Italic);
3319 ret->fake_bold = (bd && !face->Bold);
3321 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3323 if(csi.fs.fsCsb[0]) {
3324 ret->charset = lf.lfCharSet;
3325 ret->codepage = csi.ciACP;
3327 else
3328 ret->charset = get_nearest_charset(face, &ret->codepage);
3330 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
3331 debugstr_w(face->StyleName), face->file, face->face_index);
3333 if(!face->scalable) {
3334 width = face->size.x_ppem >> 6;
3335 height = face->size.y_ppem >> 6;
3337 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
3339 if (!ret->ft_face)
3341 free_font( ret );
3342 return 0;
3345 if (ret->charset == SYMBOL_CHARSET &&
3346 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3347 /* No ops */
3349 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3350 /* No ops */
3352 else {
3353 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3356 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3357 ret->name = strdupW(family->FamilyName);
3358 ret->underline = lf.lfUnderline ? 0xff : 0;
3359 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3360 create_child_font_list(ret);
3362 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3364 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
3365 list_add_head(&gdi_font_list, &ret->entry);
3366 return ret;
3369 static void dump_gdi_font_list(void)
3371 GdiFont *gdiFont;
3372 struct list *elem_ptr;
3374 TRACE("---------- gdiFont Cache ----------\n");
3375 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3376 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3377 TRACE("gdiFont=%p %s %d\n",
3378 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3381 TRACE("---------- Unused gdiFont Cache ----------\n");
3382 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3383 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3384 TRACE("gdiFont=%p %s %d\n",
3385 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3389 /*************************************************************
3390 * WineEngDestroyFontInstance
3392 * free the gdiFont associated with this handle
3395 BOOL WineEngDestroyFontInstance(HFONT handle)
3397 GdiFont *gdiFont;
3398 HFONTLIST *hflist;
3399 BOOL ret = FALSE;
3400 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3401 int i = 0;
3403 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3405 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3406 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3407 if(hflist->hfont == handle)
3409 TRACE("removing child font %p from child list\n", gdiFont);
3410 list_remove(&gdiFont->entry);
3411 return TRUE;
3415 TRACE("destroying hfont=%p\n", handle);
3416 if(TRACE_ON(font))
3417 dump_gdi_font_list();
3419 font_elem_ptr = list_head(&gdi_font_list);
3420 while(font_elem_ptr) {
3421 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3422 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3424 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3425 while(hfontlist_elem_ptr) {
3426 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3427 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3428 if(hflist->hfont == handle) {
3429 list_remove(&hflist->entry);
3430 HeapFree(GetProcessHeap(), 0, hflist);
3431 ret = TRUE;
3434 if(list_empty(&gdiFont->hfontlist)) {
3435 TRACE("Moving to Unused list\n");
3436 list_remove(&gdiFont->entry);
3437 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3442 font_elem_ptr = list_head(&unused_gdi_font_list);
3443 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3444 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3445 while(font_elem_ptr) {
3446 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3447 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3448 TRACE("freeing %p\n", gdiFont);
3449 list_remove(&gdiFont->entry);
3450 free_font(gdiFont);
3452 return ret;
3455 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3456 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3458 OUTLINETEXTMETRICW *potm = NULL;
3459 UINT size;
3460 TEXTMETRICW tm, *ptm;
3461 GdiFont *font = alloc_font();
3462 LONG width, height;
3464 if (face->cache_valid)
3466 TRACE("Cached\n");
3467 memcpy(pelf,&face->elf,sizeof(ENUMLOGFONTEXW));
3468 memcpy(pntm,&face->ntm,sizeof(NEWTEXTMETRICEXW));
3469 *ptype = face->type;
3470 return;
3473 if(face->scalable) {
3474 height = 100;
3475 width = 0;
3476 } else {
3477 height = face->size.y_ppem >> 6;
3478 width = face->size.x_ppem >> 6;
3481 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3483 free_font(font);
3484 return;
3487 font->name = strdupW(face->family->FamilyName);
3489 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3491 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3492 if(size) {
3493 potm = HeapAlloc(GetProcessHeap(), 0, size);
3494 WineEngGetOutlineTextMetrics(font, size, potm);
3495 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3496 } else {
3497 WineEngGetTextMetrics(font, &tm);
3498 ptm = &tm;
3501 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3502 pntm->ntmTm.tmAscent = ptm->tmAscent;
3503 pntm->ntmTm.tmDescent = ptm->tmDescent;
3504 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3505 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3506 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3507 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3508 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3509 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3510 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3511 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3512 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3513 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3514 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3515 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3516 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3517 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3518 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3519 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3520 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3521 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3522 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3523 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3524 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3526 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3527 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3528 *ptype |= RASTER_FONTTYPE;
3530 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3531 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3532 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3534 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3535 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3536 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3538 if(potm) {
3539 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3541 lstrcpynW(pelf->elfLogFont.lfFaceName,
3542 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3543 LF_FACESIZE);
3544 lstrcpynW(pelf->elfFullName,
3545 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3546 LF_FULLFACESIZE);
3547 lstrcpynW(pelf->elfStyle,
3548 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3549 LF_FACESIZE);
3551 HeapFree(GetProcessHeap(), 0, potm);
3552 } else {
3553 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3555 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3556 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3557 pelf->elfStyle[0] = '\0';
3560 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3562 memcpy(&face->elf,pelf,sizeof(ENUMLOGFONTEXW));
3563 memcpy(&face->ntm,pntm,sizeof(NEWTEXTMETRICEXW));
3564 face->type = *ptype;
3565 face->cache_valid = TRUE;
3567 free_font(font);
3570 /*************************************************************
3571 * WineEngEnumFonts
3574 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3576 Family *family;
3577 Face *face;
3578 struct list *family_elem_ptr, *face_elem_ptr;
3579 ENUMLOGFONTEXW elf;
3580 NEWTEXTMETRICEXW ntm;
3581 DWORD type, ret = 1;
3582 FONTSIGNATURE fs;
3583 CHARSETINFO csi;
3584 LOGFONTW lf;
3585 int i;
3587 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3589 if(plf->lfFaceName[0]) {
3590 FontSubst *psub;
3591 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3593 if(psub) {
3594 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3595 debugstr_w(psub->to.name));
3596 memcpy(&lf, plf, sizeof(lf));
3597 strcpyW(lf.lfFaceName, psub->to.name);
3598 plf = &lf;
3601 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3602 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3603 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3604 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3605 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3606 GetEnumStructs(face, &elf, &ntm, &type);
3607 for(i = 0; i < 32; i++) {
3608 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3609 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3610 strcpyW(elf.elfScript, OEM_DOSW);
3611 i = 32; /* break out of loop */
3612 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3613 continue;
3614 else {
3615 fs.fsCsb[0] = 1L << i;
3616 fs.fsCsb[1] = 0;
3617 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3618 TCI_SRCFONTSIG))
3619 csi.ciCharset = DEFAULT_CHARSET;
3620 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3621 if(csi.ciCharset != DEFAULT_CHARSET) {
3622 elf.elfLogFont.lfCharSet =
3623 ntm.ntmTm.tmCharSet = csi.ciCharset;
3624 if(ElfScriptsW[i])
3625 strcpyW(elf.elfScript, ElfScriptsW[i]);
3626 else
3627 FIXME("Unknown elfscript for bit %d\n", i);
3630 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3631 debugstr_w(elf.elfLogFont.lfFaceName),
3632 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3633 csi.ciCharset, type, debugstr_w(elf.elfScript),
3634 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3635 ntm.ntmTm.ntmFlags);
3636 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3637 if(!ret) goto end;
3642 } else {
3643 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3644 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3645 face_elem_ptr = list_head(&family->faces);
3646 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3647 GetEnumStructs(face, &elf, &ntm, &type);
3648 for(i = 0; i < 32; i++) {
3649 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3650 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3651 strcpyW(elf.elfScript, OEM_DOSW);
3652 i = 32; /* break out of loop */
3653 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3654 continue;
3655 else {
3656 fs.fsCsb[0] = 1L << i;
3657 fs.fsCsb[1] = 0;
3658 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3659 TCI_SRCFONTSIG))
3660 csi.ciCharset = DEFAULT_CHARSET;
3661 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3662 if(csi.ciCharset != DEFAULT_CHARSET) {
3663 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3664 csi.ciCharset;
3665 if(ElfScriptsW[i])
3666 strcpyW(elf.elfScript, ElfScriptsW[i]);
3667 else
3668 FIXME("Unknown elfscript for bit %d\n", i);
3671 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3672 debugstr_w(elf.elfLogFont.lfFaceName),
3673 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3674 csi.ciCharset, type, debugstr_w(elf.elfScript),
3675 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3676 ntm.ntmTm.ntmFlags);
3677 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3678 if(!ret) goto end;
3682 end:
3683 return ret;
3686 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3688 pt->x.value = vec->x >> 6;
3689 pt->x.fract = (vec->x & 0x3f) << 10;
3690 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3691 pt->y.value = vec->y >> 6;
3692 pt->y.fract = (vec->y & 0x3f) << 10;
3693 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3694 return;
3697 /***************************************************
3698 * According to the MSDN documentation on WideCharToMultiByte,
3699 * certain codepages cannot set the default_used parameter.
3700 * This returns TRUE if the codepage can set that parameter, false else
3701 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3703 static BOOL codepage_sets_default_used(UINT codepage)
3705 switch (codepage)
3707 case CP_UTF7:
3708 case CP_UTF8:
3709 case CP_SYMBOL:
3710 return FALSE;
3711 default:
3712 return TRUE;
3716 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3718 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3719 WCHAR wc = (WCHAR)glyph;
3720 BOOL default_used;
3721 BOOL *default_used_pointer;
3722 FT_UInt ret;
3723 char buf;
3724 default_used_pointer = NULL;
3725 default_used = FALSE;
3726 if (codepage_sets_default_used(font->codepage))
3727 default_used_pointer = &default_used;
3728 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3729 ret = 0;
3730 else
3731 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3732 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3733 return ret;
3736 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3737 glyph = glyph + 0xf000;
3738 return pFT_Get_Char_Index(font->ft_face, glyph);
3741 /*************************************************************
3742 * WineEngGetGlyphIndices
3744 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3746 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3747 LPWORD pgi, DWORD flags)
3749 int i;
3750 WCHAR default_char = 0;
3751 TEXTMETRICW textm;
3753 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3755 for(i = 0; i < count; i++)
3757 pgi[i] = get_glyph_index(font, lpstr[i]);
3758 if (pgi[i] == 0)
3760 if (!default_char)
3762 WineEngGetTextMetrics(font, &textm);
3763 default_char = textm.tmDefaultChar;
3765 pgi[i] = default_char;
3768 return count;
3771 /*************************************************************
3772 * WineEngGetGlyphOutline
3774 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3775 * except that the first parameter is the HWINEENGFONT of the font in
3776 * question rather than an HDC.
3779 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
3780 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3781 const MAT2* lpmat)
3783 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3784 FT_Face ft_face = font->ft_face;
3785 FT_UInt glyph_index;
3786 DWORD width, height, pitch, needed = 0;
3787 FT_Bitmap ft_bitmap;
3788 FT_Error err;
3789 INT left, right, top = 0, bottom = 0;
3790 FT_Angle angle = 0;
3791 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH |
3792 FT_LOAD_NO_AUTOHINT;
3793 float widthRatio = 1.0;
3794 FT_Matrix transMat = identityMat;
3795 BOOL needsTransform = FALSE;
3798 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3799 buflen, buf, lpmat);
3801 if(format & GGO_GLYPH_INDEX) {
3802 glyph_index = glyph;
3803 format &= ~GGO_GLYPH_INDEX;
3804 } else
3805 glyph_index = get_glyph_index(font, glyph);
3807 if(glyph_index >= font->gmsize) {
3808 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3809 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3810 font->gmsize * sizeof(*font->gm));
3811 } else {
3812 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3813 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3814 return 1; /* FIXME */
3818 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3819 load_flags |= FT_LOAD_NO_BITMAP;
3821 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3823 if(err) {
3824 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3825 return GDI_ERROR;
3828 /* Scaling factor */
3829 if (font->aveWidth && font->potm) {
3830 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3833 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3834 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3836 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3837 font->gm[glyph_index].lsb = left >> 6;
3838 font->gm[glyph_index].bbx = (right - left) >> 6;
3840 /* Scaling transform */
3841 if(font->aveWidth) {
3842 FT_Matrix scaleMat;
3843 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3844 scaleMat.xy = 0;
3845 scaleMat.yx = 0;
3846 scaleMat.yy = (1 << 16);
3848 pFT_Matrix_Multiply(&scaleMat, &transMat);
3849 needsTransform = TRUE;
3852 /* Slant transform */
3853 if (font->fake_italic) {
3854 FT_Matrix slantMat;
3856 slantMat.xx = (1 << 16);
3857 slantMat.xy = ((1 << 16) >> 2);
3858 slantMat.yx = 0;
3859 slantMat.yy = (1 << 16);
3860 pFT_Matrix_Multiply(&slantMat, &transMat);
3861 needsTransform = TRUE;
3864 /* Rotation transform */
3865 if(font->orientation) {
3866 FT_Matrix rotationMat;
3867 FT_Vector vecAngle;
3868 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3869 pFT_Vector_Unit(&vecAngle, angle);
3870 rotationMat.xx = vecAngle.x;
3871 rotationMat.xy = -vecAngle.y;
3872 rotationMat.yx = -rotationMat.xy;
3873 rotationMat.yy = rotationMat.xx;
3875 pFT_Matrix_Multiply(&rotationMat, &transMat);
3876 needsTransform = TRUE;
3879 /* Extra transformation specified by caller */
3880 if (lpmat) {
3881 FT_Matrix extraMat;
3882 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3883 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3884 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3885 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3886 pFT_Matrix_Multiply(&extraMat, &transMat);
3887 needsTransform = TRUE;
3890 if(!needsTransform) {
3891 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3892 bottom = (ft_face->glyph->metrics.horiBearingY -
3893 ft_face->glyph->metrics.height) & -64;
3894 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3895 lpgm->gmCellIncY = 0;
3896 } else {
3897 INT xc, yc;
3898 FT_Vector vec;
3899 for(xc = 0; xc < 2; xc++) {
3900 for(yc = 0; yc < 2; yc++) {
3901 vec.x = (ft_face->glyph->metrics.horiBearingX +
3902 xc * ft_face->glyph->metrics.width);
3903 vec.y = ft_face->glyph->metrics.horiBearingY -
3904 yc * ft_face->glyph->metrics.height;
3905 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3906 pFT_Vector_Transform(&vec, &transMat);
3907 if(xc == 0 && yc == 0) {
3908 left = right = vec.x;
3909 top = bottom = vec.y;
3910 } else {
3911 if(vec.x < left) left = vec.x;
3912 else if(vec.x > right) right = vec.x;
3913 if(vec.y < bottom) bottom = vec.y;
3914 else if(vec.y > top) top = vec.y;
3918 left = left & -64;
3919 right = (right + 63) & -64;
3920 bottom = bottom & -64;
3921 top = (top + 63) & -64;
3923 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3924 vec.x = ft_face->glyph->metrics.horiAdvance;
3925 vec.y = 0;
3926 pFT_Vector_Transform(&vec, &transMat);
3927 lpgm->gmCellIncX = (vec.x+63) >> 6;
3928 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3930 lpgm->gmBlackBoxX = (right - left) >> 6;
3931 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3932 lpgm->gmptGlyphOrigin.x = left >> 6;
3933 lpgm->gmptGlyphOrigin.y = top >> 6;
3935 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3936 font->gm[glyph_index].init = TRUE;
3938 if(format == GGO_METRICS)
3939 return 1; /* FIXME */
3941 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3942 TRACE("loaded a bitmap\n");
3943 return GDI_ERROR;
3946 switch(format) {
3947 case GGO_BITMAP:
3948 width = lpgm->gmBlackBoxX;
3949 height = lpgm->gmBlackBoxY;
3950 pitch = ((width + 31) >> 5) << 2;
3951 needed = pitch * height;
3953 if(!buf || !buflen) break;
3955 switch(ft_face->glyph->format) {
3956 case ft_glyph_format_bitmap:
3958 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3959 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3960 INT h = ft_face->glyph->bitmap.rows;
3961 while(h--) {
3962 memcpy(dst, src, w);
3963 src += ft_face->glyph->bitmap.pitch;
3964 dst += pitch;
3966 break;
3969 case ft_glyph_format_outline:
3970 ft_bitmap.width = width;
3971 ft_bitmap.rows = height;
3972 ft_bitmap.pitch = pitch;
3973 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3974 ft_bitmap.buffer = buf;
3976 if(needsTransform) {
3977 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3980 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3982 /* Note: FreeType will only set 'black' bits for us. */
3983 memset(buf, 0, needed);
3984 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3985 break;
3987 default:
3988 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3989 return GDI_ERROR;
3991 break;
3993 case GGO_GRAY2_BITMAP:
3994 case GGO_GRAY4_BITMAP:
3995 case GGO_GRAY8_BITMAP:
3996 case WINE_GGO_GRAY16_BITMAP:
3998 unsigned int mult, row, col;
3999 BYTE *start, *ptr;
4001 /****************** CodeWeavers hack to fix HL2 crash **************************
4003 * Both glyphs 0x2e and 0x39 of this font get rendered to a larger
4004 * size with FreeType than under Windows, and HL2 uses a fixed size
4005 * buffer on the stack to copy the data into. For now we'll clip glyphs
4006 * from that font into a rather smaller BBox
4008 ******************************************************************************/
4009 if(!strcmp(ft_face->family_name, "HL2MP") ||
4010 !strcmp(ft_face->family_name, "csd"))
4012 int i;
4013 if(lpgm->gmBlackBoxX)
4014 lpgm->gmBlackBoxX--;
4016 for(i = 0; i < 2; i++)
4018 if(lpgm->gmBlackBoxY)
4020 lpgm->gmBlackBoxY--;
4021 lpgm->gmptGlyphOrigin.y--;
4025 /*********************************** End CW's hack ****************************/
4027 width = lpgm->gmBlackBoxX;
4028 height = lpgm->gmBlackBoxY;
4029 pitch = (width + 3) / 4 * 4;
4030 needed = pitch * height;
4032 if(!buf || !buflen) break;
4033 ft_bitmap.width = width;
4034 ft_bitmap.rows = height;
4035 ft_bitmap.pitch = pitch;
4036 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4037 ft_bitmap.buffer = buf;
4039 if(needsTransform) {
4040 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4043 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4045 memset(ft_bitmap.buffer, 0, buflen);
4047 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4049 if(format == GGO_GRAY2_BITMAP)
4050 mult = 4;
4051 else if(format == GGO_GRAY4_BITMAP)
4052 mult = 16;
4053 else if(format == GGO_GRAY8_BITMAP)
4054 mult = 64;
4055 else if(format == WINE_GGO_GRAY16_BITMAP)
4056 break;
4057 else {
4058 assert(0);
4059 break;
4062 start = buf;
4063 for(row = 0; row < height; row++) {
4064 ptr = start;
4065 for(col = 0; col < width; col++, ptr++) {
4066 *ptr = (((int)*ptr) * mult + 128) / 256;
4068 start += pitch;
4070 break;
4073 case GGO_NATIVE:
4075 int contour, point = 0, first_pt;
4076 FT_Outline *outline = &ft_face->glyph->outline;
4077 TTPOLYGONHEADER *pph;
4078 TTPOLYCURVE *ppc;
4079 DWORD pph_start, cpfx, type;
4081 if(buflen == 0) buf = NULL;
4083 if (needsTransform && buf) {
4084 pFT_Outline_Transform(outline, &transMat);
4087 for(contour = 0; contour < outline->n_contours; contour++) {
4088 pph_start = needed;
4089 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4090 first_pt = point;
4091 if(buf) {
4092 pph->dwType = TT_POLYGON_TYPE;
4093 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4095 needed += sizeof(*pph);
4096 point++;
4097 while(point <= outline->contours[contour]) {
4098 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4099 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4100 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4101 cpfx = 0;
4102 do {
4103 if(buf)
4104 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4105 cpfx++;
4106 point++;
4107 } while(point <= outline->contours[contour] &&
4108 (outline->tags[point] & FT_Curve_Tag_On) ==
4109 (outline->tags[point-1] & FT_Curve_Tag_On));
4110 /* At the end of a contour Windows adds the start point, but
4111 only for Beziers */
4112 if(point > outline->contours[contour] &&
4113 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4114 if(buf)
4115 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4116 cpfx++;
4117 } else if(point <= outline->contours[contour] &&
4118 outline->tags[point] & FT_Curve_Tag_On) {
4119 /* add closing pt for bezier */
4120 if(buf)
4121 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4122 cpfx++;
4123 point++;
4125 if(buf) {
4126 ppc->wType = type;
4127 ppc->cpfx = cpfx;
4129 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4131 if(buf)
4132 pph->cb = needed - pph_start;
4134 break;
4136 case GGO_BEZIER:
4138 /* Convert the quadratic Beziers to cubic Beziers.
4139 The parametric eqn for a cubic Bezier is, from PLRM:
4140 r(t) = at^3 + bt^2 + ct + r0
4141 with the control points:
4142 r1 = r0 + c/3
4143 r2 = r1 + (c + b)/3
4144 r3 = r0 + c + b + a
4146 A quadratic Beizer has the form:
4147 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4149 So equating powers of t leads to:
4150 r1 = 2/3 p1 + 1/3 p0
4151 r2 = 2/3 p1 + 1/3 p2
4152 and of course r0 = p0, r3 = p2
4155 int contour, point = 0, first_pt;
4156 FT_Outline *outline = &ft_face->glyph->outline;
4157 TTPOLYGONHEADER *pph;
4158 TTPOLYCURVE *ppc;
4159 DWORD pph_start, cpfx, type;
4160 FT_Vector cubic_control[4];
4161 if(buflen == 0) buf = NULL;
4163 if (needsTransform && buf) {
4164 pFT_Outline_Transform(outline, &transMat);
4167 for(contour = 0; contour < outline->n_contours; contour++) {
4168 pph_start = needed;
4169 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4170 first_pt = point;
4171 if(buf) {
4172 pph->dwType = TT_POLYGON_TYPE;
4173 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4175 needed += sizeof(*pph);
4176 point++;
4177 while(point <= outline->contours[contour]) {
4178 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4179 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4180 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4181 cpfx = 0;
4182 do {
4183 if(type == TT_PRIM_LINE) {
4184 if(buf)
4185 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4186 cpfx++;
4187 point++;
4188 } else {
4189 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4190 so cpfx = 3n */
4192 /* FIXME: Possible optimization in endpoint calculation
4193 if there are two consecutive curves */
4194 cubic_control[0] = outline->points[point-1];
4195 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4196 cubic_control[0].x += outline->points[point].x + 1;
4197 cubic_control[0].y += outline->points[point].y + 1;
4198 cubic_control[0].x >>= 1;
4199 cubic_control[0].y >>= 1;
4201 if(point+1 > outline->contours[contour])
4202 cubic_control[3] = outline->points[first_pt];
4203 else {
4204 cubic_control[3] = outline->points[point+1];
4205 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4206 cubic_control[3].x += outline->points[point].x + 1;
4207 cubic_control[3].y += outline->points[point].y + 1;
4208 cubic_control[3].x >>= 1;
4209 cubic_control[3].y >>= 1;
4212 /* r1 = 1/3 p0 + 2/3 p1
4213 r2 = 1/3 p2 + 2/3 p1 */
4214 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4215 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4216 cubic_control[2] = cubic_control[1];
4217 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4218 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4219 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4220 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4221 if(buf) {
4222 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4223 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4224 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4226 cpfx += 3;
4227 point++;
4229 } while(point <= outline->contours[contour] &&
4230 (outline->tags[point] & FT_Curve_Tag_On) ==
4231 (outline->tags[point-1] & FT_Curve_Tag_On));
4232 /* At the end of a contour Windows adds the start point,
4233 but only for Beziers and we've already done that.
4235 if(point <= outline->contours[contour] &&
4236 outline->tags[point] & FT_Curve_Tag_On) {
4237 /* This is the closing pt of a bezier, but we've already
4238 added it, so just inc point and carry on */
4239 point++;
4241 if(buf) {
4242 ppc->wType = type;
4243 ppc->cpfx = cpfx;
4245 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4247 if(buf)
4248 pph->cb = needed - pph_start;
4250 break;
4253 default:
4254 FIXME("Unsupported format %d\n", format);
4255 return GDI_ERROR;
4257 return needed;
4260 static BOOL get_bitmap_text_metrics(GdiFont *font)
4262 FT_Face ft_face = font->ft_face;
4263 #ifdef HAVE_FREETYPE_FTWINFNT_H
4264 FT_WinFNT_HeaderRec winfnt_header;
4265 #endif
4266 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4267 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4268 font->potm->otmSize = size;
4270 #define TM font->potm->otmTextMetrics
4271 #ifdef HAVE_FREETYPE_FTWINFNT_H
4272 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4274 TM.tmHeight = winfnt_header.pixel_height;
4275 TM.tmAscent = winfnt_header.ascent;
4276 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4277 TM.tmInternalLeading = winfnt_header.internal_leading;
4278 TM.tmExternalLeading = winfnt_header.external_leading;
4279 TM.tmAveCharWidth = winfnt_header.avg_width;
4280 TM.tmMaxCharWidth = winfnt_header.max_width;
4281 TM.tmWeight = winfnt_header.weight;
4282 TM.tmOverhang = 0;
4283 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4284 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4285 TM.tmFirstChar = winfnt_header.first_char;
4286 TM.tmLastChar = winfnt_header.last_char;
4287 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4288 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4289 TM.tmItalic = winfnt_header.italic;
4290 TM.tmUnderlined = font->underline;
4291 TM.tmStruckOut = font->strikeout;
4292 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4293 TM.tmCharSet = winfnt_header.charset;
4295 else
4296 #endif
4298 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4299 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4300 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4301 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4302 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4303 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4304 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4305 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4306 TM.tmOverhang = 0;
4307 TM.tmDigitizedAspectX = 96; /* FIXME */
4308 TM.tmDigitizedAspectY = 96; /* FIXME */
4309 TM.tmFirstChar = 1;
4310 TM.tmLastChar = 255;
4311 TM.tmDefaultChar = 32;
4312 TM.tmBreakChar = 32;
4313 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4314 TM.tmUnderlined = font->underline;
4315 TM.tmStruckOut = font->strikeout;
4316 /* NB inverted meaning of TMPF_FIXED_PITCH */
4317 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4318 TM.tmCharSet = font->charset;
4320 #undef TM
4322 return TRUE;
4325 /*************************************************************
4326 * WineEngGetTextMetrics
4329 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4331 if(!font->potm) {
4332 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4333 if(!get_bitmap_text_metrics(font))
4334 return FALSE;
4336 if(!font->potm) return FALSE;
4337 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4339 if (font->aveWidth) {
4340 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
4342 return TRUE;
4346 /*************************************************************
4347 * WineEngGetOutlineTextMetrics
4350 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4351 OUTLINETEXTMETRICW *potm)
4353 FT_Face ft_face = font->ft_face;
4354 UINT needed, lenfam, lensty, ret;
4355 TT_OS2 *pOS2;
4356 TT_HoriHeader *pHori;
4357 TT_Postscript *pPost;
4358 FT_Fixed x_scale, y_scale;
4359 WCHAR *family_nameW, *style_nameW;
4360 static const WCHAR spaceW[] = {' ', '\0'};
4361 char *cp;
4362 INT ascent, descent;
4364 TRACE("font=%p\n", font);
4366 if(!FT_IS_SCALABLE(ft_face))
4367 return 0;
4369 if(font->potm) {
4370 if(cbSize >= font->potm->otmSize)
4371 memcpy(potm, font->potm, font->potm->otmSize);
4372 return font->potm->otmSize;
4376 needed = sizeof(*potm);
4378 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4379 family_nameW = strdupW(font->name);
4381 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4382 * sizeof(WCHAR);
4383 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4384 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4385 style_nameW, lensty/sizeof(WCHAR));
4387 /* These names should be read from the TT name table */
4389 /* length of otmpFamilyName */
4390 needed += lenfam;
4392 /* length of otmpFaceName */
4393 if(!strcasecmp(ft_face->style_name, "regular")) {
4394 needed += lenfam; /* just the family name */
4395 } else {
4396 needed += lenfam + lensty; /* family + " " + style */
4399 /* length of otmpStyleName */
4400 needed += lensty;
4402 /* length of otmpFullName */
4403 needed += lenfam + lensty;
4406 x_scale = ft_face->size->metrics.x_scale;
4407 y_scale = ft_face->size->metrics.y_scale;
4409 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4410 if(!pOS2) {
4411 FIXME("Can't find OS/2 table - not TT font?\n");
4412 ret = 0;
4413 goto end;
4416 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4417 if(!pHori) {
4418 FIXME("Can't find HHEA table - not TT font?\n");
4419 ret = 0;
4420 goto end;
4423 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4425 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",
4426 pOS2->usWinAscent, pOS2->usWinDescent,
4427 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4428 ft_face->ascender, ft_face->descender, ft_face->height,
4429 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4430 ft_face->bbox.yMax, ft_face->bbox.yMin);
4432 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4433 font->potm->otmSize = needed;
4435 #define TM font->potm->otmTextMetrics
4437 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4438 ascent = pHori->Ascender;
4439 descent = -pHori->Descender;
4440 } else {
4441 ascent = pOS2->usWinAscent;
4442 descent = pOS2->usWinDescent;
4445 if(font->yMax) {
4446 TM.tmAscent = font->yMax;
4447 TM.tmDescent = -font->yMin;
4448 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4449 } else {
4450 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4451 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4452 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4453 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4456 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4458 /* MSDN says:
4459 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4461 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4462 ((ascent + descent) -
4463 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4465 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4466 if (TM.tmAveCharWidth == 0) {
4467 TM.tmAveCharWidth = 1;
4469 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4470 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4471 TM.tmOverhang = 0;
4472 TM.tmDigitizedAspectX = 300;
4473 TM.tmDigitizedAspectY = 300;
4474 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4475 * symbol range to 0 - f0ff
4477 if (font->charset == SYMBOL_CHARSET)
4478 TM.tmFirstChar = 0;
4479 else
4480 TM.tmFirstChar = pOS2->usFirstCharIndex;
4481 TM.tmLastChar = pOS2->usLastCharIndex;
4482 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4483 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4484 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4485 TM.tmUnderlined = font->underline;
4486 TM.tmStruckOut = font->strikeout;
4488 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4489 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4490 (pOS2->version == 0xFFFFU ||
4491 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4492 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4493 else
4494 TM.tmPitchAndFamily = 0;
4496 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4497 case PAN_FAMILY_SCRIPT:
4498 TM.tmPitchAndFamily |= FF_SCRIPT;
4499 break;
4500 case PAN_FAMILY_DECORATIVE:
4501 case PAN_FAMILY_PICTORIAL:
4502 TM.tmPitchAndFamily |= FF_DECORATIVE;
4503 break;
4504 case PAN_FAMILY_TEXT_DISPLAY:
4505 if(TM.tmPitchAndFamily == 0) /* fixed */
4506 TM.tmPitchAndFamily = FF_MODERN;
4507 else {
4508 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4509 case PAN_SERIF_NORMAL_SANS:
4510 case PAN_SERIF_OBTUSE_SANS:
4511 case PAN_SERIF_PERP_SANS:
4512 TM.tmPitchAndFamily |= FF_SWISS;
4513 break;
4514 default:
4515 TM.tmPitchAndFamily |= FF_ROMAN;
4518 break;
4519 default:
4520 TM.tmPitchAndFamily |= FF_DONTCARE;
4523 if(FT_IS_SCALABLE(ft_face))
4524 TM.tmPitchAndFamily |= TMPF_VECTOR;
4525 if(FT_IS_SFNT(ft_face))
4526 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4528 TM.tmCharSet = font->charset;
4529 #undef TM
4531 font->potm->otmFiller = 0;
4532 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4533 font->potm->otmfsSelection = pOS2->fsSelection;
4534 font->potm->otmfsType = pOS2->fsType;
4535 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4536 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4537 font->potm->otmItalicAngle = 0; /* POST table */
4538 font->potm->otmEMSquare = ft_face->units_per_EM;
4539 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4540 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4541 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4542 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4543 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4544 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4545 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4546 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4547 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4548 font->potm->otmMacAscent = 0; /* where do these come from ? */
4549 font->potm->otmMacDescent = 0;
4550 font->potm->otmMacLineGap = 0;
4551 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4552 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4553 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4554 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4555 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4556 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4557 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4558 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4559 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4560 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4561 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4562 if(!pPost) {
4563 font->potm->otmsUnderscoreSize = 0;
4564 font->potm->otmsUnderscorePosition = 0;
4565 } else {
4566 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4567 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4570 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4571 cp = (char*)font->potm + sizeof(*font->potm);
4572 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4573 strcpyW((WCHAR*)cp, family_nameW);
4574 cp += lenfam;
4575 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4576 strcpyW((WCHAR*)cp, style_nameW);
4577 cp += lensty;
4578 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4579 strcpyW((WCHAR*)cp, family_nameW);
4580 if(strcasecmp(ft_face->style_name, "regular")) {
4581 strcatW((WCHAR*)cp, spaceW);
4582 strcatW((WCHAR*)cp, style_nameW);
4583 cp += lenfam + lensty;
4584 } else
4585 cp += lenfam;
4586 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4587 strcpyW((WCHAR*)cp, family_nameW);
4588 strcatW((WCHAR*)cp, spaceW);
4589 strcatW((WCHAR*)cp, style_nameW);
4590 ret = needed;
4592 if(potm && needed <= cbSize)
4593 memcpy(potm, font->potm, font->potm->otmSize);
4595 end:
4596 HeapFree(GetProcessHeap(), 0, style_nameW);
4597 HeapFree(GetProcessHeap(), 0, family_nameW);
4599 return ret;
4602 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4604 HFONTLIST *hfontlist;
4605 LOGFONTW lf;
4606 static DWORD child_font_no = 0;
4607 static const WCHAR fmt[] = {'c','h','i','l','d','%','0','8','x',0};
4609 child->font = alloc_font();
4610 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4611 if(!child->font->ft_face)
4613 free_font(child->font);
4614 child->font = NULL;
4615 return FALSE;
4618 child->font->orientation = font->orientation;
4619 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4620 memcpy(&lf, &font->font_desc.lf, sizeof(lf));
4621 sprintfW(lf.lfFaceName, fmt, child_font_no++);
4622 hfontlist->hfont = CreateFontIndirectW(&lf);
4623 child->font->name = strdupW(lf.lfFaceName);
4624 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4625 child->font->base_font = font;
4626 list_add_head(&child_font_list, &child->font->entry);
4627 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4628 return TRUE;
4631 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4633 FT_UInt g;
4634 CHILD_FONT *child_font;
4636 if(font->base_font)
4637 font = font->base_font;
4639 *linked_font = font;
4641 if((*glyph = get_glyph_index(font, c)))
4642 return TRUE;
4644 /* Codeweavers Hack.
4645 * Counterstrike: Source is being greedy with memory and allocates
4646 * about 70 versions of tahoma and then looks for glyphs in the whole
4647 * 0 to 127 range. This causes us to load our Japanese font links for
4648 * every dc, which causes us to use up all our memory.
4650 * This is a range, given to me by Huw that we can resonably expect that
4651 * an app would not be relying on system links to provide a glyph for.
4652 * This allows CS to load and not load all the system links and thus.
4653 * not use up all its memory for Japanese fonts.
4655 if (c > 31 && c != 127)
4656 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4658 if(!child_font->font)
4659 if(!load_child_font(font, child_font))
4660 continue;
4662 if(!child_font->font->ft_face)
4663 continue;
4664 g = get_glyph_index(child_font->font, c);
4665 if(g)
4667 *glyph = g;
4668 *linked_font = child_font->font;
4669 return TRUE;
4672 return FALSE;
4675 /*************************************************************
4676 * WineEngGetCharWidth
4679 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4680 LPINT buffer)
4682 UINT c;
4683 GLYPHMETRICS gm;
4684 FT_UInt glyph_index;
4685 GdiFont *linked_font;
4687 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4689 for(c = firstChar; c <= lastChar; c++) {
4690 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4691 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4692 &gm, 0, NULL, NULL);
4693 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
4695 return TRUE;
4698 /*************************************************************
4699 * WineEngGetCharABCWidths
4702 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4703 LPABC buffer)
4705 UINT c;
4706 GLYPHMETRICS gm;
4707 FT_UInt glyph_index;
4708 GdiFont *linked_font;
4710 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4712 if(!FT_IS_SCALABLE(font->ft_face))
4713 return FALSE;
4715 for(c = firstChar; c <= lastChar; c++) {
4716 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4717 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4718 &gm, 0, NULL, NULL);
4719 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
4720 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
4721 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
4722 linked_font->gm[glyph_index].bbx;
4724 return TRUE;
4727 /*************************************************************
4728 * WineEngGetCharABCWidthsI
4731 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4732 LPABC buffer)
4734 UINT c;
4735 GLYPHMETRICS gm;
4736 FT_UInt glyph_index;
4737 GdiFont *linked_font;
4739 if(!FT_IS_SCALABLE(font->ft_face))
4740 return FALSE;
4742 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4743 if (!pgi)
4744 for(c = firstChar; c < firstChar+count; c++) {
4745 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4746 &gm, 0, NULL, NULL);
4747 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
4748 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
4749 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
4750 - linked_font->gm[c].bbx;
4752 else
4753 for(c = 0; c < count; c++) {
4754 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4755 &gm, 0, NULL, NULL);
4756 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
4757 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
4758 buffer[c].abcC = linked_font->gm[pgi[c]].adv
4759 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
4762 return TRUE;
4765 /*************************************************************
4766 * WineEngGetTextExtentExPoint
4769 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4770 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4772 INT idx;
4773 INT nfit = 0, ext;
4774 GLYPHMETRICS gm;
4775 TEXTMETRICW tm;
4776 FT_UInt glyph_index;
4777 GdiFont *linked_font;
4779 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4780 max_ext, size);
4782 size->cx = 0;
4783 WineEngGetTextMetrics(font, &tm);
4784 size->cy = tm.tmHeight;
4786 for(idx = 0; idx < count; idx++) {
4787 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4788 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4789 &gm, 0, NULL, NULL);
4790 size->cx += linked_font->gm[glyph_index].adv;
4791 ext = size->cx;
4792 if (! pnfit || ext <= max_ext) {
4793 ++nfit;
4794 if (dxs)
4795 dxs[idx] = ext;
4799 if (pnfit)
4800 *pnfit = nfit;
4802 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4803 return TRUE;
4806 /*************************************************************
4807 * WineEngGetTextExtentPointI
4810 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4811 LPSIZE size)
4813 INT idx;
4814 GLYPHMETRICS gm;
4815 TEXTMETRICW tm;
4817 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4819 size->cx = 0;
4820 WineEngGetTextMetrics(font, &tm);
4821 size->cy = tm.tmHeight;
4823 for(idx = 0; idx < count; idx++) {
4824 WineEngGetGlyphOutline(font, indices[idx],
4825 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4826 NULL);
4827 size->cx += font->gm[indices[idx]].adv;
4829 TRACE("return %d,%d\n", size->cx, size->cy);
4830 return TRUE;
4833 /*************************************************************
4834 * WineEngGetFontData
4837 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4838 DWORD cbData)
4840 FT_Face ft_face = font->ft_face;
4841 FT_ULong len;
4842 FT_Error err;
4844 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4845 font, table, offset, buf, cbData);
4847 if(!FT_IS_SFNT(ft_face))
4848 return GDI_ERROR;
4850 if(!buf || !cbData)
4851 len = 0;
4852 else
4853 len = cbData;
4855 if(table) { /* MS tags differ in endidness from FT ones */
4856 table = table >> 24 | table << 24 |
4857 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4860 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4861 if(pFT_Load_Sfnt_Table) {
4862 /* make sure value of len is the value freetype says it needs */
4863 if( buf && len) {
4864 FT_ULong needed = 0;
4865 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4866 if( !err && needed < len) len = needed;
4868 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4870 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4871 else { /* Do it the hard way */
4872 TT_Face tt_face = (TT_Face) ft_face;
4873 SFNT_Interface *sfnt;
4874 if (FT_Version.major==2 && FT_Version.minor==0)
4876 /* 2.0.x */
4877 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4879 else
4881 /* A field was added in the middle of the structure in 2.1.x */
4882 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4884 /* make sure value of len is the value freetype says it needs */
4885 if( buf && len) {
4886 FT_ULong needed = 0;
4887 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4888 if( !err && needed < len) len = needed;
4890 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4892 #else
4893 else {
4894 static int msg;
4895 if(!msg) {
4896 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4897 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4898 "Please upgrade your freetype library.\n");
4899 msg++;
4901 err = FT_Err_Unimplemented_Feature;
4903 #endif
4904 if(err) {
4905 TRACE("Can't find table %08x.\n", table);
4906 return GDI_ERROR;
4908 return len;
4911 /*************************************************************
4912 * WineEngGetTextFace
4915 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4917 if(str) {
4918 lstrcpynW(str, font->name, count);
4919 return strlenW(font->name);
4920 } else
4921 return strlenW(font->name) + 1;
4924 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4926 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4927 return font->charset;
4930 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4932 GdiFont *font = dc->gdiFont, *linked_font;
4933 struct list *first_hfont;
4934 BOOL ret;
4936 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4937 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4938 if(font == linked_font)
4939 *new_hfont = dc->hFont;
4940 else
4942 first_hfont = list_head(&linked_font->hfontlist);
4943 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4946 return ret;
4949 /* Retrieve a list of supported Unicode ranges for a given font.
4950 * Can be called with NULL gs to calculate the buffer size. Returns
4951 * the number of ranges found.
4953 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4955 DWORD num_ranges = 0;
4957 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4959 FT_UInt glyph_code;
4960 FT_ULong char_code, char_code_prev;
4962 glyph_code = 0;
4963 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4965 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4966 face->num_glyphs, glyph_code, char_code);
4968 if (!glyph_code) return 0;
4970 if (gs)
4972 gs->ranges[0].wcLow = (USHORT)char_code;
4973 gs->ranges[0].cGlyphs = 0;
4974 gs->cGlyphsSupported = 0;
4977 num_ranges = 1;
4978 while (glyph_code)
4980 if (char_code < char_code_prev)
4982 ERR("expected increasing char code from FT_Get_Next_Char\n");
4983 return 0;
4985 if (char_code - char_code_prev > 1)
4987 num_ranges++;
4988 if (gs)
4990 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4991 gs->ranges[num_ranges - 1].cGlyphs = 1;
4992 gs->cGlyphsSupported++;
4995 else if (gs)
4997 gs->ranges[num_ranges - 1].cGlyphs++;
4998 gs->cGlyphsSupported++;
5000 char_code_prev = char_code;
5001 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5004 else
5005 FIXME("encoding %u not supported\n", face->charmap->encoding);
5007 return num_ranges;
5010 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
5012 DWORD size = 0;
5013 DC *dc = DC_GetDCPtr(hdc);
5015 TRACE("(%p, %p)\n", hdc, glyphset);
5017 if (!dc) return 0;
5019 if (dc->gdiFont)
5021 DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset);
5023 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5024 if (glyphset)
5026 glyphset->cbThis = size;
5027 glyphset->cRanges = num_ranges;
5031 GDI_ReleaseObj(hdc);
5032 return size;
5035 /*************************************************************
5036 * FontIsLinked
5038 BOOL WINAPI FontIsLinked(HDC hdc)
5040 DC *dc = DC_GetDCPtr(hdc);
5041 BOOL ret = FALSE;
5043 if(!dc) return FALSE;
5044 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
5045 ret = TRUE;
5046 GDI_ReleaseObj(hdc);
5047 TRACE("returning %d\n", ret);
5048 return ret;
5051 static BOOL is_hinting_enabled(void)
5053 /* Use the >= 2.2.0 function if available */
5054 if(pFT_Get_TrueType_Engine_Type)
5056 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5057 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5059 #ifdef FT_DRIVER_HAS_HINTER
5060 else
5062 FT_Module mod;
5064 /* otherwise if we've been compiled with < 2.2.0 headers
5065 use the internal macro */
5066 mod = pFT_Get_Module(library, "truetype");
5067 if(mod && FT_DRIVER_HAS_HINTER(mod))
5068 return TRUE;
5070 #endif
5072 return FALSE;
5075 /*************************************************************************
5076 * GetRasterizerCaps (GDI32.@)
5078 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5080 static int hinting = -1;
5082 if(hinting == -1)
5084 hinting = is_hinting_enabled();
5085 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5088 lprs->nSize = sizeof(RASTERIZER_STATUS);
5089 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5090 lprs->nLanguageID = 0;
5091 return TRUE;
5094 /*************************************************************************
5095 * Kerning support for TrueType fonts
5097 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5099 struct TT_kern_table
5101 USHORT version;
5102 USHORT nTables;
5105 struct TT_kern_subtable
5107 USHORT version;
5108 USHORT length;
5109 union
5111 USHORT word;
5112 struct
5114 USHORT horizontal : 1;
5115 USHORT minimum : 1;
5116 USHORT cross_stream: 1;
5117 USHORT override : 1;
5118 USHORT reserved1 : 4;
5119 USHORT format : 8;
5120 } bits;
5121 } coverage;
5124 struct TT_format0_kern_subtable
5126 USHORT nPairs;
5127 USHORT searchRange;
5128 USHORT entrySelector;
5129 USHORT rangeShift;
5132 struct TT_kern_pair
5134 USHORT left;
5135 USHORT right;
5136 short value;
5139 static DWORD parse_format0_kern_subtable(GdiFont *font,
5140 const struct TT_format0_kern_subtable *tt_f0_ks,
5141 const USHORT *glyph_to_char,
5142 KERNINGPAIR *kern_pair, DWORD cPairs)
5144 USHORT i, nPairs;
5145 const struct TT_kern_pair *tt_kern_pair;
5147 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5149 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5151 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5152 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5153 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5155 if (!kern_pair || !cPairs)
5156 return nPairs;
5158 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5160 nPairs = min(nPairs, cPairs);
5162 for (i = 0; i < nPairs; i++)
5164 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5165 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5166 /* this algorithm appears to better match what Windows does */
5167 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5168 if (kern_pair->iKernAmount < 0)
5170 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5171 kern_pair->iKernAmount -= font->ppem;
5173 else if (kern_pair->iKernAmount > 0)
5175 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5176 kern_pair->iKernAmount += font->ppem;
5178 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5180 TRACE("left %u right %u value %d\n",
5181 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5183 kern_pair++;
5185 TRACE("copied %u entries\n", nPairs);
5186 return nPairs;
5189 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5191 DWORD length;
5192 void *buf;
5193 const struct TT_kern_table *tt_kern_table;
5194 const struct TT_kern_subtable *tt_kern_subtable;
5195 USHORT i, nTables;
5196 USHORT *glyph_to_char;
5198 if (font->total_kern_pairs != (DWORD)-1)
5200 if (cPairs && kern_pair)
5202 cPairs = min(cPairs, font->total_kern_pairs);
5203 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5204 return cPairs;
5206 return font->total_kern_pairs;
5209 font->total_kern_pairs = 0;
5211 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5213 if (length == GDI_ERROR)
5215 TRACE("no kerning data in the font\n");
5216 return 0;
5219 buf = HeapAlloc(GetProcessHeap(), 0, length);
5220 if (!buf)
5222 WARN("Out of memory\n");
5223 return 0;
5226 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5228 /* build a glyph index to char code map */
5229 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5230 if (!glyph_to_char)
5232 WARN("Out of memory allocating a glyph index to char code map\n");
5233 HeapFree(GetProcessHeap(), 0, buf);
5234 return 0;
5237 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5239 FT_UInt glyph_code;
5240 FT_ULong char_code;
5242 glyph_code = 0;
5243 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5245 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5246 font->ft_face->num_glyphs, glyph_code, char_code);
5248 while (glyph_code)
5250 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5252 /* FIXME: This doesn't match what Windows does: it does some fancy
5253 * things with duplicate glyph index to char code mappings, while
5254 * we just avoid overriding existing entries.
5256 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5257 glyph_to_char[glyph_code] = (USHORT)char_code;
5259 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5262 else
5264 ULONG n;
5266 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5267 for (n = 0; n <= 65535; n++)
5268 glyph_to_char[n] = (USHORT)n;
5271 tt_kern_table = buf;
5272 nTables = GET_BE_WORD(tt_kern_table->nTables);
5273 TRACE("version %u, nTables %u\n",
5274 GET_BE_WORD(tt_kern_table->version), nTables);
5276 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5278 for (i = 0; i < nTables; i++)
5280 struct TT_kern_subtable tt_kern_subtable_copy;
5282 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5283 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5284 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5286 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5287 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5288 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5290 /* According to the TrueType specification this is the only format
5291 * that will be properly interpreted by Windows and OS/2
5293 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5295 DWORD new_chunk, old_total = font->total_kern_pairs;
5297 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5298 glyph_to_char, NULL, 0);
5299 font->total_kern_pairs += new_chunk;
5301 if (!font->kern_pairs)
5302 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5303 font->total_kern_pairs * sizeof(*font->kern_pairs));
5304 else
5305 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5306 font->total_kern_pairs * sizeof(*font->kern_pairs));
5308 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5309 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5311 else
5312 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5314 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5317 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5318 HeapFree(GetProcessHeap(), 0, buf);
5320 if (cPairs && kern_pair)
5322 cPairs = min(cPairs, font->total_kern_pairs);
5323 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5324 return cPairs;
5326 return font->total_kern_pairs;
5329 #else /* HAVE_FREETYPE */
5331 /*************************************************************************/
5333 BOOL WineEngInit(void)
5335 return FALSE;
5337 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5339 return NULL;
5341 BOOL WineEngDestroyFontInstance(HFONT hfont)
5343 return FALSE;
5346 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5348 return 1;
5351 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5352 LPWORD pgi, DWORD flags)
5354 return GDI_ERROR;
5357 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5358 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5359 const MAT2* lpmat)
5361 ERR("called but we don't have FreeType\n");
5362 return GDI_ERROR;
5365 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5367 ERR("called but we don't have FreeType\n");
5368 return FALSE;
5371 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5372 OUTLINETEXTMETRICW *potm)
5374 ERR("called but we don't have FreeType\n");
5375 return 0;
5378 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5379 LPINT buffer)
5381 ERR("called but we don't have FreeType\n");
5382 return FALSE;
5385 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5386 LPABC buffer)
5388 ERR("called but we don't have FreeType\n");
5389 return FALSE;
5392 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5393 LPABC buffer)
5395 ERR("called but we don't have FreeType\n");
5396 return FALSE;
5399 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5400 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5402 ERR("called but we don't have FreeType\n");
5403 return FALSE;
5406 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
5407 LPSIZE size)
5409 ERR("called but we don't have FreeType\n");
5410 return FALSE;
5413 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5414 DWORD cbData)
5416 ERR("called but we don't have FreeType\n");
5417 return GDI_ERROR;
5420 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5422 ERR("called but we don't have FreeType\n");
5423 return 0;
5426 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5428 FIXME(":stub\n");
5429 return 1;
5432 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5434 FIXME(":stub\n");
5435 return TRUE;
5438 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5440 FIXME(":stub\n");
5441 return DEFAULT_CHARSET;
5444 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5446 return FALSE;
5449 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
5451 FIXME("(%p, %p): stub\n", hdc, glyphset);
5452 return 0;
5455 BOOL WINAPI FontIsLinked(HDC hdc)
5457 return FALSE;
5460 /*************************************************************************
5461 * GetRasterizerCaps (GDI32.@)
5463 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5465 lprs->nSize = sizeof(RASTERIZER_STATUS);
5466 lprs->wFlags = 0;
5467 lprs->nLanguageID = 0;
5468 return TRUE;
5471 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5473 ERR("called but we don't have FreeType\n");
5474 return 0;
5477 #endif /* HAVE_FREETYPE */