crypt32: Decode cleanups.
[wine.git] / dlls / gdi / freetype.c
blobaff355d1ade2a25ac85ee8b9290ffa9819d9c469
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
86 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
88 #endif
90 static FT_Library library = 0;
91 typedef struct
93 FT_Int major;
94 FT_Int minor;
95 FT_Int patch;
96 } FT_Version_t;
97 static FT_Version_t FT_Version;
98 static DWORD FT_SimpleVersion;
100 static void *ft_handle = NULL;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
103 MAKE_FUNCPTR(FT_Vector_Unit);
104 MAKE_FUNCPTR(FT_Done_Face);
105 MAKE_FUNCPTR(FT_Get_Char_Index);
106 MAKE_FUNCPTR(FT_Get_Module);
107 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
108 MAKE_FUNCPTR(FT_Init_FreeType);
109 MAKE_FUNCPTR(FT_Load_Glyph);
110 MAKE_FUNCPTR(FT_Matrix_Multiply);
111 MAKE_FUNCPTR(FT_MulFix);
112 MAKE_FUNCPTR(FT_New_Face);
113 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
114 MAKE_FUNCPTR(FT_Outline_Transform);
115 MAKE_FUNCPTR(FT_Outline_Translate);
116 MAKE_FUNCPTR(FT_Select_Charmap);
117 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
118 MAKE_FUNCPTR(FT_Vector_Transform);
119 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
120 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
121 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
122 #ifdef HAVE_FREETYPE_FTWINFNT_H
123 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
124 #endif
126 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
127 #include <fontconfig/fontconfig.h>
128 MAKE_FUNCPTR(FcConfigGetCurrent);
129 MAKE_FUNCPTR(FcFontList);
130 MAKE_FUNCPTR(FcFontSetDestroy);
131 MAKE_FUNCPTR(FcInit);
132 MAKE_FUNCPTR(FcObjectSetAdd);
133 MAKE_FUNCPTR(FcObjectSetCreate);
134 MAKE_FUNCPTR(FcObjectSetDestroy);
135 MAKE_FUNCPTR(FcPatternCreate);
136 MAKE_FUNCPTR(FcPatternDestroy);
137 MAKE_FUNCPTR(FcPatternGet);
138 #ifndef SONAME_LIBFONTCONFIG
139 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
140 #endif
141 #endif
143 #undef MAKE_FUNCPTR
145 #ifndef ft_encoding_none
146 #define FT_ENCODING_NONE ft_encoding_none
147 #endif
148 #ifndef ft_encoding_ms_symbol
149 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
150 #endif
151 #ifndef ft_encoding_unicode
152 #define FT_ENCODING_UNICODE ft_encoding_unicode
153 #endif
154 #ifndef ft_encoding_apple_roman
155 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
156 #endif
158 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
160 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
161 typedef struct {
162 FT_Short height;
163 FT_Short width;
164 FT_Pos size;
165 FT_Pos x_ppem;
166 FT_Pos y_ppem;
167 FT_Short internal_leading;
168 } Bitmap_Size;
170 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
171 So to let this compile on older versions of FreeType we'll define the
172 new structure here. */
173 typedef struct {
174 FT_Short height, width;
175 FT_Pos size, x_ppem, y_ppem;
176 } My_FT_Bitmap_Size;
178 typedef struct tagFace {
179 struct list entry;
180 WCHAR *StyleName;
181 char *file;
182 FT_Long face_index;
183 BOOL Italic;
184 BOOL Bold;
185 FONTSIGNATURE fs;
186 FONTSIGNATURE fs_links;
187 FT_Fixed font_version;
188 BOOL scalable;
189 Bitmap_Size size; /* set if face is a bitmap */
190 BOOL external; /* TRUE if we should manually add this font to the registry */
191 struct tagFamily *family;
192 } Face;
194 typedef struct tagFamily {
195 struct list entry;
196 WCHAR *FamilyName;
197 struct list faces;
198 } Family;
200 typedef struct {
201 GLYPHMETRICS gm;
202 INT adv; /* These three hold to widths of the unrotated chars */
203 INT lsb;
204 INT bbx;
205 BOOL init;
206 } GM;
208 typedef struct {
209 FLOAT eM11, eM12;
210 FLOAT eM21, eM22;
211 } FMAT2;
213 typedef struct {
214 DWORD hash;
215 LOGFONTW lf;
216 FMAT2 matrix;
217 } FONT_DESC;
219 typedef struct tagHFONTLIST {
220 struct list entry;
221 HFONT hfont;
222 } HFONTLIST;
224 typedef struct {
225 struct list entry;
226 char *file_name;
227 INT index;
228 GdiFont font;
229 } CHILD_FONT;
231 struct tagGdiFont {
232 struct list entry;
233 FT_Face ft_face;
234 LPWSTR name;
235 int charset;
236 int codepage;
237 BOOL fake_italic;
238 BOOL fake_bold;
239 BYTE underline;
240 BYTE strikeout;
241 INT orientation;
242 GM *gm;
243 DWORD gmsize;
244 struct list hfontlist;
245 FONT_DESC font_desc;
246 LONG aveWidth;
247 SHORT yMax;
248 SHORT yMin;
249 OUTLINETEXTMETRICW *potm;
250 FONTSIGNATURE fs;
251 GdiFont base_font;
252 struct list child_fonts;
253 LONG ppem;
256 typedef struct {
257 struct list entry;
258 WCHAR *font_name;
259 struct list links;
260 } SYSTEM_LINKS;
262 #define INIT_GM_SIZE 128
264 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
265 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
266 #define UNUSED_CACHE_SIZE 10
267 static struct list child_font_list = LIST_INIT(child_font_list);
268 static struct list system_links = LIST_INIT(system_links);
270 static struct list font_list = LIST_INIT(font_list);
272 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
273 'R','o','m','a','n','\0'};
274 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
275 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
277 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
278 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
279 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
280 'S','e','r','i','f','\0'};
281 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
282 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
284 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
285 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
286 'W','i','n','d','o','w','s','\\',
287 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
288 'F','o','n','t','s','\0'};
290 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
291 'W','i','n','d','o','w','s',' ','N','T','\\',
292 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
293 'F','o','n','t','s','\0'};
295 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
296 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
297 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
298 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
300 static const WCHAR *SystemFontValues[4] = {
301 System_Value,
302 OEMFont_Value,
303 FixedSys_Value,
304 NULL
307 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
308 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
310 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
311 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
312 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
313 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
314 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
315 'E','u','r','o','p','e','a','n','\0'};
316 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
317 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
318 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
319 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
320 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
321 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
322 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
323 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
324 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
325 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
326 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
327 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
329 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
330 WesternW, /*00*/
331 Central_EuropeanW,
332 CyrillicW,
333 GreekW,
334 TurkishW,
335 HebrewW,
336 ArabicW,
337 BalticW,
338 VietnameseW, /*08*/
339 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
340 ThaiW,
341 JapaneseW,
342 CHINESE_GB2312W,
343 HangulW,
344 CHINESE_BIG5W,
345 Hangul_Johab_W,
346 NULL, NULL, /*23*/
347 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
348 SymbolW /*31*/
351 typedef struct {
352 WCHAR *name;
353 INT charset;
354 } NameCs;
356 typedef struct tagFontSubst {
357 NameCs from;
358 NameCs to;
359 struct tagFontSubst *next;
360 } FontSubst;
362 static FontSubst *substlist = NULL;
363 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
365 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
368 /****************************************
369 * Notes on .fon files
371 * The fonts System, FixedSys and Terminal are special. There are typically multiple
372 * versions installed for different resolutions and codepages. Windows stores which one to use
373 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
374 * Key Meaning
375 * FIXEDFON.FON FixedSys
376 * FONTS.FON System
377 * OEMFONT.FON Terminal
378 * LogPixels Current dpi set by the display control panel applet
379 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
380 * also has a LogPixels value that appears to mirror this)
382 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
383 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
384 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
385 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
386 * so that makes sense.
388 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
389 * to be mapped into the registry on Windows 2000 at least).
390 * I have
391 * woafont=app850.fon
392 * ega80woa.fon=ega80850.fon
393 * ega40woa.fon=ega40850.fon
394 * cga80woa.fon=cga80850.fon
395 * cga40woa.fon=cga40850.fon
399 static inline BOOL is_win9x(void)
401 return GetVersion() & 0x80000000;
404 This function builds an FT_Fixed from a float. It puts the integer part
405 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
406 It fails if the integer part of the float number is greater than SHORT_MAX.
408 static inline FT_Fixed FT_FixedFromFloat(float f)
410 short value = f;
411 unsigned short fract = (f - value) * 0xFFFF;
412 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
416 This function builds an FT_Fixed from a FIXED. It simply put f.value
417 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
419 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
421 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
424 #define ADDFONT_EXTERNAL_FONT 0x01
425 #define ADDFONT_FORCE_BITMAP 0x02
426 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
428 FT_Face ft_face;
429 TT_OS2 *pOS2;
430 TT_Header *pHeader = NULL;
431 WCHAR *FamilyW, *StyleW;
432 DWORD len;
433 Family *family;
434 Face *face;
435 struct list *family_elem_ptr, *face_elem_ptr;
436 FT_Error err;
437 FT_Long face_index = 0, num_faces;
438 #ifdef HAVE_FREETYPE_FTWINFNT_H
439 FT_WinFNT_HeaderRec winfnt_header;
440 #endif
441 int i, bitmap_num, internal_leading;
442 FONTSIGNATURE fs;
444 do {
445 char *family_name = fake_family;
447 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
448 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
449 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
450 return FALSE;
453 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*/
454 WARN("Ignoring font %s\n", debugstr_a(file));
455 pFT_Done_Face(ft_face);
456 return FALSE;
459 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
460 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
461 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
462 pFT_Done_Face(ft_face);
463 return FALSE;
466 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
467 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
468 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
469 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
470 "Skipping this font.\n", debugstr_a(file));
471 pFT_Done_Face(ft_face);
472 return FALSE;
475 if(!ft_face->family_name || !ft_face->style_name) {
476 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
477 pFT_Done_Face(ft_face);
478 return FALSE;
481 if(!family_name)
482 family_name = ft_face->family_name;
484 bitmap_num = 0;
485 do {
486 My_FT_Bitmap_Size *size = NULL;
488 if(!FT_IS_SCALABLE(ft_face))
489 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
491 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
492 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
493 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
495 family = NULL;
496 LIST_FOR_EACH(family_elem_ptr, &font_list) {
497 family = LIST_ENTRY(family_elem_ptr, Family, entry);
498 if(!strcmpW(family->FamilyName, FamilyW))
499 break;
500 family = NULL;
502 if(!family) {
503 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
504 family->FamilyName = FamilyW;
505 list_init(&family->faces);
506 list_add_tail(&font_list, &family->entry);
507 } else {
508 HeapFree(GetProcessHeap(), 0, FamilyW);
511 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
512 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
513 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
515 internal_leading = 0;
516 memset(&fs, 0, sizeof(fs));
518 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
519 if(pOS2) {
520 fs.fsCsb[0] = pOS2->ulCodePageRange1;
521 fs.fsCsb[1] = pOS2->ulCodePageRange2;
522 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
523 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
524 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
525 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
526 if(pOS2->version == 0) {
527 FT_UInt dummy;
529 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
530 fs.fsCsb[0] |= 1;
531 else
532 fs.fsCsb[0] |= 1L << 31;
535 #ifdef HAVE_FREETYPE_FTWINFNT_H
536 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
537 CHARSETINFO csi;
538 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
539 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
540 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
541 memcpy(&fs, &csi.fs, sizeof(csi.fs));
542 internal_leading = winfnt_header.internal_leading;
544 #endif
546 face_elem_ptr = list_head(&family->faces);
547 while(face_elem_ptr) {
548 face = LIST_ENTRY(face_elem_ptr, Face, entry);
549 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
550 if(!strcmpW(face->StyleName, StyleW) &&
551 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
552 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
553 debugstr_w(family->FamilyName), debugstr_w(StyleW),
554 face->font_version, pHeader ? pHeader->Font_Revision : 0);
556 if(fake_family) {
557 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
558 HeapFree(GetProcessHeap(), 0, StyleW);
559 pFT_Done_Face(ft_face);
560 return FALSE;
562 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
563 TRACE("Original font is newer so skipping this one\n");
564 HeapFree(GetProcessHeap(), 0, StyleW);
565 pFT_Done_Face(ft_face);
566 return FALSE;
567 } else {
568 TRACE("Replacing original with this one\n");
569 list_remove(&face->entry);
570 HeapFree(GetProcessHeap(), 0, face->file);
571 HeapFree(GetProcessHeap(), 0, face->StyleName);
572 HeapFree(GetProcessHeap(), 0, face);
573 break;
577 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
578 list_add_tail(&family->faces, &face->entry);
579 face->StyleName = StyleW;
580 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
581 strcpy(face->file, file);
582 face->face_index = face_index;
583 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
584 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
585 face->font_version = pHeader ? pHeader->Font_Revision : 0;
586 face->family = family;
587 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
588 memcpy(&face->fs, &fs, sizeof(face->fs));
589 memset(&face->fs_links, 0, sizeof(face->fs_links));
591 if(FT_IS_SCALABLE(ft_face)) {
592 memset(&face->size, 0, sizeof(face->size));
593 face->scalable = TRUE;
594 } else {
595 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
596 size->height, size->width, size->size >> 6,
597 size->x_ppem >> 6, size->y_ppem >> 6);
598 face->size.height = size->height;
599 face->size.width = size->width;
600 face->size.size = size->size;
601 face->size.x_ppem = size->x_ppem;
602 face->size.y_ppem = size->y_ppem;
603 face->size.internal_leading = internal_leading;
604 face->scalable = FALSE;
607 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
608 face->fs.fsCsb[0], face->fs.fsCsb[1],
609 face->fs.fsUsb[0], face->fs.fsUsb[1],
610 face->fs.fsUsb[2], face->fs.fsUsb[3]);
613 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
614 for(i = 0; i < ft_face->num_charmaps; i++) {
615 switch(ft_face->charmaps[i]->encoding) {
616 case FT_ENCODING_UNICODE:
617 case FT_ENCODING_APPLE_ROMAN:
618 face->fs.fsCsb[0] |= 1;
619 break;
620 case FT_ENCODING_MS_SYMBOL:
621 face->fs.fsCsb[0] |= 1L << 31;
622 break;
623 default:
624 break;
629 if(face->fs.fsCsb[0] & ~(1L << 31))
630 have_installed_roman_font = TRUE;
631 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
633 num_faces = ft_face->num_faces;
634 pFT_Done_Face(ft_face);
635 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
636 debugstr_w(StyleW));
637 } while(num_faces > ++face_index);
638 return TRUE;
641 static void DumpFontList(void)
643 Family *family;
644 Face *face;
645 struct list *family_elem_ptr, *face_elem_ptr;
647 LIST_FOR_EACH(family_elem_ptr, &font_list) {
648 family = LIST_ENTRY(family_elem_ptr, Family, entry);
649 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
650 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
651 face = LIST_ENTRY(face_elem_ptr, Face, entry);
652 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
653 if(!face->scalable)
654 TRACE(" %ld", face->size.y_ppem >> 6);
655 TRACE("\n");
658 return;
661 static Face *find_face_from_filename(const WCHAR *name)
663 Family *family;
664 Face *face;
665 char *file;
666 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
667 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
668 Face *ret = NULL;
670 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
671 TRACE("looking for %s\n", debugstr_a(nameA));
673 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
675 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
677 file = strrchr(face->file, '/');
678 if(!file)
679 file = face->file;
680 else
681 file++;
682 if(!strcmp(file, nameA))
683 ret = face;
684 break;
687 HeapFree(GetProcessHeap(), 0, nameA);
688 return ret;
691 static Family *find_family_from_name(const WCHAR *name)
693 Family *family;
695 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
697 if(!strcmpiW(family->FamilyName, name))
698 return family;
701 return NULL;
704 static void DumpSubstList(void)
706 FontSubst *psub;
708 for(psub = substlist; psub; psub = psub->next)
709 if(psub->from.charset != -1 || psub->to.charset != -1)
710 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
711 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
712 else
713 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
714 debugstr_w(psub->to.name));
715 return;
718 static LPWSTR strdupW(LPCWSTR p)
720 LPWSTR ret;
721 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
722 ret = HeapAlloc(GetProcessHeap(), 0, len);
723 memcpy(ret, p, len);
724 return ret;
727 static LPSTR strdupA(LPCSTR p)
729 LPSTR ret;
730 DWORD len = (strlen(p) + 1);
731 ret = HeapAlloc(GetProcessHeap(), 0, len);
732 memcpy(ret, p, len);
733 return ret;
736 static void split_subst_info(NameCs *nc, LPSTR str)
738 CHAR *p = strrchr(str, ',');
739 DWORD len;
741 nc->charset = -1;
742 if(p && *(p+1)) {
743 nc->charset = strtol(p+1, NULL, 10);
744 *p = '\0';
746 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
747 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
748 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
751 static void LoadSubstList(void)
753 FontSubst *psub, **ppsub;
754 HKEY hkey;
755 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
756 LPSTR value;
757 LPVOID data;
759 if(substlist) {
760 for(psub = substlist; psub;) {
761 FontSubst *ptmp;
762 HeapFree(GetProcessHeap(), 0, psub->to.name);
763 HeapFree(GetProcessHeap(), 0, psub->from.name);
764 ptmp = psub;
765 psub = psub->next;
766 HeapFree(GetProcessHeap(), 0, ptmp);
768 substlist = NULL;
771 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
772 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
773 &hkey) == ERROR_SUCCESS) {
775 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
776 &valuelen, &datalen, NULL, NULL);
778 valuelen++; /* returned value doesn't include room for '\0' */
779 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
780 data = HeapAlloc(GetProcessHeap(), 0, datalen);
782 dlen = datalen;
783 vlen = valuelen;
784 ppsub = &substlist;
785 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
786 &dlen) == ERROR_SUCCESS) {
787 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
789 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
790 (*ppsub)->next = NULL;
791 split_subst_info(&((*ppsub)->from), value);
792 split_subst_info(&((*ppsub)->to), data);
794 /* Win 2000 doesn't allow mapping between different charsets
795 or mapping of DEFAULT_CHARSET */
796 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
797 (*ppsub)->to.charset == DEFAULT_CHARSET) {
798 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
799 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
800 HeapFree(GetProcessHeap(), 0, *ppsub);
801 *ppsub = NULL;
802 } else {
803 ppsub = &((*ppsub)->next);
805 /* reset dlen and vlen */
806 dlen = datalen;
807 vlen = valuelen;
809 HeapFree(GetProcessHeap(), 0, data);
810 HeapFree(GetProcessHeap(), 0, value);
811 RegCloseKey(hkey);
815 /***********************************************************
816 * The replacement list is a way to map an entire font
817 * family onto another family. For example adding
819 * [HKCU\Software\Wine\Fonts\Replacements]
820 * "Wingdings"="Winedings"
822 * would enumerate the Winedings font both as Winedings and
823 * Wingdings. However if a real Wingdings font is present the
824 * replacement does not take place.
827 static void LoadReplaceList(void)
829 HKEY hkey;
830 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
831 LPSTR value;
832 LPVOID data;
833 Family *family;
834 Face *face;
835 struct list *family_elem_ptr, *face_elem_ptr;
836 WCHAR old_nameW[200];
838 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
839 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
841 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
842 &valuelen, &datalen, NULL, NULL);
844 valuelen++; /* returned value doesn't include room for '\0' */
845 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
846 data = HeapAlloc(GetProcessHeap(), 0, datalen);
848 dlen = datalen;
849 vlen = valuelen;
850 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
851 &dlen) == ERROR_SUCCESS) {
852 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
853 /* "NewName"="Oldname" */
854 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
855 break;
857 /* Find the old family and hence all of the font files
858 in that family */
859 LIST_FOR_EACH(family_elem_ptr, &font_list) {
860 family = LIST_ENTRY(family_elem_ptr, Family, entry);
861 if(!strcmpiW(family->FamilyName, old_nameW)) {
862 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
863 face = LIST_ENTRY(face_elem_ptr, Face, entry);
864 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
865 debugstr_w(face->StyleName), value);
866 /* Now add a new entry with the new family name */
867 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
869 break;
872 /* reset dlen and vlen */
873 dlen = datalen;
874 vlen = valuelen;
876 HeapFree(GetProcessHeap(), 0, data);
877 HeapFree(GetProcessHeap(), 0, value);
878 RegCloseKey(hkey);
882 /*************************************************************
883 * init_system_links
885 static BOOL init_system_links(void)
887 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
888 'W','i','n','d','o','w','s',' ','N','T','\\',
889 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
890 'S','y','s','t','e','m','L','i','n','k',0};
891 HKEY hkey;
892 BOOL ret = FALSE;
893 DWORD type, max_val, max_data, val_len, data_len, index;
894 WCHAR *value, *data;
895 WCHAR *entry, *next;
896 SYSTEM_LINKS *font_link, *system_font_link;
897 CHILD_FONT *child_font;
898 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
899 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
900 static const WCHAR System[] = {'S','y','s','t','e','m',0};
901 FONTSIGNATURE fs;
902 Family *family;
903 Face *face;
905 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
907 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
908 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
909 data = HeapAlloc(GetProcessHeap(), 0, max_data);
910 val_len = max_val + 1;
911 data_len = max_data;
912 index = 0;
913 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
915 TRACE("%s:\n", debugstr_w(value));
917 memset(&fs, 0, sizeof(fs));
918 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
919 font_link->font_name = strdupW(value);
920 list_init(&font_link->links);
921 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
923 WCHAR *face_name;
924 INT index;
925 CHILD_FONT *child_font;
927 TRACE("\t%s\n", debugstr_w(entry));
929 next = entry + strlenW(entry) + 1;
931 face_name = strchrW(entry, ',');
932 if(!face_name)
933 index = 0;
934 else
936 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
937 *face_name++ = 0;
938 while(isspaceW(*face_name))
939 face_name++;
941 index = 0;
943 face = find_face_from_filename(entry);
944 if(!face)
946 TRACE("Unable to find file %s\n", debugstr_w(entry));
947 continue;
950 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
951 child_font->file_name = strdupA(face->file);
952 child_font->index = index;
953 child_font->font = NULL;
954 fs.fsCsb[0] |= face->fs.fsCsb[0];
955 fs.fsCsb[1] |= face->fs.fsCsb[1];
956 list_add_tail(&font_link->links, &child_font->entry);
958 family = find_family_from_name(font_link->font_name);
959 if(family)
961 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
963 memcpy(&face->fs_links, &fs, sizeof(fs));
966 list_add_tail(&system_links, &font_link->entry);
967 val_len = max_val + 1;
968 data_len = max_data;
971 HeapFree(GetProcessHeap(), 0, value);
972 HeapFree(GetProcessHeap(), 0, data);
973 RegCloseKey(hkey);
976 /* Explicitly add an entry for the system font, this links to Tahoma and any links
977 that Tahoma has */
979 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
980 system_font_link->font_name = strdupW(System);
981 list_init(&system_font_link->links);
983 face = find_face_from_filename(tahoma_ttf);
984 if(face)
986 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
987 child_font->file_name = strdupA(face->file);
988 child_font->index = 0;
989 child_font->font = NULL;
990 list_add_tail(&system_font_link->links, &child_font->entry);
992 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
994 if(!strcmpiW(font_link->font_name, Tahoma))
996 CHILD_FONT *font_link_entry;
997 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
999 CHILD_FONT *new_child;
1000 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1001 new_child->file_name = strdupA(font_link_entry->file_name);
1002 new_child->index = font_link_entry->index;
1003 new_child->font = NULL;
1004 list_add_tail(&system_font_link->links, &new_child->entry);
1006 break;
1009 list_add_tail(&system_links, &system_font_link->entry);
1010 return ret;
1013 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1015 DIR *dir;
1016 struct dirent *dent;
1017 char path[MAX_PATH];
1019 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1021 dir = opendir(dirname);
1022 if(!dir) {
1023 ERR("Can't open directory %s\n", debugstr_a(dirname));
1024 return FALSE;
1026 while((dent = readdir(dir)) != NULL) {
1027 struct stat statbuf;
1029 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1030 continue;
1032 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1034 sprintf(path, "%s/%s", dirname, dent->d_name);
1036 if(stat(path, &statbuf) == -1)
1038 WARN("Can't stat %s\n", debugstr_a(path));
1039 continue;
1041 if(S_ISDIR(statbuf.st_mode))
1042 ReadFontDir(path, external_fonts);
1043 else
1044 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1046 closedir(dir);
1047 return TRUE;
1050 static void load_fontconfig_fonts(void)
1052 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1053 void *fc_handle = NULL;
1054 FcConfig *config;
1055 FcPattern *pat;
1056 FcObjectSet *os;
1057 FcFontSet *fontset;
1058 FcValue v;
1059 int i, len;
1060 const char *file, *ext;
1062 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1063 if(!fc_handle) {
1064 TRACE("Wine cannot find the fontconfig library (%s).\n",
1065 SONAME_LIBFONTCONFIG);
1066 return;
1068 #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;}
1069 LOAD_FUNCPTR(FcConfigGetCurrent);
1070 LOAD_FUNCPTR(FcFontList);
1071 LOAD_FUNCPTR(FcFontSetDestroy);
1072 LOAD_FUNCPTR(FcInit);
1073 LOAD_FUNCPTR(FcObjectSetAdd);
1074 LOAD_FUNCPTR(FcObjectSetCreate);
1075 LOAD_FUNCPTR(FcObjectSetDestroy);
1076 LOAD_FUNCPTR(FcPatternCreate);
1077 LOAD_FUNCPTR(FcPatternDestroy);
1078 LOAD_FUNCPTR(FcPatternGet);
1079 #undef LOAD_FUNCPTR
1081 if(!pFcInit()) return;
1083 config = pFcConfigGetCurrent();
1084 pat = pFcPatternCreate();
1085 os = pFcObjectSetCreate();
1086 pFcObjectSetAdd(os, FC_FILE);
1087 fontset = pFcFontList(config, pat, os);
1088 if(!fontset) return;
1089 for(i = 0; i < fontset->nfont; i++) {
1090 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1091 continue;
1092 if(v.type != FcTypeString) continue;
1093 file = (LPCSTR) v.u.s;
1094 TRACE("fontconfig: %s\n", file);
1096 /* We're just interested in OT/TT fonts for now, so this hack just
1097 picks up the standard extensions to save time loading every other
1098 font */
1099 len = strlen( file );
1100 if(len < 4) continue;
1101 ext = &file[ len - 3 ];
1102 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1103 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1105 pFcFontSetDestroy(fontset);
1106 pFcObjectSetDestroy(os);
1107 pFcPatternDestroy(pat);
1108 sym_not_found:
1109 #endif
1110 return;
1114 static void load_system_fonts(void)
1116 HKEY hkey;
1117 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1118 const WCHAR **value;
1119 DWORD dlen, type;
1120 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1121 char *unixname;
1123 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1124 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1125 strcatW(windowsdir, fontsW);
1126 for(value = SystemFontValues; *value; value++) {
1127 dlen = sizeof(data);
1128 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1129 type == REG_SZ) {
1130 sprintfW(pathW, fmtW, windowsdir, data);
1131 if((unixname = wine_get_unix_file_name(pathW))) {
1132 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1133 HeapFree(GetProcessHeap(), 0, unixname);
1137 RegCloseKey(hkey);
1141 /*************************************************************
1143 * This adds registry entries for any externally loaded fonts
1144 * (fonts from fontconfig or FontDirs). It also deletes entries
1145 * of no longer existing fonts.
1148 static void update_reg_entries(void)
1150 HKEY winkey = 0, externalkey = 0;
1151 LPWSTR valueW;
1152 LPVOID data;
1153 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1154 Family *family;
1155 Face *face;
1156 struct list *family_elem_ptr, *face_elem_ptr;
1157 WCHAR *file;
1158 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1159 static const WCHAR spaceW[] = {' ', '\0'};
1160 char *path;
1162 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1163 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1164 ERR("Can't create Windows font reg key\n");
1165 goto end;
1167 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1168 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1169 ERR("Can't create external font reg key\n");
1170 goto end;
1173 /* Delete all external fonts added last time */
1175 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1176 &valuelen, &datalen, NULL, NULL);
1177 valuelen++; /* returned value doesn't include room for '\0' */
1178 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1179 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1181 dlen = datalen * sizeof(WCHAR);
1182 vlen = valuelen;
1183 i = 0;
1184 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1185 &dlen) == ERROR_SUCCESS) {
1187 RegDeleteValueW(winkey, valueW);
1188 /* reset dlen and vlen */
1189 dlen = datalen;
1190 vlen = valuelen;
1192 HeapFree(GetProcessHeap(), 0, data);
1193 HeapFree(GetProcessHeap(), 0, valueW);
1195 /* Delete the old external fonts key */
1196 RegCloseKey(externalkey);
1197 externalkey = 0;
1198 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1200 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1201 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1202 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1203 ERR("Can't create external font reg key\n");
1204 goto end;
1207 /* enumerate the fonts and add external ones to the two keys */
1209 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1210 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1211 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1212 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1213 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1214 if(!face->external) continue;
1215 len = len_fam;
1216 if(strcmpiW(face->StyleName, RegularW))
1217 len = len_fam + strlenW(face->StyleName) + 1;
1218 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1219 strcpyW(valueW, family->FamilyName);
1220 if(len != len_fam) {
1221 strcatW(valueW, spaceW);
1222 strcatW(valueW, face->StyleName);
1224 strcatW(valueW, TrueType);
1225 if((path = strrchr(face->file, '/')) == NULL)
1226 path = face->file;
1227 else
1228 path++;
1229 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1231 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1232 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1233 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1234 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1236 HeapFree(GetProcessHeap(), 0, file);
1237 HeapFree(GetProcessHeap(), 0, valueW);
1240 end:
1241 if(externalkey)
1242 RegCloseKey(externalkey);
1243 if(winkey)
1244 RegCloseKey(winkey);
1245 return;
1249 /*************************************************************
1250 * WineEngAddFontResourceEx
1253 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1255 if (ft_handle) /* do it only if we have freetype up and running */
1257 char *unixname;
1259 if(flags)
1260 FIXME("Ignoring flags %lx\n", flags);
1262 if((unixname = wine_get_unix_file_name(file)))
1264 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1265 HeapFree(GetProcessHeap(), 0, unixname);
1268 return 1;
1271 /*************************************************************
1272 * WineEngRemoveFontResourceEx
1275 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1277 FIXME(":stub\n");
1278 return TRUE;
1281 static const struct nls_update_font_list
1283 UINT ansi_cp, oem_cp;
1284 const char *oem, *fixed, *system;
1285 const char *courier, *serif, *small, *sserif;
1286 } nls_update_font_list[] =
1288 /* Latin 1 (United States) */
1289 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1292 /* Latin 1 (Multilingual) */
1293 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1294 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1296 /* Eastern Europe */
1297 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1298 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1300 /* Cyrillic */
1301 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1302 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1304 /* Greek */
1305 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1306 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1308 /* Turkish */
1309 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1310 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1312 /* Hebrew */
1313 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1314 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1316 /* Arabic */
1317 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1318 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1320 /* Baltic */
1321 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1322 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1324 /* Vietnamese */
1325 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1328 /* Thai */
1329 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1330 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1332 /* Japanese */
1333 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1334 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1336 /* Chinese Simplified */
1337 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1338 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1340 /* Korean */
1341 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1342 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1344 /* Chinese Traditional */
1345 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1346 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1350 inline static HKEY create_fonts_NT_registry_key(void)
1352 HKEY hkey = 0;
1354 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1355 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1356 return hkey;
1359 inline static HKEY create_fonts_9x_registry_key(void)
1361 HKEY hkey = 0;
1363 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1364 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1365 return hkey;
1368 inline static HKEY create_config_fonts_registry_key(void)
1370 HKEY hkey = 0;
1372 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1373 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1374 return hkey;
1377 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1379 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1380 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1381 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1382 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1385 static void update_font_info(void)
1387 char buf[80];
1388 DWORD len, type;
1389 HKEY hkey = 0;
1390 UINT i, ansi_cp = 0, oem_cp = 0;
1391 LCID lcid = GetUserDefaultLCID();
1393 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1394 return;
1396 len = sizeof(buf);
1397 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1399 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1401 RegCloseKey(hkey);
1402 return;
1404 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1406 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1408 sprintf(buf, "%08lx", lcid);
1409 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1410 RegCloseKey(hkey);
1412 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1413 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1414 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1415 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1417 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1419 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1420 nls_update_font_list[i].oem_cp == oem_cp)
1422 HKEY hkey;
1424 hkey = create_config_fonts_registry_key();
1425 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1426 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1427 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1428 RegCloseKey(hkey);
1430 hkey = create_fonts_NT_registry_key();
1431 add_font_list(hkey, &nls_update_font_list[i]);
1432 RegCloseKey(hkey);
1434 hkey = create_fonts_9x_registry_key();
1435 add_font_list(hkey, &nls_update_font_list[i]);
1436 RegCloseKey(hkey);
1438 return;
1441 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1444 /*************************************************************
1445 * WineEngInit
1447 * Initialize FreeType library and create a list of available faces
1449 BOOL WineEngInit(void)
1451 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1452 static const WCHAR pathW[] = {'P','a','t','h',0};
1453 HKEY hkey;
1454 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1455 LPVOID data;
1456 WCHAR windowsdir[MAX_PATH];
1457 char *unixname;
1458 HANDLE font_mutex;
1460 TRACE("\n");
1462 /* update locale dependent font info in registry */
1463 update_font_info();
1465 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1466 if(!ft_handle) {
1467 WINE_MESSAGE(
1468 "Wine cannot find the FreeType font library. To enable Wine to\n"
1469 "use TrueType fonts please install a version of FreeType greater than\n"
1470 "or equal to 2.0.5.\n"
1471 "http://www.freetype.org\n");
1472 return FALSE;
1475 #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;}
1477 LOAD_FUNCPTR(FT_Vector_Unit)
1478 LOAD_FUNCPTR(FT_Done_Face)
1479 LOAD_FUNCPTR(FT_Get_Char_Index)
1480 LOAD_FUNCPTR(FT_Get_Module)
1481 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1482 LOAD_FUNCPTR(FT_Init_FreeType)
1483 LOAD_FUNCPTR(FT_Load_Glyph)
1484 LOAD_FUNCPTR(FT_Matrix_Multiply)
1485 LOAD_FUNCPTR(FT_MulFix)
1486 LOAD_FUNCPTR(FT_New_Face)
1487 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1488 LOAD_FUNCPTR(FT_Outline_Transform)
1489 LOAD_FUNCPTR(FT_Outline_Translate)
1490 LOAD_FUNCPTR(FT_Select_Charmap)
1491 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1492 LOAD_FUNCPTR(FT_Vector_Transform)
1494 #undef LOAD_FUNCPTR
1495 /* Don't warn if this one is missing */
1496 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1497 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1498 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1499 #ifdef HAVE_FREETYPE_FTWINFNT_H
1500 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1501 #endif
1502 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1503 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1504 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1505 <= 2.0.3 has FT_Sqrt64 */
1506 goto sym_not_found;
1509 if(pFT_Init_FreeType(&library) != 0) {
1510 ERR("Can't init FreeType library\n");
1511 wine_dlclose(ft_handle, NULL, 0);
1512 ft_handle = NULL;
1513 return FALSE;
1515 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1516 if (pFT_Library_Version)
1518 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1520 if (FT_Version.major<=0)
1522 FT_Version.major=2;
1523 FT_Version.minor=0;
1524 FT_Version.patch=5;
1526 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1527 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1528 ((FT_Version.minor << 8) & 0x00ff00) |
1529 ((FT_Version.patch ) & 0x0000ff);
1531 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1532 ERR("Failed to create font mutex\n");
1533 return FALSE;
1535 WaitForSingleObject(font_mutex, INFINITE);
1537 /* load the system fonts */
1538 load_system_fonts();
1540 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1541 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1542 strcatW(windowsdir, fontsW);
1543 if((unixname = wine_get_unix_file_name(windowsdir)))
1545 ReadFontDir(unixname, FALSE);
1546 HeapFree(GetProcessHeap(), 0, unixname);
1549 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1550 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1551 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1552 will skip these. */
1553 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1554 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1555 &hkey) == ERROR_SUCCESS) {
1556 LPWSTR valueW;
1557 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1558 &valuelen, &datalen, NULL, NULL);
1560 valuelen++; /* returned value doesn't include room for '\0' */
1561 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1562 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1563 if (valueW && data)
1565 dlen = datalen * sizeof(WCHAR);
1566 vlen = valuelen;
1567 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1568 &dlen) == ERROR_SUCCESS) {
1569 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1571 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1573 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1574 HeapFree(GetProcessHeap(), 0, unixname);
1577 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1579 WCHAR pathW[MAX_PATH];
1580 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1581 sprintfW(pathW, fmtW, windowsdir, data);
1582 if((unixname = wine_get_unix_file_name(pathW)))
1584 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1585 HeapFree(GetProcessHeap(), 0, unixname);
1588 /* reset dlen and vlen */
1589 dlen = datalen;
1590 vlen = valuelen;
1593 HeapFree(GetProcessHeap(), 0, data);
1594 HeapFree(GetProcessHeap(), 0, valueW);
1595 RegCloseKey(hkey);
1598 load_fontconfig_fonts();
1600 /* then look in any directories that we've specified in the config file */
1601 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1602 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1604 DWORD len;
1605 LPWSTR valueW;
1606 LPSTR valueA, ptr;
1608 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1610 len += sizeof(WCHAR);
1611 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1612 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1614 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1615 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1616 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1617 TRACE( "got font path %s\n", debugstr_a(valueA) );
1618 ptr = valueA;
1619 while (ptr)
1621 LPSTR next = strchr( ptr, ':' );
1622 if (next) *next++ = 0;
1623 ReadFontDir( ptr, TRUE );
1624 ptr = next;
1626 HeapFree( GetProcessHeap(), 0, valueA );
1628 HeapFree( GetProcessHeap(), 0, valueW );
1630 RegCloseKey(hkey);
1633 DumpFontList();
1634 LoadSubstList();
1635 DumpSubstList();
1636 LoadReplaceList();
1637 update_reg_entries();
1639 init_system_links();
1641 ReleaseMutex(font_mutex);
1642 return TRUE;
1643 sym_not_found:
1644 WINE_MESSAGE(
1645 "Wine cannot find certain functions that it needs inside the FreeType\n"
1646 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1647 "FreeType to at least version 2.0.5.\n"
1648 "http://www.freetype.org\n");
1649 wine_dlclose(ft_handle, NULL, 0);
1650 ft_handle = NULL;
1651 return FALSE;
1655 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1657 TT_OS2 *pOS2;
1658 TT_HoriHeader *pHori;
1660 LONG ppem;
1662 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1663 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1665 if(height == 0) height = 16;
1667 /* Calc. height of EM square:
1669 * For +ve lfHeight we have
1670 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1671 * Re-arranging gives:
1672 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1674 * For -ve lfHeight we have
1675 * |lfHeight| = ppem
1676 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1677 * with il = winAscent + winDescent - units_per_em]
1681 if(height > 0) {
1682 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1683 ppem = ft_face->units_per_EM * height /
1684 (pHori->Ascender - pHori->Descender);
1685 else
1686 ppem = ft_face->units_per_EM * height /
1687 (pOS2->usWinAscent + pOS2->usWinDescent);
1689 else
1690 ppem = -height;
1692 return ppem;
1695 static LONG load_VDMX(GdiFont, LONG);
1697 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1699 FT_Error err;
1700 FT_Face ft_face;
1702 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1703 err = pFT_New_Face(library, file, face_index, &ft_face);
1704 if(err) {
1705 ERR("FT_New_Face rets %d\n", err);
1706 return 0;
1709 /* set it here, as load_VDMX needs it */
1710 font->ft_face = ft_face;
1712 if(FT_IS_SCALABLE(ft_face)) {
1713 /* load the VDMX table if we have one */
1714 font->ppem = load_VDMX(font, height);
1715 if(font->ppem == 0)
1716 font->ppem = calc_ppem_for_height(ft_face, height);
1718 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1719 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1720 } else {
1721 font->ppem = height;
1722 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1723 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1725 return ft_face;
1729 static int get_nearest_charset(Face *face, int *cp)
1731 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1732 a single face with the requested charset. The idea is to check if
1733 the selected font supports the current ANSI codepage, if it does
1734 return the corresponding charset, else return the first charset */
1736 CHARSETINFO csi;
1737 int acp = GetACP(), i;
1738 DWORD fs0;
1740 *cp = acp;
1741 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1742 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1743 return csi.ciCharset;
1745 for(i = 0; i < 32; i++) {
1746 fs0 = 1L << i;
1747 if(face->fs.fsCsb[0] & fs0) {
1748 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1749 *cp = csi.ciACP;
1750 return csi.ciCharset;
1752 else
1753 FIXME("TCI failing on %lx\n", fs0);
1757 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1758 face->fs.fsCsb[0], face->file);
1759 *cp = acp;
1760 return DEFAULT_CHARSET;
1763 static GdiFont alloc_font(void)
1765 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1766 ret->gmsize = INIT_GM_SIZE;
1767 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1768 ret->gmsize * sizeof(*ret->gm));
1769 ret->potm = NULL;
1770 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1771 list_init(&ret->hfontlist);
1772 list_init(&ret->child_fonts);
1773 return ret;
1776 static void free_font(GdiFont font)
1778 struct list *cursor, *cursor2;
1780 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1782 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1783 struct list *first_hfont;
1784 HFONTLIST *hfontlist;
1785 list_remove(cursor);
1786 if(child->font)
1788 first_hfont = list_head(&child->font->hfontlist);
1789 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1790 DeleteObject(hfontlist->hfont);
1791 HeapFree(GetProcessHeap(), 0, hfontlist);
1792 free_font(child->font);
1794 HeapFree(GetProcessHeap(), 0, child->file_name);
1795 HeapFree(GetProcessHeap(), 0, child);
1798 if (font->ft_face) pFT_Done_Face(font->ft_face);
1799 HeapFree(GetProcessHeap(), 0, font->potm);
1800 HeapFree(GetProcessHeap(), 0, font->name);
1801 HeapFree(GetProcessHeap(), 0, font->gm);
1802 HeapFree(GetProcessHeap(), 0, font);
1806 /*************************************************************
1807 * load_VDMX
1809 * load the vdmx entry for the specified height
1812 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1813 ( ( (FT_ULong)_x4 << 24 ) | \
1814 ( (FT_ULong)_x3 << 16 ) | \
1815 ( (FT_ULong)_x2 << 8 ) | \
1816 (FT_ULong)_x1 )
1818 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1820 typedef struct {
1821 BYTE bCharSet;
1822 BYTE xRatio;
1823 BYTE yStartRatio;
1824 BYTE yEndRatio;
1825 } Ratios;
1828 static LONG load_VDMX(GdiFont font, LONG height)
1830 BYTE hdr[6], tmp[2], group[4];
1831 BYTE devXRatio, devYRatio;
1832 USHORT numRecs, numRatios;
1833 DWORD result, offset = -1;
1834 LONG ppem = 0;
1835 int i;
1837 /* For documentation on VDMX records, see
1838 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1841 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1843 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1844 return ppem;
1846 /* FIXME: need the real device aspect ratio */
1847 devXRatio = 1;
1848 devYRatio = 1;
1850 numRecs = GET_BE_WORD(&hdr[2]);
1851 numRatios = GET_BE_WORD(&hdr[4]);
1853 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1854 for(i = 0; i < numRatios; i++) {
1855 Ratios ratio;
1857 offset = (3 * 2) + (i * sizeof(Ratios));
1858 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1859 offset = -1;
1861 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1863 if((ratio.xRatio == 0 &&
1864 ratio.yStartRatio == 0 &&
1865 ratio.yEndRatio == 0) ||
1866 (devXRatio == ratio.xRatio &&
1867 devYRatio >= ratio.yStartRatio &&
1868 devYRatio <= ratio.yEndRatio))
1870 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1871 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1872 offset = GET_BE_WORD(tmp);
1873 break;
1877 if(offset == -1) {
1878 FIXME("No suitable ratio found\n");
1879 return ppem;
1882 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1883 USHORT recs;
1884 BYTE startsz, endsz;
1885 BYTE *vTable;
1887 recs = GET_BE_WORD(group);
1888 startsz = group[2];
1889 endsz = group[3];
1891 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1893 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1894 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1895 if(result == GDI_ERROR) {
1896 FIXME("Failed to retrieve vTable\n");
1897 goto end;
1900 if(height > 0) {
1901 for(i = 0; i < recs; i++) {
1902 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1903 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1904 ppem = GET_BE_WORD(&vTable[i * 6]);
1906 if(yMax + -yMin == height) {
1907 font->yMax = yMax;
1908 font->yMin = yMin;
1909 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1910 break;
1912 if(yMax + -yMin > height) {
1913 if(--i < 0) {
1914 ppem = 0;
1915 goto end; /* failed */
1917 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1918 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1919 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1920 break;
1923 if(!font->yMax) {
1924 ppem = 0;
1925 TRACE("ppem not found for height %ld\n", height);
1927 } else {
1928 ppem = -height;
1929 if(ppem < startsz || ppem > endsz)
1930 goto end;
1932 for(i = 0; i < recs; i++) {
1933 USHORT yPelHeight;
1934 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1936 if(yPelHeight > ppem)
1937 break; /* failed */
1939 if(yPelHeight == ppem) {
1940 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1941 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1942 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1943 break;
1947 end:
1948 HeapFree(GetProcessHeap(), 0, vTable);
1951 return ppem;
1954 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1956 if(font->font_desc.hash != fd->hash) return TRUE;
1957 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1958 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1959 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1962 static void calc_hash(FONT_DESC *pfd)
1964 DWORD hash = 0, *ptr, two_chars;
1965 WORD *pwc;
1966 unsigned int i;
1968 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1969 hash ^= *ptr;
1970 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1971 hash ^= *ptr;
1972 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1973 two_chars = *ptr;
1974 pwc = (WCHAR *)&two_chars;
1975 if(!*pwc) break;
1976 *pwc = toupperW(*pwc);
1977 pwc++;
1978 *pwc = toupperW(*pwc);
1979 hash ^= two_chars;
1980 if(!*pwc) break;
1982 pfd->hash = hash;
1983 return;
1986 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1988 GdiFont ret;
1989 FONT_DESC fd;
1990 HFONTLIST *hflist;
1991 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1993 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1994 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1995 calc_hash(&fd);
1997 /* try the in-use list */
1998 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1999 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2000 if(!fontcmp(ret, &fd)) {
2001 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2002 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2003 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2004 if(hflist->hfont == hfont)
2005 return ret;
2007 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2008 hflist->hfont = hfont;
2009 list_add_head(&ret->hfontlist, &hflist->entry);
2010 return ret;
2014 /* then the unused list */
2015 font_elem_ptr = list_head(&unused_gdi_font_list);
2016 while(font_elem_ptr) {
2017 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2018 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2019 if(!fontcmp(ret, &fd)) {
2020 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2021 assert(list_empty(&ret->hfontlist));
2022 TRACE("Found %p in unused list\n", ret);
2023 list_remove(&ret->entry);
2024 list_add_head(&gdi_font_list, &ret->entry);
2025 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2026 hflist->hfont = hfont;
2027 list_add_head(&ret->hfontlist, &hflist->entry);
2028 return ret;
2031 return NULL;
2035 /*************************************************************
2036 * create_child_font_list
2038 static BOOL create_child_font_list(GdiFont font)
2040 BOOL ret = FALSE;
2041 SYSTEM_LINKS *font_link;
2042 CHILD_FONT *font_link_entry, *new_child;
2044 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2046 if(!strcmpW(font_link->font_name, font->name))
2048 TRACE("found entry in system list\n");
2049 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2051 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2052 new_child->file_name = strdupA(font_link_entry->file_name);
2053 new_child->index = font_link_entry->index;
2054 new_child->font = NULL;
2055 list_add_tail(&font->child_fonts, &new_child->entry);
2056 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2058 ret = TRUE;
2059 break;
2063 return ret;
2066 /*************************************************************
2067 * WineEngCreateFontInstance
2070 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2072 GdiFont ret;
2073 Face *face, *best;
2074 Family *family, *last_resort_family;
2075 struct list *family_elem_ptr, *face_elem_ptr;
2076 INT height, width = 0;
2077 signed int diff = 0, newdiff;
2078 BOOL bd, it, can_use_bitmap;
2079 LOGFONTW lf;
2080 CHARSETINFO csi;
2081 HFONTLIST *hflist;
2083 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2085 struct list *first_hfont = list_head(&ret->hfontlist);
2086 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2087 if(hflist->hfont == hfont)
2088 return ret;
2091 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2092 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2094 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2095 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2096 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2097 lf.lfEscapement);
2099 /* check the cache first */
2100 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2101 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2102 return ret;
2105 TRACE("not in cache\n");
2106 if(list_empty(&font_list)) /* No fonts installed */
2108 TRACE("No fonts installed\n");
2109 return NULL;
2111 if(!have_installed_roman_font)
2113 TRACE("No roman font installed\n");
2114 return NULL;
2117 ret = alloc_font();
2119 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2120 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2121 calc_hash(&ret->font_desc);
2122 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2123 hflist->hfont = hfont;
2124 list_add_head(&ret->hfontlist, &hflist->entry);
2127 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2128 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2129 original value lfCharSet. Note this is a special case for
2130 Symbol and doesn't happen at least for "Wingdings*" */
2132 if(!strcmpiW(lf.lfFaceName, SymbolW))
2133 lf.lfCharSet = SYMBOL_CHARSET;
2135 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2136 switch(lf.lfCharSet) {
2137 case DEFAULT_CHARSET:
2138 csi.fs.fsCsb[0] = 0;
2139 break;
2140 default:
2141 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2142 csi.fs.fsCsb[0] = 0;
2143 break;
2147 family = NULL;
2148 if(lf.lfFaceName[0] != '\0') {
2149 FontSubst *psub;
2150 for(psub = substlist; psub; psub = psub->next)
2151 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
2152 (psub->from.charset == -1 ||
2153 psub->from.charset == lf.lfCharSet))
2154 break;
2155 if(psub) {
2156 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2157 debugstr_w(psub->to.name));
2158 strcpyW(lf.lfFaceName, psub->to.name);
2161 /* We want a match on name and charset or just name if
2162 charset was DEFAULT_CHARSET. If the latter then
2163 we fixup the returned charset later in get_nearest_charset
2164 where we'll either use the charset of the current ansi codepage
2165 or if that's unavailable the first charset that the font supports.
2167 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2168 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2169 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2170 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2171 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2172 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2173 if(face->scalable || can_use_bitmap)
2174 goto found;
2180 /* If requested charset was DEFAULT_CHARSET then try using charset
2181 corresponding to the current ansi codepage */
2182 if(!csi.fs.fsCsb[0]) {
2183 INT acp = GetACP();
2184 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2185 FIXME("TCI failed on codepage %d\n", acp);
2186 csi.fs.fsCsb[0] = 0;
2187 } else
2188 lf.lfCharSet = csi.ciCharset;
2191 /* Face families are in the top 4 bits of lfPitchAndFamily,
2192 so mask with 0xF0 before testing */
2194 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2195 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2196 strcpyW(lf.lfFaceName, defFixed);
2197 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2198 strcpyW(lf.lfFaceName, defSerif);
2199 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2200 strcpyW(lf.lfFaceName, defSans);
2201 else
2202 strcpyW(lf.lfFaceName, defSans);
2203 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2204 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2205 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2206 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2207 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2208 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2209 if(face->scalable || can_use_bitmap)
2210 goto found;
2215 last_resort_family = NULL;
2216 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2217 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2218 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2219 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2220 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2221 if(face->scalable)
2222 goto found;
2223 if(can_use_bitmap && !last_resort_family)
2224 last_resort_family = family;
2229 if(last_resort_family) {
2230 family = last_resort_family;
2231 csi.fs.fsCsb[0] = 0;
2232 goto found;
2235 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2236 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2237 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2238 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2239 if(face->scalable) {
2240 csi.fs.fsCsb[0] = 0;
2241 FIXME("just using first face for now\n");
2242 goto found;
2244 if(can_use_bitmap && !last_resort_family)
2245 last_resort_family = family;
2248 if(!last_resort_family) {
2249 FIXME("can't find a single appropriate font - bailing\n");
2250 free_font(ret);
2251 return NULL;
2254 WARN("could only find a bitmap font - this will probably look awful!\n");
2255 family = last_resort_family;
2256 csi.fs.fsCsb[0] = 0;
2258 found:
2259 it = lf.lfItalic ? 1 : 0;
2260 bd = lf.lfWeight > 550 ? 1 : 0;
2262 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2263 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2265 face = best = NULL;
2266 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2267 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2268 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2269 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2270 if(face->scalable)
2271 break;
2272 if(height > 0)
2273 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2274 else
2275 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2276 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2277 (diff < 0 && newdiff > diff)) {
2278 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2279 diff = newdiff;
2280 best = face;
2281 if(diff == 0)
2282 break;
2285 face = NULL;
2287 if(!face && best)
2288 face = best;
2289 else if(!face) {
2290 best = NULL;
2291 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2292 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2293 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2294 if(face->scalable)
2295 break;
2296 if(height > 0)
2297 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2298 else
2299 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2300 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2301 (diff < 0 && newdiff > diff)) {
2302 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2303 diff = newdiff;
2304 best = face;
2305 if(diff == 0)
2306 break;
2309 face = NULL;
2311 if(!face && best)
2312 face = best;
2313 if(it && !face->Italic) ret->fake_italic = TRUE;
2314 if(bd && !face->Bold) ret->fake_bold = TRUE;
2317 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2319 if(csi.fs.fsCsb[0]) {
2320 ret->charset = lf.lfCharSet;
2321 ret->codepage = csi.ciACP;
2323 else
2324 ret->charset = get_nearest_charset(face, &ret->codepage);
2326 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2327 debugstr_w(face->StyleName), face->file, face->face_index);
2329 if(!face->scalable) {
2330 width = face->size.x_ppem >> 6;
2331 height = face->size.y_ppem >> 6;
2333 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2335 if (!ret->ft_face)
2337 free_font( ret );
2338 return 0;
2341 if (ret->charset == SYMBOL_CHARSET &&
2342 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2343 /* No ops */
2345 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2346 /* No ops */
2348 else {
2349 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2352 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2353 ret->name = strdupW(family->FamilyName);
2354 ret->underline = lf.lfUnderline ? 0xff : 0;
2355 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2356 create_child_font_list(ret);
2358 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2360 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2361 list_add_head(&gdi_font_list, &ret->entry);
2362 return ret;
2365 static void dump_gdi_font_list(void)
2367 GdiFont gdiFont;
2368 struct list *elem_ptr;
2370 TRACE("---------- gdiFont Cache ----------\n");
2371 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2372 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2373 TRACE("gdiFont=%p %s %ld\n",
2374 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2377 TRACE("---------- Unused gdiFont Cache ----------\n");
2378 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2379 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2380 TRACE("gdiFont=%p %s %ld\n",
2381 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2385 /*************************************************************
2386 * WineEngDestroyFontInstance
2388 * free the gdiFont associated with this handle
2391 BOOL WineEngDestroyFontInstance(HFONT handle)
2393 GdiFont gdiFont;
2394 HFONTLIST *hflist;
2395 BOOL ret = FALSE;
2396 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2397 int i = 0;
2399 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2401 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2402 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2403 if(hflist->hfont == handle)
2405 TRACE("removing child font %p from child list\n", gdiFont);
2406 list_remove(&gdiFont->entry);
2407 return TRUE;
2411 TRACE("destroying hfont=%p\n", handle);
2412 if(TRACE_ON(font))
2413 dump_gdi_font_list();
2415 font_elem_ptr = list_head(&gdi_font_list);
2416 while(font_elem_ptr) {
2417 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2418 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2420 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2421 while(hfontlist_elem_ptr) {
2422 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2423 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2424 if(hflist->hfont == handle) {
2425 list_remove(&hflist->entry);
2426 HeapFree(GetProcessHeap(), 0, hflist);
2427 ret = TRUE;
2430 if(list_empty(&gdiFont->hfontlist)) {
2431 TRACE("Moving to Unused list\n");
2432 list_remove(&gdiFont->entry);
2433 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2438 font_elem_ptr = list_head(&unused_gdi_font_list);
2439 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2440 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2441 while(font_elem_ptr) {
2442 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2443 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2444 TRACE("freeing %p\n", gdiFont);
2445 list_remove(&gdiFont->entry);
2446 free_font(gdiFont);
2448 return ret;
2451 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2452 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2454 OUTLINETEXTMETRICW *potm = NULL;
2455 UINT size;
2456 TEXTMETRICW tm, *ptm;
2457 GdiFont font = alloc_font();
2458 LONG width, height;
2460 if(face->scalable) {
2461 height = 100;
2462 width = 0;
2463 } else {
2464 height = face->size.y_ppem >> 6;
2465 width = face->size.x_ppem >> 6;
2468 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2470 free_font(font);
2471 return;
2474 font->name = strdupW(face->family->FamilyName);
2476 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2478 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2479 if(size) {
2480 potm = HeapAlloc(GetProcessHeap(), 0, size);
2481 WineEngGetOutlineTextMetrics(font, size, potm);
2482 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2483 } else {
2484 WineEngGetTextMetrics(font, &tm);
2485 ptm = &tm;
2488 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2489 pntm->ntmTm.tmAscent = ptm->tmAscent;
2490 pntm->ntmTm.tmDescent = ptm->tmDescent;
2491 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2492 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2493 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2494 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2495 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2496 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2497 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2498 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2499 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2500 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2501 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2502 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2503 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2504 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2505 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2506 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2507 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2508 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2509 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2510 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2511 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2513 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2514 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2515 *ptype |= RASTER_FONTTYPE;
2517 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2518 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2519 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2521 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2522 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2523 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2525 if(potm) {
2526 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2528 lstrcpynW(pelf->elfLogFont.lfFaceName,
2529 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2530 LF_FACESIZE);
2531 lstrcpynW(pelf->elfFullName,
2532 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2533 LF_FULLFACESIZE);
2534 lstrcpynW(pelf->elfStyle,
2535 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2536 LF_FACESIZE);
2538 HeapFree(GetProcessHeap(), 0, potm);
2539 } else {
2540 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2542 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2543 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2544 pelf->elfStyle[0] = '\0';
2547 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2549 free_font(font);
2552 /*************************************************************
2553 * WineEngEnumFonts
2556 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2558 Family *family;
2559 Face *face;
2560 struct list *family_elem_ptr, *face_elem_ptr;
2561 ENUMLOGFONTEXW elf;
2562 NEWTEXTMETRICEXW ntm;
2563 DWORD type, ret = 1;
2564 FONTSIGNATURE fs;
2565 CHARSETINFO csi;
2566 LOGFONTW lf;
2567 int i;
2569 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2571 if(plf->lfFaceName[0]) {
2572 FontSubst *psub;
2573 for(psub = substlist; psub; psub = psub->next)
2574 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2575 (psub->from.charset == -1 ||
2576 psub->from.charset == plf->lfCharSet))
2577 break;
2578 if(psub) {
2579 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2580 debugstr_w(psub->to.name));
2581 memcpy(&lf, plf, sizeof(lf));
2582 strcpyW(lf.lfFaceName, psub->to.name);
2583 plf = &lf;
2586 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2587 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2588 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2589 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2590 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2591 GetEnumStructs(face, &elf, &ntm, &type);
2592 for(i = 0; i < 32; i++) {
2593 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2594 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2595 strcpyW(elf.elfScript, OEM_DOSW);
2596 i = 32; /* break out of loop */
2597 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2598 continue;
2599 else {
2600 fs.fsCsb[0] = 1L << i;
2601 fs.fsCsb[1] = 0;
2602 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2603 TCI_SRCFONTSIG))
2604 csi.ciCharset = DEFAULT_CHARSET;
2605 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2606 if(csi.ciCharset != DEFAULT_CHARSET) {
2607 elf.elfLogFont.lfCharSet =
2608 ntm.ntmTm.tmCharSet = csi.ciCharset;
2609 if(ElfScriptsW[i])
2610 strcpyW(elf.elfScript, ElfScriptsW[i]);
2611 else
2612 FIXME("Unknown elfscript for bit %d\n", i);
2615 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2616 debugstr_w(elf.elfLogFont.lfFaceName),
2617 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2618 csi.ciCharset, type, debugstr_w(elf.elfScript),
2619 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2620 ntm.ntmTm.ntmFlags);
2621 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2622 if(!ret) goto end;
2627 } else {
2628 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2629 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2630 face_elem_ptr = list_head(&family->faces);
2631 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2632 GetEnumStructs(face, &elf, &ntm, &type);
2633 for(i = 0; i < 32; i++) {
2634 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2635 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2636 strcpyW(elf.elfScript, OEM_DOSW);
2637 i = 32; /* break out of loop */
2638 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2639 continue;
2640 else {
2641 fs.fsCsb[0] = 1L << i;
2642 fs.fsCsb[1] = 0;
2643 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2644 TCI_SRCFONTSIG))
2645 csi.ciCharset = DEFAULT_CHARSET;
2646 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2647 if(csi.ciCharset != DEFAULT_CHARSET) {
2648 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2649 csi.ciCharset;
2650 if(ElfScriptsW[i])
2651 strcpyW(elf.elfScript, ElfScriptsW[i]);
2652 else
2653 FIXME("Unknown elfscript for bit %d\n", i);
2656 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2657 debugstr_w(elf.elfLogFont.lfFaceName),
2658 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2659 csi.ciCharset, type, debugstr_w(elf.elfScript),
2660 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2661 ntm.ntmTm.ntmFlags);
2662 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2663 if(!ret) goto end;
2667 end:
2668 return ret;
2671 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2673 pt->x.value = vec->x >> 6;
2674 pt->x.fract = (vec->x & 0x3f) << 10;
2675 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2676 pt->y.value = vec->y >> 6;
2677 pt->y.fract = (vec->y & 0x3f) << 10;
2678 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2679 return;
2682 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2684 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2685 WCHAR wc = (WCHAR)glyph;
2686 BOOL default_used;
2687 FT_UInt ret;
2688 char buf;
2689 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, &default_used) || default_used)
2690 ret = 0;
2691 else
2692 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2693 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2694 return ret;
2697 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2698 glyph = glyph + 0xf000;
2699 return pFT_Get_Char_Index(font->ft_face, glyph);
2702 /*************************************************************
2703 * WineEngGetGlyphIndices
2705 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2707 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2708 LPWORD pgi, DWORD flags)
2710 INT i;
2712 for(i = 0; i < count; i++)
2713 pgi[i] = get_glyph_index(font, lpstr[i]);
2715 return count;
2718 /*************************************************************
2719 * WineEngGetGlyphOutline
2721 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2722 * except that the first parameter is the HWINEENGFONT of the font in
2723 * question rather than an HDC.
2726 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2727 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2728 const MAT2* lpmat)
2730 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2731 FT_Face ft_face = font->ft_face;
2732 FT_UInt glyph_index;
2733 DWORD width, height, pitch, needed = 0;
2734 FT_Bitmap ft_bitmap;
2735 FT_Error err;
2736 INT left, right, top = 0, bottom = 0;
2737 FT_Angle angle = 0;
2738 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2739 float widthRatio = 1.0;
2740 FT_Matrix transMat = identityMat;
2741 BOOL needsTransform = FALSE;
2744 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2745 buflen, buf, lpmat);
2747 if(format & GGO_GLYPH_INDEX) {
2748 glyph_index = glyph;
2749 format &= ~GGO_GLYPH_INDEX;
2750 } else
2751 glyph_index = get_glyph_index(font, glyph);
2753 if(glyph_index >= font->gmsize) {
2754 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2755 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2756 font->gmsize * sizeof(*font->gm));
2757 } else {
2758 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2759 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2760 return 1; /* FIXME */
2764 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2765 load_flags |= FT_LOAD_NO_BITMAP;
2767 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2769 if(err) {
2770 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2771 return GDI_ERROR;
2774 /* Scaling factor */
2775 if (font->aveWidth && font->potm) {
2776 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2779 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2780 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2782 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2783 font->gm[glyph_index].lsb = left >> 6;
2784 font->gm[glyph_index].bbx = (right - left) >> 6;
2786 /* Scaling transform */
2787 if(font->aveWidth) {
2788 FT_Matrix scaleMat;
2789 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2790 scaleMat.xy = 0;
2791 scaleMat.yx = 0;
2792 scaleMat.yy = (1 << 16);
2794 pFT_Matrix_Multiply(&scaleMat, &transMat);
2795 needsTransform = TRUE;
2798 /* Rotation transform */
2799 if(font->orientation) {
2800 FT_Matrix rotationMat;
2801 FT_Vector vecAngle;
2802 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2803 pFT_Vector_Unit(&vecAngle, angle);
2804 rotationMat.xx = vecAngle.x;
2805 rotationMat.xy = -vecAngle.y;
2806 rotationMat.yx = -rotationMat.xy;
2807 rotationMat.yy = rotationMat.xx;
2809 pFT_Matrix_Multiply(&rotationMat, &transMat);
2810 needsTransform = TRUE;
2813 /* Extra transformation specified by caller */
2814 if (lpmat) {
2815 FT_Matrix extraMat;
2816 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2817 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2818 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2819 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2820 pFT_Matrix_Multiply(&extraMat, &transMat);
2821 needsTransform = TRUE;
2824 if(!needsTransform) {
2825 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2826 bottom = (ft_face->glyph->metrics.horiBearingY -
2827 ft_face->glyph->metrics.height) & -64;
2828 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2829 lpgm->gmCellIncY = 0;
2830 } else {
2831 INT xc, yc;
2832 FT_Vector vec;
2833 for(xc = 0; xc < 2; xc++) {
2834 for(yc = 0; yc < 2; yc++) {
2835 vec.x = (ft_face->glyph->metrics.horiBearingX +
2836 xc * ft_face->glyph->metrics.width);
2837 vec.y = ft_face->glyph->metrics.horiBearingY -
2838 yc * ft_face->glyph->metrics.height;
2839 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2840 pFT_Vector_Transform(&vec, &transMat);
2841 if(xc == 0 && yc == 0) {
2842 left = right = vec.x;
2843 top = bottom = vec.y;
2844 } else {
2845 if(vec.x < left) left = vec.x;
2846 else if(vec.x > right) right = vec.x;
2847 if(vec.y < bottom) bottom = vec.y;
2848 else if(vec.y > top) top = vec.y;
2852 left = left & -64;
2853 right = (right + 63) & -64;
2854 bottom = bottom & -64;
2855 top = (top + 63) & -64;
2857 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2858 vec.x = ft_face->glyph->metrics.horiAdvance;
2859 vec.y = 0;
2860 pFT_Vector_Transform(&vec, &transMat);
2861 lpgm->gmCellIncX = (vec.x+63) >> 6;
2862 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2864 lpgm->gmBlackBoxX = (right - left) >> 6;
2865 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2866 lpgm->gmptGlyphOrigin.x = left >> 6;
2867 lpgm->gmptGlyphOrigin.y = top >> 6;
2869 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2870 font->gm[glyph_index].init = TRUE;
2872 if(format == GGO_METRICS)
2873 return 1; /* FIXME */
2875 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2876 TRACE("loaded a bitmap\n");
2877 return GDI_ERROR;
2880 switch(format) {
2881 case GGO_BITMAP:
2882 width = lpgm->gmBlackBoxX;
2883 height = lpgm->gmBlackBoxY;
2884 pitch = ((width + 31) >> 5) << 2;
2885 needed = pitch * height;
2887 if(!buf || !buflen) break;
2889 switch(ft_face->glyph->format) {
2890 case ft_glyph_format_bitmap:
2892 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2893 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2894 INT h = ft_face->glyph->bitmap.rows;
2895 while(h--) {
2896 memcpy(dst, src, w);
2897 src += ft_face->glyph->bitmap.pitch;
2898 dst += pitch;
2900 break;
2903 case ft_glyph_format_outline:
2904 ft_bitmap.width = width;
2905 ft_bitmap.rows = height;
2906 ft_bitmap.pitch = pitch;
2907 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2908 ft_bitmap.buffer = buf;
2910 if(needsTransform) {
2911 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2914 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2916 /* Note: FreeType will only set 'black' bits for us. */
2917 memset(buf, 0, needed);
2918 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2919 break;
2921 default:
2922 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2923 return GDI_ERROR;
2925 break;
2927 case GGO_GRAY2_BITMAP:
2928 case GGO_GRAY4_BITMAP:
2929 case GGO_GRAY8_BITMAP:
2930 case WINE_GGO_GRAY16_BITMAP:
2932 unsigned int mult, row, col;
2933 BYTE *start, *ptr;
2935 width = lpgm->gmBlackBoxX;
2936 height = lpgm->gmBlackBoxY;
2937 pitch = (width + 3) / 4 * 4;
2938 needed = pitch * height;
2940 if(!buf || !buflen) break;
2941 ft_bitmap.width = width;
2942 ft_bitmap.rows = height;
2943 ft_bitmap.pitch = pitch;
2944 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2945 ft_bitmap.buffer = buf;
2947 if(needsTransform) {
2948 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2951 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2953 memset(ft_bitmap.buffer, 0, buflen);
2955 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2957 if(format == GGO_GRAY2_BITMAP)
2958 mult = 4;
2959 else if(format == GGO_GRAY4_BITMAP)
2960 mult = 16;
2961 else if(format == GGO_GRAY8_BITMAP)
2962 mult = 64;
2963 else if(format == WINE_GGO_GRAY16_BITMAP)
2964 break;
2965 else {
2966 assert(0);
2967 break;
2970 start = buf;
2971 for(row = 0; row < height; row++) {
2972 ptr = start;
2973 for(col = 0; col < width; col++, ptr++) {
2974 *ptr = (((int)*ptr) * mult + 128) / 256;
2976 start += pitch;
2978 break;
2981 case GGO_NATIVE:
2983 int contour, point = 0, first_pt;
2984 FT_Outline *outline = &ft_face->glyph->outline;
2985 TTPOLYGONHEADER *pph;
2986 TTPOLYCURVE *ppc;
2987 DWORD pph_start, cpfx, type;
2989 if(buflen == 0) buf = NULL;
2991 if (needsTransform && buf) {
2992 pFT_Outline_Transform(outline, &transMat);
2995 for(contour = 0; contour < outline->n_contours; contour++) {
2996 pph_start = needed;
2997 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2998 first_pt = point;
2999 if(buf) {
3000 pph->dwType = TT_POLYGON_TYPE;
3001 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3003 needed += sizeof(*pph);
3004 point++;
3005 while(point <= outline->contours[contour]) {
3006 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3007 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3008 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3009 cpfx = 0;
3010 do {
3011 if(buf)
3012 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3013 cpfx++;
3014 point++;
3015 } while(point <= outline->contours[contour] &&
3016 (outline->tags[point] & FT_Curve_Tag_On) ==
3017 (outline->tags[point-1] & FT_Curve_Tag_On));
3018 /* At the end of a contour Windows adds the start point, but
3019 only for Beziers */
3020 if(point > outline->contours[contour] &&
3021 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3022 if(buf)
3023 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3024 cpfx++;
3025 } else if(point <= outline->contours[contour] &&
3026 outline->tags[point] & FT_Curve_Tag_On) {
3027 /* add closing pt for bezier */
3028 if(buf)
3029 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3030 cpfx++;
3031 point++;
3033 if(buf) {
3034 ppc->wType = type;
3035 ppc->cpfx = cpfx;
3037 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3039 if(buf)
3040 pph->cb = needed - pph_start;
3042 break;
3044 case GGO_BEZIER:
3046 /* Convert the quadratic Beziers to cubic Beziers.
3047 The parametric eqn for a cubic Bezier is, from PLRM:
3048 r(t) = at^3 + bt^2 + ct + r0
3049 with the control points:
3050 r1 = r0 + c/3
3051 r2 = r1 + (c + b)/3
3052 r3 = r0 + c + b + a
3054 A quadratic Beizer has the form:
3055 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3057 So equating powers of t leads to:
3058 r1 = 2/3 p1 + 1/3 p0
3059 r2 = 2/3 p1 + 1/3 p2
3060 and of course r0 = p0, r3 = p2
3063 int contour, point = 0, first_pt;
3064 FT_Outline *outline = &ft_face->glyph->outline;
3065 TTPOLYGONHEADER *pph;
3066 TTPOLYCURVE *ppc;
3067 DWORD pph_start, cpfx, type;
3068 FT_Vector cubic_control[4];
3069 if(buflen == 0) buf = NULL;
3071 if (needsTransform && buf) {
3072 pFT_Outline_Transform(outline, &transMat);
3075 for(contour = 0; contour < outline->n_contours; contour++) {
3076 pph_start = needed;
3077 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3078 first_pt = point;
3079 if(buf) {
3080 pph->dwType = TT_POLYGON_TYPE;
3081 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3083 needed += sizeof(*pph);
3084 point++;
3085 while(point <= outline->contours[contour]) {
3086 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3087 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3088 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3089 cpfx = 0;
3090 do {
3091 if(type == TT_PRIM_LINE) {
3092 if(buf)
3093 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3094 cpfx++;
3095 point++;
3096 } else {
3097 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3098 so cpfx = 3n */
3100 /* FIXME: Possible optimization in endpoint calculation
3101 if there are two consecutive curves */
3102 cubic_control[0] = outline->points[point-1];
3103 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3104 cubic_control[0].x += outline->points[point].x + 1;
3105 cubic_control[0].y += outline->points[point].y + 1;
3106 cubic_control[0].x >>= 1;
3107 cubic_control[0].y >>= 1;
3109 if(point+1 > outline->contours[contour])
3110 cubic_control[3] = outline->points[first_pt];
3111 else {
3112 cubic_control[3] = outline->points[point+1];
3113 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3114 cubic_control[3].x += outline->points[point].x + 1;
3115 cubic_control[3].y += outline->points[point].y + 1;
3116 cubic_control[3].x >>= 1;
3117 cubic_control[3].y >>= 1;
3120 /* r1 = 1/3 p0 + 2/3 p1
3121 r2 = 1/3 p2 + 2/3 p1 */
3122 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3123 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3124 cubic_control[2] = cubic_control[1];
3125 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3126 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3127 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3128 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3129 if(buf) {
3130 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3131 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3132 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3134 cpfx += 3;
3135 point++;
3137 } while(point <= outline->contours[contour] &&
3138 (outline->tags[point] & FT_Curve_Tag_On) ==
3139 (outline->tags[point-1] & FT_Curve_Tag_On));
3140 /* At the end of a contour Windows adds the start point,
3141 but only for Beziers and we've already done that.
3143 if(point <= outline->contours[contour] &&
3144 outline->tags[point] & FT_Curve_Tag_On) {
3145 /* This is the closing pt of a bezier, but we've already
3146 added it, so just inc point and carry on */
3147 point++;
3149 if(buf) {
3150 ppc->wType = type;
3151 ppc->cpfx = cpfx;
3153 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3155 if(buf)
3156 pph->cb = needed - pph_start;
3158 break;
3161 default:
3162 FIXME("Unsupported format %d\n", format);
3163 return GDI_ERROR;
3165 return needed;
3168 static BOOL get_bitmap_text_metrics(GdiFont font)
3170 FT_Face ft_face = font->ft_face;
3171 #ifdef HAVE_FREETYPE_FTWINFNT_H
3172 FT_WinFNT_HeaderRec winfnt_header;
3173 #endif
3174 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3175 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3176 font->potm->otmSize = size;
3178 #define TM font->potm->otmTextMetrics
3179 #ifdef HAVE_FREETYPE_FTWINFNT_H
3180 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3182 TM.tmHeight = winfnt_header.pixel_height;
3183 TM.tmAscent = winfnt_header.ascent;
3184 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3185 TM.tmInternalLeading = winfnt_header.internal_leading;
3186 TM.tmExternalLeading = winfnt_header.external_leading;
3187 TM.tmAveCharWidth = winfnt_header.avg_width;
3188 TM.tmMaxCharWidth = winfnt_header.max_width;
3189 TM.tmWeight = winfnt_header.weight;
3190 TM.tmOverhang = 0;
3191 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3192 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3193 TM.tmFirstChar = winfnt_header.first_char;
3194 TM.tmLastChar = winfnt_header.last_char;
3195 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3196 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3197 TM.tmItalic = winfnt_header.italic;
3198 TM.tmUnderlined = font->underline;
3199 TM.tmStruckOut = font->strikeout;
3200 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3201 TM.tmCharSet = winfnt_header.charset;
3203 else
3204 #endif
3206 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3207 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3208 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3209 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3210 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3211 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3212 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3213 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3214 TM.tmOverhang = 0;
3215 TM.tmDigitizedAspectX = 96; /* FIXME */
3216 TM.tmDigitizedAspectY = 96; /* FIXME */
3217 TM.tmFirstChar = 1;
3218 TM.tmLastChar = 255;
3219 TM.tmDefaultChar = 32;
3220 TM.tmBreakChar = 32;
3221 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3222 TM.tmUnderlined = font->underline;
3223 TM.tmStruckOut = font->strikeout;
3224 /* NB inverted meaning of TMPF_FIXED_PITCH */
3225 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3226 TM.tmCharSet = font->charset;
3228 #undef TM
3230 return TRUE;
3233 /*************************************************************
3234 * WineEngGetTextMetrics
3237 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3239 if(!font->potm) {
3240 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3241 if(!get_bitmap_text_metrics(font))
3242 return FALSE;
3244 if(!font->potm) return FALSE;
3245 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3247 if (font->aveWidth) {
3248 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3250 return TRUE;
3254 /*************************************************************
3255 * WineEngGetOutlineTextMetrics
3258 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3259 OUTLINETEXTMETRICW *potm)
3261 FT_Face ft_face = font->ft_face;
3262 UINT needed, lenfam, lensty, ret;
3263 TT_OS2 *pOS2;
3264 TT_HoriHeader *pHori;
3265 TT_Postscript *pPost;
3266 FT_Fixed x_scale, y_scale;
3267 WCHAR *family_nameW, *style_nameW;
3268 static const WCHAR spaceW[] = {' ', '\0'};
3269 char *cp;
3270 INT ascent, descent;
3272 TRACE("font=%p\n", font);
3274 if(!FT_IS_SCALABLE(ft_face))
3275 return 0;
3277 if(font->potm) {
3278 if(cbSize >= font->potm->otmSize)
3279 memcpy(potm, font->potm, font->potm->otmSize);
3280 return font->potm->otmSize;
3284 needed = sizeof(*potm);
3286 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3287 family_nameW = strdupW(font->name);
3289 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3290 * sizeof(WCHAR);
3291 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3292 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3293 style_nameW, lensty/sizeof(WCHAR));
3295 /* These names should be read from the TT name table */
3297 /* length of otmpFamilyName */
3298 needed += lenfam;
3300 /* length of otmpFaceName */
3301 if(!strcasecmp(ft_face->style_name, "regular")) {
3302 needed += lenfam; /* just the family name */
3303 } else {
3304 needed += lenfam + lensty; /* family + " " + style */
3307 /* length of otmpStyleName */
3308 needed += lensty;
3310 /* length of otmpFullName */
3311 needed += lenfam + lensty;
3314 x_scale = ft_face->size->metrics.x_scale;
3315 y_scale = ft_face->size->metrics.y_scale;
3317 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3318 if(!pOS2) {
3319 FIXME("Can't find OS/2 table - not TT font?\n");
3320 ret = 0;
3321 goto end;
3324 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3325 if(!pHori) {
3326 FIXME("Can't find HHEA table - not TT font?\n");
3327 ret = 0;
3328 goto end;
3331 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3333 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",
3334 pOS2->usWinAscent, pOS2->usWinDescent,
3335 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3336 ft_face->ascender, ft_face->descender, ft_face->height,
3337 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3338 ft_face->bbox.yMax, ft_face->bbox.yMin);
3340 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3341 font->potm->otmSize = needed;
3343 #define TM font->potm->otmTextMetrics
3345 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3346 ascent = pHori->Ascender;
3347 descent = -pHori->Descender;
3348 } else {
3349 ascent = pOS2->usWinAscent;
3350 descent = pOS2->usWinDescent;
3353 if(font->yMax) {
3354 TM.tmAscent = font->yMax;
3355 TM.tmDescent = -font->yMin;
3356 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3357 } else {
3358 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3359 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3360 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3361 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3364 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3366 /* MSDN says:
3367 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3369 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3370 ((ascent + descent) -
3371 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3373 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3374 if (TM.tmAveCharWidth == 0) {
3375 TM.tmAveCharWidth = 1;
3377 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3378 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3379 TM.tmOverhang = 0;
3380 TM.tmDigitizedAspectX = 300;
3381 TM.tmDigitizedAspectY = 300;
3382 TM.tmFirstChar = pOS2->usFirstCharIndex;
3383 TM.tmLastChar = pOS2->usLastCharIndex;
3384 TM.tmDefaultChar = pOS2->usDefaultChar;
3385 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3386 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3387 TM.tmUnderlined = font->underline;
3388 TM.tmStruckOut = font->strikeout;
3390 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3391 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3392 (pOS2->version == 0xFFFFU ||
3393 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3394 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3395 else
3396 TM.tmPitchAndFamily = 0;
3398 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3399 case PAN_FAMILY_SCRIPT:
3400 TM.tmPitchAndFamily |= FF_SCRIPT;
3401 break;
3402 case PAN_FAMILY_DECORATIVE:
3403 case PAN_FAMILY_PICTORIAL:
3404 TM.tmPitchAndFamily |= FF_DECORATIVE;
3405 break;
3406 case PAN_FAMILY_TEXT_DISPLAY:
3407 if(TM.tmPitchAndFamily == 0) /* fixed */
3408 TM.tmPitchAndFamily = FF_MODERN;
3409 else {
3410 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3411 case PAN_SERIF_NORMAL_SANS:
3412 case PAN_SERIF_OBTUSE_SANS:
3413 case PAN_SERIF_PERP_SANS:
3414 TM.tmPitchAndFamily |= FF_SWISS;
3415 break;
3416 default:
3417 TM.tmPitchAndFamily |= FF_ROMAN;
3420 break;
3421 default:
3422 TM.tmPitchAndFamily |= FF_DONTCARE;
3425 if(FT_IS_SCALABLE(ft_face))
3426 TM.tmPitchAndFamily |= TMPF_VECTOR;
3427 if(FT_IS_SFNT(ft_face))
3428 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3430 TM.tmCharSet = font->charset;
3431 #undef TM
3433 font->potm->otmFiller = 0;
3434 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3435 font->potm->otmfsSelection = pOS2->fsSelection;
3436 font->potm->otmfsType = pOS2->fsType;
3437 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3438 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3439 font->potm->otmItalicAngle = 0; /* POST table */
3440 font->potm->otmEMSquare = ft_face->units_per_EM;
3441 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3442 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3443 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3444 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3445 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3446 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3447 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3448 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3449 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3450 font->potm->otmMacAscent = 0; /* where do these come from ? */
3451 font->potm->otmMacDescent = 0;
3452 font->potm->otmMacLineGap = 0;
3453 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3454 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3455 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3456 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3457 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3458 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3459 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3460 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3461 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3462 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3463 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3464 if(!pPost) {
3465 font->potm->otmsUnderscoreSize = 0;
3466 font->potm->otmsUnderscorePosition = 0;
3467 } else {
3468 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3469 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3472 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3473 cp = (char*)font->potm + sizeof(*font->potm);
3474 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3475 strcpyW((WCHAR*)cp, family_nameW);
3476 cp += lenfam;
3477 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3478 strcpyW((WCHAR*)cp, style_nameW);
3479 cp += lensty;
3480 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3481 strcpyW((WCHAR*)cp, family_nameW);
3482 if(strcasecmp(ft_face->style_name, "regular")) {
3483 strcatW((WCHAR*)cp, spaceW);
3484 strcatW((WCHAR*)cp, style_nameW);
3485 cp += lenfam + lensty;
3486 } else
3487 cp += lenfam;
3488 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3489 strcpyW((WCHAR*)cp, family_nameW);
3490 strcatW((WCHAR*)cp, spaceW);
3491 strcatW((WCHAR*)cp, style_nameW);
3492 ret = needed;
3494 if(potm && needed <= cbSize)
3495 memcpy(potm, font->potm, font->potm->otmSize);
3497 end:
3498 HeapFree(GetProcessHeap(), 0, style_nameW);
3499 HeapFree(GetProcessHeap(), 0, family_nameW);
3501 return ret;
3504 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3506 HFONTLIST *hfontlist;
3507 child->font = alloc_font();
3508 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3509 if(!child->font->ft_face)
3511 free_font(child->font);
3512 child->font = NULL;
3513 return FALSE;
3516 child->font->orientation = font->orientation;
3517 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3518 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3519 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3520 child->font->base_font = font;
3521 list_add_head(&child_font_list, &child->font->entry);
3522 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3523 return TRUE;
3526 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3528 FT_UInt g;
3529 CHILD_FONT *child_font;
3531 if(font->base_font)
3532 font = font->base_font;
3534 *linked_font = font;
3536 if((*glyph = get_glyph_index(font, c)))
3537 return TRUE;
3539 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3541 if(!child_font->font)
3542 if(!load_child_font(font, child_font))
3543 continue;
3545 if(!child_font->font->ft_face)
3546 continue;
3547 g = get_glyph_index(child_font->font, c);
3548 if(g)
3550 *glyph = g;
3551 *linked_font = child_font->font;
3552 return TRUE;
3555 return FALSE;
3558 /*************************************************************
3559 * WineEngGetCharWidth
3562 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3563 LPINT buffer)
3565 UINT c;
3566 GLYPHMETRICS gm;
3567 FT_UInt glyph_index;
3568 GdiFont linked_font;
3570 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3572 for(c = firstChar; c <= lastChar; c++) {
3573 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3574 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3575 &gm, 0, NULL, NULL);
3576 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3578 return TRUE;
3581 /*************************************************************
3582 * WineEngGetCharABCWidths
3585 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3586 LPABC buffer)
3588 UINT c;
3589 GLYPHMETRICS gm;
3590 FT_UInt glyph_index;
3591 GdiFont linked_font;
3593 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3595 if(!FT_IS_SCALABLE(font->ft_face))
3596 return FALSE;
3598 for(c = firstChar; c <= lastChar; c++) {
3599 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3600 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3601 &gm, 0, NULL, NULL);
3602 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3603 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3604 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3605 linked_font->gm[glyph_index].bbx;
3607 return TRUE;
3610 /*************************************************************
3611 * WineEngGetTextExtentPoint
3614 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3615 LPSIZE size)
3617 INT idx;
3618 GLYPHMETRICS gm;
3619 TEXTMETRICW tm;
3620 FT_UInt glyph_index;
3621 GdiFont linked_font;
3623 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3624 size);
3626 size->cx = 0;
3627 WineEngGetTextMetrics(font, &tm);
3628 size->cy = tm.tmHeight;
3630 for(idx = 0; idx < count; idx++) {
3631 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3632 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3633 &gm, 0, NULL, NULL);
3634 size->cx += linked_font->gm[glyph_index].adv;
3636 TRACE("return %ld,%ld\n", size->cx, size->cy);
3637 return TRUE;
3640 /*************************************************************
3641 * WineEngGetTextExtentPointI
3644 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3645 LPSIZE size)
3647 INT idx;
3648 GLYPHMETRICS gm;
3649 TEXTMETRICW tm;
3651 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3653 size->cx = 0;
3654 WineEngGetTextMetrics(font, &tm);
3655 size->cy = tm.tmHeight;
3657 for(idx = 0; idx < count; idx++) {
3658 WineEngGetGlyphOutline(font, indices[idx],
3659 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3660 NULL);
3661 size->cx += font->gm[indices[idx]].adv;
3663 TRACE("return %ld,%ld\n", size->cx, size->cy);
3664 return TRUE;
3667 /*************************************************************
3668 * WineEngGetFontData
3671 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3672 DWORD cbData)
3674 FT_Face ft_face = font->ft_face;
3675 DWORD len;
3676 FT_Error err;
3678 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3679 font, table, offset, buf, cbData);
3681 if(!FT_IS_SFNT(ft_face))
3682 return GDI_ERROR;
3684 if(!buf || !cbData)
3685 len = 0;
3686 else
3687 len = cbData;
3689 if(table) { /* MS tags differ in endidness from FT ones */
3690 table = table >> 24 | table << 24 |
3691 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3694 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3695 if(pFT_Load_Sfnt_Table) {
3696 /* make sure value of len is the value freetype says it needs */
3697 if( buf && len) {
3698 DWORD needed = 0;
3699 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3700 if( !err && needed < len) len = needed;
3702 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3703 } else { /* Do it the hard way */
3704 TT_Face tt_face = (TT_Face) ft_face;
3705 SFNT_Interface *sfnt;
3706 if (FT_Version.major==2 && FT_Version.minor==0)
3708 /* 2.0.x */
3709 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3711 else
3713 /* A field was added in the middle of the structure in 2.1.x */
3714 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3716 /* make sure value of len is the value freetype says it needs */
3717 if( buf && len) {
3718 DWORD needed = 0;
3719 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3720 if( !err && needed < len) len = needed;
3722 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3724 if(err) {
3725 TRACE("Can't find table %08lx.\n", table);
3726 return GDI_ERROR;
3728 return len;
3731 /*************************************************************
3732 * WineEngGetTextFace
3735 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3737 if(str) {
3738 lstrcpynW(str, font->name, count);
3739 return strlenW(font->name);
3740 } else
3741 return strlenW(font->name) + 1;
3744 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3746 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3747 return font->charset;
3750 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3752 GdiFont font = dc->gdiFont, linked_font;
3753 struct list *first_hfont;
3754 BOOL ret;
3756 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3757 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3758 if(font == linked_font)
3759 *new_hfont = dc->hFont;
3760 else
3762 first_hfont = list_head(&linked_font->hfontlist);
3763 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3766 return ret;
3770 /*************************************************************
3771 * FontIsLinked
3773 BOOL WINAPI FontIsLinked(HDC hdc)
3775 DC *dc = DC_GetDCPtr(hdc);
3776 BOOL ret = FALSE;
3778 if(!dc) return FALSE;
3779 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3780 ret = TRUE;
3781 GDI_ReleaseObj(hdc);
3782 TRACE("returning %d\n", ret);
3783 return ret;
3786 static BOOL is_hinting_enabled(void)
3788 FT_Module mod = pFT_Get_Module(library, "truetype");
3789 if(mod && FT_DRIVER_HAS_HINTER(mod))
3790 return TRUE;
3792 return FALSE;
3795 /*************************************************************************
3796 * GetRasterizerCaps (GDI32.@)
3798 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3800 static int hinting = -1;
3802 if(hinting == -1)
3803 hinting = is_hinting_enabled();
3805 lprs->nSize = sizeof(RASTERIZER_STATUS);
3806 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
3807 lprs->nLanguageID = 0;
3808 return TRUE;
3812 #else /* HAVE_FREETYPE */
3814 BOOL WineEngInit(void)
3816 return FALSE;
3818 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3820 return NULL;
3822 BOOL WineEngDestroyFontInstance(HFONT hfont)
3824 return FALSE;
3827 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3829 return 1;
3832 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3833 LPWORD pgi, DWORD flags)
3835 return GDI_ERROR;
3838 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3839 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3840 const MAT2* lpmat)
3842 ERR("called but we don't have FreeType\n");
3843 return GDI_ERROR;
3846 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3848 ERR("called but we don't have FreeType\n");
3849 return FALSE;
3852 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3853 OUTLINETEXTMETRICW *potm)
3855 ERR("called but we don't have FreeType\n");
3856 return 0;
3859 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3860 LPINT buffer)
3862 ERR("called but we don't have FreeType\n");
3863 return FALSE;
3866 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3867 LPABC buffer)
3869 ERR("called but we don't have FreeType\n");
3870 return FALSE;
3873 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3874 LPSIZE size)
3876 ERR("called but we don't have FreeType\n");
3877 return FALSE;
3880 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3881 LPSIZE size)
3883 ERR("called but we don't have FreeType\n");
3884 return FALSE;
3887 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3888 DWORD cbData)
3890 ERR("called but we don't have FreeType\n");
3891 return GDI_ERROR;
3894 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3896 ERR("called but we don't have FreeType\n");
3897 return 0;
3900 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3902 FIXME(":stub\n");
3903 return 1;
3906 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3908 FIXME(":stub\n");
3909 return TRUE;
3912 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3914 FIXME(":stub\n");
3915 return DEFAULT_CHARSET;
3918 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3920 return FALSE;
3923 BOOL WINAPI FontIsLinked(HDC hdc)
3925 return FALSE;
3928 /*************************************************************************
3929 * GetRasterizerCaps (GDI32.@)
3931 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3933 lprs->nSize = sizeof(RASTERIZER_STATUS);
3934 lprs->wFlags = 0;
3935 lprs->nLanguageID = 0;
3936 return TRUE;
3939 #endif /* HAVE_FREETYPE */