wineoss.drv: Remove unneeded casts.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob08e6638d60562aefb5eccf5d42efb200e2761e44
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_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_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 SONAME_LIBFONTCONFIG
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 #endif
200 #undef MAKE_FUNCPTR
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229 FT_Short height;
230 FT_Short width;
231 FT_Pos size;
232 FT_Pos x_ppem;
233 FT_Pos y_ppem;
234 FT_Short internal_leading;
235 } Bitmap_Size;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
240 typedef struct {
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
245 struct enum_data
247 ENUMLOGFONTEXW elf;
248 NEWTEXTMETRICEXW ntm;
249 DWORD type;
252 typedef struct tagFace {
253 struct list entry;
254 WCHAR *StyleName;
255 char *file;
256 void *font_data_ptr;
257 DWORD font_data_size;
258 FT_Long face_index;
259 BOOL Italic;
260 BOOL Bold;
261 FONTSIGNATURE fs;
262 FONTSIGNATURE fs_links;
263 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version;
265 BOOL scalable;
266 Bitmap_Size size; /* set if face is a bitmap */
267 BOOL external; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily *family;
269 /* Cached data for Enum */
270 struct enum_data *cached_enum_data;
271 } Face;
273 typedef struct tagFamily {
274 struct list entry;
275 const WCHAR *FamilyName;
276 struct list faces;
277 } Family;
279 typedef struct {
280 GLYPHMETRICS gm;
281 INT adv; /* These three hold to widths of the unrotated chars */
282 INT lsb;
283 INT bbx;
284 BOOL init;
285 } GM;
287 typedef struct {
288 FLOAT eM11, eM12;
289 FLOAT eM21, eM22;
290 } FMAT2;
292 typedef struct {
293 DWORD hash;
294 LOGFONTW lf;
295 FMAT2 matrix;
296 BOOL can_use_bitmap;
297 } FONT_DESC;
299 typedef struct tagHFONTLIST {
300 struct list entry;
301 HFONT hfont;
302 } HFONTLIST;
304 typedef struct {
305 struct list entry;
306 Face *face;
307 GdiFont *font;
308 } CHILD_FONT;
310 struct tagGdiFont {
311 struct list entry;
312 GM **gm;
313 DWORD gmsize;
314 struct list hfontlist;
315 OUTLINETEXTMETRICW *potm;
316 DWORD total_kern_pairs;
317 KERNINGPAIR *kern_pairs;
318 struct list child_fonts;
320 /* the following members can be accessed without locking, they are never modified after creation */
321 FT_Face ft_face;
322 struct font_mapping *mapping;
323 LPWSTR name;
324 int charset;
325 int codepage;
326 BOOL fake_italic;
327 BOOL fake_bold;
328 BYTE underline;
329 BYTE strikeout;
330 INT orientation;
331 FONT_DESC font_desc;
332 LONG aveWidth, ppem;
333 float scale_y;
334 SHORT yMax;
335 SHORT yMin;
336 DWORD ntmFlags;
337 FONTSIGNATURE fs;
338 GdiFont *base_font;
341 typedef struct {
342 struct list entry;
343 const WCHAR *font_name;
344 struct list links;
345 } SYSTEM_LINKS;
347 #define GM_BLOCK_SIZE 128
348 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
350 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
351 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
352 #define UNUSED_CACHE_SIZE 10
353 static struct list child_font_list = LIST_INIT(child_font_list);
354 static struct list system_links = LIST_INIT(system_links);
356 static struct list font_subst_list = LIST_INIT(font_subst_list);
358 static struct list font_list = LIST_INIT(font_list);
360 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
361 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
362 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
364 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
366 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
367 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
368 'W','i','n','d','o','w','s','\\',
369 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
370 'F','o','n','t','s','\0'};
372 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
373 'W','i','n','d','o','w','s',' ','N','T','\\',
374 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
375 'F','o','n','t','s','\0'};
377 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
378 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
379 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
380 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
382 static const WCHAR * const SystemFontValues[4] = {
383 System_Value,
384 OEMFont_Value,
385 FixedSys_Value,
386 NULL
389 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
390 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
392 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
393 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
394 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
395 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
396 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
397 'E','u','r','o','p','e','a','n','\0'};
398 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
399 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
400 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
401 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
402 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
403 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
404 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
405 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
406 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
407 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
408 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
409 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
411 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
412 WesternW, /*00*/
413 Central_EuropeanW,
414 CyrillicW,
415 GreekW,
416 TurkishW,
417 HebrewW,
418 ArabicW,
419 BalticW,
420 VietnameseW, /*08*/
421 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
422 ThaiW,
423 JapaneseW,
424 CHINESE_GB2312W,
425 HangulW,
426 CHINESE_BIG5W,
427 Hangul_Johab_W,
428 NULL, NULL, /*23*/
429 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
430 SymbolW /*31*/
433 typedef struct {
434 WCHAR *name;
435 INT charset;
436 } NameCs;
438 typedef struct tagFontSubst {
439 struct list entry;
440 NameCs from;
441 NameCs to;
442 } FontSubst;
444 struct font_mapping
446 struct list entry;
447 int refcount;
448 dev_t dev;
449 ino_t ino;
450 void *data;
451 size_t size;
454 static struct list mappings_list = LIST_INIT( mappings_list );
456 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
458 static CRITICAL_SECTION freetype_cs;
459 static CRITICAL_SECTION_DEBUG critsect_debug =
461 0, 0, &freetype_cs,
462 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
463 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
465 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
467 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
469 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
471 /****************************************
472 * Notes on .fon files
474 * The fonts System, FixedSys and Terminal are special. There are typically multiple
475 * versions installed for different resolutions and codepages. Windows stores which one to use
476 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
477 * Key Meaning
478 * FIXEDFON.FON FixedSys
479 * FONTS.FON System
480 * OEMFONT.FON Terminal
481 * LogPixels Current dpi set by the display control panel applet
482 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
483 * also has a LogPixels value that appears to mirror this)
485 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
486 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
487 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
488 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
489 * so that makes sense.
491 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
492 * to be mapped into the registry on Windows 2000 at least).
493 * I have
494 * woafont=app850.fon
495 * ega80woa.fon=ega80850.fon
496 * ega40woa.fon=ega40850.fon
497 * cga80woa.fon=cga80850.fon
498 * cga40woa.fon=cga40850.fon
501 #ifdef HAVE_CARBON_CARBON_H
502 static char *find_cache_dir(void)
504 FSRef ref;
505 OSErr err;
506 static char cached_path[MAX_PATH];
507 static const char *wine = "/Wine", *fonts = "/Fonts";
509 if(*cached_path) return cached_path;
511 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
512 if(err != noErr)
514 WARN("can't create cached data folder\n");
515 return NULL;
517 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
518 if(err != noErr)
520 WARN("can't create cached data path\n");
521 *cached_path = '\0';
522 return NULL;
524 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
526 ERR("Could not create full path\n");
527 *cached_path = '\0';
528 return NULL;
530 strcat(cached_path, wine);
532 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
534 WARN("Couldn't mkdir %s\n", cached_path);
535 *cached_path = '\0';
536 return NULL;
538 strcat(cached_path, fonts);
539 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
541 WARN("Couldn't mkdir %s\n", cached_path);
542 *cached_path = '\0';
543 return NULL;
545 return cached_path;
548 /******************************************************************
549 * expand_mac_font
551 * Extracts individual TrueType font files from a Mac suitcase font
552 * and saves them into the user's caches directory (see
553 * find_cache_dir()).
554 * Returns a NULL terminated array of filenames.
556 * We do this because they are apps that try to read ttf files
557 * themselves and they don't like Mac suitcase files.
559 static char **expand_mac_font(const char *path)
561 FSRef ref;
562 SInt16 res_ref;
563 OSStatus s;
564 unsigned int idx;
565 const char *out_dir;
566 const char *filename;
567 int output_len;
568 struct {
569 char **array;
570 unsigned int size, max_size;
571 } ret;
573 TRACE("path %s\n", path);
575 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
576 if(s != noErr)
578 WARN("failed to get ref\n");
579 return NULL;
582 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
583 if(s != noErr)
585 TRACE("no data fork, so trying resource fork\n");
586 res_ref = FSOpenResFile(&ref, fsRdPerm);
587 if(res_ref == -1)
589 TRACE("unable to open resource fork\n");
590 return NULL;
594 ret.size = 0;
595 ret.max_size = 10;
596 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
597 if(!ret.array)
599 CloseResFile(res_ref);
600 return NULL;
603 out_dir = find_cache_dir();
605 filename = strrchr(path, '/');
606 if(!filename) filename = path;
607 else filename++;
609 /* output filename has the form out_dir/filename_%04x.ttf */
610 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
612 UseResFile(res_ref);
613 idx = 1;
614 while(1)
616 FamRec *fam_rec;
617 unsigned short *num_faces_ptr, num_faces, face;
618 AsscEntry *assoc;
619 Handle fond;
620 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
622 fond = Get1IndResource(fond_res, idx);
623 if(!fond) break;
624 TRACE("got fond resource %d\n", idx);
625 HLock(fond);
627 fam_rec = *(FamRec**)fond;
628 num_faces_ptr = (unsigned short *)(fam_rec + 1);
629 num_faces = GET_BE_WORD(*num_faces_ptr);
630 num_faces++;
631 assoc = (AsscEntry*)(num_faces_ptr + 1);
632 TRACE("num faces %04x\n", num_faces);
633 for(face = 0; face < num_faces; face++, assoc++)
635 Handle sfnt;
636 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
637 unsigned short size, font_id;
638 char *output;
640 size = GET_BE_WORD(assoc->fontSize);
641 font_id = GET_BE_WORD(assoc->fontID);
642 if(size != 0)
644 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
645 continue;
648 TRACE("trying to load sfnt id %04x\n", font_id);
649 sfnt = GetResource(sfnt_res, font_id);
650 if(!sfnt)
652 TRACE("can't get sfnt resource %04x\n", font_id);
653 continue;
656 output = HeapAlloc(GetProcessHeap(), 0, output_len);
657 if(output)
659 int fd;
661 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
663 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
664 if(fd != -1 || errno == EEXIST)
666 if(fd != -1)
668 unsigned char *sfnt_data;
670 HLock(sfnt);
671 sfnt_data = *(unsigned char**)sfnt;
672 write(fd, sfnt_data, GetHandleSize(sfnt));
673 HUnlock(sfnt);
674 close(fd);
676 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
678 ret.max_size *= 2;
679 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
681 ret.array[ret.size++] = output;
683 else
685 WARN("unable to create %s\n", output);
686 HeapFree(GetProcessHeap(), 0, output);
689 ReleaseResource(sfnt);
691 HUnlock(fond);
692 ReleaseResource(fond);
693 idx++;
695 CloseResFile(res_ref);
697 return ret.array;
700 #endif /* HAVE_CARBON_CARBON_H */
702 static inline BOOL is_win9x(void)
704 return GetVersion() & 0x80000000;
707 This function builds an FT_Fixed from a float. It puts the integer part
708 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
709 It fails if the integer part of the float number is greater than SHORT_MAX.
711 static inline FT_Fixed FT_FixedFromFloat(float f)
713 short value = f;
714 unsigned short fract = (f - value) * 0xFFFF;
715 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
719 This function builds an FT_Fixed from a FIXED. It simply put f.value
720 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
722 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
724 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
728 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
730 Family *family;
731 Face *face;
732 const char *file;
733 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
734 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
736 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
737 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
739 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
741 if(face_name && strcmpiW(face_name, family->FamilyName))
742 continue;
743 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
745 if (!face->file)
746 continue;
747 file = strrchr(face->file, '/');
748 if(!file)
749 file = face->file;
750 else
751 file++;
752 if(!strcasecmp(file, file_nameA))
754 HeapFree(GetProcessHeap(), 0, file_nameA);
755 return face;
759 HeapFree(GetProcessHeap(), 0, file_nameA);
760 return NULL;
763 static Family *find_family_from_name(const WCHAR *name)
765 Family *family;
767 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
769 if(!strcmpiW(family->FamilyName, name))
770 return family;
773 return NULL;
776 static void DumpSubstList(void)
778 FontSubst *psub;
780 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
782 if(psub->from.charset != -1 || psub->to.charset != -1)
783 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
784 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
785 else
786 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
787 debugstr_w(psub->to.name));
789 return;
792 static LPWSTR strdupW(LPCWSTR p)
794 LPWSTR ret;
795 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
796 ret = HeapAlloc(GetProcessHeap(), 0, len);
797 memcpy(ret, p, len);
798 return ret;
801 static LPSTR strdupA(LPCSTR p)
803 LPSTR ret;
804 DWORD len = (strlen(p) + 1);
805 ret = HeapAlloc(GetProcessHeap(), 0, len);
806 memcpy(ret, p, len);
807 return ret;
810 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
811 INT from_charset)
813 FontSubst *element;
815 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
817 if(!strcmpiW(element->from.name, from_name) &&
818 (element->from.charset == from_charset ||
819 element->from.charset == -1))
820 return element;
823 return NULL;
826 #define ADD_FONT_SUBST_FORCE 1
828 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
830 FontSubst *from_exist, *to_exist;
832 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
834 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
836 list_remove(&from_exist->entry);
837 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
838 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
839 HeapFree(GetProcessHeap(), 0, from_exist);
840 from_exist = NULL;
843 if(!from_exist)
845 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
847 if(to_exist)
849 HeapFree(GetProcessHeap(), 0, subst->to.name);
850 subst->to.name = strdupW(to_exist->to.name);
853 list_add_tail(subst_list, &subst->entry);
855 return TRUE;
858 HeapFree(GetProcessHeap(), 0, subst->from.name);
859 HeapFree(GetProcessHeap(), 0, subst->to.name);
860 HeapFree(GetProcessHeap(), 0, subst);
861 return FALSE;
864 static void split_subst_info(NameCs *nc, LPSTR str)
866 CHAR *p = strrchr(str, ',');
867 DWORD len;
869 nc->charset = -1;
870 if(p && *(p+1)) {
871 nc->charset = strtol(p+1, NULL, 10);
872 *p = '\0';
874 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
875 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
876 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
879 static void LoadSubstList(void)
881 FontSubst *psub;
882 HKEY hkey;
883 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
884 LPSTR value;
885 LPVOID data;
887 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
888 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
889 &hkey) == ERROR_SUCCESS) {
891 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
892 &valuelen, &datalen, NULL, NULL);
894 valuelen++; /* returned value doesn't include room for '\0' */
895 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
896 data = HeapAlloc(GetProcessHeap(), 0, datalen);
898 dlen = datalen;
899 vlen = valuelen;
900 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
901 &dlen) == ERROR_SUCCESS) {
902 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
904 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
905 split_subst_info(&psub->from, value);
906 split_subst_info(&psub->to, data);
908 /* Win 2000 doesn't allow mapping between different charsets
909 or mapping of DEFAULT_CHARSET */
910 if((psub->to.charset != psub->from.charset) ||
911 psub->to.charset == DEFAULT_CHARSET) {
912 HeapFree(GetProcessHeap(), 0, psub->to.name);
913 HeapFree(GetProcessHeap(), 0, psub->from.name);
914 HeapFree(GetProcessHeap(), 0, psub);
915 } else {
916 add_font_subst(&font_subst_list, psub, 0);
918 /* reset dlen and vlen */
919 dlen = datalen;
920 vlen = valuelen;
922 HeapFree(GetProcessHeap(), 0, data);
923 HeapFree(GetProcessHeap(), 0, value);
924 RegCloseKey(hkey);
928 static WCHAR *get_familyname(FT_Face ft_face)
930 WCHAR *family = NULL;
931 FT_SfntName name;
932 FT_UInt num_names, name_index, i;
934 if(FT_IS_SFNT(ft_face))
936 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
938 for(name_index = 0; name_index < num_names; name_index++)
940 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
942 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
943 (name.language_id == GetUserDefaultLCID()) &&
944 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
945 (name.encoding_id == TT_MS_ID_UNICODE_CS))
947 /* String is not nul terminated and string_len is a byte length. */
948 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
949 for(i = 0; i < name.string_len / 2; i++)
951 WORD *tmp = (WORD *)&name.string[i * 2];
952 family[i] = GET_BE_WORD(*tmp);
954 family[i] = 0;
956 TRACE("Got localised name %s\n", debugstr_w(family));
957 return family;
963 return NULL;
967 /*****************************************************************
968 * load_sfnt_table
970 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
971 * of FreeType that don't export this function.
974 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
977 FT_Error err;
979 /* If the FT_Load_Sfnt_Table function is there we'll use it */
980 if(pFT_Load_Sfnt_Table)
982 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
984 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
985 else /* Do it the hard way */
987 TT_Face tt_face = (TT_Face) ft_face;
988 SFNT_Interface *sfnt;
989 if (FT_Version.major==2 && FT_Version.minor==0)
991 /* 2.0.x */
992 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
994 else
996 /* A field was added in the middle of the structure in 2.1.x */
997 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
999 err = sfnt->load_any(tt_face, table, offset, buf, len);
1001 #else
1002 else
1004 static int msg;
1005 if(!msg)
1007 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1008 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1009 "Please upgrade your freetype library.\n");
1010 msg++;
1012 err = FT_Err_Unimplemented_Feature;
1014 #endif
1015 return err;
1019 #define ADDFONT_EXTERNAL_FONT 0x01
1020 #define ADDFONT_FORCE_BITMAP 0x02
1021 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1023 FT_Face ft_face;
1024 TT_OS2 *pOS2;
1025 TT_Header *pHeader = NULL;
1026 WCHAR *english_family, *localised_family, *StyleW;
1027 DWORD len;
1028 Family *family;
1029 Face *face;
1030 struct list *family_elem_ptr, *face_elem_ptr;
1031 FT_Error err;
1032 FT_Long face_index = 0, num_faces;
1033 #ifdef HAVE_FREETYPE_FTWINFNT_H
1034 FT_WinFNT_HeaderRec winfnt_header;
1035 #endif
1036 int i, bitmap_num, internal_leading;
1037 FONTSIGNATURE fs;
1039 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1040 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1042 #ifdef HAVE_CARBON_CARBON_H
1043 if(file && !fake_family)
1045 char **mac_list = expand_mac_font(file);
1046 if(mac_list)
1048 BOOL had_one = FALSE;
1049 char **cursor;
1050 for(cursor = mac_list; *cursor; cursor++)
1052 had_one = TRUE;
1053 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1054 HeapFree(GetProcessHeap(), 0, *cursor);
1056 HeapFree(GetProcessHeap(), 0, mac_list);
1057 if(had_one)
1058 return 1;
1061 #endif /* HAVE_CARBON_CARBON_H */
1063 do {
1064 char *family_name = fake_family;
1066 if (file)
1068 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1069 err = pFT_New_Face(library, file, face_index, &ft_face);
1070 } else
1072 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1073 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1076 if(err != 0) {
1077 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1078 return 0;
1081 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*/
1082 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1083 pFT_Done_Face(ft_face);
1084 return 0;
1087 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1088 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1089 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1090 pFT_Done_Face(ft_face);
1091 return 0;
1094 if(FT_IS_SFNT(ft_face))
1096 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1097 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1098 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1100 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1101 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1102 pFT_Done_Face(ft_face);
1103 return 0;
1106 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1107 we don't want to load these. */
1108 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1110 FT_ULong len = 0;
1112 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1114 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1115 pFT_Done_Face(ft_face);
1116 return 0;
1121 if(!ft_face->family_name || !ft_face->style_name) {
1122 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1123 pFT_Done_Face(ft_face);
1124 return 0;
1127 if (target_family)
1129 localised_family = get_familyname(ft_face);
1130 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1132 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1133 HeapFree(GetProcessHeap(), 0, localised_family);
1134 num_faces = ft_face->num_faces;
1135 pFT_Done_Face(ft_face);
1136 continue;
1138 HeapFree(GetProcessHeap(), 0, localised_family);
1141 if(!family_name)
1142 family_name = ft_face->family_name;
1144 bitmap_num = 0;
1145 do {
1146 My_FT_Bitmap_Size *size = NULL;
1147 FT_ULong tmp_size;
1149 if(!FT_IS_SCALABLE(ft_face))
1150 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1152 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1153 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1154 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1156 localised_family = NULL;
1157 if(!fake_family) {
1158 localised_family = get_familyname(ft_face);
1159 if(localised_family && !strcmpW(localised_family, english_family)) {
1160 HeapFree(GetProcessHeap(), 0, localised_family);
1161 localised_family = NULL;
1165 family = NULL;
1166 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1167 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1168 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1169 break;
1170 family = NULL;
1172 if(!family) {
1173 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1174 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1175 list_init(&family->faces);
1176 list_add_tail(&font_list, &family->entry);
1178 if(localised_family) {
1179 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1180 subst->from.name = strdupW(english_family);
1181 subst->from.charset = -1;
1182 subst->to.name = strdupW(localised_family);
1183 subst->to.charset = -1;
1184 add_font_subst(&font_subst_list, subst, 0);
1187 HeapFree(GetProcessHeap(), 0, localised_family);
1188 HeapFree(GetProcessHeap(), 0, english_family);
1190 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1191 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1192 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1194 internal_leading = 0;
1195 memset(&fs, 0, sizeof(fs));
1197 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1198 if(pOS2) {
1199 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1200 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1201 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1202 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1203 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1204 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1205 if(pOS2->version == 0) {
1206 FT_UInt dummy;
1208 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1209 fs.fsCsb[0] |= FS_LATIN1;
1210 else
1211 fs.fsCsb[0] |= FS_SYMBOL;
1214 #ifdef HAVE_FREETYPE_FTWINFNT_H
1215 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1216 CHARSETINFO csi;
1217 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1218 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1219 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1220 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1221 internal_leading = winfnt_header.internal_leading;
1223 #endif
1225 face_elem_ptr = list_head(&family->faces);
1226 while(face_elem_ptr) {
1227 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1228 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1229 if(!strcmpW(face->StyleName, StyleW) &&
1230 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1231 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1232 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1233 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1235 if(fake_family) {
1236 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1237 HeapFree(GetProcessHeap(), 0, StyleW);
1238 pFT_Done_Face(ft_face);
1239 return 1;
1241 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1242 TRACE("Original font is newer so skipping this one\n");
1243 HeapFree(GetProcessHeap(), 0, StyleW);
1244 pFT_Done_Face(ft_face);
1245 return 1;
1246 } else {
1247 TRACE("Replacing original with this one\n");
1248 list_remove(&face->entry);
1249 HeapFree(GetProcessHeap(), 0, face->file);
1250 HeapFree(GetProcessHeap(), 0, face->StyleName);
1251 HeapFree(GetProcessHeap(), 0, face);
1252 break;
1256 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1257 face->cached_enum_data = NULL;
1258 list_add_tail(&family->faces, &face->entry);
1259 face->StyleName = StyleW;
1260 if (file)
1262 face->file = strdupA(file);
1263 face->font_data_ptr = NULL;
1264 face->font_data_size = 0;
1266 else
1268 face->file = NULL;
1269 face->font_data_ptr = font_data_ptr;
1270 face->font_data_size = font_data_size;
1272 face->face_index = face_index;
1273 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1274 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1275 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1276 face->family = family;
1277 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1278 memcpy(&face->fs, &fs, sizeof(face->fs));
1279 memset(&face->fs_links, 0, sizeof(face->fs_links));
1281 if(FT_IS_SCALABLE(ft_face)) {
1282 memset(&face->size, 0, sizeof(face->size));
1283 face->scalable = TRUE;
1284 } else {
1285 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1286 size->height, size->width, size->size >> 6,
1287 size->x_ppem >> 6, size->y_ppem >> 6);
1288 face->size.height = size->height;
1289 face->size.width = size->width;
1290 face->size.size = size->size;
1291 face->size.x_ppem = size->x_ppem;
1292 face->size.y_ppem = size->y_ppem;
1293 face->size.internal_leading = internal_leading;
1294 face->scalable = FALSE;
1297 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1298 tmp_size = 0;
1299 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1301 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1302 face->ntmFlags = NTM_PS_OPENTYPE;
1304 else
1305 face->ntmFlags = 0;
1307 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1308 face->fs.fsCsb[0], face->fs.fsCsb[1],
1309 face->fs.fsUsb[0], face->fs.fsUsb[1],
1310 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1313 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1314 for(i = 0; i < ft_face->num_charmaps; i++) {
1315 switch(ft_face->charmaps[i]->encoding) {
1316 case FT_ENCODING_UNICODE:
1317 case FT_ENCODING_APPLE_ROMAN:
1318 face->fs.fsCsb[0] |= FS_LATIN1;
1319 break;
1320 case FT_ENCODING_MS_SYMBOL:
1321 face->fs.fsCsb[0] |= FS_SYMBOL;
1322 break;
1323 default:
1324 break;
1329 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1330 have_installed_roman_font = TRUE;
1331 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1333 num_faces = ft_face->num_faces;
1334 pFT_Done_Face(ft_face);
1335 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1336 debugstr_w(StyleW));
1337 } while(num_faces > ++face_index);
1338 return num_faces;
1341 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1343 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1346 static void DumpFontList(void)
1348 Family *family;
1349 Face *face;
1350 struct list *family_elem_ptr, *face_elem_ptr;
1352 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1353 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1354 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1355 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1356 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1357 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1358 if(!face->scalable)
1359 TRACE(" %d", face->size.height);
1360 TRACE("\n");
1363 return;
1366 /***********************************************************
1367 * The replacement list is a way to map an entire font
1368 * family onto another family. For example adding
1370 * [HKCU\Software\Wine\Fonts\Replacements]
1371 * "Wingdings"="Winedings"
1373 * would enumerate the Winedings font both as Winedings and
1374 * Wingdings. However if a real Wingdings font is present the
1375 * replacement does not take place.
1378 static void LoadReplaceList(void)
1380 HKEY hkey;
1381 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1382 LPWSTR value;
1383 LPVOID data;
1384 Family *family;
1385 Face *face;
1386 struct list *family_elem_ptr, *face_elem_ptr;
1387 CHAR familyA[400];
1389 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1390 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1392 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1393 &valuelen, &datalen, NULL, NULL);
1395 valuelen++; /* returned value doesn't include room for '\0' */
1396 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1397 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1399 dlen = datalen;
1400 vlen = valuelen;
1401 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1402 &dlen) == ERROR_SUCCESS) {
1403 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1404 /* "NewName"="Oldname" */
1405 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1407 /* Find the old family and hence all of the font files
1408 in that family */
1409 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1410 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1411 if(!strcmpiW(family->FamilyName, data)) {
1412 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1413 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1414 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1415 debugstr_w(face->StyleName), familyA);
1416 /* Now add a new entry with the new family name */
1417 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1419 break;
1422 /* reset dlen and vlen */
1423 dlen = datalen;
1424 vlen = valuelen;
1426 HeapFree(GetProcessHeap(), 0, data);
1427 HeapFree(GetProcessHeap(), 0, value);
1428 RegCloseKey(hkey);
1432 /*************************************************************
1433 * init_system_links
1435 static BOOL init_system_links(void)
1437 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1438 'W','i','n','d','o','w','s',' ','N','T','\\',
1439 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1440 'S','y','s','t','e','m','L','i','n','k',0};
1441 HKEY hkey;
1442 BOOL ret = FALSE;
1443 DWORD type, max_val, max_data, val_len, data_len, index;
1444 WCHAR *value, *data;
1445 WCHAR *entry, *next;
1446 SYSTEM_LINKS *font_link, *system_font_link;
1447 CHILD_FONT *child_font;
1448 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1449 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1450 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1451 FONTSIGNATURE fs;
1452 Family *family;
1453 Face *face;
1454 FontSubst *psub;
1456 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1458 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1459 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1460 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1461 val_len = max_val + 1;
1462 data_len = max_data;
1463 index = 0;
1464 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1466 TRACE("%s:\n", debugstr_w(value));
1468 memset(&fs, 0, sizeof(fs));
1469 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1470 psub = get_font_subst(&font_subst_list, value, -1);
1471 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1472 list_init(&font_link->links);
1473 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1475 WCHAR *face_name;
1476 CHILD_FONT *child_font;
1478 TRACE("\t%s\n", debugstr_w(entry));
1480 next = entry + strlenW(entry) + 1;
1482 face_name = strchrW(entry, ',');
1483 if(face_name)
1485 *face_name++ = 0;
1486 while(isspaceW(*face_name))
1487 face_name++;
1489 psub = get_font_subst(&font_subst_list, face_name, -1);
1490 if(psub)
1491 face_name = psub->to.name;
1493 face = find_face_from_filename(entry, face_name);
1494 if(!face)
1496 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1497 continue;
1500 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1501 child_font->face = face;
1502 child_font->font = NULL;
1503 fs.fsCsb[0] |= face->fs.fsCsb[0];
1504 fs.fsCsb[1] |= face->fs.fsCsb[1];
1505 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1506 list_add_tail(&font_link->links, &child_font->entry);
1508 family = find_family_from_name(font_link->font_name);
1509 if(family)
1511 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1513 memcpy(&face->fs_links, &fs, sizeof(fs));
1516 list_add_tail(&system_links, &font_link->entry);
1517 val_len = max_val + 1;
1518 data_len = max_data;
1521 HeapFree(GetProcessHeap(), 0, value);
1522 HeapFree(GetProcessHeap(), 0, data);
1523 RegCloseKey(hkey);
1526 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1527 that Tahoma has */
1529 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1530 system_font_link->font_name = strdupW(System);
1531 list_init(&system_font_link->links);
1533 face = find_face_from_filename(tahoma_ttf, Tahoma);
1534 if(face)
1536 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1537 child_font->face = face;
1538 child_font->font = NULL;
1539 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1540 list_add_tail(&system_font_link->links, &child_font->entry);
1542 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1544 if(!strcmpiW(font_link->font_name, Tahoma))
1546 CHILD_FONT *font_link_entry;
1547 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1549 CHILD_FONT *new_child;
1550 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1551 new_child->face = font_link_entry->face;
1552 new_child->font = NULL;
1553 list_add_tail(&system_font_link->links, &new_child->entry);
1555 break;
1558 list_add_tail(&system_links, &system_font_link->entry);
1559 return ret;
1562 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1564 DIR *dir;
1565 struct dirent *dent;
1566 char path[MAX_PATH];
1568 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1570 dir = opendir(dirname);
1571 if(!dir) {
1572 WARN("Can't open directory %s\n", debugstr_a(dirname));
1573 return FALSE;
1575 while((dent = readdir(dir)) != NULL) {
1576 struct stat statbuf;
1578 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1579 continue;
1581 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1583 sprintf(path, "%s/%s", dirname, dent->d_name);
1585 if(stat(path, &statbuf) == -1)
1587 WARN("Can't stat %s\n", debugstr_a(path));
1588 continue;
1590 if(S_ISDIR(statbuf.st_mode))
1591 ReadFontDir(path, external_fonts);
1592 else
1593 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1595 closedir(dir);
1596 return TRUE;
1599 static void load_fontconfig_fonts(void)
1601 #ifdef SONAME_LIBFONTCONFIG
1602 void *fc_handle = NULL;
1603 FcConfig *config;
1604 FcPattern *pat;
1605 FcObjectSet *os;
1606 FcFontSet *fontset;
1607 int i, len;
1608 char *file;
1609 const char *ext;
1611 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1612 if(!fc_handle) {
1613 TRACE("Wine cannot find the fontconfig library (%s).\n",
1614 SONAME_LIBFONTCONFIG);
1615 return;
1617 #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;}
1618 LOAD_FUNCPTR(FcConfigGetCurrent);
1619 LOAD_FUNCPTR(FcFontList);
1620 LOAD_FUNCPTR(FcFontSetDestroy);
1621 LOAD_FUNCPTR(FcInit);
1622 LOAD_FUNCPTR(FcObjectSetAdd);
1623 LOAD_FUNCPTR(FcObjectSetCreate);
1624 LOAD_FUNCPTR(FcObjectSetDestroy);
1625 LOAD_FUNCPTR(FcPatternCreate);
1626 LOAD_FUNCPTR(FcPatternDestroy);
1627 LOAD_FUNCPTR(FcPatternGetBool);
1628 LOAD_FUNCPTR(FcPatternGetString);
1629 #undef LOAD_FUNCPTR
1631 if(!pFcInit()) return;
1633 config = pFcConfigGetCurrent();
1634 pat = pFcPatternCreate();
1635 os = pFcObjectSetCreate();
1636 pFcObjectSetAdd(os, FC_FILE);
1637 pFcObjectSetAdd(os, FC_SCALABLE);
1638 fontset = pFcFontList(config, pat, os);
1639 if(!fontset) return;
1640 for(i = 0; i < fontset->nfont; i++) {
1641 FcBool scalable;
1643 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1644 continue;
1645 TRACE("fontconfig: %s\n", file);
1647 /* We're just interested in OT/TT fonts for now, so this hack just
1648 picks up the scalable fonts without extensions .pf[ab] to save time
1649 loading every other font */
1651 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1653 TRACE("not scalable\n");
1654 continue;
1657 len = strlen( file );
1658 if(len < 4) continue;
1659 ext = &file[ len - 3 ];
1660 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1661 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1663 pFcFontSetDestroy(fontset);
1664 pFcObjectSetDestroy(os);
1665 pFcPatternDestroy(pat);
1666 sym_not_found:
1667 #endif
1668 return;
1671 static BOOL load_font_from_data_dir(LPCWSTR file)
1673 BOOL ret = FALSE;
1674 const char *data_dir = wine_get_data_dir();
1676 if (!data_dir) data_dir = wine_get_build_dir();
1678 if (data_dir)
1680 INT len;
1681 char *unix_name;
1683 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1685 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1687 strcpy(unix_name, data_dir);
1688 strcat(unix_name, "/fonts/");
1690 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1692 EnterCriticalSection( &freetype_cs );
1693 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1694 LeaveCriticalSection( &freetype_cs );
1695 HeapFree(GetProcessHeap(), 0, unix_name);
1697 return ret;
1700 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1702 static const WCHAR slashW[] = {'\\','\0'};
1703 BOOL ret = FALSE;
1704 WCHAR windowsdir[MAX_PATH];
1705 char *unixname;
1707 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1708 strcatW(windowsdir, fontsW);
1709 strcatW(windowsdir, slashW);
1710 strcatW(windowsdir, file);
1711 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1712 EnterCriticalSection( &freetype_cs );
1713 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1714 LeaveCriticalSection( &freetype_cs );
1715 HeapFree(GetProcessHeap(), 0, unixname);
1717 return ret;
1720 static void load_system_fonts(void)
1722 HKEY hkey;
1723 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1724 const WCHAR * const *value;
1725 DWORD dlen, type;
1726 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1727 char *unixname;
1729 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1730 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1731 strcatW(windowsdir, fontsW);
1732 for(value = SystemFontValues; *value; value++) {
1733 dlen = sizeof(data);
1734 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1735 type == REG_SZ) {
1736 BOOL added = FALSE;
1738 sprintfW(pathW, fmtW, windowsdir, data);
1739 if((unixname = wine_get_unix_file_name(pathW))) {
1740 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1741 HeapFree(GetProcessHeap(), 0, unixname);
1743 if (!added)
1744 load_font_from_data_dir(data);
1747 RegCloseKey(hkey);
1751 /*************************************************************
1753 * This adds registry entries for any externally loaded fonts
1754 * (fonts from fontconfig or FontDirs). It also deletes entries
1755 * of no longer existing fonts.
1758 static void update_reg_entries(void)
1760 HKEY winkey = 0, externalkey = 0;
1761 LPWSTR valueW;
1762 LPVOID data;
1763 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1764 Family *family;
1765 Face *face;
1766 struct list *family_elem_ptr, *face_elem_ptr;
1767 WCHAR *file;
1768 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1769 static const WCHAR spaceW[] = {' ', '\0'};
1770 char *path;
1772 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1773 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1774 ERR("Can't create Windows font reg key\n");
1775 goto end;
1777 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1778 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1779 ERR("Can't create external font reg key\n");
1780 goto end;
1783 /* Delete all external fonts added last time */
1785 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1786 &valuelen, &datalen, NULL, NULL);
1787 valuelen++; /* returned value doesn't include room for '\0' */
1788 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1789 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1791 dlen = datalen * sizeof(WCHAR);
1792 vlen = valuelen;
1793 i = 0;
1794 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1795 &dlen) == ERROR_SUCCESS) {
1797 RegDeleteValueW(winkey, valueW);
1798 /* reset dlen and vlen */
1799 dlen = datalen;
1800 vlen = valuelen;
1802 HeapFree(GetProcessHeap(), 0, data);
1803 HeapFree(GetProcessHeap(), 0, valueW);
1805 /* Delete the old external fonts key */
1806 RegCloseKey(externalkey);
1807 externalkey = 0;
1808 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1810 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1811 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1812 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1813 ERR("Can't create external font reg key\n");
1814 goto end;
1817 /* enumerate the fonts and add external ones to the two keys */
1819 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1820 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1821 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1822 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1823 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1824 if(!face->external) continue;
1825 len = len_fam;
1826 if(strcmpiW(face->StyleName, RegularW))
1827 len = len_fam + strlenW(face->StyleName) + 1;
1828 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1829 strcpyW(valueW, family->FamilyName);
1830 if(len != len_fam) {
1831 strcatW(valueW, spaceW);
1832 strcatW(valueW, face->StyleName);
1834 strcatW(valueW, TrueType);
1835 if((path = strrchr(face->file, '/')) == NULL)
1836 path = face->file;
1837 else
1838 path++;
1839 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1841 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1842 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1843 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1844 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1846 HeapFree(GetProcessHeap(), 0, file);
1847 HeapFree(GetProcessHeap(), 0, valueW);
1850 end:
1851 if(externalkey)
1852 RegCloseKey(externalkey);
1853 if(winkey)
1854 RegCloseKey(winkey);
1855 return;
1859 /*************************************************************
1860 * WineEngAddFontResourceEx
1863 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1865 INT ret = 0;
1866 if (ft_handle) /* do it only if we have freetype up and running */
1868 char *unixname;
1870 if(flags)
1871 FIXME("Ignoring flags %x\n", flags);
1873 if((unixname = wine_get_unix_file_name(file)))
1875 EnterCriticalSection( &freetype_cs );
1876 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1877 LeaveCriticalSection( &freetype_cs );
1878 HeapFree(GetProcessHeap(), 0, unixname);
1880 if (!ret && !strchrW(file, '\\')) {
1881 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
1882 ret = load_font_from_winfonts_dir(file);
1883 if (!ret) {
1884 /* Try in datadir/fonts (or builddir/fonts),
1885 * needed for Magic the Gathering Online
1887 ret = load_font_from_data_dir(file);
1891 return ret;
1894 /*************************************************************
1895 * WineEngAddFontMemResourceEx
1898 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1900 if (ft_handle) /* do it only if we have freetype up and running */
1902 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1904 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1905 memcpy(pFontCopy, pbFont, cbFont);
1907 EnterCriticalSection( &freetype_cs );
1908 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1909 LeaveCriticalSection( &freetype_cs );
1911 if (*pcFonts == 0)
1913 TRACE("AddFontToList failed\n");
1914 HeapFree(GetProcessHeap(), 0, pFontCopy);
1915 return NULL;
1917 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1918 * For now return something unique but quite random
1920 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1921 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1924 *pcFonts = 0;
1925 return 0;
1928 /*************************************************************
1929 * WineEngRemoveFontResourceEx
1932 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1934 FIXME(":stub\n");
1935 return TRUE;
1938 static const struct nls_update_font_list
1940 UINT ansi_cp, oem_cp;
1941 const char *oem, *fixed, *system;
1942 const char *courier, *serif, *small, *sserif;
1943 /* these are for font substitute */
1944 const char *shelldlg, *tmsrmn;
1945 } nls_update_font_list[] =
1947 /* Latin 1 (United States) */
1948 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1949 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1950 "Tahoma","Times New Roman",
1952 /* Latin 1 (Multilingual) */
1953 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1954 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1955 "Tahoma","Times New Roman", /* FIXME unverified */
1957 /* Eastern Europe */
1958 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1959 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1960 "Tahoma","Times New Roman", /* FIXME unverified */
1962 /* Cyrillic */
1963 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1964 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1965 "Tahoma","Times New Roman", /* FIXME unverified */
1967 /* Greek */
1968 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1969 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1970 "Tahoma","Times New Roman", /* FIXME unverified */
1972 /* Turkish */
1973 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1974 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1975 "Tahoma","Times New Roman", /* FIXME unverified */
1977 /* Hebrew */
1978 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1979 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1980 "Tahoma","Times New Roman", /* FIXME unverified */
1982 /* Arabic */
1983 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1984 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1985 "Tahoma","Times New Roman", /* FIXME unverified */
1987 /* Baltic */
1988 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1989 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1990 "Tahoma","Times New Roman", /* FIXME unverified */
1992 /* Vietnamese */
1993 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1994 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1995 "Tahoma","Times New Roman", /* FIXME unverified */
1997 /* Thai */
1998 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1999 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2000 "Tahoma","Times New Roman", /* FIXME unverified */
2002 /* Japanese */
2003 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2004 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2005 "MS UI Gothic","MS Serif",
2007 /* Chinese Simplified */
2008 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2009 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2010 "Tahoma", "Times New Roman", /* FIXME unverified */
2012 /* Korean */
2013 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2014 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2015 "Gulim", "Batang",
2017 /* Chinese Traditional */
2018 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2019 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2020 "PMingLiU", "MingLiU",
2024 static inline HKEY create_fonts_NT_registry_key(void)
2026 HKEY hkey = 0;
2028 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2029 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2030 return hkey;
2033 static inline HKEY create_fonts_9x_registry_key(void)
2035 HKEY hkey = 0;
2037 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2038 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2039 return hkey;
2042 static inline HKEY create_config_fonts_registry_key(void)
2044 HKEY hkey = 0;
2046 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2047 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2048 return hkey;
2051 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2053 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2054 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2055 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2056 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2059 static void update_font_info(void)
2061 char buf[40], cpbuf[40];
2062 DWORD len, type;
2063 HKEY hkey = 0;
2064 UINT i, ansi_cp = 0, oem_cp = 0;
2066 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2067 return;
2069 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2070 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2071 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2072 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2073 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2075 len = sizeof(buf);
2076 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2078 if (!strcmp( buf, cpbuf )) /* already set correctly */
2080 RegCloseKey(hkey);
2081 return;
2083 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2085 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2087 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2088 RegCloseKey(hkey);
2090 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2092 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2093 nls_update_font_list[i].oem_cp == oem_cp)
2095 HKEY hkey;
2097 hkey = create_config_fonts_registry_key();
2098 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2099 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2100 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2101 RegCloseKey(hkey);
2103 hkey = create_fonts_NT_registry_key();
2104 add_font_list(hkey, &nls_update_font_list[i]);
2105 RegCloseKey(hkey);
2107 hkey = create_fonts_9x_registry_key();
2108 add_font_list(hkey, &nls_update_font_list[i]);
2109 RegCloseKey(hkey);
2111 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2113 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2114 strlen(nls_update_font_list[i].shelldlg)+1);
2115 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2116 strlen(nls_update_font_list[i].tmsrmn)+1);
2117 RegCloseKey(hkey);
2119 return;
2122 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2125 /*************************************************************
2126 * WineEngInit
2128 * Initialize FreeType library and create a list of available faces
2130 BOOL WineEngInit(void)
2132 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2133 static const WCHAR pathW[] = {'P','a','t','h',0};
2134 HKEY hkey;
2135 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2136 LPVOID data;
2137 WCHAR windowsdir[MAX_PATH];
2138 char *unixname;
2139 HANDLE font_mutex;
2140 const char *data_dir;
2142 TRACE("\n");
2144 /* update locale dependent font info in registry */
2145 update_font_info();
2147 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2148 if(!ft_handle) {
2149 WINE_MESSAGE(
2150 "Wine cannot find the FreeType font library. To enable Wine to\n"
2151 "use TrueType fonts please install a version of FreeType greater than\n"
2152 "or equal to 2.0.5.\n"
2153 "http://www.freetype.org\n");
2154 return FALSE;
2157 #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;}
2159 LOAD_FUNCPTR(FT_Vector_Unit)
2160 LOAD_FUNCPTR(FT_Done_Face)
2161 LOAD_FUNCPTR(FT_Get_Char_Index)
2162 LOAD_FUNCPTR(FT_Get_Module)
2163 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2164 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2165 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2166 LOAD_FUNCPTR(FT_Init_FreeType)
2167 LOAD_FUNCPTR(FT_Load_Glyph)
2168 LOAD_FUNCPTR(FT_Matrix_Multiply)
2169 LOAD_FUNCPTR(FT_MulFix)
2170 LOAD_FUNCPTR(FT_New_Face)
2171 LOAD_FUNCPTR(FT_New_Memory_Face)
2172 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2173 LOAD_FUNCPTR(FT_Outline_Transform)
2174 LOAD_FUNCPTR(FT_Outline_Translate)
2175 LOAD_FUNCPTR(FT_Select_Charmap)
2176 LOAD_FUNCPTR(FT_Set_Charmap)
2177 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2178 LOAD_FUNCPTR(FT_Vector_Transform)
2180 #undef LOAD_FUNCPTR
2181 /* Don't warn if this one is missing */
2182 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2183 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2184 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2185 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2186 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2187 #ifdef HAVE_FREETYPE_FTWINFNT_H
2188 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2189 #endif
2190 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2191 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2192 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2193 <= 2.0.3 has FT_Sqrt64 */
2194 goto sym_not_found;
2197 if(pFT_Init_FreeType(&library) != 0) {
2198 ERR("Can't init FreeType library\n");
2199 wine_dlclose(ft_handle, NULL, 0);
2200 ft_handle = NULL;
2201 return FALSE;
2203 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2204 if (pFT_Library_Version)
2206 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2208 if (FT_Version.major<=0)
2210 FT_Version.major=2;
2211 FT_Version.minor=0;
2212 FT_Version.patch=5;
2214 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2215 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2216 ((FT_Version.minor << 8) & 0x00ff00) |
2217 ((FT_Version.patch ) & 0x0000ff);
2219 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2220 ERR("Failed to create font mutex\n");
2221 return FALSE;
2223 WaitForSingleObject(font_mutex, INFINITE);
2225 /* load the system bitmap fonts */
2226 load_system_fonts();
2228 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2229 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2230 strcatW(windowsdir, fontsW);
2231 if((unixname = wine_get_unix_file_name(windowsdir)))
2233 ReadFontDir(unixname, FALSE);
2234 HeapFree(GetProcessHeap(), 0, unixname);
2237 /* load the system truetype fonts */
2238 data_dir = wine_get_data_dir();
2239 if (!data_dir) data_dir = wine_get_build_dir();
2240 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2241 strcpy(unixname, data_dir);
2242 strcat(unixname, "/fonts/");
2243 ReadFontDir(unixname, TRUE);
2244 HeapFree(GetProcessHeap(), 0, unixname);
2247 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2248 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2249 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2250 will skip these. */
2251 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2252 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2253 &hkey) == ERROR_SUCCESS) {
2254 LPWSTR valueW;
2255 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2256 &valuelen, &datalen, NULL, NULL);
2258 valuelen++; /* returned value doesn't include room for '\0' */
2259 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2260 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2261 if (valueW && data)
2263 dlen = datalen * sizeof(WCHAR);
2264 vlen = valuelen;
2265 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2266 &dlen) == ERROR_SUCCESS) {
2267 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2269 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2271 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2272 HeapFree(GetProcessHeap(), 0, unixname);
2275 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2277 WCHAR pathW[MAX_PATH];
2278 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2279 BOOL added = FALSE;
2281 sprintfW(pathW, fmtW, windowsdir, data);
2282 if((unixname = wine_get_unix_file_name(pathW)))
2284 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2285 HeapFree(GetProcessHeap(), 0, unixname);
2287 if (!added)
2288 load_font_from_data_dir(data);
2290 /* reset dlen and vlen */
2291 dlen = datalen;
2292 vlen = valuelen;
2295 HeapFree(GetProcessHeap(), 0, data);
2296 HeapFree(GetProcessHeap(), 0, valueW);
2297 RegCloseKey(hkey);
2300 load_fontconfig_fonts();
2302 /* then look in any directories that we've specified in the config file */
2303 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2304 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2306 DWORD len;
2307 LPWSTR valueW;
2308 LPSTR valueA, ptr;
2310 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2312 len += sizeof(WCHAR);
2313 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2314 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2316 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2317 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2318 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2319 TRACE( "got font path %s\n", debugstr_a(valueA) );
2320 ptr = valueA;
2321 while (ptr)
2323 LPSTR next = strchr( ptr, ':' );
2324 if (next) *next++ = 0;
2325 ReadFontDir( ptr, TRUE );
2326 ptr = next;
2328 HeapFree( GetProcessHeap(), 0, valueA );
2330 HeapFree( GetProcessHeap(), 0, valueW );
2332 RegCloseKey(hkey);
2335 DumpFontList();
2336 LoadSubstList();
2337 DumpSubstList();
2338 LoadReplaceList();
2339 update_reg_entries();
2341 init_system_links();
2343 ReleaseMutex(font_mutex);
2344 return TRUE;
2345 sym_not_found:
2346 WINE_MESSAGE(
2347 "Wine cannot find certain functions that it needs inside the FreeType\n"
2348 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2349 "FreeType to at least version 2.0.5.\n"
2350 "http://www.freetype.org\n");
2351 wine_dlclose(ft_handle, NULL, 0);
2352 ft_handle = NULL;
2353 return FALSE;
2357 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2359 TT_OS2 *pOS2;
2360 TT_HoriHeader *pHori;
2362 LONG ppem;
2364 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2365 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2367 if(height == 0) height = 16;
2369 /* Calc. height of EM square:
2371 * For +ve lfHeight we have
2372 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2373 * Re-arranging gives:
2374 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2376 * For -ve lfHeight we have
2377 * |lfHeight| = ppem
2378 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2379 * with il = winAscent + winDescent - units_per_em]
2383 if(height > 0) {
2384 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2385 ppem = ft_face->units_per_EM * height /
2386 (pHori->Ascender - pHori->Descender);
2387 else
2388 ppem = ft_face->units_per_EM * height /
2389 (pOS2->usWinAscent + pOS2->usWinDescent);
2391 else
2392 ppem = -height;
2394 return ppem;
2397 static struct font_mapping *map_font_file( const char *name )
2399 struct font_mapping *mapping;
2400 struct stat st;
2401 int fd;
2403 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2404 if (fstat( fd, &st ) == -1) goto error;
2406 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2408 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2410 mapping->refcount++;
2411 close( fd );
2412 return mapping;
2415 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2416 goto error;
2418 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2419 close( fd );
2421 if (mapping->data == MAP_FAILED)
2423 HeapFree( GetProcessHeap(), 0, mapping );
2424 return NULL;
2426 mapping->refcount = 1;
2427 mapping->dev = st.st_dev;
2428 mapping->ino = st.st_ino;
2429 mapping->size = st.st_size;
2430 list_add_tail( &mappings_list, &mapping->entry );
2431 return mapping;
2433 error:
2434 close( fd );
2435 return NULL;
2438 static void unmap_font_file( struct font_mapping *mapping )
2440 if (!--mapping->refcount)
2442 list_remove( &mapping->entry );
2443 munmap( mapping->data, mapping->size );
2444 HeapFree( GetProcessHeap(), 0, mapping );
2448 static LONG load_VDMX(GdiFont*, LONG);
2450 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2452 FT_Error err;
2453 FT_Face ft_face;
2454 void *data_ptr;
2455 DWORD data_size;
2457 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2459 if (face->file)
2461 if (!(font->mapping = map_font_file( face->file )))
2463 WARN("failed to map %s\n", debugstr_a(face->file));
2464 return 0;
2466 data_ptr = font->mapping->data;
2467 data_size = font->mapping->size;
2469 else
2471 data_ptr = face->font_data_ptr;
2472 data_size = face->font_data_size;
2475 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2476 if(err) {
2477 ERR("FT_New_Face rets %d\n", err);
2478 return 0;
2481 /* set it here, as load_VDMX needs it */
2482 font->ft_face = ft_face;
2484 if(FT_IS_SCALABLE(ft_face)) {
2485 /* load the VDMX table if we have one */
2486 font->ppem = load_VDMX(font, height);
2487 if(font->ppem == 0)
2488 font->ppem = calc_ppem_for_height(ft_face, height);
2490 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2491 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2492 } else {
2493 font->ppem = height;
2494 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2495 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2497 return ft_face;
2501 static int get_nearest_charset(Face *face, int *cp)
2503 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2504 a single face with the requested charset. The idea is to check if
2505 the selected font supports the current ANSI codepage, if it does
2506 return the corresponding charset, else return the first charset */
2508 CHARSETINFO csi;
2509 int acp = GetACP(), i;
2510 DWORD fs0;
2512 *cp = acp;
2513 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2514 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2515 return csi.ciCharset;
2517 for(i = 0; i < 32; i++) {
2518 fs0 = 1L << i;
2519 if(face->fs.fsCsb[0] & fs0) {
2520 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2521 *cp = csi.ciACP;
2522 return csi.ciCharset;
2524 else
2525 FIXME("TCI failing on %x\n", fs0);
2529 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2530 face->fs.fsCsb[0], face->file);
2531 *cp = acp;
2532 return DEFAULT_CHARSET;
2535 static GdiFont *alloc_font(void)
2537 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2538 ret->gmsize = 1;
2539 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2540 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2541 ret->potm = NULL;
2542 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2543 ret->total_kern_pairs = (DWORD)-1;
2544 ret->kern_pairs = NULL;
2545 list_init(&ret->hfontlist);
2546 list_init(&ret->child_fonts);
2547 return ret;
2550 static void free_font(GdiFont *font)
2552 struct list *cursor, *cursor2;
2553 int i;
2555 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2557 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2558 struct list *first_hfont;
2559 HFONTLIST *hfontlist;
2560 list_remove(cursor);
2561 if(child->font)
2563 first_hfont = list_head(&child->font->hfontlist);
2564 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2565 DeleteObject(hfontlist->hfont);
2566 HeapFree(GetProcessHeap(), 0, hfontlist);
2567 free_font(child->font);
2569 HeapFree(GetProcessHeap(), 0, child);
2572 if (font->ft_face) pFT_Done_Face(font->ft_face);
2573 if (font->mapping) unmap_font_file( font->mapping );
2574 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2575 HeapFree(GetProcessHeap(), 0, font->potm);
2576 HeapFree(GetProcessHeap(), 0, font->name);
2577 for (i = 0; i < font->gmsize; i++)
2578 HeapFree(GetProcessHeap(),0,font->gm[i]);
2579 HeapFree(GetProcessHeap(), 0, font->gm);
2580 HeapFree(GetProcessHeap(), 0, font);
2584 /*************************************************************
2585 * load_VDMX
2587 * load the vdmx entry for the specified height
2590 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2591 ( ( (FT_ULong)_x4 << 24 ) | \
2592 ( (FT_ULong)_x3 << 16 ) | \
2593 ( (FT_ULong)_x2 << 8 ) | \
2594 (FT_ULong)_x1 )
2596 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2598 typedef struct {
2599 BYTE bCharSet;
2600 BYTE xRatio;
2601 BYTE yStartRatio;
2602 BYTE yEndRatio;
2603 } Ratios;
2605 typedef struct {
2606 WORD recs;
2607 BYTE startsz;
2608 BYTE endsz;
2609 } VDMX_group;
2611 static LONG load_VDMX(GdiFont *font, LONG height)
2613 WORD hdr[3], tmp;
2614 VDMX_group group;
2615 BYTE devXRatio, devYRatio;
2616 USHORT numRecs, numRatios;
2617 DWORD result, offset = -1;
2618 LONG ppem = 0;
2619 int i;
2621 /* For documentation on VDMX records, see
2622 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2625 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2627 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2628 return ppem;
2630 /* FIXME: need the real device aspect ratio */
2631 devXRatio = 1;
2632 devYRatio = 1;
2634 numRecs = GET_BE_WORD(hdr[1]);
2635 numRatios = GET_BE_WORD(hdr[2]);
2637 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2638 for(i = 0; i < numRatios; i++) {
2639 Ratios ratio;
2641 offset = (3 * 2) + (i * sizeof(Ratios));
2642 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2643 offset = -1;
2645 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2647 if((ratio.xRatio == 0 &&
2648 ratio.yStartRatio == 0 &&
2649 ratio.yEndRatio == 0) ||
2650 (devXRatio == ratio.xRatio &&
2651 devYRatio >= ratio.yStartRatio &&
2652 devYRatio <= ratio.yEndRatio))
2654 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2655 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2656 offset = GET_BE_WORD(tmp);
2657 break;
2661 if(offset == -1) {
2662 FIXME("No suitable ratio found\n");
2663 return ppem;
2666 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2667 USHORT recs;
2668 BYTE startsz, endsz;
2669 WORD *vTable;
2671 recs = GET_BE_WORD(group.recs);
2672 startsz = group.startsz;
2673 endsz = group.endsz;
2675 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2677 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2678 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2679 if(result == GDI_ERROR) {
2680 FIXME("Failed to retrieve vTable\n");
2681 goto end;
2684 if(height > 0) {
2685 for(i = 0; i < recs; i++) {
2686 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2687 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2688 ppem = GET_BE_WORD(vTable[i * 3]);
2690 if(yMax + -yMin == height) {
2691 font->yMax = yMax;
2692 font->yMin = yMin;
2693 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2694 break;
2696 if(yMax + -yMin > height) {
2697 if(--i < 0) {
2698 ppem = 0;
2699 goto end; /* failed */
2701 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2702 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2703 ppem = GET_BE_WORD(vTable[i * 3]);
2704 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2705 break;
2708 if(!font->yMax) {
2709 ppem = 0;
2710 TRACE("ppem not found for height %d\n", height);
2712 } else {
2713 ppem = -height;
2714 if(ppem < startsz || ppem > endsz)
2715 goto end;
2717 for(i = 0; i < recs; i++) {
2718 USHORT yPelHeight;
2719 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2721 if(yPelHeight > ppem)
2722 break; /* failed */
2724 if(yPelHeight == ppem) {
2725 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2726 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2727 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2728 break;
2732 end:
2733 HeapFree(GetProcessHeap(), 0, vTable);
2736 return ppem;
2739 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2741 if(font->font_desc.hash != fd->hash) return TRUE;
2742 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2743 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2744 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2745 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2748 static void calc_hash(FONT_DESC *pfd)
2750 DWORD hash = 0, *ptr, two_chars;
2751 WORD *pwc;
2752 unsigned int i;
2754 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2755 hash ^= *ptr;
2756 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2757 hash ^= *ptr;
2758 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2759 two_chars = *ptr;
2760 pwc = (WCHAR *)&two_chars;
2761 if(!*pwc) break;
2762 *pwc = toupperW(*pwc);
2763 pwc++;
2764 *pwc = toupperW(*pwc);
2765 hash ^= two_chars;
2766 if(!*pwc) break;
2768 hash ^= !pfd->can_use_bitmap;
2769 pfd->hash = hash;
2770 return;
2773 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2775 GdiFont *ret;
2776 FONT_DESC fd;
2777 HFONTLIST *hflist;
2778 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2780 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2781 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2782 fd.can_use_bitmap = can_use_bitmap;
2783 calc_hash(&fd);
2785 /* try the in-use list */
2786 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2787 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2788 if(!fontcmp(ret, &fd)) {
2789 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2790 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2791 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2792 if(hflist->hfont == hfont)
2793 return ret;
2795 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2796 hflist->hfont = hfont;
2797 list_add_head(&ret->hfontlist, &hflist->entry);
2798 return ret;
2802 /* then the unused list */
2803 font_elem_ptr = list_head(&unused_gdi_font_list);
2804 while(font_elem_ptr) {
2805 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2806 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2807 if(!fontcmp(ret, &fd)) {
2808 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2809 assert(list_empty(&ret->hfontlist));
2810 TRACE("Found %p in unused list\n", ret);
2811 list_remove(&ret->entry);
2812 list_add_head(&gdi_font_list, &ret->entry);
2813 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2814 hflist->hfont = hfont;
2815 list_add_head(&ret->hfontlist, &hflist->entry);
2816 return ret;
2819 return NULL;
2823 /*************************************************************
2824 * create_child_font_list
2826 static BOOL create_child_font_list(GdiFont *font)
2828 BOOL ret = FALSE;
2829 SYSTEM_LINKS *font_link;
2830 CHILD_FONT *font_link_entry, *new_child;
2832 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2834 if(!strcmpW(font_link->font_name, font->name))
2836 TRACE("found entry in system list\n");
2837 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2839 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2840 new_child->face = font_link_entry->face;
2841 new_child->font = NULL;
2842 list_add_tail(&font->child_fonts, &new_child->entry);
2843 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2845 ret = TRUE;
2846 break;
2850 return ret;
2853 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2855 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2857 if (pFT_Set_Charmap)
2859 FT_Int i;
2860 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2862 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2864 for (i = 0; i < ft_face->num_charmaps; i++)
2866 if (ft_face->charmaps[i]->encoding == encoding)
2868 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2869 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2871 switch (ft_face->charmaps[i]->platform_id)
2873 default:
2874 cmap_def = ft_face->charmaps[i];
2875 break;
2876 case 0: /* Apple Unicode */
2877 cmap0 = ft_face->charmaps[i];
2878 break;
2879 case 1: /* Macintosh */
2880 cmap1 = ft_face->charmaps[i];
2881 break;
2882 case 2: /* ISO */
2883 cmap2 = ft_face->charmaps[i];
2884 break;
2885 case 3: /* Microsoft */
2886 cmap3 = ft_face->charmaps[i];
2887 break;
2891 if (cmap3) /* prefer Microsoft cmap table */
2892 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2893 else if (cmap1)
2894 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2895 else if (cmap2)
2896 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2897 else if (cmap0)
2898 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2899 else if (cmap_def)
2900 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2902 return ft_err == FT_Err_Ok;
2905 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2908 /*************************************************************
2909 * WineEngCreateFontInstance
2912 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2914 GdiFont *ret;
2915 Face *face, *best, *best_bitmap;
2916 Family *family, *last_resort_family;
2917 struct list *family_elem_ptr, *face_elem_ptr;
2918 INT height, width = 0;
2919 unsigned int score = 0, new_score;
2920 signed int diff = 0, newdiff;
2921 BOOL bd, it, can_use_bitmap;
2922 LOGFONTW lf;
2923 CHARSETINFO csi;
2924 HFONTLIST *hflist;
2926 EnterCriticalSection( &freetype_cs );
2928 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2930 struct list *first_hfont = list_head(&ret->hfontlist);
2931 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2932 if(hflist->hfont == hfont)
2934 LeaveCriticalSection( &freetype_cs );
2935 return ret;
2939 if (!GetObjectW( hfont, sizeof(lf), &lf ))
2941 LeaveCriticalSection( &freetype_cs );
2942 return NULL;
2944 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2946 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2947 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2948 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2949 lf.lfEscapement);
2951 /* check the cache first */
2952 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2953 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2954 LeaveCriticalSection( &freetype_cs );
2955 return ret;
2958 TRACE("not in cache\n");
2959 if(list_empty(&font_list)) /* No fonts installed */
2961 TRACE("No fonts installed\n");
2962 LeaveCriticalSection( &freetype_cs );
2963 return NULL;
2965 if(!have_installed_roman_font)
2967 TRACE("No roman font installed\n");
2968 LeaveCriticalSection( &freetype_cs );
2969 return NULL;
2972 ret = alloc_font();
2974 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2975 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2976 ret->font_desc.can_use_bitmap = can_use_bitmap;
2977 calc_hash(&ret->font_desc);
2978 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2979 hflist->hfont = hfont;
2980 list_add_head(&ret->hfontlist, &hflist->entry);
2983 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2984 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2985 original value lfCharSet. Note this is a special case for
2986 Symbol and doesn't happen at least for "Wingdings*" */
2988 if(!strcmpiW(lf.lfFaceName, SymbolW))
2989 lf.lfCharSet = SYMBOL_CHARSET;
2991 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2992 switch(lf.lfCharSet) {
2993 case DEFAULT_CHARSET:
2994 csi.fs.fsCsb[0] = 0;
2995 break;
2996 default:
2997 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2998 csi.fs.fsCsb[0] = 0;
2999 break;
3003 family = NULL;
3004 if(lf.lfFaceName[0] != '\0') {
3005 FontSubst *psub;
3006 SYSTEM_LINKS *font_link;
3007 CHILD_FONT *font_link_entry;
3009 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
3011 if(psub) {
3012 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
3013 debugstr_w(psub->to.name));
3014 strcpyW(lf.lfFaceName, psub->to.name);
3017 /* We want a match on name and charset or just name if
3018 charset was DEFAULT_CHARSET. If the latter then
3019 we fixup the returned charset later in get_nearest_charset
3020 where we'll either use the charset of the current ansi codepage
3021 or if that's unavailable the first charset that the font supports.
3023 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3024 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3025 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3026 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3027 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3028 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3029 if(face->scalable || can_use_bitmap)
3030 goto found;
3036 * Try check the SystemLink list first for a replacement font.
3037 * We may find good replacements there.
3039 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3041 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
3043 TRACE("found entry in system list\n");
3044 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3046 face = font_link_entry->face;
3047 family = face->family;
3048 if(csi.fs.fsCsb[0] &
3049 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3051 if(face->scalable || can_use_bitmap)
3052 goto found;
3059 /* If requested charset was DEFAULT_CHARSET then try using charset
3060 corresponding to the current ansi codepage */
3061 if(!csi.fs.fsCsb[0]) {
3062 INT acp = GetACP();
3063 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3064 FIXME("TCI failed on codepage %d\n", acp);
3065 csi.fs.fsCsb[0] = 0;
3066 } else
3067 lf.lfCharSet = csi.ciCharset;
3070 /* Face families are in the top 4 bits of lfPitchAndFamily,
3071 so mask with 0xF0 before testing */
3073 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3074 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3075 strcpyW(lf.lfFaceName, defFixed);
3076 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3077 strcpyW(lf.lfFaceName, defSerif);
3078 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3079 strcpyW(lf.lfFaceName, defSans);
3080 else
3081 strcpyW(lf.lfFaceName, defSans);
3082 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3083 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3084 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3085 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3086 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3087 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3088 if(face->scalable || can_use_bitmap)
3089 goto found;
3094 last_resort_family = NULL;
3095 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3096 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3097 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3098 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3099 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3100 if(face->scalable)
3101 goto found;
3102 if(can_use_bitmap && !last_resort_family)
3103 last_resort_family = family;
3108 if(last_resort_family) {
3109 family = last_resort_family;
3110 csi.fs.fsCsb[0] = 0;
3111 goto found;
3114 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3115 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3116 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3117 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3118 if(face->scalable) {
3119 csi.fs.fsCsb[0] = 0;
3120 WARN("just using first face for now\n");
3121 goto found;
3123 if(can_use_bitmap && !last_resort_family)
3124 last_resort_family = family;
3127 if(!last_resort_family) {
3128 FIXME("can't find a single appropriate font - bailing\n");
3129 free_font(ret);
3130 LeaveCriticalSection( &freetype_cs );
3131 return NULL;
3134 WARN("could only find a bitmap font - this will probably look awful!\n");
3135 family = last_resort_family;
3136 csi.fs.fsCsb[0] = 0;
3138 found:
3139 it = lf.lfItalic ? 1 : 0;
3140 bd = lf.lfWeight > 550 ? 1 : 0;
3142 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3143 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3145 face = best = best_bitmap = NULL;
3146 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3148 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3150 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3151 if(!best || new_score <= score)
3153 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3154 face->Italic, face->Bold, it, bd);
3155 score = new_score;
3156 best = face;
3157 if(best->scalable && score == 0) break;
3158 if(!best->scalable)
3160 if(height > 0)
3161 newdiff = height - (signed int)(best->size.height);
3162 else
3163 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3164 if(!best_bitmap || new_score < score ||
3165 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3167 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3168 diff = newdiff;
3169 best_bitmap = best;
3170 if(score == 0 && diff == 0) break;
3176 if(best)
3177 face = best->scalable ? best : best_bitmap;
3178 ret->fake_italic = (it && !face->Italic);
3179 ret->fake_bold = (bd && !face->Bold);
3181 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3183 if(csi.fs.fsCsb[0]) {
3184 ret->charset = lf.lfCharSet;
3185 ret->codepage = csi.ciACP;
3187 else
3188 ret->charset = get_nearest_charset(face, &ret->codepage);
3190 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3191 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3193 ret->aveWidth = abs(lf.lfWidth);
3195 if(!face->scalable) {
3196 /* Windows uses integer scaling factors for bitmap fonts */
3197 INT scale, scaled_height;
3199 if (height != 0) height = diff;
3200 else height = 0;
3201 height += face->size.height;
3203 scale = (height + face->size.height - 1) / face->size.height;
3204 scaled_height = scale * face->size.height;
3205 /* XP allows not more than 10% deviation */
3206 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3207 ret->scale_y = scale;
3209 width = face->size.x_ppem >> 6;
3210 height = face->size.y_ppem >> 6;
3212 else
3213 ret->scale_y = 1.0;
3214 TRACE("font scale y: %f\n", ret->scale_y);
3216 ret->ft_face = OpenFontFace(ret, face, width, height);
3218 if (!ret->ft_face)
3220 free_font( ret );
3221 LeaveCriticalSection( &freetype_cs );
3222 return 0;
3225 ret->ntmFlags = face->ntmFlags;
3227 if (ret->charset == SYMBOL_CHARSET &&
3228 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3229 /* No ops */
3231 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3232 /* No ops */
3234 else {
3235 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3238 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3239 ret->name = strdupW(family->FamilyName);
3240 ret->underline = lf.lfUnderline ? 0xff : 0;
3241 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3242 create_child_font_list(ret);
3244 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3246 list_add_head(&gdi_font_list, &ret->entry);
3247 LeaveCriticalSection( &freetype_cs );
3248 return ret;
3251 static void dump_gdi_font_list(void)
3253 GdiFont *gdiFont;
3254 struct list *elem_ptr;
3256 TRACE("---------- gdiFont Cache ----------\n");
3257 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3258 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3259 TRACE("gdiFont=%p %s %d\n",
3260 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3263 TRACE("---------- Unused gdiFont Cache ----------\n");
3264 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3265 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3266 TRACE("gdiFont=%p %s %d\n",
3267 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3271 /*************************************************************
3272 * WineEngDestroyFontInstance
3274 * free the gdiFont associated with this handle
3277 BOOL WineEngDestroyFontInstance(HFONT handle)
3279 GdiFont *gdiFont;
3280 HFONTLIST *hflist;
3281 BOOL ret = FALSE;
3282 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3283 int i = 0;
3285 EnterCriticalSection( &freetype_cs );
3287 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3289 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3290 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3291 if(hflist->hfont == handle)
3293 TRACE("removing child font %p from child list\n", gdiFont);
3294 list_remove(&gdiFont->entry);
3295 LeaveCriticalSection( &freetype_cs );
3296 return TRUE;
3300 TRACE("destroying hfont=%p\n", handle);
3301 if(TRACE_ON(font))
3302 dump_gdi_font_list();
3304 font_elem_ptr = list_head(&gdi_font_list);
3305 while(font_elem_ptr) {
3306 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3307 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3309 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3310 while(hfontlist_elem_ptr) {
3311 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3312 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3313 if(hflist->hfont == handle) {
3314 list_remove(&hflist->entry);
3315 HeapFree(GetProcessHeap(), 0, hflist);
3316 ret = TRUE;
3319 if(list_empty(&gdiFont->hfontlist)) {
3320 TRACE("Moving to Unused list\n");
3321 list_remove(&gdiFont->entry);
3322 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3327 font_elem_ptr = list_head(&unused_gdi_font_list);
3328 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3329 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3330 while(font_elem_ptr) {
3331 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3332 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3333 TRACE("freeing %p\n", gdiFont);
3334 list_remove(&gdiFont->entry);
3335 free_font(gdiFont);
3337 LeaveCriticalSection( &freetype_cs );
3338 return ret;
3341 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3342 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3344 GdiFont *font;
3345 LONG width, height;
3347 if (face->cached_enum_data)
3349 TRACE("Cached\n");
3350 memcpy(pelf, &face->cached_enum_data->elf, sizeof(ENUMLOGFONTEXW));
3351 memcpy(pntm, &face->cached_enum_data->ntm, sizeof(NEWTEXTMETRICEXW));
3352 *ptype = face->cached_enum_data->type;
3353 return;
3356 font = alloc_font();
3358 if(face->scalable) {
3359 height = 100;
3360 width = 0;
3361 } else {
3362 height = face->size.y_ppem >> 6;
3363 width = face->size.x_ppem >> 6;
3365 font->scale_y = 1.0;
3367 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3369 free_font(font);
3370 return;
3373 font->name = strdupW(face->family->FamilyName);
3374 font->ntmFlags = face->ntmFlags;
3376 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3378 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3380 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3382 lstrcpynW(pelf->elfLogFont.lfFaceName,
3383 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3384 LF_FACESIZE);
3385 lstrcpynW(pelf->elfFullName,
3386 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3387 LF_FULLFACESIZE);
3388 lstrcpynW(pelf->elfStyle,
3389 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3390 LF_FACESIZE);
3392 else
3394 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3396 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3398 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3399 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3400 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3403 pntm->ntmTm.ntmFlags = face->ntmFlags;
3404 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3405 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3406 memcpy(&pntm->ntmFontSig, &face->fs, sizeof(FONTSIGNATURE));
3408 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3410 pelf->elfLogFont.lfEscapement = 0;
3411 pelf->elfLogFont.lfOrientation = 0;
3412 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3413 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3414 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3415 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3416 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3417 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3418 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3419 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3420 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3421 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3422 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3424 *ptype = 0;
3425 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3426 *ptype |= TRUETYPE_FONTTYPE;
3427 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3428 *ptype |= DEVICE_FONTTYPE;
3429 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3430 *ptype |= RASTER_FONTTYPE;
3432 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3433 if (face->cached_enum_data)
3435 memcpy(&face->cached_enum_data->elf, pelf, sizeof(ENUMLOGFONTEXW));
3436 memcpy(&face->cached_enum_data->ntm, pntm, sizeof(NEWTEXTMETRICEXW));
3437 face->cached_enum_data->type = *ptype;
3440 free_font(font);
3443 /*************************************************************
3444 * WineEngEnumFonts
3447 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3449 Family *family;
3450 Face *face;
3451 struct list *family_elem_ptr, *face_elem_ptr;
3452 ENUMLOGFONTEXW elf;
3453 NEWTEXTMETRICEXW ntm;
3454 DWORD type;
3455 FONTSIGNATURE fs;
3456 CHARSETINFO csi;
3457 LOGFONTW lf;
3458 int i;
3460 if (!plf)
3462 lf.lfCharSet = DEFAULT_CHARSET;
3463 lf.lfPitchAndFamily = 0;
3464 lf.lfFaceName[0] = 0;
3465 plf = &lf;
3468 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3470 EnterCriticalSection( &freetype_cs );
3471 if(plf->lfFaceName[0]) {
3472 FontSubst *psub;
3473 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3475 if(psub) {
3476 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3477 debugstr_w(psub->to.name));
3478 memcpy(&lf, plf, sizeof(lf));
3479 strcpyW(lf.lfFaceName, psub->to.name);
3480 plf = &lf;
3483 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3484 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3485 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3486 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3487 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3488 GetEnumStructs(face, &elf, &ntm, &type);
3489 for(i = 0; i < 32; i++) {
3490 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3491 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3492 strcpyW(elf.elfScript, OEM_DOSW);
3493 i = 32; /* break out of loop */
3494 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3495 continue;
3496 else {
3497 fs.fsCsb[0] = 1L << i;
3498 fs.fsCsb[1] = 0;
3499 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3500 TCI_SRCFONTSIG))
3501 csi.ciCharset = DEFAULT_CHARSET;
3502 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3503 if(csi.ciCharset != DEFAULT_CHARSET) {
3504 elf.elfLogFont.lfCharSet =
3505 ntm.ntmTm.tmCharSet = csi.ciCharset;
3506 if(ElfScriptsW[i])
3507 strcpyW(elf.elfScript, ElfScriptsW[i]);
3508 else
3509 FIXME("Unknown elfscript for bit %d\n", i);
3512 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3513 debugstr_w(elf.elfLogFont.lfFaceName),
3514 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3515 csi.ciCharset, type, debugstr_w(elf.elfScript),
3516 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3517 ntm.ntmTm.ntmFlags);
3518 /* release section before callback (FIXME) */
3519 LeaveCriticalSection( &freetype_cs );
3520 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3521 EnterCriticalSection( &freetype_cs );
3526 } else {
3527 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3528 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3529 face_elem_ptr = list_head(&family->faces);
3530 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3531 GetEnumStructs(face, &elf, &ntm, &type);
3532 for(i = 0; i < 32; i++) {
3533 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3534 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3535 strcpyW(elf.elfScript, OEM_DOSW);
3536 i = 32; /* break out of loop */
3537 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3538 continue;
3539 else {
3540 fs.fsCsb[0] = 1L << i;
3541 fs.fsCsb[1] = 0;
3542 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3543 TCI_SRCFONTSIG))
3544 csi.ciCharset = DEFAULT_CHARSET;
3545 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3546 if(csi.ciCharset != DEFAULT_CHARSET) {
3547 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3548 csi.ciCharset;
3549 if(ElfScriptsW[i])
3550 strcpyW(elf.elfScript, ElfScriptsW[i]);
3551 else
3552 FIXME("Unknown elfscript for bit %d\n", i);
3555 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3556 debugstr_w(elf.elfLogFont.lfFaceName),
3557 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3558 csi.ciCharset, type, debugstr_w(elf.elfScript),
3559 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3560 ntm.ntmTm.ntmFlags);
3561 /* release section before callback (FIXME) */
3562 LeaveCriticalSection( &freetype_cs );
3563 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3564 EnterCriticalSection( &freetype_cs );
3568 LeaveCriticalSection( &freetype_cs );
3569 return 1;
3572 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3574 pt->x.value = vec->x >> 6;
3575 pt->x.fract = (vec->x & 0x3f) << 10;
3576 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3577 pt->y.value = vec->y >> 6;
3578 pt->y.fract = (vec->y & 0x3f) << 10;
3579 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3580 return;
3583 /***************************************************
3584 * According to the MSDN documentation on WideCharToMultiByte,
3585 * certain codepages cannot set the default_used parameter.
3586 * This returns TRUE if the codepage can set that parameter, false else
3587 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3589 static BOOL codepage_sets_default_used(UINT codepage)
3591 switch (codepage)
3593 case CP_UTF7:
3594 case CP_UTF8:
3595 case CP_SYMBOL:
3596 return FALSE;
3597 default:
3598 return TRUE;
3602 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
3604 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3605 WCHAR wc = (WCHAR)glyph;
3606 BOOL default_used;
3607 BOOL *default_used_pointer;
3608 FT_UInt ret;
3609 char buf;
3610 default_used_pointer = NULL;
3611 default_used = FALSE;
3612 if (codepage_sets_default_used(font->codepage))
3613 default_used_pointer = &default_used;
3614 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3615 ret = 0;
3616 else
3617 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3618 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3619 return ret;
3622 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3623 glyph = glyph + 0xf000;
3624 return pFT_Get_Char_Index(font->ft_face, glyph);
3627 /*************************************************************
3628 * WineEngGetGlyphIndices
3630 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3632 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3633 LPWORD pgi, DWORD flags)
3635 int i;
3636 WCHAR default_char = 0;
3637 TEXTMETRICW textm;
3639 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3641 for(i = 0; i < count; i++)
3643 pgi[i] = get_glyph_index(font, lpstr[i]);
3644 if (pgi[i] == 0)
3646 if (!default_char)
3648 WineEngGetTextMetrics(font, &textm);
3649 default_char = textm.tmDefaultChar;
3651 pgi[i] = default_char;
3654 return count;
3657 /*************************************************************
3658 * WineEngGetGlyphOutline
3660 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3661 * except that the first parameter is the HWINEENGFONT of the font in
3662 * question rather than an HDC.
3665 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3666 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3667 const MAT2* lpmat)
3669 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3670 FT_Face ft_face = incoming_font->ft_face;
3671 GdiFont *font = incoming_font;
3672 FT_UInt glyph_index;
3673 DWORD width, height, pitch, needed = 0;
3674 FT_Bitmap ft_bitmap;
3675 FT_Error err;
3676 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3677 FT_Angle angle = 0;
3678 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3679 float widthRatio = 1.0;
3680 FT_Matrix transMat = identityMat;
3681 BOOL needsTransform = FALSE;
3684 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3685 buflen, buf, lpmat);
3687 EnterCriticalSection( &freetype_cs );
3689 if(format & GGO_GLYPH_INDEX) {
3690 glyph_index = glyph;
3691 format &= ~GGO_GLYPH_INDEX;
3692 } else {
3693 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3694 ft_face = font->ft_face;
3697 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3698 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3699 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3700 font->gmsize * sizeof(GM*));
3701 } else {
3702 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3703 *lpgm = FONT_GM(font,glyph_index)->gm;
3704 LeaveCriticalSection( &freetype_cs );
3705 return 1; /* FIXME */
3709 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3710 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3712 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
3713 load_flags |= FT_LOAD_NO_BITMAP;
3715 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3717 if(err) {
3718 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3719 LeaveCriticalSection( &freetype_cs );
3720 return GDI_ERROR;
3723 /* Scaling factor */
3724 if (font->aveWidth && font->potm)
3726 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
3727 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
3729 else
3730 widthRatio = font->scale_y;
3732 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3733 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3735 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3736 lsb = left >> 6;
3737 bbx = (right - left) >> 6;
3739 /* Scaling transform */
3740 if(font->aveWidth) {
3741 FT_Matrix scaleMat;
3742 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3743 scaleMat.xy = 0;
3744 scaleMat.yx = 0;
3745 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
3747 pFT_Matrix_Multiply(&scaleMat, &transMat);
3748 needsTransform = TRUE;
3751 /* Slant transform */
3752 if (font->fake_italic) {
3753 FT_Matrix slantMat;
3755 slantMat.xx = (1 << 16);
3756 slantMat.xy = ((1 << 16) >> 2);
3757 slantMat.yx = 0;
3758 slantMat.yy = (1 << 16);
3759 pFT_Matrix_Multiply(&slantMat, &transMat);
3760 needsTransform = TRUE;
3763 /* Rotation transform */
3764 if(font->orientation) {
3765 FT_Matrix rotationMat;
3766 FT_Vector vecAngle;
3767 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3768 pFT_Vector_Unit(&vecAngle, angle);
3769 rotationMat.xx = vecAngle.x;
3770 rotationMat.xy = -vecAngle.y;
3771 rotationMat.yx = -rotationMat.xy;
3772 rotationMat.yy = rotationMat.xx;
3774 pFT_Matrix_Multiply(&rotationMat, &transMat);
3775 needsTransform = TRUE;
3778 /* Extra transformation specified by caller */
3779 if (lpmat) {
3780 FT_Matrix extraMat;
3781 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3782 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3783 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3784 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3785 pFT_Matrix_Multiply(&extraMat, &transMat);
3786 needsTransform = TRUE;
3789 if(!needsTransform) {
3790 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3791 bottom = (ft_face->glyph->metrics.horiBearingY -
3792 ft_face->glyph->metrics.height) & -64;
3793 lpgm->gmCellIncX = adv;
3794 lpgm->gmCellIncY = 0;
3795 } else {
3796 INT xc, yc;
3797 FT_Vector vec;
3798 for(xc = 0; xc < 2; xc++) {
3799 for(yc = 0; yc < 2; yc++) {
3800 vec.x = (ft_face->glyph->metrics.horiBearingX +
3801 xc * ft_face->glyph->metrics.width);
3802 vec.y = ft_face->glyph->metrics.horiBearingY -
3803 yc * ft_face->glyph->metrics.height;
3804 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3805 pFT_Vector_Transform(&vec, &transMat);
3806 if(xc == 0 && yc == 0) {
3807 left = right = vec.x;
3808 top = bottom = vec.y;
3809 } else {
3810 if(vec.x < left) left = vec.x;
3811 else if(vec.x > right) right = vec.x;
3812 if(vec.y < bottom) bottom = vec.y;
3813 else if(vec.y > top) top = vec.y;
3817 left = left & -64;
3818 right = (right + 63) & -64;
3819 bottom = bottom & -64;
3820 top = (top + 63) & -64;
3822 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3823 vec.x = ft_face->glyph->metrics.horiAdvance;
3824 vec.y = 0;
3825 pFT_Vector_Transform(&vec, &transMat);
3826 lpgm->gmCellIncX = (vec.x+63) >> 6;
3827 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3829 lpgm->gmBlackBoxX = (right - left) >> 6;
3830 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3831 lpgm->gmptGlyphOrigin.x = left >> 6;
3832 lpgm->gmptGlyphOrigin.y = top >> 6;
3834 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3836 FONT_GM(font,glyph_index)->gm = *lpgm;
3837 FONT_GM(font,glyph_index)->adv = adv;
3838 FONT_GM(font,glyph_index)->lsb = lsb;
3839 FONT_GM(font,glyph_index)->bbx = bbx;
3840 FONT_GM(font,glyph_index)->init = TRUE;
3843 if(format == GGO_METRICS)
3845 LeaveCriticalSection( &freetype_cs );
3846 return 1; /* FIXME */
3849 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3850 TRACE("loaded a bitmap\n");
3851 LeaveCriticalSection( &freetype_cs );
3852 return GDI_ERROR;
3855 switch(format) {
3856 case GGO_BITMAP:
3857 width = lpgm->gmBlackBoxX;
3858 height = lpgm->gmBlackBoxY;
3859 pitch = ((width + 31) >> 5) << 2;
3860 needed = pitch * height;
3862 if(!buf || !buflen) break;
3864 switch(ft_face->glyph->format) {
3865 case ft_glyph_format_bitmap:
3867 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3868 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3869 INT h = ft_face->glyph->bitmap.rows;
3870 while(h--) {
3871 memcpy(dst, src, w);
3872 src += ft_face->glyph->bitmap.pitch;
3873 dst += pitch;
3875 break;
3878 case ft_glyph_format_outline:
3879 ft_bitmap.width = width;
3880 ft_bitmap.rows = height;
3881 ft_bitmap.pitch = pitch;
3882 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3883 ft_bitmap.buffer = buf;
3885 if(needsTransform) {
3886 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3889 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3891 /* Note: FreeType will only set 'black' bits for us. */
3892 memset(buf, 0, needed);
3893 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3894 break;
3896 default:
3897 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3898 LeaveCriticalSection( &freetype_cs );
3899 return GDI_ERROR;
3901 break;
3903 case GGO_GRAY2_BITMAP:
3904 case GGO_GRAY4_BITMAP:
3905 case GGO_GRAY8_BITMAP:
3906 case WINE_GGO_GRAY16_BITMAP:
3908 unsigned int mult, row, col;
3909 BYTE *start, *ptr;
3911 width = lpgm->gmBlackBoxX;
3912 height = lpgm->gmBlackBoxY;
3913 pitch = (width + 3) / 4 * 4;
3914 needed = pitch * height;
3916 if(!buf || !buflen) break;
3918 switch(ft_face->glyph->format) {
3919 case ft_glyph_format_bitmap:
3921 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3922 INT h = ft_face->glyph->bitmap.rows;
3923 INT x;
3924 while(h--) {
3925 for(x = 0; x < pitch; x++)
3926 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3927 src += ft_face->glyph->bitmap.pitch;
3928 dst += pitch;
3930 LeaveCriticalSection( &freetype_cs );
3931 return needed;
3933 case ft_glyph_format_outline:
3935 ft_bitmap.width = width;
3936 ft_bitmap.rows = height;
3937 ft_bitmap.pitch = pitch;
3938 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3939 ft_bitmap.buffer = buf;
3941 if(needsTransform)
3942 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3944 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3946 memset(ft_bitmap.buffer, 0, buflen);
3948 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3950 if(format == GGO_GRAY2_BITMAP)
3951 mult = 4;
3952 else if(format == GGO_GRAY4_BITMAP)
3953 mult = 16;
3954 else if(format == GGO_GRAY8_BITMAP)
3955 mult = 64;
3956 else /* format == WINE_GGO_GRAY16_BITMAP */
3958 LeaveCriticalSection( &freetype_cs );
3959 return needed;
3961 break;
3963 default:
3964 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3965 LeaveCriticalSection( &freetype_cs );
3966 return GDI_ERROR;
3969 start = buf;
3970 for(row = 0; row < height; row++) {
3971 ptr = start;
3972 for(col = 0; col < width; col++, ptr++) {
3973 *ptr = (((int)*ptr) * mult + 128) / 256;
3975 start += pitch;
3977 break;
3980 case GGO_NATIVE:
3982 int contour, point = 0, first_pt;
3983 FT_Outline *outline = &ft_face->glyph->outline;
3984 TTPOLYGONHEADER *pph;
3985 TTPOLYCURVE *ppc;
3986 DWORD pph_start, cpfx, type;
3988 if(buflen == 0) buf = NULL;
3990 if (needsTransform && buf) {
3991 pFT_Outline_Transform(outline, &transMat);
3994 for(contour = 0; contour < outline->n_contours; contour++) {
3995 pph_start = needed;
3996 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3997 first_pt = point;
3998 if(buf) {
3999 pph->dwType = TT_POLYGON_TYPE;
4000 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4002 needed += sizeof(*pph);
4003 point++;
4004 while(point <= outline->contours[contour]) {
4005 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4006 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4007 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4008 cpfx = 0;
4009 do {
4010 if(buf)
4011 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4012 cpfx++;
4013 point++;
4014 } while(point <= outline->contours[contour] &&
4015 (outline->tags[point] & FT_Curve_Tag_On) ==
4016 (outline->tags[point-1] & FT_Curve_Tag_On));
4017 /* At the end of a contour Windows adds the start point, but
4018 only for Beziers */
4019 if(point > outline->contours[contour] &&
4020 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4021 if(buf)
4022 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4023 cpfx++;
4024 } else if(point <= outline->contours[contour] &&
4025 outline->tags[point] & FT_Curve_Tag_On) {
4026 /* add closing pt for bezier */
4027 if(buf)
4028 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4029 cpfx++;
4030 point++;
4032 if(buf) {
4033 ppc->wType = type;
4034 ppc->cpfx = cpfx;
4036 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4038 if(buf)
4039 pph->cb = needed - pph_start;
4041 break;
4043 case GGO_BEZIER:
4045 /* Convert the quadratic Beziers to cubic Beziers.
4046 The parametric eqn for a cubic Bezier is, from PLRM:
4047 r(t) = at^3 + bt^2 + ct + r0
4048 with the control points:
4049 r1 = r0 + c/3
4050 r2 = r1 + (c + b)/3
4051 r3 = r0 + c + b + a
4053 A quadratic Beizer has the form:
4054 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4056 So equating powers of t leads to:
4057 r1 = 2/3 p1 + 1/3 p0
4058 r2 = 2/3 p1 + 1/3 p2
4059 and of course r0 = p0, r3 = p2
4062 int contour, point = 0, first_pt;
4063 FT_Outline *outline = &ft_face->glyph->outline;
4064 TTPOLYGONHEADER *pph;
4065 TTPOLYCURVE *ppc;
4066 DWORD pph_start, cpfx, type;
4067 FT_Vector cubic_control[4];
4068 if(buflen == 0) buf = NULL;
4070 if (needsTransform && buf) {
4071 pFT_Outline_Transform(outline, &transMat);
4074 for(contour = 0; contour < outline->n_contours; contour++) {
4075 pph_start = needed;
4076 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4077 first_pt = point;
4078 if(buf) {
4079 pph->dwType = TT_POLYGON_TYPE;
4080 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4082 needed += sizeof(*pph);
4083 point++;
4084 while(point <= outline->contours[contour]) {
4085 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4086 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4087 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4088 cpfx = 0;
4089 do {
4090 if(type == TT_PRIM_LINE) {
4091 if(buf)
4092 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4093 cpfx++;
4094 point++;
4095 } else {
4096 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4097 so cpfx = 3n */
4099 /* FIXME: Possible optimization in endpoint calculation
4100 if there are two consecutive curves */
4101 cubic_control[0] = outline->points[point-1];
4102 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4103 cubic_control[0].x += outline->points[point].x + 1;
4104 cubic_control[0].y += outline->points[point].y + 1;
4105 cubic_control[0].x >>= 1;
4106 cubic_control[0].y >>= 1;
4108 if(point+1 > outline->contours[contour])
4109 cubic_control[3] = outline->points[first_pt];
4110 else {
4111 cubic_control[3] = outline->points[point+1];
4112 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4113 cubic_control[3].x += outline->points[point].x + 1;
4114 cubic_control[3].y += outline->points[point].y + 1;
4115 cubic_control[3].x >>= 1;
4116 cubic_control[3].y >>= 1;
4119 /* r1 = 1/3 p0 + 2/3 p1
4120 r2 = 1/3 p2 + 2/3 p1 */
4121 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4122 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4123 cubic_control[2] = cubic_control[1];
4124 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4125 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4126 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4127 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4128 if(buf) {
4129 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4130 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4131 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4133 cpfx += 3;
4134 point++;
4136 } while(point <= outline->contours[contour] &&
4137 (outline->tags[point] & FT_Curve_Tag_On) ==
4138 (outline->tags[point-1] & FT_Curve_Tag_On));
4139 /* At the end of a contour Windows adds the start point,
4140 but only for Beziers and we've already done that.
4142 if(point <= outline->contours[contour] &&
4143 outline->tags[point] & FT_Curve_Tag_On) {
4144 /* This is the closing pt of a bezier, but we've already
4145 added it, so just inc point and carry on */
4146 point++;
4148 if(buf) {
4149 ppc->wType = type;
4150 ppc->cpfx = cpfx;
4152 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4154 if(buf)
4155 pph->cb = needed - pph_start;
4157 break;
4160 default:
4161 FIXME("Unsupported format %d\n", format);
4162 LeaveCriticalSection( &freetype_cs );
4163 return GDI_ERROR;
4165 LeaveCriticalSection( &freetype_cs );
4166 return needed;
4169 static BOOL get_bitmap_text_metrics(GdiFont *font)
4171 FT_Face ft_face = font->ft_face;
4172 #ifdef HAVE_FREETYPE_FTWINFNT_H
4173 FT_WinFNT_HeaderRec winfnt_header;
4174 #endif
4175 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4176 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4177 font->potm->otmSize = size;
4179 #define TM font->potm->otmTextMetrics
4180 #ifdef HAVE_FREETYPE_FTWINFNT_H
4181 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4183 TM.tmHeight = winfnt_header.pixel_height;
4184 TM.tmAscent = winfnt_header.ascent;
4185 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4186 TM.tmInternalLeading = winfnt_header.internal_leading;
4187 TM.tmExternalLeading = winfnt_header.external_leading;
4188 TM.tmAveCharWidth = winfnt_header.avg_width;
4189 TM.tmMaxCharWidth = winfnt_header.max_width;
4190 TM.tmWeight = winfnt_header.weight;
4191 TM.tmOverhang = 0;
4192 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4193 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4194 TM.tmFirstChar = winfnt_header.first_char;
4195 TM.tmLastChar = winfnt_header.last_char;
4196 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4197 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4198 TM.tmItalic = winfnt_header.italic;
4199 TM.tmUnderlined = font->underline;
4200 TM.tmStruckOut = font->strikeout;
4201 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4202 TM.tmCharSet = winfnt_header.charset;
4204 else
4205 #endif
4207 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4208 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4209 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4210 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4211 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4212 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4213 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4214 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4215 TM.tmOverhang = 0;
4216 TM.tmDigitizedAspectX = 96; /* FIXME */
4217 TM.tmDigitizedAspectY = 96; /* FIXME */
4218 TM.tmFirstChar = 1;
4219 TM.tmLastChar = 255;
4220 TM.tmDefaultChar = 32;
4221 TM.tmBreakChar = 32;
4222 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4223 TM.tmUnderlined = font->underline;
4224 TM.tmStruckOut = font->strikeout;
4225 /* NB inverted meaning of TMPF_FIXED_PITCH */
4226 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4227 TM.tmCharSet = font->charset;
4229 #undef TM
4231 return TRUE;
4235 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4237 float scale_x;
4239 if (font->aveWidth)
4241 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4242 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4244 else
4245 scale_x = font->scale_y;
4247 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4248 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4249 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4250 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4251 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4253 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4254 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4257 /*************************************************************
4258 * WineEngGetTextMetrics
4261 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4263 EnterCriticalSection( &freetype_cs );
4264 if(!font->potm) {
4265 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4266 if(!get_bitmap_text_metrics(font))
4268 LeaveCriticalSection( &freetype_cs );
4269 return FALSE;
4272 if(!font->potm)
4274 LeaveCriticalSection( &freetype_cs );
4275 return FALSE;
4277 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4278 scale_font_metrics(font, ptm);
4279 LeaveCriticalSection( &freetype_cs );
4280 return TRUE;
4284 /*************************************************************
4285 * WineEngGetOutlineTextMetrics
4288 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4289 OUTLINETEXTMETRICW *potm)
4291 FT_Face ft_face = font->ft_face;
4292 UINT needed, lenfam, lensty, ret;
4293 TT_OS2 *pOS2;
4294 TT_HoriHeader *pHori;
4295 TT_Postscript *pPost;
4296 FT_Fixed x_scale, y_scale;
4297 WCHAR *family_nameW, *style_nameW;
4298 static const WCHAR spaceW[] = {' ', '\0'};
4299 char *cp;
4300 INT ascent, descent;
4302 TRACE("font=%p\n", font);
4304 if(!FT_IS_SCALABLE(ft_face))
4305 return 0;
4307 EnterCriticalSection( &freetype_cs );
4309 if(font->potm) {
4310 if(cbSize >= font->potm->otmSize)
4312 memcpy(potm, font->potm, font->potm->otmSize);
4313 scale_font_metrics(font, &potm->otmTextMetrics);
4315 LeaveCriticalSection( &freetype_cs );
4316 return font->potm->otmSize;
4320 needed = sizeof(*potm);
4322 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4323 family_nameW = strdupW(font->name);
4325 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4326 * sizeof(WCHAR);
4327 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4328 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4329 style_nameW, lensty/sizeof(WCHAR));
4331 /* These names should be read from the TT name table */
4333 /* length of otmpFamilyName */
4334 needed += lenfam;
4336 /* length of otmpFaceName */
4337 if(!strcasecmp(ft_face->style_name, "regular")) {
4338 needed += lenfam; /* just the family name */
4339 } else {
4340 needed += lenfam + lensty; /* family + " " + style */
4343 /* length of otmpStyleName */
4344 needed += lensty;
4346 /* length of otmpFullName */
4347 needed += lenfam + lensty;
4350 x_scale = ft_face->size->metrics.x_scale;
4351 y_scale = ft_face->size->metrics.y_scale;
4353 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4354 if(!pOS2) {
4355 FIXME("Can't find OS/2 table - not TT font?\n");
4356 ret = 0;
4357 goto end;
4360 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4361 if(!pHori) {
4362 FIXME("Can't find HHEA table - not TT font?\n");
4363 ret = 0;
4364 goto end;
4367 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4369 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",
4370 pOS2->usWinAscent, pOS2->usWinDescent,
4371 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4372 ft_face->ascender, ft_face->descender, ft_face->height,
4373 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4374 ft_face->bbox.yMax, ft_face->bbox.yMin);
4376 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4377 font->potm->otmSize = needed;
4379 #define TM font->potm->otmTextMetrics
4381 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4382 ascent = pHori->Ascender;
4383 descent = -pHori->Descender;
4384 } else {
4385 ascent = pOS2->usWinAscent;
4386 descent = pOS2->usWinDescent;
4389 if(font->yMax) {
4390 TM.tmAscent = font->yMax;
4391 TM.tmDescent = -font->yMin;
4392 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4393 } else {
4394 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4395 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4396 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4397 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4400 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4402 /* MSDN says:
4403 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4405 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4406 ((ascent + descent) -
4407 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4409 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4410 if (TM.tmAveCharWidth == 0) {
4411 TM.tmAveCharWidth = 1;
4413 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4414 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4415 TM.tmOverhang = 0;
4416 TM.tmDigitizedAspectX = 300;
4417 TM.tmDigitizedAspectY = 300;
4418 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4419 * symbol range to 0 - f0ff
4421 if (font->charset == SYMBOL_CHARSET)
4422 TM.tmFirstChar = 0;
4423 else
4424 TM.tmFirstChar = pOS2->usFirstCharIndex;
4425 TM.tmLastChar = pOS2->usLastCharIndex;
4426 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4427 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4428 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4429 TM.tmUnderlined = font->underline;
4430 TM.tmStruckOut = font->strikeout;
4432 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4433 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4434 (pOS2->version == 0xFFFFU ||
4435 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4436 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4437 else
4438 TM.tmPitchAndFamily = 0;
4440 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4441 case PAN_FAMILY_SCRIPT:
4442 TM.tmPitchAndFamily |= FF_SCRIPT;
4443 break;
4444 case PAN_FAMILY_DECORATIVE:
4445 case PAN_FAMILY_PICTORIAL:
4446 TM.tmPitchAndFamily |= FF_DECORATIVE;
4447 break;
4448 case PAN_FAMILY_TEXT_DISPLAY:
4449 if(TM.tmPitchAndFamily == 0) /* fixed */
4450 TM.tmPitchAndFamily = FF_MODERN;
4451 else {
4452 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4453 case PAN_SERIF_NORMAL_SANS:
4454 case PAN_SERIF_OBTUSE_SANS:
4455 case PAN_SERIF_PERP_SANS:
4456 TM.tmPitchAndFamily |= FF_SWISS;
4457 break;
4458 default:
4459 TM.tmPitchAndFamily |= FF_ROMAN;
4462 break;
4463 default:
4464 TM.tmPitchAndFamily |= FF_DONTCARE;
4467 if(FT_IS_SCALABLE(ft_face))
4468 TM.tmPitchAndFamily |= TMPF_VECTOR;
4470 if(FT_IS_SFNT(ft_face))
4472 if (font->ntmFlags & NTM_PS_OPENTYPE)
4473 TM.tmPitchAndFamily |= TMPF_DEVICE;
4474 else
4475 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4478 TM.tmCharSet = font->charset;
4479 #undef TM
4481 font->potm->otmFiller = 0;
4482 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4483 font->potm->otmfsSelection = pOS2->fsSelection;
4484 font->potm->otmfsType = pOS2->fsType;
4485 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4486 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4487 font->potm->otmItalicAngle = 0; /* POST table */
4488 font->potm->otmEMSquare = ft_face->units_per_EM;
4489 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4490 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4491 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4492 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4493 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4494 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4495 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4496 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4497 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4498 font->potm->otmMacAscent = 0; /* where do these come from ? */
4499 font->potm->otmMacDescent = 0;
4500 font->potm->otmMacLineGap = 0;
4501 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4502 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4503 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4504 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4505 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4506 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4507 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4508 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4509 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4510 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4511 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4512 if(!pPost) {
4513 font->potm->otmsUnderscoreSize = 0;
4514 font->potm->otmsUnderscorePosition = 0;
4515 } else {
4516 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4517 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4520 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4521 cp = (char*)font->potm + sizeof(*font->potm);
4522 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4523 strcpyW((WCHAR*)cp, family_nameW);
4524 cp += lenfam;
4525 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4526 strcpyW((WCHAR*)cp, style_nameW);
4527 cp += lensty;
4528 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4529 strcpyW((WCHAR*)cp, family_nameW);
4530 if(strcasecmp(ft_face->style_name, "regular")) {
4531 strcatW((WCHAR*)cp, spaceW);
4532 strcatW((WCHAR*)cp, style_nameW);
4533 cp += lenfam + lensty;
4534 } else
4535 cp += lenfam;
4536 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4537 strcpyW((WCHAR*)cp, family_nameW);
4538 strcatW((WCHAR*)cp, spaceW);
4539 strcatW((WCHAR*)cp, style_nameW);
4540 ret = needed;
4542 if(potm && needed <= cbSize)
4544 memcpy(potm, font->potm, font->potm->otmSize);
4545 scale_font_metrics(font, &potm->otmTextMetrics);
4548 end:
4549 HeapFree(GetProcessHeap(), 0, style_nameW);
4550 HeapFree(GetProcessHeap(), 0, family_nameW);
4552 LeaveCriticalSection( &freetype_cs );
4553 return ret;
4556 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4558 HFONTLIST *hfontlist;
4559 child->font = alloc_font();
4560 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4561 if(!child->font->ft_face)
4563 free_font(child->font);
4564 child->font = NULL;
4565 return FALSE;
4568 child->font->ntmFlags = child->face->ntmFlags;
4569 child->font->orientation = font->orientation;
4570 child->font->scale_y = font->scale_y;
4571 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4572 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4573 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4574 child->font->base_font = font;
4575 list_add_head(&child_font_list, &child->font->entry);
4576 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4577 return TRUE;
4580 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4582 FT_UInt g;
4583 CHILD_FONT *child_font;
4585 if(font->base_font)
4586 font = font->base_font;
4588 *linked_font = font;
4590 if((*glyph = get_glyph_index(font, c)))
4591 return TRUE;
4593 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4595 if(!child_font->font)
4596 if(!load_child_font(font, child_font))
4597 continue;
4599 if(!child_font->font->ft_face)
4600 continue;
4601 g = get_glyph_index(child_font->font, c);
4602 if(g)
4604 *glyph = g;
4605 *linked_font = child_font->font;
4606 return TRUE;
4609 return FALSE;
4612 /*************************************************************
4613 * WineEngGetCharWidth
4616 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4617 LPINT buffer)
4619 UINT c;
4620 GLYPHMETRICS gm;
4621 FT_UInt glyph_index;
4622 GdiFont *linked_font;
4624 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4626 EnterCriticalSection( &freetype_cs );
4627 for(c = firstChar; c <= lastChar; c++) {
4628 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4629 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4630 &gm, 0, NULL, NULL);
4631 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4633 LeaveCriticalSection( &freetype_cs );
4634 return TRUE;
4637 /*************************************************************
4638 * WineEngGetCharABCWidths
4641 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4642 LPABC buffer)
4644 UINT c;
4645 GLYPHMETRICS gm;
4646 FT_UInt glyph_index;
4647 GdiFont *linked_font;
4649 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4651 if(!FT_IS_SCALABLE(font->ft_face))
4652 return FALSE;
4654 EnterCriticalSection( &freetype_cs );
4656 for(c = firstChar; c <= lastChar; c++) {
4657 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4658 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4659 &gm, 0, NULL, NULL);
4660 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4661 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4662 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4663 FONT_GM(linked_font,glyph_index)->bbx;
4665 LeaveCriticalSection( &freetype_cs );
4666 return TRUE;
4669 /*************************************************************
4670 * WineEngGetCharABCWidthsI
4673 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4674 LPABC buffer)
4676 UINT c;
4677 GLYPHMETRICS gm;
4678 FT_UInt glyph_index;
4679 GdiFont *linked_font;
4681 if(!FT_HAS_HORIZONTAL(font->ft_face))
4682 return FALSE;
4684 EnterCriticalSection( &freetype_cs );
4686 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4687 if (!pgi)
4688 for(c = firstChar; c < firstChar+count; c++) {
4689 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4690 &gm, 0, NULL, NULL);
4691 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4692 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4693 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4694 - FONT_GM(linked_font,c)->bbx;
4696 else
4697 for(c = 0; c < count; c++) {
4698 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4699 &gm, 0, NULL, NULL);
4700 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4701 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4702 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4703 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4706 LeaveCriticalSection( &freetype_cs );
4707 return TRUE;
4710 /*************************************************************
4711 * WineEngGetTextExtentExPoint
4714 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4715 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4717 INT idx;
4718 INT nfit = 0, ext;
4719 GLYPHMETRICS gm;
4720 TEXTMETRICW tm;
4721 FT_UInt glyph_index;
4722 GdiFont *linked_font;
4724 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4725 max_ext, size);
4727 EnterCriticalSection( &freetype_cs );
4729 size->cx = 0;
4730 WineEngGetTextMetrics(font, &tm);
4731 size->cy = tm.tmHeight;
4733 for(idx = 0; idx < count; idx++) {
4734 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4735 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4736 &gm, 0, NULL, NULL);
4737 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4738 ext = size->cx;
4739 if (! pnfit || ext <= max_ext) {
4740 ++nfit;
4741 if (dxs)
4742 dxs[idx] = ext;
4746 if (pnfit)
4747 *pnfit = nfit;
4749 LeaveCriticalSection( &freetype_cs );
4750 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4751 return TRUE;
4754 /*************************************************************
4755 * WineEngGetTextExtentExPointI
4758 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
4759 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4761 INT idx;
4762 INT nfit = 0, ext;
4763 GLYPHMETRICS gm;
4764 TEXTMETRICW tm;
4766 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
4768 EnterCriticalSection( &freetype_cs );
4770 size->cx = 0;
4771 WineEngGetTextMetrics(font, &tm);
4772 size->cy = tm.tmHeight;
4774 for(idx = 0; idx < count; idx++) {
4775 WineEngGetGlyphOutline(font, indices[idx],
4776 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4777 NULL);
4778 size->cx += FONT_GM(font,indices[idx])->adv;
4779 ext = size->cx;
4780 if (! pnfit || ext <= max_ext) {
4781 ++nfit;
4782 if (dxs)
4783 dxs[idx] = ext;
4787 if (pnfit)
4788 *pnfit = nfit;
4790 LeaveCriticalSection( &freetype_cs );
4791 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4792 return TRUE;
4795 /*************************************************************
4796 * WineEngGetFontData
4799 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4800 DWORD cbData)
4802 FT_Face ft_face = font->ft_face;
4803 FT_ULong len;
4804 FT_Error err;
4806 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4807 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4808 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4810 if(!FT_IS_SFNT(ft_face))
4811 return GDI_ERROR;
4813 if(!buf || !cbData)
4814 len = 0;
4815 else
4816 len = cbData;
4818 if(table) { /* MS tags differ in endidness from FT ones */
4819 table = table >> 24 | table << 24 |
4820 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4823 /* make sure value of len is the value freetype says it needs */
4824 if(buf && len)
4826 FT_ULong needed = 0;
4827 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
4828 if( !err && needed < len) len = needed;
4830 err = load_sfnt_table(ft_face, table, offset, buf, &len);
4832 if(err) {
4833 TRACE("Can't find table %c%c%c%c\n",
4834 /* bytes were reversed */
4835 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4836 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4837 return GDI_ERROR;
4839 return len;
4842 /*************************************************************
4843 * WineEngGetTextFace
4846 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4848 if(str) {
4849 lstrcpynW(str, font->name, count);
4850 return strlenW(font->name);
4851 } else
4852 return strlenW(font->name) + 1;
4855 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4857 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4858 return font->charset;
4861 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4863 GdiFont *font = dc->gdiFont, *linked_font;
4864 struct list *first_hfont;
4865 BOOL ret;
4867 EnterCriticalSection( &freetype_cs );
4868 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4869 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4870 if(font == linked_font)
4871 *new_hfont = dc->hFont;
4872 else
4874 first_hfont = list_head(&linked_font->hfontlist);
4875 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4877 LeaveCriticalSection( &freetype_cs );
4878 return ret;
4881 /* Retrieve a list of supported Unicode ranges for a given font.
4882 * Can be called with NULL gs to calculate the buffer size. Returns
4883 * the number of ranges found.
4885 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4887 DWORD num_ranges = 0;
4889 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4891 FT_UInt glyph_code;
4892 FT_ULong char_code, char_code_prev;
4894 glyph_code = 0;
4895 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4897 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4898 face->num_glyphs, glyph_code, char_code);
4900 if (!glyph_code) return 0;
4902 if (gs)
4904 gs->ranges[0].wcLow = (USHORT)char_code;
4905 gs->ranges[0].cGlyphs = 0;
4906 gs->cGlyphsSupported = 0;
4909 num_ranges = 1;
4910 while (glyph_code)
4912 if (char_code < char_code_prev)
4914 ERR("expected increasing char code from FT_Get_Next_Char\n");
4915 return 0;
4917 if (char_code - char_code_prev > 1)
4919 num_ranges++;
4920 if (gs)
4922 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4923 gs->ranges[num_ranges - 1].cGlyphs = 1;
4924 gs->cGlyphsSupported++;
4927 else if (gs)
4929 gs->ranges[num_ranges - 1].cGlyphs++;
4930 gs->cGlyphsSupported++;
4932 char_code_prev = char_code;
4933 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4936 else
4937 FIXME("encoding %u not supported\n", face->charmap->encoding);
4939 return num_ranges;
4942 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4944 DWORD size = 0;
4945 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4947 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4948 if (glyphset)
4950 glyphset->cbThis = size;
4951 glyphset->cRanges = num_ranges;
4953 return size;
4956 /*************************************************************
4957 * FontIsLinked
4959 BOOL WineEngFontIsLinked(GdiFont *font)
4961 BOOL ret;
4962 EnterCriticalSection( &freetype_cs );
4963 ret = !list_empty(&font->child_fonts);
4964 LeaveCriticalSection( &freetype_cs );
4965 return ret;
4968 static BOOL is_hinting_enabled(void)
4970 /* Use the >= 2.2.0 function if available */
4971 if(pFT_Get_TrueType_Engine_Type)
4973 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4974 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4976 #ifdef FT_DRIVER_HAS_HINTER
4977 else
4979 FT_Module mod;
4981 /* otherwise if we've been compiled with < 2.2.0 headers
4982 use the internal macro */
4983 mod = pFT_Get_Module(library, "truetype");
4984 if(mod && FT_DRIVER_HAS_HINTER(mod))
4985 return TRUE;
4987 #endif
4989 return FALSE;
4992 /*************************************************************************
4993 * GetRasterizerCaps (GDI32.@)
4995 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4997 static int hinting = -1;
4999 if(hinting == -1)
5001 hinting = is_hinting_enabled();
5002 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5005 lprs->nSize = sizeof(RASTERIZER_STATUS);
5006 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5007 lprs->nLanguageID = 0;
5008 return TRUE;
5011 /*************************************************************************
5012 * Kerning support for TrueType fonts
5014 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5016 struct TT_kern_table
5018 USHORT version;
5019 USHORT nTables;
5022 struct TT_kern_subtable
5024 USHORT version;
5025 USHORT length;
5026 union
5028 USHORT word;
5029 struct
5031 USHORT horizontal : 1;
5032 USHORT minimum : 1;
5033 USHORT cross_stream: 1;
5034 USHORT override : 1;
5035 USHORT reserved1 : 4;
5036 USHORT format : 8;
5037 } bits;
5038 } coverage;
5041 struct TT_format0_kern_subtable
5043 USHORT nPairs;
5044 USHORT searchRange;
5045 USHORT entrySelector;
5046 USHORT rangeShift;
5049 struct TT_kern_pair
5051 USHORT left;
5052 USHORT right;
5053 short value;
5056 static DWORD parse_format0_kern_subtable(GdiFont *font,
5057 const struct TT_format0_kern_subtable *tt_f0_ks,
5058 const USHORT *glyph_to_char,
5059 KERNINGPAIR *kern_pair, DWORD cPairs)
5061 USHORT i, nPairs;
5062 const struct TT_kern_pair *tt_kern_pair;
5064 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5066 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5068 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5069 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5070 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5072 if (!kern_pair || !cPairs)
5073 return nPairs;
5075 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5077 nPairs = min(nPairs, cPairs);
5079 for (i = 0; i < nPairs; i++)
5081 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5082 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5083 /* this algorithm appears to better match what Windows does */
5084 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5085 if (kern_pair->iKernAmount < 0)
5087 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5088 kern_pair->iKernAmount -= font->ppem;
5090 else if (kern_pair->iKernAmount > 0)
5092 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5093 kern_pair->iKernAmount += font->ppem;
5095 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5097 TRACE("left %u right %u value %d\n",
5098 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5100 kern_pair++;
5102 TRACE("copied %u entries\n", nPairs);
5103 return nPairs;
5106 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5108 DWORD length;
5109 void *buf;
5110 const struct TT_kern_table *tt_kern_table;
5111 const struct TT_kern_subtable *tt_kern_subtable;
5112 USHORT i, nTables;
5113 USHORT *glyph_to_char;
5115 EnterCriticalSection( &freetype_cs );
5116 if (font->total_kern_pairs != (DWORD)-1)
5118 if (cPairs && kern_pair)
5120 cPairs = min(cPairs, font->total_kern_pairs);
5121 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5122 LeaveCriticalSection( &freetype_cs );
5123 return cPairs;
5125 LeaveCriticalSection( &freetype_cs );
5126 return font->total_kern_pairs;
5129 font->total_kern_pairs = 0;
5131 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5133 if (length == GDI_ERROR)
5135 TRACE("no kerning data in the font\n");
5136 LeaveCriticalSection( &freetype_cs );
5137 return 0;
5140 buf = HeapAlloc(GetProcessHeap(), 0, length);
5141 if (!buf)
5143 WARN("Out of memory\n");
5144 LeaveCriticalSection( &freetype_cs );
5145 return 0;
5148 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5150 /* build a glyph index to char code map */
5151 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5152 if (!glyph_to_char)
5154 WARN("Out of memory allocating a glyph index to char code map\n");
5155 HeapFree(GetProcessHeap(), 0, buf);
5156 LeaveCriticalSection( &freetype_cs );
5157 return 0;
5160 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5162 FT_UInt glyph_code;
5163 FT_ULong char_code;
5165 glyph_code = 0;
5166 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5168 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5169 font->ft_face->num_glyphs, glyph_code, char_code);
5171 while (glyph_code)
5173 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5175 /* FIXME: This doesn't match what Windows does: it does some fancy
5176 * things with duplicate glyph index to char code mappings, while
5177 * we just avoid overriding existing entries.
5179 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5180 glyph_to_char[glyph_code] = (USHORT)char_code;
5182 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5185 else
5187 ULONG n;
5189 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5190 for (n = 0; n <= 65535; n++)
5191 glyph_to_char[n] = (USHORT)n;
5194 tt_kern_table = buf;
5195 nTables = GET_BE_WORD(tt_kern_table->nTables);
5196 TRACE("version %u, nTables %u\n",
5197 GET_BE_WORD(tt_kern_table->version), nTables);
5199 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5201 for (i = 0; i < nTables; i++)
5203 struct TT_kern_subtable tt_kern_subtable_copy;
5205 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5206 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5207 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5209 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5210 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5211 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5213 /* According to the TrueType specification this is the only format
5214 * that will be properly interpreted by Windows and OS/2
5216 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5218 DWORD new_chunk, old_total = font->total_kern_pairs;
5220 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5221 glyph_to_char, NULL, 0);
5222 font->total_kern_pairs += new_chunk;
5224 if (!font->kern_pairs)
5225 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5226 font->total_kern_pairs * sizeof(*font->kern_pairs));
5227 else
5228 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5229 font->total_kern_pairs * sizeof(*font->kern_pairs));
5231 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5232 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5234 else
5235 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5237 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5240 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5241 HeapFree(GetProcessHeap(), 0, buf);
5243 if (cPairs && kern_pair)
5245 cPairs = min(cPairs, font->total_kern_pairs);
5246 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5247 LeaveCriticalSection( &freetype_cs );
5248 return cPairs;
5250 LeaveCriticalSection( &freetype_cs );
5251 return font->total_kern_pairs;
5254 #else /* HAVE_FREETYPE */
5256 /*************************************************************************/
5258 BOOL WineEngInit(void)
5260 return FALSE;
5262 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5264 return NULL;
5266 BOOL WineEngDestroyFontInstance(HFONT hfont)
5268 return FALSE;
5271 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5273 return 1;
5276 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5277 LPWORD pgi, DWORD flags)
5279 return GDI_ERROR;
5282 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5283 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5284 const MAT2* lpmat)
5286 ERR("called but we don't have FreeType\n");
5287 return GDI_ERROR;
5290 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5292 ERR("called but we don't have FreeType\n");
5293 return FALSE;
5296 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5297 OUTLINETEXTMETRICW *potm)
5299 ERR("called but we don't have FreeType\n");
5300 return 0;
5303 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5304 LPINT buffer)
5306 ERR("called but we don't have FreeType\n");
5307 return FALSE;
5310 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5311 LPABC buffer)
5313 ERR("called but we don't have FreeType\n");
5314 return FALSE;
5317 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5318 LPABC buffer)
5320 ERR("called but we don't have FreeType\n");
5321 return FALSE;
5324 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5325 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5327 ERR("called but we don't have FreeType\n");
5328 return FALSE;
5331 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5332 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5334 ERR("called but we don't have FreeType\n");
5335 return FALSE;
5338 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5339 DWORD cbData)
5341 ERR("called but we don't have FreeType\n");
5342 return GDI_ERROR;
5345 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5347 ERR("called but we don't have FreeType\n");
5348 return 0;
5351 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5353 FIXME(":stub\n");
5354 return 1;
5357 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5359 FIXME(":stub\n");
5360 return TRUE;
5363 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5365 FIXME(":stub\n");
5366 return NULL;
5369 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5371 FIXME(":stub\n");
5372 return DEFAULT_CHARSET;
5375 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5377 return FALSE;
5380 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5382 FIXME("(%p, %p): stub\n", font, glyphset);
5383 return 0;
5386 BOOL WineEngFontIsLinked(GdiFont *font)
5388 return FALSE;
5391 /*************************************************************************
5392 * GetRasterizerCaps (GDI32.@)
5394 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5396 lprs->nSize = sizeof(RASTERIZER_STATUS);
5397 lprs->wFlags = 0;
5398 lprs->nLanguageID = 0;
5399 return TRUE;
5402 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5404 ERR("called but we don't have FreeType\n");
5405 return 0;
5408 #endif /* HAVE_FREETYPE */