gdi: Load system fonts from $(datadir)/wine/fonts if loading from
[wine/multimedia.git] / dlls / gdi / freetype.c
bloba3657785d984e8e79906dd14b14e5965857d833e
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
30 #endif
31 #include <string.h>
32 #include <dirent.h>
33 #include <stdio.h>
34 #include <assert.h>
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winerror.h"
39 #include "winreg.h"
40 #include "wingdi.h"
41 #include "gdi.h"
42 #include "gdi_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(font);
49 #ifdef HAVE_FREETYPE
51 #ifdef HAVE_FT2BUILD_H
52 #include <ft2build.h>
53 #endif
54 #ifdef HAVE_FREETYPE_FREETYPE_H
55 #include <freetype/freetype.h>
56 #endif
57 #ifdef HAVE_FREETYPE_FTGLYPH_H
58 #include <freetype/ftglyph.h>
59 #endif
60 #ifdef HAVE_FREETYPE_TTTABLES_H
61 #include <freetype/tttables.h>
62 #endif
63 #ifdef HAVE_FREETYPE_FTSNAMES_H
64 #include <freetype/ftsnames.h>
65 #else
66 # ifdef HAVE_FREETYPE_FTNAMES_H
67 # include <freetype/ftnames.h>
68 # endif
69 #endif
70 #ifdef HAVE_FREETYPE_TTNAMEID_H
71 #include <freetype/ttnameid.h>
72 #endif
73 #ifdef HAVE_FREETYPE_FTOUTLN_H
74 #include <freetype/ftoutln.h>
75 #endif
76 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
77 #include <freetype/internal/sfnt.h>
78 #endif
79 #ifdef HAVE_FREETYPE_FTTRIGON_H
80 #include <freetype/fttrigon.h>
81 #endif
82 #ifdef HAVE_FREETYPE_FTWINFNT_H
83 #include <freetype/ftwinfnt.h>
84 #endif
85 #ifdef HAVE_FREETYPE_FTMODAPI_H
86 #include <freetype/ftmodapi.h>
87 #endif
89 #ifndef SONAME_LIBFREETYPE
90 #define SONAME_LIBFREETYPE "libfreetype.so"
91 #endif
93 #ifndef HAVE_FT_TRUETYPEENGINETYPE
94 typedef enum
96 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
97 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
98 FT_TRUETYPE_ENGINE_TYPE_PATENTED
99 } FT_TrueTypeEngineType;
100 #endif
102 static FT_Library library = 0;
103 typedef struct
105 FT_Int major;
106 FT_Int minor;
107 FT_Int patch;
108 } FT_Version_t;
109 static FT_Version_t FT_Version;
110 static DWORD FT_SimpleVersion;
112 static void *ft_handle = NULL;
114 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
115 MAKE_FUNCPTR(FT_Vector_Unit);
116 MAKE_FUNCPTR(FT_Done_Face);
117 MAKE_FUNCPTR(FT_Get_Char_Index);
118 MAKE_FUNCPTR(FT_Get_Module);
119 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
120 MAKE_FUNCPTR(FT_Init_FreeType);
121 MAKE_FUNCPTR(FT_Load_Glyph);
122 MAKE_FUNCPTR(FT_Matrix_Multiply);
123 MAKE_FUNCPTR(FT_MulFix);
124 MAKE_FUNCPTR(FT_New_Face);
125 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
126 MAKE_FUNCPTR(FT_Outline_Transform);
127 MAKE_FUNCPTR(FT_Outline_Translate);
128 MAKE_FUNCPTR(FT_Select_Charmap);
129 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
130 MAKE_FUNCPTR(FT_Vector_Transform);
131 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
132 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
133 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
134 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
135 #ifdef HAVE_FREETYPE_FTWINFNT_H
136 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
137 #endif
139 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
140 #include <fontconfig/fontconfig.h>
141 MAKE_FUNCPTR(FcConfigGetCurrent);
142 MAKE_FUNCPTR(FcFontList);
143 MAKE_FUNCPTR(FcFontSetDestroy);
144 MAKE_FUNCPTR(FcInit);
145 MAKE_FUNCPTR(FcObjectSetAdd);
146 MAKE_FUNCPTR(FcObjectSetCreate);
147 MAKE_FUNCPTR(FcObjectSetDestroy);
148 MAKE_FUNCPTR(FcPatternCreate);
149 MAKE_FUNCPTR(FcPatternDestroy);
150 MAKE_FUNCPTR(FcPatternGet);
151 #ifndef SONAME_LIBFONTCONFIG
152 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
153 #endif
154 #endif
156 #undef MAKE_FUNCPTR
158 #ifndef ft_encoding_none
159 #define FT_ENCODING_NONE ft_encoding_none
160 #endif
161 #ifndef ft_encoding_ms_symbol
162 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
163 #endif
164 #ifndef ft_encoding_unicode
165 #define FT_ENCODING_UNICODE ft_encoding_unicode
166 #endif
167 #ifndef ft_encoding_apple_roman
168 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
169 #endif
171 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
173 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
174 typedef struct {
175 FT_Short height;
176 FT_Short width;
177 FT_Pos size;
178 FT_Pos x_ppem;
179 FT_Pos y_ppem;
180 FT_Short internal_leading;
181 } Bitmap_Size;
183 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
184 So to let this compile on older versions of FreeType we'll define the
185 new structure here. */
186 typedef struct {
187 FT_Short height, width;
188 FT_Pos size, x_ppem, y_ppem;
189 } My_FT_Bitmap_Size;
191 typedef struct tagFace {
192 struct list entry;
193 WCHAR *StyleName;
194 char *file;
195 FT_Long face_index;
196 BOOL Italic;
197 BOOL Bold;
198 FONTSIGNATURE fs;
199 FONTSIGNATURE fs_links;
200 FT_Fixed font_version;
201 BOOL scalable;
202 Bitmap_Size size; /* set if face is a bitmap */
203 BOOL external; /* TRUE if we should manually add this font to the registry */
204 struct tagFamily *family;
205 } Face;
207 typedef struct tagFamily {
208 struct list entry;
209 WCHAR *FamilyName;
210 struct list faces;
211 } Family;
213 typedef struct {
214 GLYPHMETRICS gm;
215 INT adv; /* These three hold to widths of the unrotated chars */
216 INT lsb;
217 INT bbx;
218 BOOL init;
219 } GM;
221 typedef struct {
222 FLOAT eM11, eM12;
223 FLOAT eM21, eM22;
224 } FMAT2;
226 typedef struct {
227 DWORD hash;
228 LOGFONTW lf;
229 FMAT2 matrix;
230 } FONT_DESC;
232 typedef struct tagHFONTLIST {
233 struct list entry;
234 HFONT hfont;
235 } HFONTLIST;
237 typedef struct {
238 struct list entry;
239 char *file_name;
240 INT index;
241 GdiFont font;
242 } CHILD_FONT;
244 struct tagGdiFont {
245 struct list entry;
246 FT_Face ft_face;
247 LPWSTR name;
248 int charset;
249 int codepage;
250 BOOL fake_italic;
251 BOOL fake_bold;
252 BYTE underline;
253 BYTE strikeout;
254 INT orientation;
255 GM *gm;
256 DWORD gmsize;
257 struct list hfontlist;
258 FONT_DESC font_desc;
259 LONG aveWidth;
260 SHORT yMax;
261 SHORT yMin;
262 OUTLINETEXTMETRICW *potm;
263 FONTSIGNATURE fs;
264 GdiFont base_font;
265 struct list child_fonts;
266 LONG ppem;
269 typedef struct {
270 struct list entry;
271 WCHAR *font_name;
272 struct list links;
273 } SYSTEM_LINKS;
275 #define INIT_GM_SIZE 128
277 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
278 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
279 #define UNUSED_CACHE_SIZE 10
280 static struct list child_font_list = LIST_INIT(child_font_list);
281 static struct list system_links = LIST_INIT(system_links);
283 static struct list font_list = LIST_INIT(font_list);
285 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
286 'R','o','m','a','n','\0'};
287 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
288 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
290 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
291 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
292 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
293 'S','e','r','i','f','\0'};
294 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
295 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
297 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
298 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
299 'W','i','n','d','o','w','s','\\',
300 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
301 'F','o','n','t','s','\0'};
303 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
304 'W','i','n','d','o','w','s',' ','N','T','\\',
305 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
306 'F','o','n','t','s','\0'};
308 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
309 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
310 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
311 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
313 static const WCHAR *SystemFontValues[4] = {
314 System_Value,
315 OEMFont_Value,
316 FixedSys_Value,
317 NULL
320 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
321 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
323 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
324 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
325 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
326 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
327 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
328 'E','u','r','o','p','e','a','n','\0'};
329 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
330 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
331 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
332 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
333 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
334 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
335 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
336 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
337 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
338 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
339 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
340 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
342 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
343 WesternW, /*00*/
344 Central_EuropeanW,
345 CyrillicW,
346 GreekW,
347 TurkishW,
348 HebrewW,
349 ArabicW,
350 BalticW,
351 VietnameseW, /*08*/
352 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
353 ThaiW,
354 JapaneseW,
355 CHINESE_GB2312W,
356 HangulW,
357 CHINESE_BIG5W,
358 Hangul_Johab_W,
359 NULL, NULL, /*23*/
360 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
361 SymbolW /*31*/
364 typedef struct {
365 WCHAR *name;
366 INT charset;
367 } NameCs;
369 typedef struct tagFontSubst {
370 NameCs from;
371 NameCs to;
372 struct tagFontSubst *next;
373 } FontSubst;
375 static FontSubst *substlist = NULL;
376 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
378 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
381 /****************************************
382 * Notes on .fon files
384 * The fonts System, FixedSys and Terminal are special. There are typically multiple
385 * versions installed for different resolutions and codepages. Windows stores which one to use
386 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
387 * Key Meaning
388 * FIXEDFON.FON FixedSys
389 * FONTS.FON System
390 * OEMFONT.FON Terminal
391 * LogPixels Current dpi set by the display control panel applet
392 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
393 * also has a LogPixels value that appears to mirror this)
395 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
396 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
397 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
398 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
399 * so that makes sense.
401 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
402 * to be mapped into the registry on Windows 2000 at least).
403 * I have
404 * woafont=app850.fon
405 * ega80woa.fon=ega80850.fon
406 * ega40woa.fon=ega40850.fon
407 * cga80woa.fon=cga80850.fon
408 * cga40woa.fon=cga40850.fon
412 static inline BOOL is_win9x(void)
414 return GetVersion() & 0x80000000;
417 This function builds an FT_Fixed from a float. It puts the integer part
418 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
419 It fails if the integer part of the float number is greater than SHORT_MAX.
421 static inline FT_Fixed FT_FixedFromFloat(float f)
423 short value = f;
424 unsigned short fract = (f - value) * 0xFFFF;
425 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
429 This function builds an FT_Fixed from a FIXED. It simply put f.value
430 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
432 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
434 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
437 #define ADDFONT_EXTERNAL_FONT 0x01
438 #define ADDFONT_FORCE_BITMAP 0x02
439 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
441 FT_Face ft_face;
442 TT_OS2 *pOS2;
443 TT_Header *pHeader = NULL;
444 WCHAR *FamilyW, *StyleW;
445 DWORD len;
446 Family *family;
447 Face *face;
448 struct list *family_elem_ptr, *face_elem_ptr;
449 FT_Error err;
450 FT_Long face_index = 0, num_faces;
451 #ifdef HAVE_FREETYPE_FTWINFNT_H
452 FT_WinFNT_HeaderRec winfnt_header;
453 #endif
454 int i, bitmap_num, internal_leading;
455 FONTSIGNATURE fs;
457 do {
458 char *family_name = fake_family;
460 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
461 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
462 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
463 return FALSE;
466 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*/
467 WARN("Ignoring font %s\n", debugstr_a(file));
468 pFT_Done_Face(ft_face);
469 return FALSE;
472 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
473 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
474 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
475 pFT_Done_Face(ft_face);
476 return FALSE;
479 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
480 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
481 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
482 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
483 "Skipping this font.\n", debugstr_a(file));
484 pFT_Done_Face(ft_face);
485 return FALSE;
488 if(!ft_face->family_name || !ft_face->style_name) {
489 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
490 pFT_Done_Face(ft_face);
491 return FALSE;
494 if(!family_name)
495 family_name = ft_face->family_name;
497 bitmap_num = 0;
498 do {
499 My_FT_Bitmap_Size *size = NULL;
501 if(!FT_IS_SCALABLE(ft_face))
502 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
504 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
505 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
506 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
508 family = NULL;
509 LIST_FOR_EACH(family_elem_ptr, &font_list) {
510 family = LIST_ENTRY(family_elem_ptr, Family, entry);
511 if(!strcmpW(family->FamilyName, FamilyW))
512 break;
513 family = NULL;
515 if(!family) {
516 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
517 family->FamilyName = FamilyW;
518 list_init(&family->faces);
519 list_add_tail(&font_list, &family->entry);
520 } else {
521 HeapFree(GetProcessHeap(), 0, FamilyW);
524 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
525 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
526 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
528 internal_leading = 0;
529 memset(&fs, 0, sizeof(fs));
531 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
532 if(pOS2) {
533 fs.fsCsb[0] = pOS2->ulCodePageRange1;
534 fs.fsCsb[1] = pOS2->ulCodePageRange2;
535 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
536 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
537 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
538 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
539 if(pOS2->version == 0) {
540 FT_UInt dummy;
542 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
543 fs.fsCsb[0] |= 1;
544 else
545 fs.fsCsb[0] |= 1L << 31;
548 #ifdef HAVE_FREETYPE_FTWINFNT_H
549 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
550 CHARSETINFO csi;
551 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
552 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
553 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
554 memcpy(&fs, &csi.fs, sizeof(csi.fs));
555 internal_leading = winfnt_header.internal_leading;
557 #endif
559 face_elem_ptr = list_head(&family->faces);
560 while(face_elem_ptr) {
561 face = LIST_ENTRY(face_elem_ptr, Face, entry);
562 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
563 if(!strcmpW(face->StyleName, StyleW) &&
564 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
565 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
566 debugstr_w(family->FamilyName), debugstr_w(StyleW),
567 face->font_version, pHeader ? pHeader->Font_Revision : 0);
569 if(fake_family) {
570 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
571 HeapFree(GetProcessHeap(), 0, StyleW);
572 pFT_Done_Face(ft_face);
573 return FALSE;
575 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
576 TRACE("Original font is newer so skipping this one\n");
577 HeapFree(GetProcessHeap(), 0, StyleW);
578 pFT_Done_Face(ft_face);
579 return FALSE;
580 } else {
581 TRACE("Replacing original with this one\n");
582 list_remove(&face->entry);
583 HeapFree(GetProcessHeap(), 0, face->file);
584 HeapFree(GetProcessHeap(), 0, face->StyleName);
585 HeapFree(GetProcessHeap(), 0, face);
586 break;
590 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
591 list_add_tail(&family->faces, &face->entry);
592 face->StyleName = StyleW;
593 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
594 strcpy(face->file, file);
595 face->face_index = face_index;
596 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
597 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
598 face->font_version = pHeader ? pHeader->Font_Revision : 0;
599 face->family = family;
600 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
601 memcpy(&face->fs, &fs, sizeof(face->fs));
602 memset(&face->fs_links, 0, sizeof(face->fs_links));
604 if(FT_IS_SCALABLE(ft_face)) {
605 memset(&face->size, 0, sizeof(face->size));
606 face->scalable = TRUE;
607 } else {
608 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
609 size->height, size->width, size->size >> 6,
610 size->x_ppem >> 6, size->y_ppem >> 6);
611 face->size.height = size->height;
612 face->size.width = size->width;
613 face->size.size = size->size;
614 face->size.x_ppem = size->x_ppem;
615 face->size.y_ppem = size->y_ppem;
616 face->size.internal_leading = internal_leading;
617 face->scalable = FALSE;
620 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
621 face->fs.fsCsb[0], face->fs.fsCsb[1],
622 face->fs.fsUsb[0], face->fs.fsUsb[1],
623 face->fs.fsUsb[2], face->fs.fsUsb[3]);
626 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
627 for(i = 0; i < ft_face->num_charmaps; i++) {
628 switch(ft_face->charmaps[i]->encoding) {
629 case FT_ENCODING_UNICODE:
630 case FT_ENCODING_APPLE_ROMAN:
631 face->fs.fsCsb[0] |= 1;
632 break;
633 case FT_ENCODING_MS_SYMBOL:
634 face->fs.fsCsb[0] |= 1L << 31;
635 break;
636 default:
637 break;
642 if(face->fs.fsCsb[0] & ~(1L << 31))
643 have_installed_roman_font = TRUE;
644 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
646 num_faces = ft_face->num_faces;
647 pFT_Done_Face(ft_face);
648 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
649 debugstr_w(StyleW));
650 } while(num_faces > ++face_index);
651 return TRUE;
654 static void DumpFontList(void)
656 Family *family;
657 Face *face;
658 struct list *family_elem_ptr, *face_elem_ptr;
660 LIST_FOR_EACH(family_elem_ptr, &font_list) {
661 family = LIST_ENTRY(family_elem_ptr, Family, entry);
662 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
663 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
664 face = LIST_ENTRY(face_elem_ptr, Face, entry);
665 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
666 if(!face->scalable)
667 TRACE(" %ld", face->size.y_ppem >> 6);
668 TRACE("\n");
671 return;
674 static Face *find_face_from_filename(const WCHAR *name)
676 Family *family;
677 Face *face;
678 char *file;
679 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
680 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
681 Face *ret = NULL;
683 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
684 TRACE("looking for %s\n", debugstr_a(nameA));
686 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
688 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
690 file = strrchr(face->file, '/');
691 if(!file)
692 file = face->file;
693 else
694 file++;
695 if(!strcmp(file, nameA))
696 ret = face;
697 break;
700 HeapFree(GetProcessHeap(), 0, nameA);
701 return ret;
704 static Family *find_family_from_name(const WCHAR *name)
706 Family *family;
708 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
710 if(!strcmpiW(family->FamilyName, name))
711 return family;
714 return NULL;
717 static void DumpSubstList(void)
719 FontSubst *psub;
721 for(psub = substlist; psub; psub = psub->next)
722 if(psub->from.charset != -1 || psub->to.charset != -1)
723 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
724 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
725 else
726 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
727 debugstr_w(psub->to.name));
728 return;
731 static LPWSTR strdupW(LPCWSTR p)
733 LPWSTR ret;
734 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
735 ret = HeapAlloc(GetProcessHeap(), 0, len);
736 memcpy(ret, p, len);
737 return ret;
740 static LPSTR strdupA(LPCSTR p)
742 LPSTR ret;
743 DWORD len = (strlen(p) + 1);
744 ret = HeapAlloc(GetProcessHeap(), 0, len);
745 memcpy(ret, p, len);
746 return ret;
749 static void split_subst_info(NameCs *nc, LPSTR str)
751 CHAR *p = strrchr(str, ',');
752 DWORD len;
754 nc->charset = -1;
755 if(p && *(p+1)) {
756 nc->charset = strtol(p+1, NULL, 10);
757 *p = '\0';
759 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
760 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
761 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
764 static void LoadSubstList(void)
766 FontSubst *psub, **ppsub;
767 HKEY hkey;
768 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
769 LPSTR value;
770 LPVOID data;
772 if(substlist) {
773 for(psub = substlist; psub;) {
774 FontSubst *ptmp;
775 HeapFree(GetProcessHeap(), 0, psub->to.name);
776 HeapFree(GetProcessHeap(), 0, psub->from.name);
777 ptmp = psub;
778 psub = psub->next;
779 HeapFree(GetProcessHeap(), 0, ptmp);
781 substlist = NULL;
784 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
785 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
786 &hkey) == ERROR_SUCCESS) {
788 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
789 &valuelen, &datalen, NULL, NULL);
791 valuelen++; /* returned value doesn't include room for '\0' */
792 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
793 data = HeapAlloc(GetProcessHeap(), 0, datalen);
795 dlen = datalen;
796 vlen = valuelen;
797 ppsub = &substlist;
798 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
799 &dlen) == ERROR_SUCCESS) {
800 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
802 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
803 (*ppsub)->next = NULL;
804 split_subst_info(&((*ppsub)->from), value);
805 split_subst_info(&((*ppsub)->to), data);
807 /* Win 2000 doesn't allow mapping between different charsets
808 or mapping of DEFAULT_CHARSET */
809 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
810 (*ppsub)->to.charset == DEFAULT_CHARSET) {
811 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
812 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
813 HeapFree(GetProcessHeap(), 0, *ppsub);
814 *ppsub = NULL;
815 } else {
816 ppsub = &((*ppsub)->next);
818 /* reset dlen and vlen */
819 dlen = datalen;
820 vlen = valuelen;
822 HeapFree(GetProcessHeap(), 0, data);
823 HeapFree(GetProcessHeap(), 0, value);
824 RegCloseKey(hkey);
828 /***********************************************************
829 * The replacement list is a way to map an entire font
830 * family onto another family. For example adding
832 * [HKCU\Software\Wine\Fonts\Replacements]
833 * "Wingdings"="Winedings"
835 * would enumerate the Winedings font both as Winedings and
836 * Wingdings. However if a real Wingdings font is present the
837 * replacement does not take place.
840 static void LoadReplaceList(void)
842 HKEY hkey;
843 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
844 LPSTR value;
845 LPVOID data;
846 Family *family;
847 Face *face;
848 struct list *family_elem_ptr, *face_elem_ptr;
849 WCHAR old_nameW[200];
851 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
852 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
854 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
855 &valuelen, &datalen, NULL, NULL);
857 valuelen++; /* returned value doesn't include room for '\0' */
858 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
859 data = HeapAlloc(GetProcessHeap(), 0, datalen);
861 dlen = datalen;
862 vlen = valuelen;
863 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
864 &dlen) == ERROR_SUCCESS) {
865 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
866 /* "NewName"="Oldname" */
867 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
868 break;
870 /* Find the old family and hence all of the font files
871 in that family */
872 LIST_FOR_EACH(family_elem_ptr, &font_list) {
873 family = LIST_ENTRY(family_elem_ptr, Family, entry);
874 if(!strcmpiW(family->FamilyName, old_nameW)) {
875 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
876 face = LIST_ENTRY(face_elem_ptr, Face, entry);
877 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
878 debugstr_w(face->StyleName), value);
879 /* Now add a new entry with the new family name */
880 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
882 break;
885 /* reset dlen and vlen */
886 dlen = datalen;
887 vlen = valuelen;
889 HeapFree(GetProcessHeap(), 0, data);
890 HeapFree(GetProcessHeap(), 0, value);
891 RegCloseKey(hkey);
895 /*************************************************************
896 * init_system_links
898 static BOOL init_system_links(void)
900 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
901 'W','i','n','d','o','w','s',' ','N','T','\\',
902 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
903 'S','y','s','t','e','m','L','i','n','k',0};
904 HKEY hkey;
905 BOOL ret = FALSE;
906 DWORD type, max_val, max_data, val_len, data_len, index;
907 WCHAR *value, *data;
908 WCHAR *entry, *next;
909 SYSTEM_LINKS *font_link, *system_font_link;
910 CHILD_FONT *child_font;
911 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
912 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
913 static const WCHAR System[] = {'S','y','s','t','e','m',0};
914 FONTSIGNATURE fs;
915 Family *family;
916 Face *face;
918 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
920 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
921 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
922 data = HeapAlloc(GetProcessHeap(), 0, max_data);
923 val_len = max_val + 1;
924 data_len = max_data;
925 index = 0;
926 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
928 TRACE("%s:\n", debugstr_w(value));
930 memset(&fs, 0, sizeof(fs));
931 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
932 font_link->font_name = strdupW(value);
933 list_init(&font_link->links);
934 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
936 WCHAR *face_name;
937 INT index;
938 CHILD_FONT *child_font;
940 TRACE("\t%s\n", debugstr_w(entry));
942 next = entry + strlenW(entry) + 1;
944 face_name = strchrW(entry, ',');
945 if(!face_name)
946 index = 0;
947 else
949 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
950 *face_name++ = 0;
951 while(isspaceW(*face_name))
952 face_name++;
954 index = 0;
956 face = find_face_from_filename(entry);
957 if(!face)
959 TRACE("Unable to find file %s\n", debugstr_w(entry));
960 continue;
963 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
964 child_font->file_name = strdupA(face->file);
965 child_font->index = index;
966 child_font->font = NULL;
967 fs.fsCsb[0] |= face->fs.fsCsb[0];
968 fs.fsCsb[1] |= face->fs.fsCsb[1];
969 list_add_tail(&font_link->links, &child_font->entry);
971 family = find_family_from_name(font_link->font_name);
972 if(family)
974 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
976 memcpy(&face->fs_links, &fs, sizeof(fs));
979 list_add_tail(&system_links, &font_link->entry);
980 val_len = max_val + 1;
981 data_len = max_data;
984 HeapFree(GetProcessHeap(), 0, value);
985 HeapFree(GetProcessHeap(), 0, data);
986 RegCloseKey(hkey);
989 /* Explicitly add an entry for the system font, this links to Tahoma and any links
990 that Tahoma has */
992 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
993 system_font_link->font_name = strdupW(System);
994 list_init(&system_font_link->links);
996 face = find_face_from_filename(tahoma_ttf);
997 if(face)
999 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1000 child_font->file_name = strdupA(face->file);
1001 child_font->index = 0;
1002 child_font->font = NULL;
1003 list_add_tail(&system_font_link->links, &child_font->entry);
1005 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1007 if(!strcmpiW(font_link->font_name, Tahoma))
1009 CHILD_FONT *font_link_entry;
1010 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1012 CHILD_FONT *new_child;
1013 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1014 new_child->file_name = strdupA(font_link_entry->file_name);
1015 new_child->index = font_link_entry->index;
1016 new_child->font = NULL;
1017 list_add_tail(&system_font_link->links, &new_child->entry);
1019 break;
1022 list_add_tail(&system_links, &system_font_link->entry);
1023 return ret;
1026 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1028 DIR *dir;
1029 struct dirent *dent;
1030 char path[MAX_PATH];
1032 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1034 dir = opendir(dirname);
1035 if(!dir) {
1036 ERR("Can't open directory %s\n", debugstr_a(dirname));
1037 return FALSE;
1039 while((dent = readdir(dir)) != NULL) {
1040 struct stat statbuf;
1042 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1043 continue;
1045 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1047 sprintf(path, "%s/%s", dirname, dent->d_name);
1049 if(stat(path, &statbuf) == -1)
1051 WARN("Can't stat %s\n", debugstr_a(path));
1052 continue;
1054 if(S_ISDIR(statbuf.st_mode))
1055 ReadFontDir(path, external_fonts);
1056 else
1057 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1059 closedir(dir);
1060 return TRUE;
1063 static void load_fontconfig_fonts(void)
1065 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1066 void *fc_handle = NULL;
1067 FcConfig *config;
1068 FcPattern *pat;
1069 FcObjectSet *os;
1070 FcFontSet *fontset;
1071 FcValue v;
1072 int i, len;
1073 const char *file, *ext;
1075 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1076 if(!fc_handle) {
1077 TRACE("Wine cannot find the fontconfig library (%s).\n",
1078 SONAME_LIBFONTCONFIG);
1079 return;
1081 #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;}
1082 LOAD_FUNCPTR(FcConfigGetCurrent);
1083 LOAD_FUNCPTR(FcFontList);
1084 LOAD_FUNCPTR(FcFontSetDestroy);
1085 LOAD_FUNCPTR(FcInit);
1086 LOAD_FUNCPTR(FcObjectSetAdd);
1087 LOAD_FUNCPTR(FcObjectSetCreate);
1088 LOAD_FUNCPTR(FcObjectSetDestroy);
1089 LOAD_FUNCPTR(FcPatternCreate);
1090 LOAD_FUNCPTR(FcPatternDestroy);
1091 LOAD_FUNCPTR(FcPatternGet);
1092 #undef LOAD_FUNCPTR
1094 if(!pFcInit()) return;
1096 config = pFcConfigGetCurrent();
1097 pat = pFcPatternCreate();
1098 os = pFcObjectSetCreate();
1099 pFcObjectSetAdd(os, FC_FILE);
1100 fontset = pFcFontList(config, pat, os);
1101 if(!fontset) return;
1102 for(i = 0; i < fontset->nfont; i++) {
1103 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1104 continue;
1105 if(v.type != FcTypeString) continue;
1106 file = (LPCSTR) v.u.s;
1107 TRACE("fontconfig: %s\n", file);
1109 /* We're just interested in OT/TT fonts for now, so this hack just
1110 picks up the standard extensions to save time loading every other
1111 font */
1112 len = strlen( file );
1113 if(len < 4) continue;
1114 ext = &file[ len - 3 ];
1115 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1116 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1118 pFcFontSetDestroy(fontset);
1119 pFcObjectSetDestroy(os);
1120 pFcPatternDestroy(pat);
1121 sym_not_found:
1122 #endif
1123 return;
1126 static BOOL load_font_from_data_dir(LPCWSTR file)
1128 BOOL ret = FALSE;
1129 const char *data_dir = wine_get_data_dir();
1131 if (data_dir)
1133 INT len;
1134 char *unix_name;
1136 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1138 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1140 strcpy(unix_name, data_dir);
1141 strcat(unix_name, "/fonts/");
1143 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1145 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1146 HeapFree(GetProcessHeap(), 0, unix_name);
1148 return ret;
1151 static void load_system_fonts(void)
1153 HKEY hkey;
1154 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1155 const WCHAR **value;
1156 DWORD dlen, type;
1157 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1158 char *unixname;
1160 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1161 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1162 strcatW(windowsdir, fontsW);
1163 for(value = SystemFontValues; *value; value++) {
1164 dlen = sizeof(data);
1165 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1166 type == REG_SZ) {
1167 BOOL added = FALSE;
1169 sprintfW(pathW, fmtW, windowsdir, data);
1170 if((unixname = wine_get_unix_file_name(pathW))) {
1171 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1172 HeapFree(GetProcessHeap(), 0, unixname);
1174 if (!added)
1175 load_font_from_data_dir(data);
1178 RegCloseKey(hkey);
1182 /*************************************************************
1184 * This adds registry entries for any externally loaded fonts
1185 * (fonts from fontconfig or FontDirs). It also deletes entries
1186 * of no longer existing fonts.
1189 static void update_reg_entries(void)
1191 HKEY winkey = 0, externalkey = 0;
1192 LPWSTR valueW;
1193 LPVOID data;
1194 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1195 Family *family;
1196 Face *face;
1197 struct list *family_elem_ptr, *face_elem_ptr;
1198 WCHAR *file;
1199 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1200 static const WCHAR spaceW[] = {' ', '\0'};
1201 char *path;
1203 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1204 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1205 ERR("Can't create Windows font reg key\n");
1206 goto end;
1208 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1209 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1210 ERR("Can't create external font reg key\n");
1211 goto end;
1214 /* Delete all external fonts added last time */
1216 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1217 &valuelen, &datalen, NULL, NULL);
1218 valuelen++; /* returned value doesn't include room for '\0' */
1219 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1220 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1222 dlen = datalen * sizeof(WCHAR);
1223 vlen = valuelen;
1224 i = 0;
1225 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1226 &dlen) == ERROR_SUCCESS) {
1228 RegDeleteValueW(winkey, valueW);
1229 /* reset dlen and vlen */
1230 dlen = datalen;
1231 vlen = valuelen;
1233 HeapFree(GetProcessHeap(), 0, data);
1234 HeapFree(GetProcessHeap(), 0, valueW);
1236 /* Delete the old external fonts key */
1237 RegCloseKey(externalkey);
1238 externalkey = 0;
1239 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1241 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1242 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1243 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1244 ERR("Can't create external font reg key\n");
1245 goto end;
1248 /* enumerate the fonts and add external ones to the two keys */
1250 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1251 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1252 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1253 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1254 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1255 if(!face->external) continue;
1256 len = len_fam;
1257 if(strcmpiW(face->StyleName, RegularW))
1258 len = len_fam + strlenW(face->StyleName) + 1;
1259 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1260 strcpyW(valueW, family->FamilyName);
1261 if(len != len_fam) {
1262 strcatW(valueW, spaceW);
1263 strcatW(valueW, face->StyleName);
1265 strcatW(valueW, TrueType);
1266 if((path = strrchr(face->file, '/')) == NULL)
1267 path = face->file;
1268 else
1269 path++;
1270 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1272 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1273 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1274 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1275 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1277 HeapFree(GetProcessHeap(), 0, file);
1278 HeapFree(GetProcessHeap(), 0, valueW);
1281 end:
1282 if(externalkey)
1283 RegCloseKey(externalkey);
1284 if(winkey)
1285 RegCloseKey(winkey);
1286 return;
1290 /*************************************************************
1291 * WineEngAddFontResourceEx
1294 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1296 if (ft_handle) /* do it only if we have freetype up and running */
1298 char *unixname;
1300 if(flags)
1301 FIXME("Ignoring flags %lx\n", flags);
1303 if((unixname = wine_get_unix_file_name(file)))
1305 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1306 HeapFree(GetProcessHeap(), 0, unixname);
1309 return 1;
1312 /*************************************************************
1313 * WineEngRemoveFontResourceEx
1316 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1318 FIXME(":stub\n");
1319 return TRUE;
1322 static const struct nls_update_font_list
1324 UINT ansi_cp, oem_cp;
1325 const char *oem, *fixed, *system;
1326 const char *courier, *serif, *small, *sserif;
1327 } nls_update_font_list[] =
1329 /* Latin 1 (United States) */
1330 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1331 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1333 /* Latin 1 (Multilingual) */
1334 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1335 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1337 /* Eastern Europe */
1338 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1339 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1341 /* Cyrillic */
1342 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1343 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1345 /* Greek */
1346 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1347 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1349 /* Turkish */
1350 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1351 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1353 /* Hebrew */
1354 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1355 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1357 /* Arabic */
1358 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1359 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1361 /* Baltic */
1362 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1363 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1365 /* Vietnamese */
1366 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1367 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1369 /* Thai */
1370 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1371 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1373 /* Japanese */
1374 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1375 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1377 /* Chinese Simplified */
1378 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1379 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1381 /* Korean */
1382 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1383 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1385 /* Chinese Traditional */
1386 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1387 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1391 inline static HKEY create_fonts_NT_registry_key(void)
1393 HKEY hkey = 0;
1395 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1396 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1397 return hkey;
1400 inline static HKEY create_fonts_9x_registry_key(void)
1402 HKEY hkey = 0;
1404 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1405 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1406 return hkey;
1409 inline static HKEY create_config_fonts_registry_key(void)
1411 HKEY hkey = 0;
1413 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1414 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1415 return hkey;
1418 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1420 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1421 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1422 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1423 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1426 static void update_font_info(void)
1428 char buf[80];
1429 DWORD len, type;
1430 HKEY hkey = 0;
1431 UINT i, ansi_cp = 0, oem_cp = 0;
1432 LCID lcid = GetUserDefaultLCID();
1434 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1435 return;
1437 len = sizeof(buf);
1438 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1440 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1442 RegCloseKey(hkey);
1443 return;
1445 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1447 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1449 sprintf(buf, "%08lx", lcid);
1450 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1451 RegCloseKey(hkey);
1453 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1454 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1455 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1456 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1458 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1460 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1461 nls_update_font_list[i].oem_cp == oem_cp)
1463 HKEY hkey;
1465 hkey = create_config_fonts_registry_key();
1466 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1467 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1468 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1469 RegCloseKey(hkey);
1471 hkey = create_fonts_NT_registry_key();
1472 add_font_list(hkey, &nls_update_font_list[i]);
1473 RegCloseKey(hkey);
1475 hkey = create_fonts_9x_registry_key();
1476 add_font_list(hkey, &nls_update_font_list[i]);
1477 RegCloseKey(hkey);
1479 return;
1482 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1485 /*************************************************************
1486 * WineEngInit
1488 * Initialize FreeType library and create a list of available faces
1490 BOOL WineEngInit(void)
1492 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1493 static const WCHAR pathW[] = {'P','a','t','h',0};
1494 HKEY hkey;
1495 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1496 LPVOID data;
1497 WCHAR windowsdir[MAX_PATH];
1498 char *unixname;
1499 HANDLE font_mutex;
1501 TRACE("\n");
1503 /* update locale dependent font info in registry */
1504 update_font_info();
1506 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1507 if(!ft_handle) {
1508 WINE_MESSAGE(
1509 "Wine cannot find the FreeType font library. To enable Wine to\n"
1510 "use TrueType fonts please install a version of FreeType greater than\n"
1511 "or equal to 2.0.5.\n"
1512 "http://www.freetype.org\n");
1513 return FALSE;
1516 #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;}
1518 LOAD_FUNCPTR(FT_Vector_Unit)
1519 LOAD_FUNCPTR(FT_Done_Face)
1520 LOAD_FUNCPTR(FT_Get_Char_Index)
1521 LOAD_FUNCPTR(FT_Get_Module)
1522 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1523 LOAD_FUNCPTR(FT_Init_FreeType)
1524 LOAD_FUNCPTR(FT_Load_Glyph)
1525 LOAD_FUNCPTR(FT_Matrix_Multiply)
1526 LOAD_FUNCPTR(FT_MulFix)
1527 LOAD_FUNCPTR(FT_New_Face)
1528 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1529 LOAD_FUNCPTR(FT_Outline_Transform)
1530 LOAD_FUNCPTR(FT_Outline_Translate)
1531 LOAD_FUNCPTR(FT_Select_Charmap)
1532 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1533 LOAD_FUNCPTR(FT_Vector_Transform)
1535 #undef LOAD_FUNCPTR
1536 /* Don't warn if this one is missing */
1537 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1538 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1539 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1540 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1541 #ifdef HAVE_FREETYPE_FTWINFNT_H
1542 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1543 #endif
1544 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1545 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1546 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1547 <= 2.0.3 has FT_Sqrt64 */
1548 goto sym_not_found;
1551 if(pFT_Init_FreeType(&library) != 0) {
1552 ERR("Can't init FreeType library\n");
1553 wine_dlclose(ft_handle, NULL, 0);
1554 ft_handle = NULL;
1555 return FALSE;
1557 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1558 if (pFT_Library_Version)
1560 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1562 if (FT_Version.major<=0)
1564 FT_Version.major=2;
1565 FT_Version.minor=0;
1566 FT_Version.patch=5;
1568 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1569 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1570 ((FT_Version.minor << 8) & 0x00ff00) |
1571 ((FT_Version.patch ) & 0x0000ff);
1573 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1574 ERR("Failed to create font mutex\n");
1575 return FALSE;
1577 WaitForSingleObject(font_mutex, INFINITE);
1579 /* load the system fonts */
1580 load_system_fonts();
1582 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1583 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1584 strcatW(windowsdir, fontsW);
1585 if((unixname = wine_get_unix_file_name(windowsdir)))
1587 ReadFontDir(unixname, FALSE);
1588 HeapFree(GetProcessHeap(), 0, unixname);
1591 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1592 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1593 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1594 will skip these. */
1595 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1596 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1597 &hkey) == ERROR_SUCCESS) {
1598 LPWSTR valueW;
1599 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1600 &valuelen, &datalen, NULL, NULL);
1602 valuelen++; /* returned value doesn't include room for '\0' */
1603 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1604 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1605 if (valueW && data)
1607 dlen = datalen * sizeof(WCHAR);
1608 vlen = valuelen;
1609 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1610 &dlen) == ERROR_SUCCESS) {
1611 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1613 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1615 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1616 HeapFree(GetProcessHeap(), 0, unixname);
1619 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1621 WCHAR pathW[MAX_PATH];
1622 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1623 BOOL added = FALSE;
1625 sprintfW(pathW, fmtW, windowsdir, data);
1626 if((unixname = wine_get_unix_file_name(pathW)))
1628 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1629 HeapFree(GetProcessHeap(), 0, unixname);
1631 if (!added)
1632 load_font_from_data_dir(data);
1634 /* reset dlen and vlen */
1635 dlen = datalen;
1636 vlen = valuelen;
1639 HeapFree(GetProcessHeap(), 0, data);
1640 HeapFree(GetProcessHeap(), 0, valueW);
1641 RegCloseKey(hkey);
1644 load_fontconfig_fonts();
1646 /* then look in any directories that we've specified in the config file */
1647 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1648 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1650 DWORD len;
1651 LPWSTR valueW;
1652 LPSTR valueA, ptr;
1654 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1656 len += sizeof(WCHAR);
1657 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1658 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1660 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1661 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1662 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1663 TRACE( "got font path %s\n", debugstr_a(valueA) );
1664 ptr = valueA;
1665 while (ptr)
1667 LPSTR next = strchr( ptr, ':' );
1668 if (next) *next++ = 0;
1669 ReadFontDir( ptr, TRUE );
1670 ptr = next;
1672 HeapFree( GetProcessHeap(), 0, valueA );
1674 HeapFree( GetProcessHeap(), 0, valueW );
1676 RegCloseKey(hkey);
1679 DumpFontList();
1680 LoadSubstList();
1681 DumpSubstList();
1682 LoadReplaceList();
1683 update_reg_entries();
1685 init_system_links();
1687 ReleaseMutex(font_mutex);
1688 return TRUE;
1689 sym_not_found:
1690 WINE_MESSAGE(
1691 "Wine cannot find certain functions that it needs inside the FreeType\n"
1692 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1693 "FreeType to at least version 2.0.5.\n"
1694 "http://www.freetype.org\n");
1695 wine_dlclose(ft_handle, NULL, 0);
1696 ft_handle = NULL;
1697 return FALSE;
1701 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1703 TT_OS2 *pOS2;
1704 TT_HoriHeader *pHori;
1706 LONG ppem;
1708 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1709 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1711 if(height == 0) height = 16;
1713 /* Calc. height of EM square:
1715 * For +ve lfHeight we have
1716 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1717 * Re-arranging gives:
1718 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1720 * For -ve lfHeight we have
1721 * |lfHeight| = ppem
1722 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1723 * with il = winAscent + winDescent - units_per_em]
1727 if(height > 0) {
1728 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1729 ppem = ft_face->units_per_EM * height /
1730 (pHori->Ascender - pHori->Descender);
1731 else
1732 ppem = ft_face->units_per_EM * height /
1733 (pOS2->usWinAscent + pOS2->usWinDescent);
1735 else
1736 ppem = -height;
1738 return ppem;
1741 static LONG load_VDMX(GdiFont, LONG);
1743 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1745 FT_Error err;
1746 FT_Face ft_face;
1748 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1749 err = pFT_New_Face(library, file, face_index, &ft_face);
1750 if(err) {
1751 ERR("FT_New_Face rets %d\n", err);
1752 return 0;
1755 /* set it here, as load_VDMX needs it */
1756 font->ft_face = ft_face;
1758 if(FT_IS_SCALABLE(ft_face)) {
1759 /* load the VDMX table if we have one */
1760 font->ppem = load_VDMX(font, height);
1761 if(font->ppem == 0)
1762 font->ppem = calc_ppem_for_height(ft_face, height);
1764 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1765 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1766 } else {
1767 font->ppem = height;
1768 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1769 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1771 return ft_face;
1775 static int get_nearest_charset(Face *face, int *cp)
1777 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1778 a single face with the requested charset. The idea is to check if
1779 the selected font supports the current ANSI codepage, if it does
1780 return the corresponding charset, else return the first charset */
1782 CHARSETINFO csi;
1783 int acp = GetACP(), i;
1784 DWORD fs0;
1786 *cp = acp;
1787 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1788 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1789 return csi.ciCharset;
1791 for(i = 0; i < 32; i++) {
1792 fs0 = 1L << i;
1793 if(face->fs.fsCsb[0] & fs0) {
1794 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1795 *cp = csi.ciACP;
1796 return csi.ciCharset;
1798 else
1799 FIXME("TCI failing on %lx\n", fs0);
1803 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1804 face->fs.fsCsb[0], face->file);
1805 *cp = acp;
1806 return DEFAULT_CHARSET;
1809 static GdiFont alloc_font(void)
1811 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1812 ret->gmsize = INIT_GM_SIZE;
1813 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1814 ret->gmsize * sizeof(*ret->gm));
1815 ret->potm = NULL;
1816 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1817 list_init(&ret->hfontlist);
1818 list_init(&ret->child_fonts);
1819 return ret;
1822 static void free_font(GdiFont font)
1824 struct list *cursor, *cursor2;
1826 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1828 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1829 struct list *first_hfont;
1830 HFONTLIST *hfontlist;
1831 list_remove(cursor);
1832 if(child->font)
1834 first_hfont = list_head(&child->font->hfontlist);
1835 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1836 DeleteObject(hfontlist->hfont);
1837 HeapFree(GetProcessHeap(), 0, hfontlist);
1838 free_font(child->font);
1840 HeapFree(GetProcessHeap(), 0, child->file_name);
1841 HeapFree(GetProcessHeap(), 0, child);
1844 if (font->ft_face) pFT_Done_Face(font->ft_face);
1845 HeapFree(GetProcessHeap(), 0, font->potm);
1846 HeapFree(GetProcessHeap(), 0, font->name);
1847 HeapFree(GetProcessHeap(), 0, font->gm);
1848 HeapFree(GetProcessHeap(), 0, font);
1852 /*************************************************************
1853 * load_VDMX
1855 * load the vdmx entry for the specified height
1858 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1859 ( ( (FT_ULong)_x4 << 24 ) | \
1860 ( (FT_ULong)_x3 << 16 ) | \
1861 ( (FT_ULong)_x2 << 8 ) | \
1862 (FT_ULong)_x1 )
1864 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1866 typedef struct {
1867 BYTE bCharSet;
1868 BYTE xRatio;
1869 BYTE yStartRatio;
1870 BYTE yEndRatio;
1871 } Ratios;
1874 static LONG load_VDMX(GdiFont font, LONG height)
1876 BYTE hdr[6], tmp[2], group[4];
1877 BYTE devXRatio, devYRatio;
1878 USHORT numRecs, numRatios;
1879 DWORD result, offset = -1;
1880 LONG ppem = 0;
1881 int i;
1883 /* For documentation on VDMX records, see
1884 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1887 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1889 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1890 return ppem;
1892 /* FIXME: need the real device aspect ratio */
1893 devXRatio = 1;
1894 devYRatio = 1;
1896 numRecs = GET_BE_WORD(&hdr[2]);
1897 numRatios = GET_BE_WORD(&hdr[4]);
1899 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1900 for(i = 0; i < numRatios; i++) {
1901 Ratios ratio;
1903 offset = (3 * 2) + (i * sizeof(Ratios));
1904 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1905 offset = -1;
1907 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1909 if((ratio.xRatio == 0 &&
1910 ratio.yStartRatio == 0 &&
1911 ratio.yEndRatio == 0) ||
1912 (devXRatio == ratio.xRatio &&
1913 devYRatio >= ratio.yStartRatio &&
1914 devYRatio <= ratio.yEndRatio))
1916 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1917 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1918 offset = GET_BE_WORD(tmp);
1919 break;
1923 if(offset == -1) {
1924 FIXME("No suitable ratio found\n");
1925 return ppem;
1928 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1929 USHORT recs;
1930 BYTE startsz, endsz;
1931 BYTE *vTable;
1933 recs = GET_BE_WORD(group);
1934 startsz = group[2];
1935 endsz = group[3];
1937 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1939 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1940 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1941 if(result == GDI_ERROR) {
1942 FIXME("Failed to retrieve vTable\n");
1943 goto end;
1946 if(height > 0) {
1947 for(i = 0; i < recs; i++) {
1948 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1949 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1950 ppem = GET_BE_WORD(&vTable[i * 6]);
1952 if(yMax + -yMin == height) {
1953 font->yMax = yMax;
1954 font->yMin = yMin;
1955 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1956 break;
1958 if(yMax + -yMin > height) {
1959 if(--i < 0) {
1960 ppem = 0;
1961 goto end; /* failed */
1963 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1964 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1965 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1966 break;
1969 if(!font->yMax) {
1970 ppem = 0;
1971 TRACE("ppem not found for height %ld\n", height);
1973 } else {
1974 ppem = -height;
1975 if(ppem < startsz || ppem > endsz)
1976 goto end;
1978 for(i = 0; i < recs; i++) {
1979 USHORT yPelHeight;
1980 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1982 if(yPelHeight > ppem)
1983 break; /* failed */
1985 if(yPelHeight == ppem) {
1986 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1987 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1988 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1989 break;
1993 end:
1994 HeapFree(GetProcessHeap(), 0, vTable);
1997 return ppem;
2000 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
2002 if(font->font_desc.hash != fd->hash) return TRUE;
2003 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2004 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2005 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2008 static void calc_hash(FONT_DESC *pfd)
2010 DWORD hash = 0, *ptr, two_chars;
2011 WORD *pwc;
2012 unsigned int i;
2014 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2015 hash ^= *ptr;
2016 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2017 hash ^= *ptr;
2018 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2019 two_chars = *ptr;
2020 pwc = (WCHAR *)&two_chars;
2021 if(!*pwc) break;
2022 *pwc = toupperW(*pwc);
2023 pwc++;
2024 *pwc = toupperW(*pwc);
2025 hash ^= two_chars;
2026 if(!*pwc) break;
2028 pfd->hash = hash;
2029 return;
2032 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2034 GdiFont ret;
2035 FONT_DESC fd;
2036 HFONTLIST *hflist;
2037 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2039 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2040 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2041 calc_hash(&fd);
2043 /* try the in-use list */
2044 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2045 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2046 if(!fontcmp(ret, &fd)) {
2047 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2048 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2049 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2050 if(hflist->hfont == hfont)
2051 return ret;
2053 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2054 hflist->hfont = hfont;
2055 list_add_head(&ret->hfontlist, &hflist->entry);
2056 return ret;
2060 /* then the unused list */
2061 font_elem_ptr = list_head(&unused_gdi_font_list);
2062 while(font_elem_ptr) {
2063 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2064 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2065 if(!fontcmp(ret, &fd)) {
2066 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2067 assert(list_empty(&ret->hfontlist));
2068 TRACE("Found %p in unused list\n", ret);
2069 list_remove(&ret->entry);
2070 list_add_head(&gdi_font_list, &ret->entry);
2071 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2072 hflist->hfont = hfont;
2073 list_add_head(&ret->hfontlist, &hflist->entry);
2074 return ret;
2077 return NULL;
2081 /*************************************************************
2082 * create_child_font_list
2084 static BOOL create_child_font_list(GdiFont font)
2086 BOOL ret = FALSE;
2087 SYSTEM_LINKS *font_link;
2088 CHILD_FONT *font_link_entry, *new_child;
2090 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2092 if(!strcmpW(font_link->font_name, font->name))
2094 TRACE("found entry in system list\n");
2095 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2097 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2098 new_child->file_name = strdupA(font_link_entry->file_name);
2099 new_child->index = font_link_entry->index;
2100 new_child->font = NULL;
2101 list_add_tail(&font->child_fonts, &new_child->entry);
2102 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2104 ret = TRUE;
2105 break;
2109 return ret;
2112 /*************************************************************
2113 * WineEngCreateFontInstance
2116 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2118 GdiFont ret;
2119 Face *face, *best;
2120 Family *family, *last_resort_family;
2121 struct list *family_elem_ptr, *face_elem_ptr;
2122 INT height, width = 0;
2123 signed int diff = 0, newdiff;
2124 BOOL bd, it, can_use_bitmap;
2125 LOGFONTW lf;
2126 CHARSETINFO csi;
2127 HFONTLIST *hflist;
2129 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2131 struct list *first_hfont = list_head(&ret->hfontlist);
2132 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2133 if(hflist->hfont == hfont)
2134 return ret;
2137 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2138 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2140 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2141 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2142 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2143 lf.lfEscapement);
2145 /* check the cache first */
2146 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2147 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2148 return ret;
2151 TRACE("not in cache\n");
2152 if(list_empty(&font_list)) /* No fonts installed */
2154 TRACE("No fonts installed\n");
2155 return NULL;
2157 if(!have_installed_roman_font)
2159 TRACE("No roman font installed\n");
2160 return NULL;
2163 ret = alloc_font();
2165 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2166 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2167 calc_hash(&ret->font_desc);
2168 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2169 hflist->hfont = hfont;
2170 list_add_head(&ret->hfontlist, &hflist->entry);
2173 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2174 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2175 original value lfCharSet. Note this is a special case for
2176 Symbol and doesn't happen at least for "Wingdings*" */
2178 if(!strcmpiW(lf.lfFaceName, SymbolW))
2179 lf.lfCharSet = SYMBOL_CHARSET;
2181 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2182 switch(lf.lfCharSet) {
2183 case DEFAULT_CHARSET:
2184 csi.fs.fsCsb[0] = 0;
2185 break;
2186 default:
2187 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2188 csi.fs.fsCsb[0] = 0;
2189 break;
2193 family = NULL;
2194 if(lf.lfFaceName[0] != '\0') {
2195 FontSubst *psub;
2196 for(psub = substlist; psub; psub = psub->next)
2197 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
2198 (psub->from.charset == -1 ||
2199 psub->from.charset == lf.lfCharSet))
2200 break;
2201 if(psub) {
2202 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2203 debugstr_w(psub->to.name));
2204 strcpyW(lf.lfFaceName, psub->to.name);
2207 /* We want a match on name and charset or just name if
2208 charset was DEFAULT_CHARSET. If the latter then
2209 we fixup the returned charset later in get_nearest_charset
2210 where we'll either use the charset of the current ansi codepage
2211 or if that's unavailable the first charset that the font supports.
2213 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2214 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2215 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2216 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2217 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2218 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2219 if(face->scalable || can_use_bitmap)
2220 goto found;
2226 /* If requested charset was DEFAULT_CHARSET then try using charset
2227 corresponding to the current ansi codepage */
2228 if(!csi.fs.fsCsb[0]) {
2229 INT acp = GetACP();
2230 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2231 FIXME("TCI failed on codepage %d\n", acp);
2232 csi.fs.fsCsb[0] = 0;
2233 } else
2234 lf.lfCharSet = csi.ciCharset;
2237 /* Face families are in the top 4 bits of lfPitchAndFamily,
2238 so mask with 0xF0 before testing */
2240 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2241 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2242 strcpyW(lf.lfFaceName, defFixed);
2243 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2244 strcpyW(lf.lfFaceName, defSerif);
2245 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2246 strcpyW(lf.lfFaceName, defSans);
2247 else
2248 strcpyW(lf.lfFaceName, defSans);
2249 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2250 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2251 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2252 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2253 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2254 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2255 if(face->scalable || can_use_bitmap)
2256 goto found;
2261 last_resort_family = NULL;
2262 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2263 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2264 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2265 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2266 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2267 if(face->scalable)
2268 goto found;
2269 if(can_use_bitmap && !last_resort_family)
2270 last_resort_family = family;
2275 if(last_resort_family) {
2276 family = last_resort_family;
2277 csi.fs.fsCsb[0] = 0;
2278 goto found;
2281 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2282 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2283 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2284 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2285 if(face->scalable) {
2286 csi.fs.fsCsb[0] = 0;
2287 FIXME("just using first face for now\n");
2288 goto found;
2290 if(can_use_bitmap && !last_resort_family)
2291 last_resort_family = family;
2294 if(!last_resort_family) {
2295 FIXME("can't find a single appropriate font - bailing\n");
2296 free_font(ret);
2297 return NULL;
2300 WARN("could only find a bitmap font - this will probably look awful!\n");
2301 family = last_resort_family;
2302 csi.fs.fsCsb[0] = 0;
2304 found:
2305 it = lf.lfItalic ? 1 : 0;
2306 bd = lf.lfWeight > 550 ? 1 : 0;
2308 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2309 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2311 face = best = NULL;
2312 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2313 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2314 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2315 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2316 if(face->scalable)
2317 break;
2318 if(height > 0)
2319 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2320 else
2321 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2322 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2323 (diff < 0 && newdiff > diff)) {
2324 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2325 diff = newdiff;
2326 best = face;
2327 if(diff == 0)
2328 break;
2331 face = NULL;
2333 if(!face && best)
2334 face = best;
2335 else if(!face) {
2336 best = NULL;
2337 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2338 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2339 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2340 if(face->scalable)
2341 break;
2342 if(height > 0)
2343 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2344 else
2345 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2346 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2347 (diff < 0 && newdiff > diff)) {
2348 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2349 diff = newdiff;
2350 best = face;
2351 if(diff == 0)
2352 break;
2355 face = NULL;
2357 if(!face && best)
2358 face = best;
2359 if(it && !face->Italic) ret->fake_italic = TRUE;
2360 if(bd && !face->Bold) ret->fake_bold = TRUE;
2363 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2365 if(csi.fs.fsCsb[0]) {
2366 ret->charset = lf.lfCharSet;
2367 ret->codepage = csi.ciACP;
2369 else
2370 ret->charset = get_nearest_charset(face, &ret->codepage);
2372 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2373 debugstr_w(face->StyleName), face->file, face->face_index);
2375 if(!face->scalable) {
2376 width = face->size.x_ppem >> 6;
2377 height = face->size.y_ppem >> 6;
2379 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2381 if (!ret->ft_face)
2383 free_font( ret );
2384 return 0;
2387 if (ret->charset == SYMBOL_CHARSET &&
2388 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2389 /* No ops */
2391 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2392 /* No ops */
2394 else {
2395 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2398 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2399 ret->name = strdupW(family->FamilyName);
2400 ret->underline = lf.lfUnderline ? 0xff : 0;
2401 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2402 create_child_font_list(ret);
2404 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2406 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2407 list_add_head(&gdi_font_list, &ret->entry);
2408 return ret;
2411 static void dump_gdi_font_list(void)
2413 GdiFont gdiFont;
2414 struct list *elem_ptr;
2416 TRACE("---------- gdiFont Cache ----------\n");
2417 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2418 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2419 TRACE("gdiFont=%p %s %ld\n",
2420 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2423 TRACE("---------- Unused gdiFont Cache ----------\n");
2424 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2425 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2426 TRACE("gdiFont=%p %s %ld\n",
2427 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2431 /*************************************************************
2432 * WineEngDestroyFontInstance
2434 * free the gdiFont associated with this handle
2437 BOOL WineEngDestroyFontInstance(HFONT handle)
2439 GdiFont gdiFont;
2440 HFONTLIST *hflist;
2441 BOOL ret = FALSE;
2442 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2443 int i = 0;
2445 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2447 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2448 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2449 if(hflist->hfont == handle)
2451 TRACE("removing child font %p from child list\n", gdiFont);
2452 list_remove(&gdiFont->entry);
2453 return TRUE;
2457 TRACE("destroying hfont=%p\n", handle);
2458 if(TRACE_ON(font))
2459 dump_gdi_font_list();
2461 font_elem_ptr = list_head(&gdi_font_list);
2462 while(font_elem_ptr) {
2463 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2464 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2466 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2467 while(hfontlist_elem_ptr) {
2468 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2469 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2470 if(hflist->hfont == handle) {
2471 list_remove(&hflist->entry);
2472 HeapFree(GetProcessHeap(), 0, hflist);
2473 ret = TRUE;
2476 if(list_empty(&gdiFont->hfontlist)) {
2477 TRACE("Moving to Unused list\n");
2478 list_remove(&gdiFont->entry);
2479 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2484 font_elem_ptr = list_head(&unused_gdi_font_list);
2485 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2486 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2487 while(font_elem_ptr) {
2488 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2489 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2490 TRACE("freeing %p\n", gdiFont);
2491 list_remove(&gdiFont->entry);
2492 free_font(gdiFont);
2494 return ret;
2497 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2498 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2500 OUTLINETEXTMETRICW *potm = NULL;
2501 UINT size;
2502 TEXTMETRICW tm, *ptm;
2503 GdiFont font = alloc_font();
2504 LONG width, height;
2506 if(face->scalable) {
2507 height = 100;
2508 width = 0;
2509 } else {
2510 height = face->size.y_ppem >> 6;
2511 width = face->size.x_ppem >> 6;
2514 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2516 free_font(font);
2517 return;
2520 font->name = strdupW(face->family->FamilyName);
2522 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2524 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2525 if(size) {
2526 potm = HeapAlloc(GetProcessHeap(), 0, size);
2527 WineEngGetOutlineTextMetrics(font, size, potm);
2528 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2529 } else {
2530 WineEngGetTextMetrics(font, &tm);
2531 ptm = &tm;
2534 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2535 pntm->ntmTm.tmAscent = ptm->tmAscent;
2536 pntm->ntmTm.tmDescent = ptm->tmDescent;
2537 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2538 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2539 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2540 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2541 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2542 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2543 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2544 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2545 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2546 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2547 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2548 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2549 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2550 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2551 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2552 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2553 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2554 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2555 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2556 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2557 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2559 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2560 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2561 *ptype |= RASTER_FONTTYPE;
2563 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2564 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2565 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2567 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2568 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2569 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2571 if(potm) {
2572 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2574 lstrcpynW(pelf->elfLogFont.lfFaceName,
2575 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2576 LF_FACESIZE);
2577 lstrcpynW(pelf->elfFullName,
2578 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2579 LF_FULLFACESIZE);
2580 lstrcpynW(pelf->elfStyle,
2581 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2582 LF_FACESIZE);
2584 HeapFree(GetProcessHeap(), 0, potm);
2585 } else {
2586 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2588 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2589 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2590 pelf->elfStyle[0] = '\0';
2593 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2595 free_font(font);
2598 /*************************************************************
2599 * WineEngEnumFonts
2602 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2604 Family *family;
2605 Face *face;
2606 struct list *family_elem_ptr, *face_elem_ptr;
2607 ENUMLOGFONTEXW elf;
2608 NEWTEXTMETRICEXW ntm;
2609 DWORD type, ret = 1;
2610 FONTSIGNATURE fs;
2611 CHARSETINFO csi;
2612 LOGFONTW lf;
2613 int i;
2615 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2617 if(plf->lfFaceName[0]) {
2618 FontSubst *psub;
2619 for(psub = substlist; psub; psub = psub->next)
2620 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2621 (psub->from.charset == -1 ||
2622 psub->from.charset == plf->lfCharSet))
2623 break;
2624 if(psub) {
2625 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2626 debugstr_w(psub->to.name));
2627 memcpy(&lf, plf, sizeof(lf));
2628 strcpyW(lf.lfFaceName, psub->to.name);
2629 plf = &lf;
2632 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2633 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2634 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2635 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2636 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2637 GetEnumStructs(face, &elf, &ntm, &type);
2638 for(i = 0; i < 32; i++) {
2639 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2640 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2641 strcpyW(elf.elfScript, OEM_DOSW);
2642 i = 32; /* break out of loop */
2643 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2644 continue;
2645 else {
2646 fs.fsCsb[0] = 1L << i;
2647 fs.fsCsb[1] = 0;
2648 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2649 TCI_SRCFONTSIG))
2650 csi.ciCharset = DEFAULT_CHARSET;
2651 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2652 if(csi.ciCharset != DEFAULT_CHARSET) {
2653 elf.elfLogFont.lfCharSet =
2654 ntm.ntmTm.tmCharSet = csi.ciCharset;
2655 if(ElfScriptsW[i])
2656 strcpyW(elf.elfScript, ElfScriptsW[i]);
2657 else
2658 FIXME("Unknown elfscript for bit %d\n", i);
2661 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2662 debugstr_w(elf.elfLogFont.lfFaceName),
2663 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2664 csi.ciCharset, type, debugstr_w(elf.elfScript),
2665 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2666 ntm.ntmTm.ntmFlags);
2667 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2668 if(!ret) goto end;
2673 } else {
2674 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2675 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2676 face_elem_ptr = list_head(&family->faces);
2677 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2678 GetEnumStructs(face, &elf, &ntm, &type);
2679 for(i = 0; i < 32; i++) {
2680 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2681 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2682 strcpyW(elf.elfScript, OEM_DOSW);
2683 i = 32; /* break out of loop */
2684 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2685 continue;
2686 else {
2687 fs.fsCsb[0] = 1L << i;
2688 fs.fsCsb[1] = 0;
2689 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2690 TCI_SRCFONTSIG))
2691 csi.ciCharset = DEFAULT_CHARSET;
2692 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2693 if(csi.ciCharset != DEFAULT_CHARSET) {
2694 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2695 csi.ciCharset;
2696 if(ElfScriptsW[i])
2697 strcpyW(elf.elfScript, ElfScriptsW[i]);
2698 else
2699 FIXME("Unknown elfscript for bit %d\n", i);
2702 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2703 debugstr_w(elf.elfLogFont.lfFaceName),
2704 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2705 csi.ciCharset, type, debugstr_w(elf.elfScript),
2706 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2707 ntm.ntmTm.ntmFlags);
2708 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2709 if(!ret) goto end;
2713 end:
2714 return ret;
2717 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2719 pt->x.value = vec->x >> 6;
2720 pt->x.fract = (vec->x & 0x3f) << 10;
2721 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2722 pt->y.value = vec->y >> 6;
2723 pt->y.fract = (vec->y & 0x3f) << 10;
2724 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2725 return;
2728 /***************************************************
2729 * According to the MSDN documentation on WideCharToMultiByte,
2730 * certain codepages cannot set the default_used parameter.
2731 * This returns TRUE if the codepage can set that parameter, false else
2732 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2734 static BOOL codepage_sets_default_used(UINT codepage)
2736 switch (codepage)
2738 case CP_UTF7:
2739 case CP_UTF8:
2740 case CP_SYMBOL:
2741 return FALSE;
2742 default:
2743 return TRUE;
2747 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2749 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2750 WCHAR wc = (WCHAR)glyph;
2751 BOOL default_used;
2752 BOOL *default_used_pointer;
2753 FT_UInt ret;
2754 char buf;
2755 default_used_pointer = NULL;
2756 default_used = FALSE;
2757 if (codepage_sets_default_used(font->codepage))
2758 default_used_pointer = &default_used;
2759 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2760 ret = 0;
2761 else
2762 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2763 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2764 return ret;
2767 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2768 glyph = glyph + 0xf000;
2769 return pFT_Get_Char_Index(font->ft_face, glyph);
2772 /*************************************************************
2773 * WineEngGetGlyphIndices
2775 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2777 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2778 LPWORD pgi, DWORD flags)
2780 INT i;
2782 for(i = 0; i < count; i++)
2783 pgi[i] = get_glyph_index(font, lpstr[i]);
2785 return count;
2788 /*************************************************************
2789 * WineEngGetGlyphOutline
2791 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2792 * except that the first parameter is the HWINEENGFONT of the font in
2793 * question rather than an HDC.
2796 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2797 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2798 const MAT2* lpmat)
2800 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2801 FT_Face ft_face = font->ft_face;
2802 FT_UInt glyph_index;
2803 DWORD width, height, pitch, needed = 0;
2804 FT_Bitmap ft_bitmap;
2805 FT_Error err;
2806 INT left, right, top = 0, bottom = 0;
2807 FT_Angle angle = 0;
2808 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2809 float widthRatio = 1.0;
2810 FT_Matrix transMat = identityMat;
2811 BOOL needsTransform = FALSE;
2814 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2815 buflen, buf, lpmat);
2817 if(format & GGO_GLYPH_INDEX) {
2818 glyph_index = glyph;
2819 format &= ~GGO_GLYPH_INDEX;
2820 } else
2821 glyph_index = get_glyph_index(font, glyph);
2823 if(glyph_index >= font->gmsize) {
2824 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2825 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2826 font->gmsize * sizeof(*font->gm));
2827 } else {
2828 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2829 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2830 return 1; /* FIXME */
2834 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2835 load_flags |= FT_LOAD_NO_BITMAP;
2837 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2839 if(err) {
2840 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2841 return GDI_ERROR;
2844 /* Scaling factor */
2845 if (font->aveWidth && font->potm) {
2846 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2849 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2850 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2852 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2853 font->gm[glyph_index].lsb = left >> 6;
2854 font->gm[glyph_index].bbx = (right - left) >> 6;
2856 /* Scaling transform */
2857 if(font->aveWidth) {
2858 FT_Matrix scaleMat;
2859 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2860 scaleMat.xy = 0;
2861 scaleMat.yx = 0;
2862 scaleMat.yy = (1 << 16);
2864 pFT_Matrix_Multiply(&scaleMat, &transMat);
2865 needsTransform = TRUE;
2868 /* Slant transform */
2869 if (font->fake_italic) {
2870 FT_Matrix slantMat;
2872 slantMat.xx = (1 << 16);
2873 slantMat.xy = ((1 << 16) >> 2);
2874 slantMat.yx = 0;
2875 slantMat.yy = (1 << 16);
2876 pFT_Matrix_Multiply(&slantMat, &transMat);
2877 needsTransform = TRUE;
2880 /* Rotation transform */
2881 if(font->orientation) {
2882 FT_Matrix rotationMat;
2883 FT_Vector vecAngle;
2884 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2885 pFT_Vector_Unit(&vecAngle, angle);
2886 rotationMat.xx = vecAngle.x;
2887 rotationMat.xy = -vecAngle.y;
2888 rotationMat.yx = -rotationMat.xy;
2889 rotationMat.yy = rotationMat.xx;
2891 pFT_Matrix_Multiply(&rotationMat, &transMat);
2892 needsTransform = TRUE;
2895 /* Extra transformation specified by caller */
2896 if (lpmat) {
2897 FT_Matrix extraMat;
2898 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2899 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2900 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2901 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2902 pFT_Matrix_Multiply(&extraMat, &transMat);
2903 needsTransform = TRUE;
2906 if(!needsTransform) {
2907 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2908 bottom = (ft_face->glyph->metrics.horiBearingY -
2909 ft_face->glyph->metrics.height) & -64;
2910 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2911 lpgm->gmCellIncY = 0;
2912 } else {
2913 INT xc, yc;
2914 FT_Vector vec;
2915 for(xc = 0; xc < 2; xc++) {
2916 for(yc = 0; yc < 2; yc++) {
2917 vec.x = (ft_face->glyph->metrics.horiBearingX +
2918 xc * ft_face->glyph->metrics.width);
2919 vec.y = ft_face->glyph->metrics.horiBearingY -
2920 yc * ft_face->glyph->metrics.height;
2921 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2922 pFT_Vector_Transform(&vec, &transMat);
2923 if(xc == 0 && yc == 0) {
2924 left = right = vec.x;
2925 top = bottom = vec.y;
2926 } else {
2927 if(vec.x < left) left = vec.x;
2928 else if(vec.x > right) right = vec.x;
2929 if(vec.y < bottom) bottom = vec.y;
2930 else if(vec.y > top) top = vec.y;
2934 left = left & -64;
2935 right = (right + 63) & -64;
2936 bottom = bottom & -64;
2937 top = (top + 63) & -64;
2939 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2940 vec.x = ft_face->glyph->metrics.horiAdvance;
2941 vec.y = 0;
2942 pFT_Vector_Transform(&vec, &transMat);
2943 lpgm->gmCellIncX = (vec.x+63) >> 6;
2944 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2946 lpgm->gmBlackBoxX = (right - left) >> 6;
2947 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2948 lpgm->gmptGlyphOrigin.x = left >> 6;
2949 lpgm->gmptGlyphOrigin.y = top >> 6;
2951 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2952 font->gm[glyph_index].init = TRUE;
2954 if(format == GGO_METRICS)
2955 return 1; /* FIXME */
2957 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2958 TRACE("loaded a bitmap\n");
2959 return GDI_ERROR;
2962 switch(format) {
2963 case GGO_BITMAP:
2964 width = lpgm->gmBlackBoxX;
2965 height = lpgm->gmBlackBoxY;
2966 pitch = ((width + 31) >> 5) << 2;
2967 needed = pitch * height;
2969 if(!buf || !buflen) break;
2971 switch(ft_face->glyph->format) {
2972 case ft_glyph_format_bitmap:
2974 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2975 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2976 INT h = ft_face->glyph->bitmap.rows;
2977 while(h--) {
2978 memcpy(dst, src, w);
2979 src += ft_face->glyph->bitmap.pitch;
2980 dst += pitch;
2982 break;
2985 case ft_glyph_format_outline:
2986 ft_bitmap.width = width;
2987 ft_bitmap.rows = height;
2988 ft_bitmap.pitch = pitch;
2989 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2990 ft_bitmap.buffer = buf;
2992 if(needsTransform) {
2993 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2996 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2998 /* Note: FreeType will only set 'black' bits for us. */
2999 memset(buf, 0, needed);
3000 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3001 break;
3003 default:
3004 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3005 return GDI_ERROR;
3007 break;
3009 case GGO_GRAY2_BITMAP:
3010 case GGO_GRAY4_BITMAP:
3011 case GGO_GRAY8_BITMAP:
3012 case WINE_GGO_GRAY16_BITMAP:
3014 unsigned int mult, row, col;
3015 BYTE *start, *ptr;
3017 width = lpgm->gmBlackBoxX;
3018 height = lpgm->gmBlackBoxY;
3019 pitch = (width + 3) / 4 * 4;
3020 needed = pitch * height;
3022 if(!buf || !buflen) break;
3023 ft_bitmap.width = width;
3024 ft_bitmap.rows = height;
3025 ft_bitmap.pitch = pitch;
3026 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3027 ft_bitmap.buffer = buf;
3029 if(needsTransform) {
3030 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3033 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3035 memset(ft_bitmap.buffer, 0, buflen);
3037 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3039 if(format == GGO_GRAY2_BITMAP)
3040 mult = 4;
3041 else if(format == GGO_GRAY4_BITMAP)
3042 mult = 16;
3043 else if(format == GGO_GRAY8_BITMAP)
3044 mult = 64;
3045 else if(format == WINE_GGO_GRAY16_BITMAP)
3046 break;
3047 else {
3048 assert(0);
3049 break;
3052 start = buf;
3053 for(row = 0; row < height; row++) {
3054 ptr = start;
3055 for(col = 0; col < width; col++, ptr++) {
3056 *ptr = (((int)*ptr) * mult + 128) / 256;
3058 start += pitch;
3060 break;
3063 case GGO_NATIVE:
3065 int contour, point = 0, first_pt;
3066 FT_Outline *outline = &ft_face->glyph->outline;
3067 TTPOLYGONHEADER *pph;
3068 TTPOLYCURVE *ppc;
3069 DWORD pph_start, cpfx, type;
3071 if(buflen == 0) buf = NULL;
3073 if (needsTransform && buf) {
3074 pFT_Outline_Transform(outline, &transMat);
3077 for(contour = 0; contour < outline->n_contours; contour++) {
3078 pph_start = needed;
3079 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3080 first_pt = point;
3081 if(buf) {
3082 pph->dwType = TT_POLYGON_TYPE;
3083 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3085 needed += sizeof(*pph);
3086 point++;
3087 while(point <= outline->contours[contour]) {
3088 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3089 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3090 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3091 cpfx = 0;
3092 do {
3093 if(buf)
3094 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3095 cpfx++;
3096 point++;
3097 } while(point <= outline->contours[contour] &&
3098 (outline->tags[point] & FT_Curve_Tag_On) ==
3099 (outline->tags[point-1] & FT_Curve_Tag_On));
3100 /* At the end of a contour Windows adds the start point, but
3101 only for Beziers */
3102 if(point > outline->contours[contour] &&
3103 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3104 if(buf)
3105 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3106 cpfx++;
3107 } else if(point <= outline->contours[contour] &&
3108 outline->tags[point] & FT_Curve_Tag_On) {
3109 /* add closing pt for bezier */
3110 if(buf)
3111 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3112 cpfx++;
3113 point++;
3115 if(buf) {
3116 ppc->wType = type;
3117 ppc->cpfx = cpfx;
3119 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3121 if(buf)
3122 pph->cb = needed - pph_start;
3124 break;
3126 case GGO_BEZIER:
3128 /* Convert the quadratic Beziers to cubic Beziers.
3129 The parametric eqn for a cubic Bezier is, from PLRM:
3130 r(t) = at^3 + bt^2 + ct + r0
3131 with the control points:
3132 r1 = r0 + c/3
3133 r2 = r1 + (c + b)/3
3134 r3 = r0 + c + b + a
3136 A quadratic Beizer has the form:
3137 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3139 So equating powers of t leads to:
3140 r1 = 2/3 p1 + 1/3 p0
3141 r2 = 2/3 p1 + 1/3 p2
3142 and of course r0 = p0, r3 = p2
3145 int contour, point = 0, first_pt;
3146 FT_Outline *outline = &ft_face->glyph->outline;
3147 TTPOLYGONHEADER *pph;
3148 TTPOLYCURVE *ppc;
3149 DWORD pph_start, cpfx, type;
3150 FT_Vector cubic_control[4];
3151 if(buflen == 0) buf = NULL;
3153 if (needsTransform && buf) {
3154 pFT_Outline_Transform(outline, &transMat);
3157 for(contour = 0; contour < outline->n_contours; contour++) {
3158 pph_start = needed;
3159 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3160 first_pt = point;
3161 if(buf) {
3162 pph->dwType = TT_POLYGON_TYPE;
3163 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3165 needed += sizeof(*pph);
3166 point++;
3167 while(point <= outline->contours[contour]) {
3168 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3169 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3170 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3171 cpfx = 0;
3172 do {
3173 if(type == TT_PRIM_LINE) {
3174 if(buf)
3175 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3176 cpfx++;
3177 point++;
3178 } else {
3179 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3180 so cpfx = 3n */
3182 /* FIXME: Possible optimization in endpoint calculation
3183 if there are two consecutive curves */
3184 cubic_control[0] = outline->points[point-1];
3185 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3186 cubic_control[0].x += outline->points[point].x + 1;
3187 cubic_control[0].y += outline->points[point].y + 1;
3188 cubic_control[0].x >>= 1;
3189 cubic_control[0].y >>= 1;
3191 if(point+1 > outline->contours[contour])
3192 cubic_control[3] = outline->points[first_pt];
3193 else {
3194 cubic_control[3] = outline->points[point+1];
3195 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3196 cubic_control[3].x += outline->points[point].x + 1;
3197 cubic_control[3].y += outline->points[point].y + 1;
3198 cubic_control[3].x >>= 1;
3199 cubic_control[3].y >>= 1;
3202 /* r1 = 1/3 p0 + 2/3 p1
3203 r2 = 1/3 p2 + 2/3 p1 */
3204 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3205 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3206 cubic_control[2] = cubic_control[1];
3207 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3208 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3209 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3210 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3211 if(buf) {
3212 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3213 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3214 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3216 cpfx += 3;
3217 point++;
3219 } while(point <= outline->contours[contour] &&
3220 (outline->tags[point] & FT_Curve_Tag_On) ==
3221 (outline->tags[point-1] & FT_Curve_Tag_On));
3222 /* At the end of a contour Windows adds the start point,
3223 but only for Beziers and we've already done that.
3225 if(point <= outline->contours[contour] &&
3226 outline->tags[point] & FT_Curve_Tag_On) {
3227 /* This is the closing pt of a bezier, but we've already
3228 added it, so just inc point and carry on */
3229 point++;
3231 if(buf) {
3232 ppc->wType = type;
3233 ppc->cpfx = cpfx;
3235 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3237 if(buf)
3238 pph->cb = needed - pph_start;
3240 break;
3243 default:
3244 FIXME("Unsupported format %d\n", format);
3245 return GDI_ERROR;
3247 return needed;
3250 static BOOL get_bitmap_text_metrics(GdiFont font)
3252 FT_Face ft_face = font->ft_face;
3253 #ifdef HAVE_FREETYPE_FTWINFNT_H
3254 FT_WinFNT_HeaderRec winfnt_header;
3255 #endif
3256 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3257 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3258 font->potm->otmSize = size;
3260 #define TM font->potm->otmTextMetrics
3261 #ifdef HAVE_FREETYPE_FTWINFNT_H
3262 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3264 TM.tmHeight = winfnt_header.pixel_height;
3265 TM.tmAscent = winfnt_header.ascent;
3266 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3267 TM.tmInternalLeading = winfnt_header.internal_leading;
3268 TM.tmExternalLeading = winfnt_header.external_leading;
3269 TM.tmAveCharWidth = winfnt_header.avg_width;
3270 TM.tmMaxCharWidth = winfnt_header.max_width;
3271 TM.tmWeight = winfnt_header.weight;
3272 TM.tmOverhang = 0;
3273 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3274 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3275 TM.tmFirstChar = winfnt_header.first_char;
3276 TM.tmLastChar = winfnt_header.last_char;
3277 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3278 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3279 TM.tmItalic = winfnt_header.italic;
3280 TM.tmUnderlined = font->underline;
3281 TM.tmStruckOut = font->strikeout;
3282 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3283 TM.tmCharSet = winfnt_header.charset;
3285 else
3286 #endif
3288 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3289 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3290 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3291 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3292 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3293 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3294 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3295 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3296 TM.tmOverhang = 0;
3297 TM.tmDigitizedAspectX = 96; /* FIXME */
3298 TM.tmDigitizedAspectY = 96; /* FIXME */
3299 TM.tmFirstChar = 1;
3300 TM.tmLastChar = 255;
3301 TM.tmDefaultChar = 32;
3302 TM.tmBreakChar = 32;
3303 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3304 TM.tmUnderlined = font->underline;
3305 TM.tmStruckOut = font->strikeout;
3306 /* NB inverted meaning of TMPF_FIXED_PITCH */
3307 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3308 TM.tmCharSet = font->charset;
3310 #undef TM
3312 return TRUE;
3315 /*************************************************************
3316 * WineEngGetTextMetrics
3319 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3321 if(!font->potm) {
3322 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3323 if(!get_bitmap_text_metrics(font))
3324 return FALSE;
3326 if(!font->potm) return FALSE;
3327 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3329 if (font->aveWidth) {
3330 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3332 return TRUE;
3336 /*************************************************************
3337 * WineEngGetOutlineTextMetrics
3340 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3341 OUTLINETEXTMETRICW *potm)
3343 FT_Face ft_face = font->ft_face;
3344 UINT needed, lenfam, lensty, ret;
3345 TT_OS2 *pOS2;
3346 TT_HoriHeader *pHori;
3347 TT_Postscript *pPost;
3348 FT_Fixed x_scale, y_scale;
3349 WCHAR *family_nameW, *style_nameW;
3350 static const WCHAR spaceW[] = {' ', '\0'};
3351 char *cp;
3352 INT ascent, descent;
3354 TRACE("font=%p\n", font);
3356 if(!FT_IS_SCALABLE(ft_face))
3357 return 0;
3359 if(font->potm) {
3360 if(cbSize >= font->potm->otmSize)
3361 memcpy(potm, font->potm, font->potm->otmSize);
3362 return font->potm->otmSize;
3366 needed = sizeof(*potm);
3368 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3369 family_nameW = strdupW(font->name);
3371 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3372 * sizeof(WCHAR);
3373 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3374 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3375 style_nameW, lensty/sizeof(WCHAR));
3377 /* These names should be read from the TT name table */
3379 /* length of otmpFamilyName */
3380 needed += lenfam;
3382 /* length of otmpFaceName */
3383 if(!strcasecmp(ft_face->style_name, "regular")) {
3384 needed += lenfam; /* just the family name */
3385 } else {
3386 needed += lenfam + lensty; /* family + " " + style */
3389 /* length of otmpStyleName */
3390 needed += lensty;
3392 /* length of otmpFullName */
3393 needed += lenfam + lensty;
3396 x_scale = ft_face->size->metrics.x_scale;
3397 y_scale = ft_face->size->metrics.y_scale;
3399 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3400 if(!pOS2) {
3401 FIXME("Can't find OS/2 table - not TT font?\n");
3402 ret = 0;
3403 goto end;
3406 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3407 if(!pHori) {
3408 FIXME("Can't find HHEA table - not TT font?\n");
3409 ret = 0;
3410 goto end;
3413 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3415 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",
3416 pOS2->usWinAscent, pOS2->usWinDescent,
3417 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3418 ft_face->ascender, ft_face->descender, ft_face->height,
3419 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3420 ft_face->bbox.yMax, ft_face->bbox.yMin);
3422 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3423 font->potm->otmSize = needed;
3425 #define TM font->potm->otmTextMetrics
3427 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3428 ascent = pHori->Ascender;
3429 descent = -pHori->Descender;
3430 } else {
3431 ascent = pOS2->usWinAscent;
3432 descent = pOS2->usWinDescent;
3435 if(font->yMax) {
3436 TM.tmAscent = font->yMax;
3437 TM.tmDescent = -font->yMin;
3438 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3439 } else {
3440 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3441 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3442 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3443 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3446 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3448 /* MSDN says:
3449 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3451 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3452 ((ascent + descent) -
3453 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3455 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3456 if (TM.tmAveCharWidth == 0) {
3457 TM.tmAveCharWidth = 1;
3459 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3460 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3461 TM.tmOverhang = 0;
3462 TM.tmDigitizedAspectX = 300;
3463 TM.tmDigitizedAspectY = 300;
3464 TM.tmFirstChar = pOS2->usFirstCharIndex;
3465 TM.tmLastChar = pOS2->usLastCharIndex;
3466 TM.tmDefaultChar = pOS2->usDefaultChar;
3467 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3468 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3469 TM.tmUnderlined = font->underline;
3470 TM.tmStruckOut = font->strikeout;
3472 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3473 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3474 (pOS2->version == 0xFFFFU ||
3475 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3476 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3477 else
3478 TM.tmPitchAndFamily = 0;
3480 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3481 case PAN_FAMILY_SCRIPT:
3482 TM.tmPitchAndFamily |= FF_SCRIPT;
3483 break;
3484 case PAN_FAMILY_DECORATIVE:
3485 case PAN_FAMILY_PICTORIAL:
3486 TM.tmPitchAndFamily |= FF_DECORATIVE;
3487 break;
3488 case PAN_FAMILY_TEXT_DISPLAY:
3489 if(TM.tmPitchAndFamily == 0) /* fixed */
3490 TM.tmPitchAndFamily = FF_MODERN;
3491 else {
3492 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3493 case PAN_SERIF_NORMAL_SANS:
3494 case PAN_SERIF_OBTUSE_SANS:
3495 case PAN_SERIF_PERP_SANS:
3496 TM.tmPitchAndFamily |= FF_SWISS;
3497 break;
3498 default:
3499 TM.tmPitchAndFamily |= FF_ROMAN;
3502 break;
3503 default:
3504 TM.tmPitchAndFamily |= FF_DONTCARE;
3507 if(FT_IS_SCALABLE(ft_face))
3508 TM.tmPitchAndFamily |= TMPF_VECTOR;
3509 if(FT_IS_SFNT(ft_face))
3510 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3512 TM.tmCharSet = font->charset;
3513 #undef TM
3515 font->potm->otmFiller = 0;
3516 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3517 font->potm->otmfsSelection = pOS2->fsSelection;
3518 font->potm->otmfsType = pOS2->fsType;
3519 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3520 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3521 font->potm->otmItalicAngle = 0; /* POST table */
3522 font->potm->otmEMSquare = ft_face->units_per_EM;
3523 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3524 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3525 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3526 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3527 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3528 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3529 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3530 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3531 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3532 font->potm->otmMacAscent = 0; /* where do these come from ? */
3533 font->potm->otmMacDescent = 0;
3534 font->potm->otmMacLineGap = 0;
3535 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3536 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3537 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3538 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3539 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3540 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3541 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3542 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3543 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3544 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3545 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3546 if(!pPost) {
3547 font->potm->otmsUnderscoreSize = 0;
3548 font->potm->otmsUnderscorePosition = 0;
3549 } else {
3550 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3551 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3554 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3555 cp = (char*)font->potm + sizeof(*font->potm);
3556 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3557 strcpyW((WCHAR*)cp, family_nameW);
3558 cp += lenfam;
3559 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3560 strcpyW((WCHAR*)cp, style_nameW);
3561 cp += lensty;
3562 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3563 strcpyW((WCHAR*)cp, family_nameW);
3564 if(strcasecmp(ft_face->style_name, "regular")) {
3565 strcatW((WCHAR*)cp, spaceW);
3566 strcatW((WCHAR*)cp, style_nameW);
3567 cp += lenfam + lensty;
3568 } else
3569 cp += lenfam;
3570 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3571 strcpyW((WCHAR*)cp, family_nameW);
3572 strcatW((WCHAR*)cp, spaceW);
3573 strcatW((WCHAR*)cp, style_nameW);
3574 ret = needed;
3576 if(potm && needed <= cbSize)
3577 memcpy(potm, font->potm, font->potm->otmSize);
3579 end:
3580 HeapFree(GetProcessHeap(), 0, style_nameW);
3581 HeapFree(GetProcessHeap(), 0, family_nameW);
3583 return ret;
3586 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3588 HFONTLIST *hfontlist;
3589 child->font = alloc_font();
3590 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3591 if(!child->font->ft_face)
3593 free_font(child->font);
3594 child->font = NULL;
3595 return FALSE;
3598 child->font->orientation = font->orientation;
3599 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3600 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3601 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3602 child->font->base_font = font;
3603 list_add_head(&child_font_list, &child->font->entry);
3604 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3605 return TRUE;
3608 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3610 FT_UInt g;
3611 CHILD_FONT *child_font;
3613 if(font->base_font)
3614 font = font->base_font;
3616 *linked_font = font;
3618 if((*glyph = get_glyph_index(font, c)))
3619 return TRUE;
3621 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3623 if(!child_font->font)
3624 if(!load_child_font(font, child_font))
3625 continue;
3627 if(!child_font->font->ft_face)
3628 continue;
3629 g = get_glyph_index(child_font->font, c);
3630 if(g)
3632 *glyph = g;
3633 *linked_font = child_font->font;
3634 return TRUE;
3637 return FALSE;
3640 /*************************************************************
3641 * WineEngGetCharWidth
3644 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3645 LPINT buffer)
3647 UINT c;
3648 GLYPHMETRICS gm;
3649 FT_UInt glyph_index;
3650 GdiFont linked_font;
3652 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3654 for(c = firstChar; c <= lastChar; c++) {
3655 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3656 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3657 &gm, 0, NULL, NULL);
3658 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3660 return TRUE;
3663 /*************************************************************
3664 * WineEngGetCharABCWidths
3667 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3668 LPABC buffer)
3670 UINT c;
3671 GLYPHMETRICS gm;
3672 FT_UInt glyph_index;
3673 GdiFont linked_font;
3675 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3677 if(!FT_IS_SCALABLE(font->ft_face))
3678 return FALSE;
3680 for(c = firstChar; c <= lastChar; c++) {
3681 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3682 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3683 &gm, 0, NULL, NULL);
3684 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3685 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3686 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3687 linked_font->gm[glyph_index].bbx;
3689 return TRUE;
3692 /*************************************************************
3693 * WineEngGetTextExtentPoint
3696 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3697 LPSIZE size)
3699 INT idx;
3700 GLYPHMETRICS gm;
3701 TEXTMETRICW tm;
3702 FT_UInt glyph_index;
3703 GdiFont linked_font;
3705 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3706 size);
3708 size->cx = 0;
3709 WineEngGetTextMetrics(font, &tm);
3710 size->cy = tm.tmHeight;
3712 for(idx = 0; idx < count; idx++) {
3713 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3714 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3715 &gm, 0, NULL, NULL);
3716 size->cx += linked_font->gm[glyph_index].adv;
3718 TRACE("return %ld,%ld\n", size->cx, size->cy);
3719 return TRUE;
3722 /*************************************************************
3723 * WineEngGetTextExtentPointI
3726 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3727 LPSIZE size)
3729 INT idx;
3730 GLYPHMETRICS gm;
3731 TEXTMETRICW tm;
3733 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3735 size->cx = 0;
3736 WineEngGetTextMetrics(font, &tm);
3737 size->cy = tm.tmHeight;
3739 for(idx = 0; idx < count; idx++) {
3740 WineEngGetGlyphOutline(font, indices[idx],
3741 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3742 NULL);
3743 size->cx += font->gm[indices[idx]].adv;
3745 TRACE("return %ld,%ld\n", size->cx, size->cy);
3746 return TRUE;
3749 /*************************************************************
3750 * WineEngGetFontData
3753 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3754 DWORD cbData)
3756 FT_Face ft_face = font->ft_face;
3757 DWORD len;
3758 FT_Error err;
3760 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3761 font, table, offset, buf, cbData);
3763 if(!FT_IS_SFNT(ft_face))
3764 return GDI_ERROR;
3766 if(!buf || !cbData)
3767 len = 0;
3768 else
3769 len = cbData;
3771 if(table) { /* MS tags differ in endidness from FT ones */
3772 table = table >> 24 | table << 24 |
3773 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3776 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3777 if(pFT_Load_Sfnt_Table) {
3778 /* make sure value of len is the value freetype says it needs */
3779 if( buf && len) {
3780 DWORD needed = 0;
3781 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3782 if( !err && needed < len) len = needed;
3784 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3786 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3787 else { /* Do it the hard way */
3788 TT_Face tt_face = (TT_Face) ft_face;
3789 SFNT_Interface *sfnt;
3790 if (FT_Version.major==2 && FT_Version.minor==0)
3792 /* 2.0.x */
3793 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3795 else
3797 /* A field was added in the middle of the structure in 2.1.x */
3798 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3800 /* make sure value of len is the value freetype says it needs */
3801 if( buf && len) {
3802 DWORD needed = 0;
3803 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3804 if( !err && needed < len) len = needed;
3806 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3808 #else
3809 else {
3810 static int msg;
3811 if(!msg) {
3812 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3813 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3814 "Please upgrade your freetype library.\n");
3815 msg++;
3817 err = FT_Err_Unimplemented_Feature;
3819 #endif
3820 if(err) {
3821 TRACE("Can't find table %08lx.\n", table);
3822 return GDI_ERROR;
3824 return len;
3827 /*************************************************************
3828 * WineEngGetTextFace
3831 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3833 if(str) {
3834 lstrcpynW(str, font->name, count);
3835 return strlenW(font->name);
3836 } else
3837 return strlenW(font->name) + 1;
3840 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3842 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3843 return font->charset;
3846 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3848 GdiFont font = dc->gdiFont, linked_font;
3849 struct list *first_hfont;
3850 BOOL ret;
3852 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3853 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3854 if(font == linked_font)
3855 *new_hfont = dc->hFont;
3856 else
3858 first_hfont = list_head(&linked_font->hfontlist);
3859 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3862 return ret;
3866 /*************************************************************
3867 * FontIsLinked
3869 BOOL WINAPI FontIsLinked(HDC hdc)
3871 DC *dc = DC_GetDCPtr(hdc);
3872 BOOL ret = FALSE;
3874 if(!dc) return FALSE;
3875 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3876 ret = TRUE;
3877 GDI_ReleaseObj(hdc);
3878 TRACE("returning %d\n", ret);
3879 return ret;
3882 static BOOL is_hinting_enabled(void)
3884 FT_Module mod;
3886 /* Use the >= 2.2.0 function if available */
3887 if(pFT_Get_TrueType_Engine_Type)
3889 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
3890 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
3893 /* otherwise if we've been compiled with < 2.2.0 headers
3894 use the internal macro */
3895 #ifdef FT_DRIVER_HAS_HINTER
3896 mod = pFT_Get_Module(library, "truetype");
3897 if(mod && FT_DRIVER_HAS_HINTER(mod))
3898 return TRUE;
3899 #endif
3901 return FALSE;
3904 /*************************************************************************
3905 * GetRasterizerCaps (GDI32.@)
3907 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3909 static int hinting = -1;
3911 if(hinting == -1)
3912 hinting = is_hinting_enabled();
3914 lprs->nSize = sizeof(RASTERIZER_STATUS);
3915 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
3916 lprs->nLanguageID = 0;
3917 return TRUE;
3921 #else /* HAVE_FREETYPE */
3923 BOOL WineEngInit(void)
3925 return FALSE;
3927 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3929 return NULL;
3931 BOOL WineEngDestroyFontInstance(HFONT hfont)
3933 return FALSE;
3936 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3938 return 1;
3941 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3942 LPWORD pgi, DWORD flags)
3944 return GDI_ERROR;
3947 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3948 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3949 const MAT2* lpmat)
3951 ERR("called but we don't have FreeType\n");
3952 return GDI_ERROR;
3955 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3957 ERR("called but we don't have FreeType\n");
3958 return FALSE;
3961 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3962 OUTLINETEXTMETRICW *potm)
3964 ERR("called but we don't have FreeType\n");
3965 return 0;
3968 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3969 LPINT buffer)
3971 ERR("called but we don't have FreeType\n");
3972 return FALSE;
3975 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3976 LPABC buffer)
3978 ERR("called but we don't have FreeType\n");
3979 return FALSE;
3982 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3983 LPSIZE size)
3985 ERR("called but we don't have FreeType\n");
3986 return FALSE;
3989 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3990 LPSIZE size)
3992 ERR("called but we don't have FreeType\n");
3993 return FALSE;
3996 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3997 DWORD cbData)
3999 ERR("called but we don't have FreeType\n");
4000 return GDI_ERROR;
4003 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4005 ERR("called but we don't have FreeType\n");
4006 return 0;
4009 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4011 FIXME(":stub\n");
4012 return 1;
4015 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4017 FIXME(":stub\n");
4018 return TRUE;
4021 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4023 FIXME(":stub\n");
4024 return DEFAULT_CHARSET;
4027 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4029 return FALSE;
4032 BOOL WINAPI FontIsLinked(HDC hdc)
4034 return FALSE;
4037 /*************************************************************************
4038 * GetRasterizerCaps (GDI32.@)
4040 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4042 lprs->nSize = sizeof(RASTERIZER_STATUS);
4043 lprs->wFlags = 0;
4044 lprs->nLanguageID = 0;
4045 return TRUE;
4048 #endif /* HAVE_FREETYPE */