Remember to remove a child font from the child font list.
[wine/wine-kai.git] / dlls / gdi / freetype.c
blobeb4692867836c5f2d930a2471df2c65033683391
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_Sfnt_Table);
107 MAKE_FUNCPTR(FT_Init_FreeType);
108 MAKE_FUNCPTR(FT_Load_Glyph);
109 MAKE_FUNCPTR(FT_Matrix_Multiply);
110 MAKE_FUNCPTR(FT_MulFix);
111 MAKE_FUNCPTR(FT_New_Face);
112 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
113 MAKE_FUNCPTR(FT_Outline_Transform);
114 MAKE_FUNCPTR(FT_Outline_Translate);
115 MAKE_FUNCPTR(FT_Select_Charmap);
116 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
117 MAKE_FUNCPTR(FT_Vector_Transform);
118 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
119 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
120 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
121 #ifdef HAVE_FREETYPE_FTWINFNT_H
122 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
123 #endif
125 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
126 #include <fontconfig/fontconfig.h>
127 MAKE_FUNCPTR(FcConfigGetCurrent);
128 MAKE_FUNCPTR(FcFontList);
129 MAKE_FUNCPTR(FcFontSetDestroy);
130 MAKE_FUNCPTR(FcInit);
131 MAKE_FUNCPTR(FcObjectSetAdd);
132 MAKE_FUNCPTR(FcObjectSetCreate);
133 MAKE_FUNCPTR(FcObjectSetDestroy);
134 MAKE_FUNCPTR(FcPatternCreate);
135 MAKE_FUNCPTR(FcPatternDestroy);
136 MAKE_FUNCPTR(FcPatternGet);
137 #ifndef SONAME_LIBFONTCONFIG
138 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
139 #endif
140 #endif
142 #undef MAKE_FUNCPTR
144 #ifndef ft_encoding_none
145 #define FT_ENCODING_NONE ft_encoding_none
146 #endif
147 #ifndef ft_encoding_ms_symbol
148 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
149 #endif
150 #ifndef ft_encoding_unicode
151 #define FT_ENCODING_UNICODE ft_encoding_unicode
152 #endif
153 #ifndef ft_encoding_apple_roman
154 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
155 #endif
157 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
159 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
160 typedef struct {
161 FT_Short height;
162 FT_Short width;
163 FT_Pos size;
164 FT_Pos x_ppem;
165 FT_Pos y_ppem;
166 FT_Short internal_leading;
167 } Bitmap_Size;
169 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
170 So to let this compile on older versions of FreeType we'll define the
171 new structure here. */
172 typedef struct {
173 FT_Short height, width;
174 FT_Pos size, x_ppem, y_ppem;
175 } My_FT_Bitmap_Size;
177 typedef struct tagFace {
178 struct list entry;
179 WCHAR *StyleName;
180 char *file;
181 FT_Long face_index;
182 BOOL Italic;
183 BOOL Bold;
184 FONTSIGNATURE fs;
185 FONTSIGNATURE fs_links;
186 FT_Fixed font_version;
187 BOOL scalable;
188 Bitmap_Size size; /* set if face is a bitmap */
189 BOOL external; /* TRUE if we should manually add this font to the registry */
190 struct tagFamily *family;
191 } Face;
193 typedef struct tagFamily {
194 struct list entry;
195 WCHAR *FamilyName;
196 struct list faces;
197 } Family;
199 typedef struct {
200 GLYPHMETRICS gm;
201 INT adv; /* These three hold to widths of the unrotated chars */
202 INT lsb;
203 INT bbx;
204 BOOL init;
205 } GM;
207 typedef struct {
208 FLOAT eM11, eM12;
209 FLOAT eM21, eM22;
210 } FMAT2;
212 typedef struct {
213 DWORD hash;
214 LOGFONTW lf;
215 FMAT2 matrix;
216 } FONT_DESC;
218 typedef struct tagHFONTLIST {
219 struct list entry;
220 HFONT hfont;
221 } HFONTLIST;
223 typedef struct {
224 struct list entry;
225 char *file_name;
226 INT index;
227 GdiFont font;
228 } CHILD_FONT;
230 struct tagGdiFont {
231 struct list entry;
232 FT_Face ft_face;
233 LPWSTR name;
234 int charset;
235 int codepage;
236 BOOL fake_italic;
237 BOOL fake_bold;
238 BYTE underline;
239 BYTE strikeout;
240 INT orientation;
241 GM *gm;
242 DWORD gmsize;
243 struct list hfontlist;
244 FONT_DESC font_desc;
245 LONG aveWidth;
246 SHORT yMax;
247 SHORT yMin;
248 OUTLINETEXTMETRICW *potm;
249 FONTSIGNATURE fs;
250 GdiFont base_font;
251 struct list child_fonts;
252 LONG ppem;
255 typedef struct {
256 struct list entry;
257 WCHAR *font_name;
258 struct list links;
259 } SYSTEM_LINKS;
261 #define INIT_GM_SIZE 128
263 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
264 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
265 #define UNUSED_CACHE_SIZE 10
266 static struct list child_font_list = LIST_INIT(child_font_list);
267 static struct list system_links = LIST_INIT(system_links);
269 static struct list font_list = LIST_INIT(font_list);
271 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
272 'R','o','m','a','n','\0'};
273 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
274 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
276 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
277 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
278 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
279 'S','e','r','i','f','\0'};
280 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
281 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
283 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
284 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
285 'W','i','n','d','o','w','s','\\',
286 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
287 'F','o','n','t','s','\0'};
289 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
290 'W','i','n','d','o','w','s',' ','N','T','\\',
291 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
292 'F','o','n','t','s','\0'};
294 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
295 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
296 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
297 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
299 static const WCHAR *SystemFontValues[4] = {
300 System_Value,
301 OEMFont_Value,
302 FixedSys_Value,
303 NULL
306 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
307 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
309 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
310 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
311 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
312 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
313 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
314 'E','u','r','o','p','e','a','n','\0'};
315 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
316 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
317 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
318 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
319 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
320 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
321 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
322 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
323 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
324 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
325 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
326 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
328 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
329 WesternW, /*00*/
330 Central_EuropeanW,
331 CyrillicW,
332 GreekW,
333 TurkishW,
334 HebrewW,
335 ArabicW,
336 BalticW,
337 VietnameseW, /*08*/
338 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
339 ThaiW,
340 JapaneseW,
341 CHINESE_GB2312W,
342 HangulW,
343 CHINESE_BIG5W,
344 Hangul_Johab_W,
345 NULL, NULL, /*23*/
346 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
347 SymbolW /*31*/
350 typedef struct {
351 WCHAR *name;
352 INT charset;
353 } NameCs;
355 typedef struct tagFontSubst {
356 NameCs from;
357 NameCs to;
358 struct tagFontSubst *next;
359 } FontSubst;
361 static FontSubst *substlist = NULL;
362 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
364 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
367 /****************************************
368 * Notes on .fon files
370 * The fonts System, FixedSys and Terminal are special. There are typically multiple
371 * versions installed for different resolutions and codepages. Windows stores which one to use
372 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
373 * Key Meaning
374 * FIXEDFON.FON FixedSys
375 * FONTS.FON System
376 * OEMFONT.FON Terminal
377 * LogPixels Current dpi set by the display control panel applet
378 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
379 * also has a LogPixels value that appears to mirror this)
381 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
382 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
383 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
384 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
385 * so that makes sense.
387 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
388 * to be mapped into the registry on Windows 2000 at least).
389 * I have
390 * woafont=app850.fon
391 * ega80woa.fon=ega80850.fon
392 * ega40woa.fon=ega40850.fon
393 * cga80woa.fon=cga80850.fon
394 * cga40woa.fon=cga40850.fon
398 static inline BOOL is_win9x(void)
400 return GetVersion() & 0x80000000;
403 This function builds an FT_Fixed from a float. It puts the integer part
404 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
405 It fails if the integer part of the float number is greater than SHORT_MAX.
407 static inline FT_Fixed FT_FixedFromFloat(float f)
409 short value = f;
410 unsigned short fract = (f - value) * 0xFFFF;
411 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
415 This function builds an FT_Fixed from a FIXED. It simply put f.value
416 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
418 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
420 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
423 #define ADDFONT_EXTERNAL_FONT 0x01
424 #define ADDFONT_FORCE_BITMAP 0x02
425 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
427 FT_Face ft_face;
428 TT_OS2 *pOS2;
429 TT_Header *pHeader = NULL;
430 WCHAR *FamilyW, *StyleW;
431 DWORD len;
432 Family *family;
433 Face *face;
434 struct list *family_elem_ptr, *face_elem_ptr;
435 FT_Error err;
436 FT_Long face_index = 0, num_faces;
437 #ifdef HAVE_FREETYPE_FTWINFNT_H
438 FT_WinFNT_HeaderRec winfnt_header;
439 #endif
440 int i, bitmap_num, internal_leading;
441 FONTSIGNATURE fs;
443 do {
444 char *family_name = fake_family;
446 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
447 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
448 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
449 return FALSE;
452 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*/
453 WARN("Ignoring font %s\n", debugstr_a(file));
454 pFT_Done_Face(ft_face);
455 return FALSE;
458 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
459 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
460 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
461 pFT_Done_Face(ft_face);
462 return FALSE;
465 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
466 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
467 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
468 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
469 "Skipping this font.\n", debugstr_a(file));
470 pFT_Done_Face(ft_face);
471 return FALSE;
474 if(!ft_face->family_name || !ft_face->style_name) {
475 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
476 pFT_Done_Face(ft_face);
477 return FALSE;
480 if(!family_name)
481 family_name = ft_face->family_name;
483 bitmap_num = 0;
484 do {
485 My_FT_Bitmap_Size *size = NULL;
487 if(!FT_IS_SCALABLE(ft_face))
488 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
490 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
491 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
492 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
494 family = NULL;
495 LIST_FOR_EACH(family_elem_ptr, &font_list) {
496 family = LIST_ENTRY(family_elem_ptr, Family, entry);
497 if(!strcmpW(family->FamilyName, FamilyW))
498 break;
499 family = NULL;
501 if(!family) {
502 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
503 family->FamilyName = FamilyW;
504 list_init(&family->faces);
505 list_add_tail(&font_list, &family->entry);
506 } else {
507 HeapFree(GetProcessHeap(), 0, FamilyW);
510 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
511 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
512 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
514 internal_leading = 0;
515 memset(&fs, 0, sizeof(fs));
517 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
518 if(pOS2) {
519 fs.fsCsb[0] = pOS2->ulCodePageRange1;
520 fs.fsCsb[1] = pOS2->ulCodePageRange2;
521 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
522 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
523 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
524 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
525 if(pOS2->version == 0) {
526 FT_UInt dummy;
528 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
529 fs.fsCsb[0] |= 1;
530 else
531 fs.fsCsb[0] |= 1L << 31;
534 #ifdef HAVE_FREETYPE_FTWINFNT_H
535 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
536 CHARSETINFO csi;
537 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
538 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
539 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
540 memcpy(&fs, &csi.fs, sizeof(csi.fs));
541 internal_leading = winfnt_header.internal_leading;
543 #endif
545 face_elem_ptr = list_head(&family->faces);
546 while(face_elem_ptr) {
547 face = LIST_ENTRY(face_elem_ptr, Face, entry);
548 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
549 if(!strcmpW(face->StyleName, StyleW) &&
550 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
551 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
552 debugstr_w(family->FamilyName), debugstr_w(StyleW),
553 face->font_version, pHeader ? pHeader->Font_Revision : 0);
555 if(fake_family) {
556 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
557 HeapFree(GetProcessHeap(), 0, StyleW);
558 pFT_Done_Face(ft_face);
559 return FALSE;
561 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
562 TRACE("Original font is newer so skipping this one\n");
563 HeapFree(GetProcessHeap(), 0, StyleW);
564 pFT_Done_Face(ft_face);
565 return FALSE;
566 } else {
567 TRACE("Replacing original with this one\n");
568 list_remove(&face->entry);
569 HeapFree(GetProcessHeap(), 0, face->file);
570 HeapFree(GetProcessHeap(), 0, face->StyleName);
571 HeapFree(GetProcessHeap(), 0, face);
572 break;
576 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
577 list_add_tail(&family->faces, &face->entry);
578 face->StyleName = StyleW;
579 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
580 strcpy(face->file, file);
581 face->face_index = face_index;
582 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
583 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
584 face->font_version = pHeader ? pHeader->Font_Revision : 0;
585 face->family = family;
586 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
587 memcpy(&face->fs, &fs, sizeof(face->fs));
588 memset(&face->fs_links, 0, sizeof(face->fs_links));
590 if(FT_IS_SCALABLE(ft_face)) {
591 memset(&face->size, 0, sizeof(face->size));
592 face->scalable = TRUE;
593 } else {
594 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
595 size->height, size->width, size->size >> 6,
596 size->x_ppem >> 6, size->y_ppem >> 6);
597 face->size.height = size->height;
598 face->size.width = size->width;
599 face->size.size = size->size;
600 face->size.x_ppem = size->x_ppem;
601 face->size.y_ppem = size->y_ppem;
602 face->size.internal_leading = internal_leading;
603 face->scalable = FALSE;
606 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
607 face->fs.fsCsb[0], face->fs.fsCsb[1],
608 face->fs.fsUsb[0], face->fs.fsUsb[1],
609 face->fs.fsUsb[2], face->fs.fsUsb[3]);
612 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
613 for(i = 0; i < ft_face->num_charmaps; i++) {
614 switch(ft_face->charmaps[i]->encoding) {
615 case FT_ENCODING_UNICODE:
616 case FT_ENCODING_APPLE_ROMAN:
617 face->fs.fsCsb[0] |= 1;
618 break;
619 case FT_ENCODING_MS_SYMBOL:
620 face->fs.fsCsb[0] |= 1L << 31;
621 break;
622 default:
623 break;
628 if(face->fs.fsCsb[0] & ~(1L << 31))
629 have_installed_roman_font = TRUE;
630 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
632 num_faces = ft_face->num_faces;
633 pFT_Done_Face(ft_face);
634 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
635 debugstr_w(StyleW));
636 } while(num_faces > ++face_index);
637 return TRUE;
640 static void DumpFontList(void)
642 Family *family;
643 Face *face;
644 struct list *family_elem_ptr, *face_elem_ptr;
646 LIST_FOR_EACH(family_elem_ptr, &font_list) {
647 family = LIST_ENTRY(family_elem_ptr, Family, entry);
648 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
649 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
650 face = LIST_ENTRY(face_elem_ptr, Face, entry);
651 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
652 if(!face->scalable)
653 TRACE(" %ld", face->size.y_ppem >> 6);
654 TRACE("\n");
657 return;
660 static Face *find_face_from_filename(const WCHAR *name)
662 Family *family;
663 Face *face;
664 char *file;
665 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
666 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
667 Face *ret = NULL;
669 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
670 TRACE("looking for %s\n", debugstr_a(nameA));
672 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
674 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
676 file = strrchr(face->file, '/');
677 if(!file)
678 file = face->file;
679 else
680 file++;
681 if(!strcmp(file, nameA))
682 ret = face;
683 break;
686 HeapFree(GetProcessHeap(), 0, nameA);
687 return ret;
690 static Family *find_family_from_name(const WCHAR *name)
692 Family *family;
694 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
696 if(!strcmpiW(family->FamilyName, name))
697 return family;
700 return NULL;
703 static void DumpSubstList(void)
705 FontSubst *psub;
707 for(psub = substlist; psub; psub = psub->next)
708 if(psub->from.charset != -1 || psub->to.charset != -1)
709 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
710 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
711 else
712 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
713 debugstr_w(psub->to.name));
714 return;
717 static LPWSTR strdupW(LPCWSTR p)
719 LPWSTR ret;
720 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
721 ret = HeapAlloc(GetProcessHeap(), 0, len);
722 memcpy(ret, p, len);
723 return ret;
726 static LPSTR strdupA(LPCSTR p)
728 LPSTR ret;
729 DWORD len = (strlen(p) + 1);
730 ret = HeapAlloc(GetProcessHeap(), 0, len);
731 memcpy(ret, p, len);
732 return ret;
735 static void split_subst_info(NameCs *nc, LPSTR str)
737 CHAR *p = strrchr(str, ',');
738 DWORD len;
740 nc->charset = -1;
741 if(p && *(p+1)) {
742 nc->charset = strtol(p+1, NULL, 10);
743 *p = '\0';
745 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
746 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
747 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
750 static void LoadSubstList(void)
752 FontSubst *psub, **ppsub;
753 HKEY hkey;
754 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
755 LPSTR value;
756 LPVOID data;
758 if(substlist) {
759 for(psub = substlist; psub;) {
760 FontSubst *ptmp;
761 HeapFree(GetProcessHeap(), 0, psub->to.name);
762 HeapFree(GetProcessHeap(), 0, psub->from.name);
763 ptmp = psub;
764 psub = psub->next;
765 HeapFree(GetProcessHeap(), 0, ptmp);
767 substlist = NULL;
770 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
771 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
772 &hkey) == ERROR_SUCCESS) {
774 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
775 &valuelen, &datalen, NULL, NULL);
777 valuelen++; /* returned value doesn't include room for '\0' */
778 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
779 data = HeapAlloc(GetProcessHeap(), 0, datalen);
781 dlen = datalen;
782 vlen = valuelen;
783 ppsub = &substlist;
784 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
785 &dlen) == ERROR_SUCCESS) {
786 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
788 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
789 (*ppsub)->next = NULL;
790 split_subst_info(&((*ppsub)->from), value);
791 split_subst_info(&((*ppsub)->to), data);
793 /* Win 2000 doesn't allow mapping between different charsets
794 or mapping of DEFAULT_CHARSET */
795 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
796 (*ppsub)->to.charset == DEFAULT_CHARSET) {
797 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
798 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
799 HeapFree(GetProcessHeap(), 0, *ppsub);
800 *ppsub = NULL;
801 } else {
802 ppsub = &((*ppsub)->next);
804 /* reset dlen and vlen */
805 dlen = datalen;
806 vlen = valuelen;
808 HeapFree(GetProcessHeap(), 0, data);
809 HeapFree(GetProcessHeap(), 0, value);
810 RegCloseKey(hkey);
814 /***********************************************************
815 * The replacement list is a way to map an entire font
816 * family onto another family. For example adding
818 * [HKCU\Software\Wine\Fonts\Replacements]
819 * "Wingdings"="Winedings"
821 * would enumerate the Winedings font both as Winedings and
822 * Wingdings. However if a real Wingdings font is present the
823 * replacement does not take place.
826 static void LoadReplaceList(void)
828 HKEY hkey;
829 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
830 LPSTR value;
831 LPVOID data;
832 Family *family;
833 Face *face;
834 struct list *family_elem_ptr, *face_elem_ptr;
835 WCHAR old_nameW[200];
837 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
838 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
840 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
841 &valuelen, &datalen, NULL, NULL);
843 valuelen++; /* returned value doesn't include room for '\0' */
844 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
845 data = HeapAlloc(GetProcessHeap(), 0, datalen);
847 dlen = datalen;
848 vlen = valuelen;
849 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
850 &dlen) == ERROR_SUCCESS) {
851 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
852 /* "NewName"="Oldname" */
853 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
854 break;
856 /* Find the old family and hence all of the font files
857 in that family */
858 LIST_FOR_EACH(family_elem_ptr, &font_list) {
859 family = LIST_ENTRY(family_elem_ptr, Family, entry);
860 if(!strcmpiW(family->FamilyName, old_nameW)) {
861 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
862 face = LIST_ENTRY(face_elem_ptr, Face, entry);
863 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
864 debugstr_w(face->StyleName), value);
865 /* Now add a new entry with the new family name */
866 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
868 break;
871 /* reset dlen and vlen */
872 dlen = datalen;
873 vlen = valuelen;
875 HeapFree(GetProcessHeap(), 0, data);
876 HeapFree(GetProcessHeap(), 0, value);
877 RegCloseKey(hkey);
881 /*************************************************************
882 * init_system_links
884 static BOOL init_system_links(void)
886 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
887 'W','i','n','d','o','w','s',' ','N','T','\\',
888 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
889 'S','y','s','t','e','m','L','i','n','k',0};
890 HKEY hkey;
891 BOOL ret = FALSE;
892 DWORD type, max_val, max_data, val_len, data_len, index;
893 WCHAR *value, *data;
894 WCHAR *entry, *next;
895 SYSTEM_LINKS *font_link, *system_font_link;
896 CHILD_FONT *child_font;
897 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
898 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
899 static const WCHAR System[] = {'S','y','s','t','e','m',0};
900 FONTSIGNATURE fs;
901 Family *family;
902 Face *face;
904 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
906 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
907 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
908 data = HeapAlloc(GetProcessHeap(), 0, max_data);
909 val_len = max_val + 1;
910 data_len = max_data;
911 index = 0;
912 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
914 TRACE("%s:\n", debugstr_w(value));
916 memset(&fs, 0, sizeof(fs));
917 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
918 font_link->font_name = strdupW(value);
919 list_init(&font_link->links);
920 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
922 WCHAR *face_name;
923 INT index;
924 CHILD_FONT *child_font;
926 TRACE("\t%s\n", debugstr_w(entry));
928 next = entry + strlenW(entry) + 1;
930 face_name = strchrW(entry, ',');
931 if(!face_name)
932 index = 0;
933 else
935 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
936 *face_name++ = 0;
937 while(isspaceW(*face_name))
938 face_name++;
940 index = 0;
942 face = find_face_from_filename(entry);
943 if(!face)
945 TRACE("Unable to find file %s\n", debugstr_w(entry));
946 continue;
949 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
950 child_font->file_name = strdupA(face->file);
951 child_font->index = index;
952 child_font->font = NULL;
953 fs.fsCsb[0] |= face->fs.fsCsb[0];
954 fs.fsCsb[1] |= face->fs.fsCsb[1];
955 list_add_tail(&font_link->links, &child_font->entry);
957 family = find_family_from_name(font_link->font_name);
958 if(family)
960 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
962 memcpy(&face->fs_links, &fs, sizeof(fs));
965 list_add_tail(&system_links, &font_link->entry);
966 val_len = max_val + 1;
967 data_len = max_data;
970 HeapFree(GetProcessHeap(), 0, value);
971 HeapFree(GetProcessHeap(), 0, data);
972 RegCloseKey(hkey);
975 /* Explicitly add an entry for the system font, this links to Tahoma and any links
976 that Tahoma has */
978 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
979 system_font_link->font_name = strdupW(System);
980 list_init(&system_font_link->links);
982 face = find_face_from_filename(tahoma_ttf);
983 if(face)
985 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
986 child_font->file_name = strdupA(face->file);
987 child_font->index = 0;
988 child_font->font = NULL;
989 list_add_tail(&system_font_link->links, &child_font->entry);
991 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
993 if(!strcmpiW(font_link->font_name, Tahoma))
995 CHILD_FONT *font_link_entry;
996 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
998 CHILD_FONT *new_child;
999 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1000 new_child->file_name = strdupA(font_link_entry->file_name);
1001 new_child->index = font_link_entry->index;
1002 new_child->font = NULL;
1003 list_add_tail(&system_font_link->links, &new_child->entry);
1005 break;
1008 list_add_tail(&system_links, &system_font_link->entry);
1009 return ret;
1012 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1014 DIR *dir;
1015 struct dirent *dent;
1016 char path[MAX_PATH];
1018 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1020 dir = opendir(dirname);
1021 if(!dir) {
1022 ERR("Can't open directory %s\n", debugstr_a(dirname));
1023 return FALSE;
1025 while((dent = readdir(dir)) != NULL) {
1026 struct stat statbuf;
1028 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1029 continue;
1031 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1033 sprintf(path, "%s/%s", dirname, dent->d_name);
1035 if(stat(path, &statbuf) == -1)
1037 WARN("Can't stat %s\n", debugstr_a(path));
1038 continue;
1040 if(S_ISDIR(statbuf.st_mode))
1041 ReadFontDir(path, external_fonts);
1042 else
1043 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1045 closedir(dir);
1046 return TRUE;
1049 static void load_fontconfig_fonts(void)
1051 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1052 void *fc_handle = NULL;
1053 FcConfig *config;
1054 FcPattern *pat;
1055 FcObjectSet *os;
1056 FcFontSet *fontset;
1057 FcValue v;
1058 int i, len;
1059 const char *file, *ext;
1061 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1062 if(!fc_handle) {
1063 TRACE("Wine cannot find the fontconfig library (%s).\n",
1064 SONAME_LIBFONTCONFIG);
1065 return;
1067 #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;}
1068 LOAD_FUNCPTR(FcConfigGetCurrent);
1069 LOAD_FUNCPTR(FcFontList);
1070 LOAD_FUNCPTR(FcFontSetDestroy);
1071 LOAD_FUNCPTR(FcInit);
1072 LOAD_FUNCPTR(FcObjectSetAdd);
1073 LOAD_FUNCPTR(FcObjectSetCreate);
1074 LOAD_FUNCPTR(FcObjectSetDestroy);
1075 LOAD_FUNCPTR(FcPatternCreate);
1076 LOAD_FUNCPTR(FcPatternDestroy);
1077 LOAD_FUNCPTR(FcPatternGet);
1078 #undef LOAD_FUNCPTR
1080 if(!pFcInit()) return;
1082 config = pFcConfigGetCurrent();
1083 pat = pFcPatternCreate();
1084 os = pFcObjectSetCreate();
1085 pFcObjectSetAdd(os, FC_FILE);
1086 fontset = pFcFontList(config, pat, os);
1087 if(!fontset) return;
1088 for(i = 0; i < fontset->nfont; i++) {
1089 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1090 continue;
1091 if(v.type != FcTypeString) continue;
1092 file = (LPCSTR) v.u.s;
1093 TRACE("fontconfig: %s\n", file);
1095 /* We're just interested in OT/TT fonts for now, so this hack just
1096 picks up the standard extensions to save time loading every other
1097 font */
1098 len = strlen( file );
1099 if(len < 4) continue;
1100 ext = &file[ len - 3 ];
1101 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1102 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1104 pFcFontSetDestroy(fontset);
1105 pFcObjectSetDestroy(os);
1106 pFcPatternDestroy(pat);
1107 sym_not_found:
1108 #endif
1109 return;
1113 static void load_system_fonts(void)
1115 HKEY hkey;
1116 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1117 const WCHAR **value;
1118 DWORD dlen, type;
1119 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1120 char *unixname;
1122 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1123 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1124 strcatW(windowsdir, fontsW);
1125 for(value = SystemFontValues; *value; value++) {
1126 dlen = sizeof(data);
1127 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1128 type == REG_SZ) {
1129 sprintfW(pathW, fmtW, windowsdir, data);
1130 if((unixname = wine_get_unix_file_name(pathW))) {
1131 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1132 HeapFree(GetProcessHeap(), 0, unixname);
1136 RegCloseKey(hkey);
1140 /*************************************************************
1142 * This adds registry entries for any externally loaded fonts
1143 * (fonts from fontconfig or FontDirs). It also deletes entries
1144 * of no longer existing fonts.
1147 static void update_reg_entries(void)
1149 HKEY winkey = 0, externalkey = 0;
1150 LPWSTR valueW;
1151 LPVOID data;
1152 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1153 Family *family;
1154 Face *face;
1155 struct list *family_elem_ptr, *face_elem_ptr;
1156 WCHAR *file;
1157 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1158 static const WCHAR spaceW[] = {' ', '\0'};
1159 char *path;
1161 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1162 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1163 ERR("Can't create Windows font reg key\n");
1164 goto end;
1166 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1167 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1168 ERR("Can't create external font reg key\n");
1169 goto end;
1172 /* Delete all external fonts added last time */
1174 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1175 &valuelen, &datalen, NULL, NULL);
1176 valuelen++; /* returned value doesn't include room for '\0' */
1177 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1178 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1180 dlen = datalen * sizeof(WCHAR);
1181 vlen = valuelen;
1182 i = 0;
1183 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1184 &dlen) == ERROR_SUCCESS) {
1186 RegDeleteValueW(winkey, valueW);
1187 /* reset dlen and vlen */
1188 dlen = datalen;
1189 vlen = valuelen;
1191 HeapFree(GetProcessHeap(), 0, data);
1192 HeapFree(GetProcessHeap(), 0, valueW);
1194 /* Delete the old external fonts key */
1195 RegCloseKey(externalkey);
1196 externalkey = 0;
1197 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1199 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1200 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1201 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1202 ERR("Can't create external font reg key\n");
1203 goto end;
1206 /* enumerate the fonts and add external ones to the two keys */
1208 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1209 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1210 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1211 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1212 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1213 if(!face->external) continue;
1214 len = len_fam;
1215 if(strcmpiW(face->StyleName, RegularW))
1216 len = len_fam + strlenW(face->StyleName) + 1;
1217 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1218 strcpyW(valueW, family->FamilyName);
1219 if(len != len_fam) {
1220 strcatW(valueW, spaceW);
1221 strcatW(valueW, face->StyleName);
1223 strcatW(valueW, TrueType);
1224 if((path = strrchr(face->file, '/')) == NULL)
1225 path = face->file;
1226 else
1227 path++;
1228 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1230 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1231 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1232 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1233 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1235 HeapFree(GetProcessHeap(), 0, file);
1236 HeapFree(GetProcessHeap(), 0, valueW);
1239 end:
1240 if(externalkey)
1241 RegCloseKey(externalkey);
1242 if(winkey)
1243 RegCloseKey(winkey);
1244 return;
1248 /*************************************************************
1249 * WineEngAddFontResourceEx
1252 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1254 if (ft_handle) /* do it only if we have freetype up and running */
1256 char *unixname;
1258 if(flags)
1259 FIXME("Ignoring flags %lx\n", flags);
1261 if((unixname = wine_get_unix_file_name(file)))
1263 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1264 HeapFree(GetProcessHeap(), 0, unixname);
1267 return 1;
1270 /*************************************************************
1271 * WineEngRemoveFontResourceEx
1274 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1276 FIXME(":stub\n");
1277 return TRUE;
1280 static const struct nls_update_font_list
1282 UINT ansi_cp, oem_cp;
1283 const char *oem, *fixed, *system;
1284 const char *courier, *serif, *small, *sserif;
1285 } nls_update_font_list[] =
1287 /* Arabic */
1288 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1289 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1291 /* Baltic */
1292 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1293 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1295 /* Chinese Simplified */
1296 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1297 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1299 /* Chinese Traditional */
1300 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1301 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1303 /* Central European */
1304 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1305 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1307 /* Cyrillic */
1308 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1309 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1311 /* Greek */
1312 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1313 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1315 /* Hebrew */
1316 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1317 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1319 /* "Japanese */
1320 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1321 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1323 /* Korean */
1324 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1325 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1327 /* Thai */
1328 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1329 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1331 /* Turkish */
1332 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1333 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1335 /* Vietnamese */
1336 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1337 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1339 /* English (United States) */
1340 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1341 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1343 /* English (United Kingdom) */
1344 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1345 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1349 inline static HKEY create_fonts_NT_registry_key(void)
1351 HKEY hkey = 0;
1353 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1354 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1355 return hkey;
1358 inline static HKEY create_fonts_9x_registry_key(void)
1360 HKEY hkey = 0;
1362 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1363 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1364 return hkey;
1367 inline static HKEY create_config_fonts_registry_key(void)
1369 HKEY hkey = 0;
1371 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1372 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1373 return hkey;
1376 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1378 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1379 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1380 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1381 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1384 static void update_font_info(void)
1386 char buf[80];
1387 DWORD len, type;
1388 HKEY hkey = 0;
1389 UINT i, ansi_cp = 0, oem_cp = 0;
1390 LCID lcid = GetUserDefaultLCID();
1392 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1393 return;
1395 len = sizeof(buf);
1396 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1398 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1400 RegCloseKey(hkey);
1401 return;
1403 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1405 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1407 sprintf(buf, "%08lx", lcid);
1408 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1409 RegCloseKey(hkey);
1411 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1412 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1413 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1414 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1416 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1418 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1419 nls_update_font_list[i].oem_cp == oem_cp)
1421 HKEY hkey;
1423 hkey = create_config_fonts_registry_key();
1424 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1425 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1426 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1427 RegCloseKey(hkey);
1429 hkey = create_fonts_NT_registry_key();
1430 add_font_list(hkey, &nls_update_font_list[i]);
1431 RegCloseKey(hkey);
1433 hkey = create_fonts_9x_registry_key();
1434 add_font_list(hkey, &nls_update_font_list[i]);
1435 RegCloseKey(hkey);
1437 return;
1440 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1443 /*************************************************************
1444 * WineEngInit
1446 * Initialize FreeType library and create a list of available faces
1448 BOOL WineEngInit(void)
1450 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1451 static const WCHAR pathW[] = {'P','a','t','h',0};
1452 HKEY hkey;
1453 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1454 LPVOID data;
1455 WCHAR windowsdir[MAX_PATH];
1456 char *unixname;
1457 HANDLE font_mutex;
1459 TRACE("\n");
1461 /* update locale dependent font info in registry */
1462 update_font_info();
1464 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1465 if(!ft_handle) {
1466 WINE_MESSAGE(
1467 "Wine cannot find the FreeType font library. To enable Wine to\n"
1468 "use TrueType fonts please install a version of FreeType greater than\n"
1469 "or equal to 2.0.5.\n"
1470 "http://www.freetype.org\n");
1471 return FALSE;
1474 #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;}
1476 LOAD_FUNCPTR(FT_Vector_Unit)
1477 LOAD_FUNCPTR(FT_Done_Face)
1478 LOAD_FUNCPTR(FT_Get_Char_Index)
1479 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1480 LOAD_FUNCPTR(FT_Init_FreeType)
1481 LOAD_FUNCPTR(FT_Load_Glyph)
1482 LOAD_FUNCPTR(FT_Matrix_Multiply)
1483 LOAD_FUNCPTR(FT_MulFix)
1484 LOAD_FUNCPTR(FT_New_Face)
1485 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1486 LOAD_FUNCPTR(FT_Outline_Transform)
1487 LOAD_FUNCPTR(FT_Outline_Translate)
1488 LOAD_FUNCPTR(FT_Select_Charmap)
1489 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1490 LOAD_FUNCPTR(FT_Vector_Transform)
1492 #undef LOAD_FUNCPTR
1493 /* Don't warn if this one is missing */
1494 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1495 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1496 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1497 #ifdef HAVE_FREETYPE_FTWINFNT_H
1498 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1499 #endif
1500 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1501 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1502 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1503 <= 2.0.3 has FT_Sqrt64 */
1504 goto sym_not_found;
1507 if(pFT_Init_FreeType(&library) != 0) {
1508 ERR("Can't init FreeType library\n");
1509 wine_dlclose(ft_handle, NULL, 0);
1510 ft_handle = NULL;
1511 return FALSE;
1513 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1514 if (pFT_Library_Version)
1516 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1518 if (FT_Version.major<=0)
1520 FT_Version.major=2;
1521 FT_Version.minor=0;
1522 FT_Version.patch=5;
1524 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1525 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1526 ((FT_Version.minor << 8) & 0x00ff00) |
1527 ((FT_Version.patch ) & 0x0000ff);
1529 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1530 ERR("Failed to create font mutex\n");
1531 return FALSE;
1533 WaitForSingleObject(font_mutex, INFINITE);
1535 /* load the system fonts */
1536 load_system_fonts();
1538 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1539 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1540 strcatW(windowsdir, fontsW);
1541 if((unixname = wine_get_unix_file_name(windowsdir)))
1543 ReadFontDir(unixname, FALSE);
1544 HeapFree(GetProcessHeap(), 0, unixname);
1547 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1548 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1549 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1550 will skip these. */
1551 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1552 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1553 &hkey) == ERROR_SUCCESS) {
1554 LPWSTR valueW;
1555 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1556 &valuelen, &datalen, NULL, NULL);
1558 valuelen++; /* returned value doesn't include room for '\0' */
1559 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1560 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1561 if (valueW && data)
1563 dlen = datalen * sizeof(WCHAR);
1564 vlen = valuelen;
1565 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1566 &dlen) == ERROR_SUCCESS) {
1567 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1569 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1571 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1572 HeapFree(GetProcessHeap(), 0, unixname);
1575 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1577 WCHAR pathW[MAX_PATH];
1578 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1579 sprintfW(pathW, fmtW, windowsdir, data);
1580 if((unixname = wine_get_unix_file_name(pathW)))
1582 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1583 HeapFree(GetProcessHeap(), 0, unixname);
1586 /* reset dlen and vlen */
1587 dlen = datalen;
1588 vlen = valuelen;
1591 HeapFree(GetProcessHeap(), 0, data);
1592 HeapFree(GetProcessHeap(), 0, valueW);
1593 RegCloseKey(hkey);
1596 load_fontconfig_fonts();
1598 /* then look in any directories that we've specified in the config file */
1599 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1600 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1602 DWORD len;
1603 LPWSTR valueW;
1604 LPSTR valueA, ptr;
1606 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1608 len += sizeof(WCHAR);
1609 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1610 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1612 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1613 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1614 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1615 TRACE( "got font path %s\n", debugstr_a(valueA) );
1616 ptr = valueA;
1617 while (ptr)
1619 LPSTR next = strchr( ptr, ':' );
1620 if (next) *next++ = 0;
1621 ReadFontDir( ptr, TRUE );
1622 ptr = next;
1624 HeapFree( GetProcessHeap(), 0, valueA );
1626 HeapFree( GetProcessHeap(), 0, valueW );
1628 RegCloseKey(hkey);
1631 DumpFontList();
1632 LoadSubstList();
1633 DumpSubstList();
1634 LoadReplaceList();
1635 update_reg_entries();
1637 init_system_links();
1639 ReleaseMutex(font_mutex);
1640 return TRUE;
1641 sym_not_found:
1642 WINE_MESSAGE(
1643 "Wine cannot find certain functions that it needs inside the FreeType\n"
1644 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1645 "FreeType to at least version 2.0.5.\n"
1646 "http://www.freetype.org\n");
1647 wine_dlclose(ft_handle, NULL, 0);
1648 ft_handle = NULL;
1649 return FALSE;
1653 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1655 TT_OS2 *pOS2;
1656 TT_HoriHeader *pHori;
1658 LONG ppem;
1660 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1661 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1663 if(height == 0) height = 16;
1665 /* Calc. height of EM square:
1667 * For +ve lfHeight we have
1668 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1669 * Re-arranging gives:
1670 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1672 * For -ve lfHeight we have
1673 * |lfHeight| = ppem
1674 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1675 * with il = winAscent + winDescent - units_per_em]
1679 if(height > 0) {
1680 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1681 ppem = ft_face->units_per_EM * height /
1682 (pHori->Ascender - pHori->Descender);
1683 else
1684 ppem = ft_face->units_per_EM * height /
1685 (pOS2->usWinAscent + pOS2->usWinDescent);
1687 else
1688 ppem = -height;
1690 return ppem;
1693 static LONG load_VDMX(GdiFont, LONG);
1695 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1697 FT_Error err;
1698 FT_Face ft_face;
1700 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1701 err = pFT_New_Face(library, file, face_index, &ft_face);
1702 if(err) {
1703 ERR("FT_New_Face rets %d\n", err);
1704 return 0;
1707 /* set it here, as load_VDMX needs it */
1708 font->ft_face = ft_face;
1710 if(FT_IS_SCALABLE(ft_face)) {
1711 /* load the VDMX table if we have one */
1712 font->ppem = load_VDMX(font, height);
1713 if(font->ppem == 0)
1714 font->ppem = calc_ppem_for_height(ft_face, height);
1716 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1717 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1718 } else {
1719 font->ppem = height;
1720 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1721 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1723 return ft_face;
1727 static int get_nearest_charset(Face *face, int *cp)
1729 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1730 a single face with the requested charset. The idea is to check if
1731 the selected font supports the current ANSI codepage, if it does
1732 return the corresponding charset, else return the first charset */
1734 CHARSETINFO csi;
1735 int acp = GetACP(), i;
1736 DWORD fs0;
1738 *cp = acp;
1739 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1740 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1741 return csi.ciCharset;
1743 for(i = 0; i < 32; i++) {
1744 fs0 = 1L << i;
1745 if(face->fs.fsCsb[0] & fs0) {
1746 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1747 *cp = csi.ciACP;
1748 return csi.ciCharset;
1750 else
1751 FIXME("TCI failing on %lx\n", fs0);
1755 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1756 face->fs.fsCsb[0], face->file);
1757 *cp = acp;
1758 return DEFAULT_CHARSET;
1761 static GdiFont alloc_font(void)
1763 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1764 ret->gmsize = INIT_GM_SIZE;
1765 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1766 ret->gmsize * sizeof(*ret->gm));
1767 ret->potm = NULL;
1768 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1769 list_init(&ret->hfontlist);
1770 list_init(&ret->child_fonts);
1771 return ret;
1774 static void free_font(GdiFont font)
1776 struct list *cursor, *cursor2;
1778 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1780 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1781 struct list *first_hfont;
1782 HFONTLIST *hfontlist;
1783 list_remove(cursor);
1784 if(child->font)
1786 first_hfont = list_head(&child->font->hfontlist);
1787 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1788 DeleteObject(hfontlist->hfont);
1789 HeapFree(GetProcessHeap(), 0, hfontlist);
1790 free_font(child->font);
1792 HeapFree(GetProcessHeap(), 0, child->file_name);
1793 HeapFree(GetProcessHeap(), 0, child);
1796 if (font->ft_face) pFT_Done_Face(font->ft_face);
1797 HeapFree(GetProcessHeap(), 0, font->potm);
1798 HeapFree(GetProcessHeap(), 0, font->name);
1799 HeapFree(GetProcessHeap(), 0, font->gm);
1800 HeapFree(GetProcessHeap(), 0, font);
1804 /*************************************************************
1805 * load_VDMX
1807 * load the vdmx entry for the specified height
1810 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1811 ( ( (FT_ULong)_x4 << 24 ) | \
1812 ( (FT_ULong)_x3 << 16 ) | \
1813 ( (FT_ULong)_x2 << 8 ) | \
1814 (FT_ULong)_x1 )
1816 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1818 typedef struct {
1819 BYTE bCharSet;
1820 BYTE xRatio;
1821 BYTE yStartRatio;
1822 BYTE yEndRatio;
1823 } Ratios;
1826 static LONG load_VDMX(GdiFont font, LONG height)
1828 BYTE hdr[6], tmp[2], group[4];
1829 BYTE devXRatio, devYRatio;
1830 USHORT numRecs, numRatios;
1831 DWORD result, offset = -1;
1832 LONG ppem = 0;
1833 int i;
1835 /* For documentation on VDMX records, see
1836 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1839 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1841 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1842 return ppem;
1844 /* FIXME: need the real device aspect ratio */
1845 devXRatio = 1;
1846 devYRatio = 1;
1848 numRecs = GET_BE_WORD(&hdr[2]);
1849 numRatios = GET_BE_WORD(&hdr[4]);
1851 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1852 for(i = 0; i < numRatios; i++) {
1853 Ratios ratio;
1855 offset = (3 * 2) + (i * sizeof(Ratios));
1856 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1857 offset = -1;
1859 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1861 if((ratio.xRatio == 0 &&
1862 ratio.yStartRatio == 0 &&
1863 ratio.yEndRatio == 0) ||
1864 (devXRatio == ratio.xRatio &&
1865 devYRatio >= ratio.yStartRatio &&
1866 devYRatio <= ratio.yEndRatio))
1868 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1869 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1870 offset = GET_BE_WORD(tmp);
1871 break;
1875 if(offset == -1) {
1876 FIXME("No suitable ratio found\n");
1877 return ppem;
1880 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1881 USHORT recs;
1882 BYTE startsz, endsz;
1883 BYTE *vTable;
1885 recs = GET_BE_WORD(group);
1886 startsz = group[2];
1887 endsz = group[3];
1889 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1891 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1892 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1893 if(result == GDI_ERROR) {
1894 FIXME("Failed to retrieve vTable\n");
1895 goto end;
1898 if(height > 0) {
1899 for(i = 0; i < recs; i++) {
1900 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1901 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1902 ppem = GET_BE_WORD(&vTable[i * 6]);
1904 if(yMax + -yMin == height) {
1905 font->yMax = yMax;
1906 font->yMin = yMin;
1907 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1908 break;
1910 if(yMax + -yMin > height) {
1911 if(--i < 0) {
1912 ppem = 0;
1913 goto end; /* failed */
1915 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1916 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1917 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1918 break;
1921 if(!font->yMax) {
1922 ppem = 0;
1923 TRACE("ppem not found for height %ld\n", height);
1925 } else {
1926 ppem = -height;
1927 if(ppem < startsz || ppem > endsz)
1928 goto end;
1930 for(i = 0; i < recs; i++) {
1931 USHORT yPelHeight;
1932 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1934 if(yPelHeight > ppem)
1935 break; /* failed */
1937 if(yPelHeight == ppem) {
1938 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1939 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1940 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1941 break;
1945 end:
1946 HeapFree(GetProcessHeap(), 0, vTable);
1949 return ppem;
1952 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1954 if(font->font_desc.hash != fd->hash) return TRUE;
1955 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1956 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1957 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1960 static void calc_hash(FONT_DESC *pfd)
1962 DWORD hash = 0, *ptr, two_chars;
1963 WORD *pwc;
1964 unsigned int i;
1966 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1967 hash ^= *ptr;
1968 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1969 hash ^= *ptr;
1970 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1971 two_chars = *ptr;
1972 pwc = (WCHAR *)&two_chars;
1973 if(!*pwc) break;
1974 *pwc = toupperW(*pwc);
1975 pwc++;
1976 *pwc = toupperW(*pwc);
1977 hash ^= two_chars;
1978 if(!*pwc) break;
1980 pfd->hash = hash;
1981 return;
1984 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1986 GdiFont ret;
1987 FONT_DESC fd;
1988 HFONTLIST *hflist;
1989 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1991 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1992 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1993 calc_hash(&fd);
1995 /* try the in-use list */
1996 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1997 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1998 if(!fontcmp(ret, &fd)) {
1999 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2000 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2001 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2002 if(hflist->hfont == hfont)
2003 return ret;
2005 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2006 hflist->hfont = hfont;
2007 list_add_head(&ret->hfontlist, &hflist->entry);
2008 return ret;
2012 /* then the unused list */
2013 font_elem_ptr = list_head(&unused_gdi_font_list);
2014 while(font_elem_ptr) {
2015 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2016 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2017 if(!fontcmp(ret, &fd)) {
2018 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2019 assert(list_empty(&ret->hfontlist));
2020 TRACE("Found %p in unused list\n", ret);
2021 list_remove(&ret->entry);
2022 list_add_head(&gdi_font_list, &ret->entry);
2023 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2024 hflist->hfont = hfont;
2025 list_add_head(&ret->hfontlist, &hflist->entry);
2026 return ret;
2029 return NULL;
2033 /*************************************************************
2034 * create_child_font_list
2036 static BOOL create_child_font_list(GdiFont font)
2038 BOOL ret = FALSE;
2039 SYSTEM_LINKS *font_link;
2040 CHILD_FONT *font_link_entry, *new_child;
2042 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2044 if(!strcmpW(font_link->font_name, font->name))
2046 TRACE("found entry in system list\n");
2047 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2049 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2050 new_child->file_name = strdupA(font_link_entry->file_name);
2051 new_child->index = font_link_entry->index;
2052 new_child->font = NULL;
2053 list_add_tail(&font->child_fonts, &new_child->entry);
2054 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2056 ret = TRUE;
2057 break;
2061 return ret;
2064 /*************************************************************
2065 * WineEngCreateFontInstance
2068 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2070 GdiFont ret;
2071 Face *face, *best;
2072 Family *family;
2073 struct list *family_elem_ptr, *face_elem_ptr;
2074 INT height, width = 0;
2075 signed int diff = 0, newdiff;
2076 BOOL bd, it, can_use_bitmap;
2077 LOGFONTW lf;
2078 CHARSETINFO csi;
2079 HFONTLIST *hflist;
2081 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2083 struct list *first_hfont = list_head(&ret->hfontlist);
2084 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2085 if(hflist->hfont == hfont)
2086 return ret;
2089 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2090 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2092 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2093 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2094 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2095 lf.lfEscapement);
2097 /* check the cache first */
2098 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2099 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2100 return ret;
2103 TRACE("not in cache\n");
2104 if(list_empty(&font_list)) /* No fonts installed */
2106 TRACE("No fonts installed\n");
2107 return NULL;
2109 if(!have_installed_roman_font)
2111 TRACE("No roman font installed\n");
2112 return NULL;
2115 ret = alloc_font();
2117 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2118 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2119 calc_hash(&ret->font_desc);
2120 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2121 hflist->hfont = hfont;
2122 list_add_head(&ret->hfontlist, &hflist->entry);
2125 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2126 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2127 original value lfCharSet. Note this is a special case for
2128 Symbol and doesn't happen at least for "Wingdings*" */
2130 if(!strcmpiW(lf.lfFaceName, SymbolW))
2131 lf.lfCharSet = SYMBOL_CHARSET;
2133 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2134 switch(lf.lfCharSet) {
2135 case DEFAULT_CHARSET:
2136 csi.fs.fsCsb[0] = 0;
2137 break;
2138 default:
2139 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2140 csi.fs.fsCsb[0] = 0;
2141 break;
2145 family = NULL;
2146 if(lf.lfFaceName[0] != '\0') {
2147 FontSubst *psub;
2148 for(psub = substlist; psub; psub = psub->next)
2149 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
2150 (psub->from.charset == -1 ||
2151 psub->from.charset == lf.lfCharSet))
2152 break;
2153 if(psub) {
2154 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2155 debugstr_w(psub->to.name));
2156 strcpyW(lf.lfFaceName, psub->to.name);
2159 /* We want a match on name and charset or just name if
2160 charset was DEFAULT_CHARSET. If the latter then
2161 we fixup the returned charset later in get_nearest_charset
2162 where we'll either use the charset of the current ansi codepage
2163 or if that's unavailable the first charset that the font supports.
2165 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2166 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2167 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2168 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2169 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2170 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2171 if(face->scalable || can_use_bitmap)
2172 goto found;
2178 /* If requested charset was DEFAULT_CHARSET then try using charset
2179 corresponding to the current ansi codepage */
2180 if(!csi.fs.fsCsb[0]) {
2181 INT acp = GetACP();
2182 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2183 FIXME("TCI failed on codepage %d\n", acp);
2184 csi.fs.fsCsb[0] = 0;
2185 } else
2186 lf.lfCharSet = csi.ciCharset;
2189 /* Face families are in the top 4 bits of lfPitchAndFamily,
2190 so mask with 0xF0 before testing */
2192 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2193 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2194 strcpyW(lf.lfFaceName, defFixed);
2195 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2196 strcpyW(lf.lfFaceName, defSerif);
2197 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2198 strcpyW(lf.lfFaceName, defSans);
2199 else
2200 strcpyW(lf.lfFaceName, defSans);
2201 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2202 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2203 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2204 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2205 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2206 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2207 if(face->scalable || can_use_bitmap)
2208 goto found;
2213 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2214 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2215 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2216 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2217 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2218 if(face->scalable || can_use_bitmap)
2219 goto found;
2224 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2225 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2226 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2227 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2228 if(face->scalable || can_use_bitmap) {
2229 csi.fs.fsCsb[0] = 0;
2230 FIXME("just using first face for now\n");
2231 goto found;
2235 FIXME("can't find a single appropriate font - bailing\n");
2236 free_font(ret);
2237 return NULL;
2239 found:
2240 it = lf.lfItalic ? 1 : 0;
2241 bd = lf.lfWeight > 550 ? 1 : 0;
2243 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2244 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2246 face = best = NULL;
2247 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2248 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2249 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2250 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2251 if(face->scalable)
2252 break;
2253 if(height > 0)
2254 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2255 else
2256 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2257 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2258 (diff < 0 && newdiff > diff)) {
2259 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2260 diff = newdiff;
2261 best = face;
2262 if(diff == 0)
2263 break;
2266 face = NULL;
2268 if(!face && best)
2269 face = best;
2270 else if(!face) {
2271 best = NULL;
2272 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2273 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2274 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2275 if(face->scalable)
2276 break;
2277 if(height > 0)
2278 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2279 else
2280 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2281 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2282 (diff < 0 && newdiff > diff)) {
2283 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2284 diff = newdiff;
2285 best = face;
2286 if(diff == 0)
2287 break;
2290 face = NULL;
2292 if(!face && best)
2293 face = best;
2294 if(it && !face->Italic) ret->fake_italic = TRUE;
2295 if(bd && !face->Bold) ret->fake_bold = TRUE;
2298 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2300 if(csi.fs.fsCsb[0]) {
2301 ret->charset = lf.lfCharSet;
2302 ret->codepage = csi.ciACP;
2304 else
2305 ret->charset = get_nearest_charset(face, &ret->codepage);
2307 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2308 debugstr_w(face->StyleName), face->file, face->face_index);
2310 if(!face->scalable) {
2311 width = face->size.x_ppem >> 6;
2312 height = face->size.y_ppem >> 6;
2314 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2316 if (!ret->ft_face)
2318 free_font( ret );
2319 return 0;
2322 if (ret->charset == SYMBOL_CHARSET &&
2323 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2324 /* No ops */
2326 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2327 /* No ops */
2329 else {
2330 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2333 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2334 ret->name = strdupW(family->FamilyName);
2335 ret->underline = lf.lfUnderline ? 0xff : 0;
2336 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2337 create_child_font_list(ret);
2339 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2341 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2342 list_add_head(&gdi_font_list, &ret->entry);
2343 return ret;
2346 static void dump_gdi_font_list(void)
2348 GdiFont gdiFont;
2349 struct list *elem_ptr;
2351 TRACE("---------- gdiFont Cache ----------\n");
2352 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2353 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2354 TRACE("gdiFont=%p %s %ld\n",
2355 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2358 TRACE("---------- Unused gdiFont Cache ----------\n");
2359 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2360 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2361 TRACE("gdiFont=%p %s %ld\n",
2362 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2366 /*************************************************************
2367 * WineEngDestroyFontInstance
2369 * free the gdiFont associated with this handle
2372 BOOL WineEngDestroyFontInstance(HFONT handle)
2374 GdiFont gdiFont;
2375 HFONTLIST *hflist;
2376 BOOL ret = FALSE;
2377 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2378 int i = 0;
2380 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2382 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2383 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2384 if(hflist->hfont == handle)
2386 TRACE("removing child font %p from child list\n", gdiFont);
2387 list_remove(&gdiFont->entry);
2388 return TRUE;
2392 TRACE("destroying hfont=%p\n", handle);
2393 if(TRACE_ON(font))
2394 dump_gdi_font_list();
2396 font_elem_ptr = list_head(&gdi_font_list);
2397 while(font_elem_ptr) {
2398 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2399 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2401 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2402 while(hfontlist_elem_ptr) {
2403 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2404 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2405 if(hflist->hfont == handle) {
2406 list_remove(&hflist->entry);
2407 HeapFree(GetProcessHeap(), 0, hflist);
2408 ret = TRUE;
2411 if(list_empty(&gdiFont->hfontlist)) {
2412 TRACE("Moving to Unused list\n");
2413 list_remove(&gdiFont->entry);
2414 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2419 font_elem_ptr = list_head(&unused_gdi_font_list);
2420 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2421 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2422 while(font_elem_ptr) {
2423 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2424 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2425 TRACE("freeing %p\n", gdiFont);
2426 list_remove(&gdiFont->entry);
2427 free_font(gdiFont);
2429 return ret;
2432 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2433 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2435 OUTLINETEXTMETRICW *potm = NULL;
2436 UINT size;
2437 TEXTMETRICW tm, *ptm;
2438 GdiFont font = alloc_font();
2439 LONG width, height;
2441 if(face->scalable) {
2442 height = 100;
2443 width = 0;
2444 } else {
2445 height = face->size.y_ppem >> 6;
2446 width = face->size.x_ppem >> 6;
2449 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2451 free_font(font);
2452 return;
2455 font->name = strdupW(face->family->FamilyName);
2457 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2459 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2460 if(size) {
2461 potm = HeapAlloc(GetProcessHeap(), 0, size);
2462 WineEngGetOutlineTextMetrics(font, size, potm);
2463 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2464 } else {
2465 WineEngGetTextMetrics(font, &tm);
2466 ptm = &tm;
2469 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2470 pntm->ntmTm.tmAscent = ptm->tmAscent;
2471 pntm->ntmTm.tmDescent = ptm->tmDescent;
2472 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2473 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2474 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2475 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2476 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2477 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2478 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2479 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2480 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2481 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2482 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2483 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2484 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2485 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2486 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2487 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2488 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2489 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2490 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2491 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2492 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2494 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2495 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2496 *ptype |= RASTER_FONTTYPE;
2498 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2499 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2500 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2502 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2503 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2504 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2506 if(potm) {
2507 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2509 lstrcpynW(pelf->elfLogFont.lfFaceName,
2510 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2511 LF_FACESIZE);
2512 lstrcpynW(pelf->elfFullName,
2513 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2514 LF_FULLFACESIZE);
2515 lstrcpynW(pelf->elfStyle,
2516 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2517 LF_FACESIZE);
2519 HeapFree(GetProcessHeap(), 0, potm);
2520 } else {
2521 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2523 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2524 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2525 pelf->elfStyle[0] = '\0';
2528 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2530 free_font(font);
2533 /*************************************************************
2534 * WineEngEnumFonts
2537 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2539 Family *family;
2540 Face *face;
2541 struct list *family_elem_ptr, *face_elem_ptr;
2542 ENUMLOGFONTEXW elf;
2543 NEWTEXTMETRICEXW ntm;
2544 DWORD type, ret = 1;
2545 FONTSIGNATURE fs;
2546 CHARSETINFO csi;
2547 LOGFONTW lf;
2548 int i;
2550 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2552 if(plf->lfFaceName[0]) {
2553 FontSubst *psub;
2554 for(psub = substlist; psub; psub = psub->next)
2555 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2556 (psub->from.charset == -1 ||
2557 psub->from.charset == plf->lfCharSet))
2558 break;
2559 if(psub) {
2560 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2561 debugstr_w(psub->to.name));
2562 memcpy(&lf, plf, sizeof(lf));
2563 strcpyW(lf.lfFaceName, psub->to.name);
2564 plf = &lf;
2567 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2568 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2569 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2570 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2571 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2572 GetEnumStructs(face, &elf, &ntm, &type);
2573 for(i = 0; i < 32; i++) {
2574 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2575 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2576 strcpyW(elf.elfScript, OEM_DOSW);
2577 i = 32; /* break out of loop */
2578 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2579 continue;
2580 else {
2581 fs.fsCsb[0] = 1L << i;
2582 fs.fsCsb[1] = 0;
2583 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2584 TCI_SRCFONTSIG))
2585 csi.ciCharset = DEFAULT_CHARSET;
2586 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2587 if(csi.ciCharset != DEFAULT_CHARSET) {
2588 elf.elfLogFont.lfCharSet =
2589 ntm.ntmTm.tmCharSet = csi.ciCharset;
2590 if(ElfScriptsW[i])
2591 strcpyW(elf.elfScript, ElfScriptsW[i]);
2592 else
2593 FIXME("Unknown elfscript for bit %d\n", i);
2596 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2597 debugstr_w(elf.elfLogFont.lfFaceName),
2598 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2599 csi.ciCharset, type, debugstr_w(elf.elfScript),
2600 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2601 ntm.ntmTm.ntmFlags);
2602 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2603 if(!ret) goto end;
2608 } else {
2609 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2610 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2611 face_elem_ptr = list_head(&family->faces);
2612 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2613 GetEnumStructs(face, &elf, &ntm, &type);
2614 for(i = 0; i < 32; i++) {
2615 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2616 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2617 strcpyW(elf.elfScript, OEM_DOSW);
2618 i = 32; /* break out of loop */
2619 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2620 continue;
2621 else {
2622 fs.fsCsb[0] = 1L << i;
2623 fs.fsCsb[1] = 0;
2624 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2625 TCI_SRCFONTSIG))
2626 csi.ciCharset = DEFAULT_CHARSET;
2627 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2628 if(csi.ciCharset != DEFAULT_CHARSET) {
2629 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2630 csi.ciCharset;
2631 if(ElfScriptsW[i])
2632 strcpyW(elf.elfScript, ElfScriptsW[i]);
2633 else
2634 FIXME("Unknown elfscript for bit %d\n", i);
2637 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2638 debugstr_w(elf.elfLogFont.lfFaceName),
2639 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2640 csi.ciCharset, type, debugstr_w(elf.elfScript),
2641 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2642 ntm.ntmTm.ntmFlags);
2643 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2644 if(!ret) goto end;
2648 end:
2649 return ret;
2652 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2654 pt->x.value = vec->x >> 6;
2655 pt->x.fract = (vec->x & 0x3f) << 10;
2656 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2657 pt->y.value = vec->y >> 6;
2658 pt->y.fract = (vec->y & 0x3f) << 10;
2659 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2660 return;
2663 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2665 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2666 WCHAR wc = (WCHAR)glyph;
2667 BOOL default_used;
2668 FT_UInt ret;
2669 char buf;
2670 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, &default_used) || default_used)
2671 ret = 0;
2672 else
2673 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2674 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2675 return ret;
2678 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2679 glyph = glyph + 0xf000;
2680 return pFT_Get_Char_Index(font->ft_face, glyph);
2683 /*************************************************************
2684 * WineEngGetGlyphIndices
2686 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2688 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2689 LPWORD pgi, DWORD flags)
2691 INT i;
2693 for(i = 0; i < count; i++)
2694 pgi[i] = get_glyph_index(font, lpstr[i]);
2696 return count;
2699 /*************************************************************
2700 * WineEngGetGlyphOutline
2702 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2703 * except that the first parameter is the HWINEENGFONT of the font in
2704 * question rather than an HDC.
2707 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2708 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2709 const MAT2* lpmat)
2711 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2712 FT_Face ft_face = font->ft_face;
2713 FT_UInt glyph_index;
2714 DWORD width, height, pitch, needed = 0;
2715 FT_Bitmap ft_bitmap;
2716 FT_Error err;
2717 INT left, right, top = 0, bottom = 0;
2718 FT_Angle angle = 0;
2719 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2720 float widthRatio = 1.0;
2721 FT_Matrix transMat = identityMat;
2722 BOOL needsTransform = FALSE;
2725 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2726 buflen, buf, lpmat);
2728 if(format & GGO_GLYPH_INDEX) {
2729 glyph_index = glyph;
2730 format &= ~GGO_GLYPH_INDEX;
2731 } else
2732 glyph_index = get_glyph_index(font, glyph);
2734 if(glyph_index >= font->gmsize) {
2735 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2736 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2737 font->gmsize * sizeof(*font->gm));
2738 } else {
2739 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2740 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2741 return 1; /* FIXME */
2745 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2746 load_flags |= FT_LOAD_NO_BITMAP;
2748 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2750 if(err) {
2751 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2752 return GDI_ERROR;
2755 /* Scaling factor */
2756 if (font->aveWidth && font->potm) {
2757 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2760 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2761 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2763 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2764 font->gm[glyph_index].lsb = left >> 6;
2765 font->gm[glyph_index].bbx = (right - left) >> 6;
2767 /* Scaling transform */
2768 if(font->aveWidth) {
2769 FT_Matrix scaleMat;
2770 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2771 scaleMat.xy = 0;
2772 scaleMat.yx = 0;
2773 scaleMat.yy = (1 << 16);
2775 pFT_Matrix_Multiply(&scaleMat, &transMat);
2776 needsTransform = TRUE;
2779 /* Rotation transform */
2780 if(font->orientation) {
2781 FT_Matrix rotationMat;
2782 FT_Vector vecAngle;
2783 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2784 pFT_Vector_Unit(&vecAngle, angle);
2785 rotationMat.xx = vecAngle.x;
2786 rotationMat.xy = -vecAngle.y;
2787 rotationMat.yx = -rotationMat.xy;
2788 rotationMat.yy = rotationMat.xx;
2790 pFT_Matrix_Multiply(&rotationMat, &transMat);
2791 needsTransform = TRUE;
2794 /* Extra transformation specified by caller */
2795 if (lpmat) {
2796 FT_Matrix extraMat;
2797 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2798 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2799 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2800 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2801 pFT_Matrix_Multiply(&extraMat, &transMat);
2802 needsTransform = TRUE;
2805 if(!needsTransform) {
2806 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2807 bottom = (ft_face->glyph->metrics.horiBearingY -
2808 ft_face->glyph->metrics.height) & -64;
2809 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2810 lpgm->gmCellIncY = 0;
2811 } else {
2812 INT xc, yc;
2813 FT_Vector vec;
2814 for(xc = 0; xc < 2; xc++) {
2815 for(yc = 0; yc < 2; yc++) {
2816 vec.x = (ft_face->glyph->metrics.horiBearingX +
2817 xc * ft_face->glyph->metrics.width);
2818 vec.y = ft_face->glyph->metrics.horiBearingY -
2819 yc * ft_face->glyph->metrics.height;
2820 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2821 pFT_Vector_Transform(&vec, &transMat);
2822 if(xc == 0 && yc == 0) {
2823 left = right = vec.x;
2824 top = bottom = vec.y;
2825 } else {
2826 if(vec.x < left) left = vec.x;
2827 else if(vec.x > right) right = vec.x;
2828 if(vec.y < bottom) bottom = vec.y;
2829 else if(vec.y > top) top = vec.y;
2833 left = left & -64;
2834 right = (right + 63) & -64;
2835 bottom = bottom & -64;
2836 top = (top + 63) & -64;
2838 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2839 vec.x = ft_face->glyph->metrics.horiAdvance;
2840 vec.y = 0;
2841 pFT_Vector_Transform(&vec, &transMat);
2842 lpgm->gmCellIncX = (vec.x+63) >> 6;
2843 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2845 lpgm->gmBlackBoxX = (right - left) >> 6;
2846 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2847 lpgm->gmptGlyphOrigin.x = left >> 6;
2848 lpgm->gmptGlyphOrigin.y = top >> 6;
2850 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2851 font->gm[glyph_index].init = TRUE;
2853 if(format == GGO_METRICS)
2854 return 1; /* FIXME */
2856 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2857 TRACE("loaded a bitmap\n");
2858 return GDI_ERROR;
2861 switch(format) {
2862 case GGO_BITMAP:
2863 width = lpgm->gmBlackBoxX;
2864 height = lpgm->gmBlackBoxY;
2865 pitch = ((width + 31) >> 5) << 2;
2866 needed = pitch * height;
2868 if(!buf || !buflen) break;
2870 switch(ft_face->glyph->format) {
2871 case ft_glyph_format_bitmap:
2873 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2874 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2875 INT h = ft_face->glyph->bitmap.rows;
2876 while(h--) {
2877 memcpy(dst, src, w);
2878 src += ft_face->glyph->bitmap.pitch;
2879 dst += pitch;
2881 break;
2884 case ft_glyph_format_outline:
2885 ft_bitmap.width = width;
2886 ft_bitmap.rows = height;
2887 ft_bitmap.pitch = pitch;
2888 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2889 ft_bitmap.buffer = buf;
2891 if(needsTransform) {
2892 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2895 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2897 /* Note: FreeType will only set 'black' bits for us. */
2898 memset(buf, 0, needed);
2899 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2900 break;
2902 default:
2903 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2904 return GDI_ERROR;
2906 break;
2908 case GGO_GRAY2_BITMAP:
2909 case GGO_GRAY4_BITMAP:
2910 case GGO_GRAY8_BITMAP:
2911 case WINE_GGO_GRAY16_BITMAP:
2913 unsigned int mult, row, col;
2914 BYTE *start, *ptr;
2916 width = lpgm->gmBlackBoxX;
2917 height = lpgm->gmBlackBoxY;
2918 pitch = (width + 3) / 4 * 4;
2919 needed = pitch * height;
2921 if(!buf || !buflen) break;
2922 ft_bitmap.width = width;
2923 ft_bitmap.rows = height;
2924 ft_bitmap.pitch = pitch;
2925 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2926 ft_bitmap.buffer = buf;
2928 if(needsTransform) {
2929 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2932 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2934 memset(ft_bitmap.buffer, 0, buflen);
2936 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2938 if(format == GGO_GRAY2_BITMAP)
2939 mult = 4;
2940 else if(format == GGO_GRAY4_BITMAP)
2941 mult = 16;
2942 else if(format == GGO_GRAY8_BITMAP)
2943 mult = 64;
2944 else if(format == WINE_GGO_GRAY16_BITMAP)
2945 break;
2946 else {
2947 assert(0);
2948 break;
2951 start = buf;
2952 for(row = 0; row < height; row++) {
2953 ptr = start;
2954 for(col = 0; col < width; col++, ptr++) {
2955 *ptr = (((int)*ptr) * mult + 128) / 256;
2957 start += pitch;
2959 break;
2962 case GGO_NATIVE:
2964 int contour, point = 0, first_pt;
2965 FT_Outline *outline = &ft_face->glyph->outline;
2966 TTPOLYGONHEADER *pph;
2967 TTPOLYCURVE *ppc;
2968 DWORD pph_start, cpfx, type;
2970 if(buflen == 0) buf = NULL;
2972 if (needsTransform && buf) {
2973 pFT_Outline_Transform(outline, &transMat);
2976 for(contour = 0; contour < outline->n_contours; contour++) {
2977 pph_start = needed;
2978 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2979 first_pt = point;
2980 if(buf) {
2981 pph->dwType = TT_POLYGON_TYPE;
2982 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2984 needed += sizeof(*pph);
2985 point++;
2986 while(point <= outline->contours[contour]) {
2987 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2988 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2989 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2990 cpfx = 0;
2991 do {
2992 if(buf)
2993 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2994 cpfx++;
2995 point++;
2996 } while(point <= outline->contours[contour] &&
2997 (outline->tags[point] & FT_Curve_Tag_On) ==
2998 (outline->tags[point-1] & FT_Curve_Tag_On));
2999 /* At the end of a contour Windows adds the start point, but
3000 only for Beziers */
3001 if(point > outline->contours[contour] &&
3002 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3003 if(buf)
3004 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3005 cpfx++;
3006 } else if(point <= outline->contours[contour] &&
3007 outline->tags[point] & FT_Curve_Tag_On) {
3008 /* add closing pt for bezier */
3009 if(buf)
3010 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3011 cpfx++;
3012 point++;
3014 if(buf) {
3015 ppc->wType = type;
3016 ppc->cpfx = cpfx;
3018 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3020 if(buf)
3021 pph->cb = needed - pph_start;
3023 break;
3025 case GGO_BEZIER:
3027 /* Convert the quadratic Beziers to cubic Beziers.
3028 The parametric eqn for a cubic Bezier is, from PLRM:
3029 r(t) = at^3 + bt^2 + ct + r0
3030 with the control points:
3031 r1 = r0 + c/3
3032 r2 = r1 + (c + b)/3
3033 r3 = r0 + c + b + a
3035 A quadratic Beizer has the form:
3036 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3038 So equating powers of t leads to:
3039 r1 = 2/3 p1 + 1/3 p0
3040 r2 = 2/3 p1 + 1/3 p2
3041 and of course r0 = p0, r3 = p2
3044 int contour, point = 0, first_pt;
3045 FT_Outline *outline = &ft_face->glyph->outline;
3046 TTPOLYGONHEADER *pph;
3047 TTPOLYCURVE *ppc;
3048 DWORD pph_start, cpfx, type;
3049 FT_Vector cubic_control[4];
3050 if(buflen == 0) buf = NULL;
3052 if (needsTransform && buf) {
3053 pFT_Outline_Transform(outline, &transMat);
3056 for(contour = 0; contour < outline->n_contours; contour++) {
3057 pph_start = needed;
3058 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3059 first_pt = point;
3060 if(buf) {
3061 pph->dwType = TT_POLYGON_TYPE;
3062 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3064 needed += sizeof(*pph);
3065 point++;
3066 while(point <= outline->contours[contour]) {
3067 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3068 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3069 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3070 cpfx = 0;
3071 do {
3072 if(type == TT_PRIM_LINE) {
3073 if(buf)
3074 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3075 cpfx++;
3076 point++;
3077 } else {
3078 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3079 so cpfx = 3n */
3081 /* FIXME: Possible optimization in endpoint calculation
3082 if there are two consecutive curves */
3083 cubic_control[0] = outline->points[point-1];
3084 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3085 cubic_control[0].x += outline->points[point].x + 1;
3086 cubic_control[0].y += outline->points[point].y + 1;
3087 cubic_control[0].x >>= 1;
3088 cubic_control[0].y >>= 1;
3090 if(point+1 > outline->contours[contour])
3091 cubic_control[3] = outline->points[first_pt];
3092 else {
3093 cubic_control[3] = outline->points[point+1];
3094 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3095 cubic_control[3].x += outline->points[point].x + 1;
3096 cubic_control[3].y += outline->points[point].y + 1;
3097 cubic_control[3].x >>= 1;
3098 cubic_control[3].y >>= 1;
3101 /* r1 = 1/3 p0 + 2/3 p1
3102 r2 = 1/3 p2 + 2/3 p1 */
3103 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3104 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3105 cubic_control[2] = cubic_control[1];
3106 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3107 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3108 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3109 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3110 if(buf) {
3111 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3112 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3113 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3115 cpfx += 3;
3116 point++;
3118 } while(point <= outline->contours[contour] &&
3119 (outline->tags[point] & FT_Curve_Tag_On) ==
3120 (outline->tags[point-1] & FT_Curve_Tag_On));
3121 /* At the end of a contour Windows adds the start point,
3122 but only for Beziers and we've already done that.
3124 if(point <= outline->contours[contour] &&
3125 outline->tags[point] & FT_Curve_Tag_On) {
3126 /* This is the closing pt of a bezier, but we've already
3127 added it, so just inc point and carry on */
3128 point++;
3130 if(buf) {
3131 ppc->wType = type;
3132 ppc->cpfx = cpfx;
3134 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3136 if(buf)
3137 pph->cb = needed - pph_start;
3139 break;
3142 default:
3143 FIXME("Unsupported format %d\n", format);
3144 return GDI_ERROR;
3146 return needed;
3149 static BOOL get_bitmap_text_metrics(GdiFont font)
3151 FT_Face ft_face = font->ft_face;
3152 #ifdef HAVE_FREETYPE_FTWINFNT_H
3153 FT_WinFNT_HeaderRec winfnt_header;
3154 #endif
3155 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3156 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3157 font->potm->otmSize = size;
3159 #define TM font->potm->otmTextMetrics
3160 #ifdef HAVE_FREETYPE_FTWINFNT_H
3161 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3163 TM.tmHeight = winfnt_header.pixel_height;
3164 TM.tmAscent = winfnt_header.ascent;
3165 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3166 TM.tmInternalLeading = winfnt_header.internal_leading;
3167 TM.tmExternalLeading = winfnt_header.external_leading;
3168 TM.tmAveCharWidth = winfnt_header.avg_width;
3169 TM.tmMaxCharWidth = winfnt_header.max_width;
3170 TM.tmWeight = winfnt_header.weight;
3171 TM.tmOverhang = 0;
3172 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3173 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3174 TM.tmFirstChar = winfnt_header.first_char;
3175 TM.tmLastChar = winfnt_header.last_char;
3176 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3177 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3178 TM.tmItalic = winfnt_header.italic;
3179 TM.tmUnderlined = font->underline;
3180 TM.tmStruckOut = font->strikeout;
3181 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3182 TM.tmCharSet = winfnt_header.charset;
3184 else
3185 #endif
3187 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3188 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3189 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3190 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3191 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3192 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3193 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3194 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3195 TM.tmOverhang = 0;
3196 TM.tmDigitizedAspectX = 96; /* FIXME */
3197 TM.tmDigitizedAspectY = 96; /* FIXME */
3198 TM.tmFirstChar = 1;
3199 TM.tmLastChar = 255;
3200 TM.tmDefaultChar = 32;
3201 TM.tmBreakChar = 32;
3202 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3203 TM.tmUnderlined = font->underline;
3204 TM.tmStruckOut = font->strikeout;
3205 /* NB inverted meaning of TMPF_FIXED_PITCH */
3206 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3207 TM.tmCharSet = font->charset;
3209 #undef TM
3211 return TRUE;
3214 /*************************************************************
3215 * WineEngGetTextMetrics
3218 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3220 if(!font->potm) {
3221 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3222 if(!get_bitmap_text_metrics(font))
3223 return FALSE;
3225 if(!font->potm) return FALSE;
3226 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3228 if (font->aveWidth) {
3229 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3231 return TRUE;
3235 /*************************************************************
3236 * WineEngGetOutlineTextMetrics
3239 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3240 OUTLINETEXTMETRICW *potm)
3242 FT_Face ft_face = font->ft_face;
3243 UINT needed, lenfam, lensty, ret;
3244 TT_OS2 *pOS2;
3245 TT_HoriHeader *pHori;
3246 TT_Postscript *pPost;
3247 FT_Fixed x_scale, y_scale;
3248 WCHAR *family_nameW, *style_nameW;
3249 static const WCHAR spaceW[] = {' ', '\0'};
3250 char *cp;
3251 INT ascent, descent;
3253 TRACE("font=%p\n", font);
3255 if(!FT_IS_SCALABLE(ft_face))
3256 return 0;
3258 if(font->potm) {
3259 if(cbSize >= font->potm->otmSize)
3260 memcpy(potm, font->potm, font->potm->otmSize);
3261 return font->potm->otmSize;
3265 needed = sizeof(*potm);
3267 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3268 family_nameW = strdupW(font->name);
3270 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3271 * sizeof(WCHAR);
3272 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3273 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3274 style_nameW, lensty/sizeof(WCHAR));
3276 /* These names should be read from the TT name table */
3278 /* length of otmpFamilyName */
3279 needed += lenfam;
3281 /* length of otmpFaceName */
3282 if(!strcasecmp(ft_face->style_name, "regular")) {
3283 needed += lenfam; /* just the family name */
3284 } else {
3285 needed += lenfam + lensty; /* family + " " + style */
3288 /* length of otmpStyleName */
3289 needed += lensty;
3291 /* length of otmpFullName */
3292 needed += lenfam + lensty;
3295 x_scale = ft_face->size->metrics.x_scale;
3296 y_scale = ft_face->size->metrics.y_scale;
3298 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3299 if(!pOS2) {
3300 FIXME("Can't find OS/2 table - not TT font?\n");
3301 ret = 0;
3302 goto end;
3305 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3306 if(!pHori) {
3307 FIXME("Can't find HHEA table - not TT font?\n");
3308 ret = 0;
3309 goto end;
3312 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3314 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",
3315 pOS2->usWinAscent, pOS2->usWinDescent,
3316 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3317 ft_face->ascender, ft_face->descender, ft_face->height,
3318 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3319 ft_face->bbox.yMax, ft_face->bbox.yMin);
3321 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3322 font->potm->otmSize = needed;
3324 #define TM font->potm->otmTextMetrics
3326 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3327 ascent = pHori->Ascender;
3328 descent = -pHori->Descender;
3329 } else {
3330 ascent = pOS2->usWinAscent;
3331 descent = pOS2->usWinDescent;
3334 if(font->yMax) {
3335 TM.tmAscent = font->yMax;
3336 TM.tmDescent = -font->yMin;
3337 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3338 } else {
3339 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3340 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3341 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3342 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3345 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3347 /* MSDN says:
3348 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3350 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3351 ((ascent + descent) -
3352 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3354 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3355 if (TM.tmAveCharWidth == 0) {
3356 TM.tmAveCharWidth = 1;
3358 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3359 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3360 TM.tmOverhang = 0;
3361 TM.tmDigitizedAspectX = 300;
3362 TM.tmDigitizedAspectY = 300;
3363 TM.tmFirstChar = pOS2->usFirstCharIndex;
3364 TM.tmLastChar = pOS2->usLastCharIndex;
3365 TM.tmDefaultChar = pOS2->usDefaultChar;
3366 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3367 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3368 TM.tmUnderlined = font->underline;
3369 TM.tmStruckOut = font->strikeout;
3371 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3372 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3373 (pOS2->version == 0xFFFFU ||
3374 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3375 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3376 else
3377 TM.tmPitchAndFamily = 0;
3379 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3380 case PAN_FAMILY_SCRIPT:
3381 TM.tmPitchAndFamily |= FF_SCRIPT;
3382 break;
3383 case PAN_FAMILY_DECORATIVE:
3384 case PAN_FAMILY_PICTORIAL:
3385 TM.tmPitchAndFamily |= FF_DECORATIVE;
3386 break;
3387 case PAN_FAMILY_TEXT_DISPLAY:
3388 if(TM.tmPitchAndFamily == 0) /* fixed */
3389 TM.tmPitchAndFamily = FF_MODERN;
3390 else {
3391 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3392 case PAN_SERIF_NORMAL_SANS:
3393 case PAN_SERIF_OBTUSE_SANS:
3394 case PAN_SERIF_PERP_SANS:
3395 TM.tmPitchAndFamily |= FF_SWISS;
3396 break;
3397 default:
3398 TM.tmPitchAndFamily |= FF_ROMAN;
3401 break;
3402 default:
3403 TM.tmPitchAndFamily |= FF_DONTCARE;
3406 if(FT_IS_SCALABLE(ft_face))
3407 TM.tmPitchAndFamily |= TMPF_VECTOR;
3408 if(FT_IS_SFNT(ft_face))
3409 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3411 TM.tmCharSet = font->charset;
3412 #undef TM
3414 font->potm->otmFiller = 0;
3415 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3416 font->potm->otmfsSelection = pOS2->fsSelection;
3417 font->potm->otmfsType = pOS2->fsType;
3418 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3419 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3420 font->potm->otmItalicAngle = 0; /* POST table */
3421 font->potm->otmEMSquare = ft_face->units_per_EM;
3422 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3423 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3424 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3425 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3426 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3427 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3428 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3429 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3430 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3431 font->potm->otmMacAscent = 0; /* where do these come from ? */
3432 font->potm->otmMacDescent = 0;
3433 font->potm->otmMacLineGap = 0;
3434 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3435 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3436 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3437 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3438 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3439 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3440 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3441 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3442 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3443 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3444 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3445 if(!pPost) {
3446 font->potm->otmsUnderscoreSize = 0;
3447 font->potm->otmsUnderscorePosition = 0;
3448 } else {
3449 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3450 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3453 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3454 cp = (char*)font->potm + sizeof(*font->potm);
3455 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3456 strcpyW((WCHAR*)cp, family_nameW);
3457 cp += lenfam;
3458 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3459 strcpyW((WCHAR*)cp, style_nameW);
3460 cp += lensty;
3461 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3462 strcpyW((WCHAR*)cp, family_nameW);
3463 if(strcasecmp(ft_face->style_name, "regular")) {
3464 strcatW((WCHAR*)cp, spaceW);
3465 strcatW((WCHAR*)cp, style_nameW);
3466 cp += lenfam + lensty;
3467 } else
3468 cp += lenfam;
3469 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3470 strcpyW((WCHAR*)cp, family_nameW);
3471 strcatW((WCHAR*)cp, spaceW);
3472 strcatW((WCHAR*)cp, style_nameW);
3473 ret = needed;
3475 if(potm && needed <= cbSize)
3476 memcpy(potm, font->potm, font->potm->otmSize);
3478 end:
3479 HeapFree(GetProcessHeap(), 0, style_nameW);
3480 HeapFree(GetProcessHeap(), 0, family_nameW);
3482 return ret;
3485 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3487 HFONTLIST *hfontlist;
3488 child->font = alloc_font();
3489 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3490 if(!child->font->ft_face)
3492 free_font(child->font);
3493 child->font = NULL;
3494 return FALSE;
3497 child->font->orientation = font->orientation;
3498 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3499 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3500 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3501 child->font->base_font = font;
3502 list_add_head(&child_font_list, &child->font->entry);
3503 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3504 return TRUE;
3507 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3509 FT_UInt g;
3510 CHILD_FONT *child_font;
3512 if(font->base_font)
3513 font = font->base_font;
3515 *linked_font = font;
3517 if((*glyph = get_glyph_index(font, c)))
3518 return TRUE;
3520 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3522 if(!child_font->font)
3523 if(!load_child_font(font, child_font))
3524 continue;
3526 if(!child_font->font->ft_face)
3527 continue;
3528 g = get_glyph_index(child_font->font, c);
3529 if(g)
3531 *glyph = g;
3532 *linked_font = child_font->font;
3533 return TRUE;
3536 return FALSE;
3539 /*************************************************************
3540 * WineEngGetCharWidth
3543 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3544 LPINT buffer)
3546 UINT c;
3547 GLYPHMETRICS gm;
3548 FT_UInt glyph_index;
3549 GdiFont linked_font;
3551 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3553 for(c = firstChar; c <= lastChar; c++) {
3554 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3555 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3556 &gm, 0, NULL, NULL);
3557 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3559 return TRUE;
3562 /*************************************************************
3563 * WineEngGetCharABCWidths
3566 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3567 LPABC buffer)
3569 UINT c;
3570 GLYPHMETRICS gm;
3571 FT_UInt glyph_index;
3572 GdiFont linked_font;
3574 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3576 if(!FT_IS_SCALABLE(font->ft_face))
3577 return FALSE;
3579 for(c = firstChar; c <= lastChar; c++) {
3580 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3581 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3582 &gm, 0, NULL, NULL);
3583 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3584 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3585 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3586 linked_font->gm[glyph_index].bbx;
3588 return TRUE;
3591 /*************************************************************
3592 * WineEngGetTextExtentPoint
3595 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3596 LPSIZE size)
3598 INT idx;
3599 GLYPHMETRICS gm;
3600 TEXTMETRICW tm;
3601 FT_UInt glyph_index;
3602 GdiFont linked_font;
3604 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3605 size);
3607 size->cx = 0;
3608 WineEngGetTextMetrics(font, &tm);
3609 size->cy = tm.tmHeight;
3611 for(idx = 0; idx < count; idx++) {
3612 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3613 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3614 &gm, 0, NULL, NULL);
3615 size->cx += linked_font->gm[glyph_index].adv;
3617 TRACE("return %ld,%ld\n", size->cx, size->cy);
3618 return TRUE;
3621 /*************************************************************
3622 * WineEngGetTextExtentPointI
3625 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3626 LPSIZE size)
3628 INT idx;
3629 GLYPHMETRICS gm;
3630 TEXTMETRICW tm;
3632 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3634 size->cx = 0;
3635 WineEngGetTextMetrics(font, &tm);
3636 size->cy = tm.tmHeight;
3638 for(idx = 0; idx < count; idx++) {
3639 WineEngGetGlyphOutline(font, indices[idx],
3640 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3641 NULL);
3642 size->cx += font->gm[indices[idx]].adv;
3644 TRACE("return %ld,%ld\n", size->cx, size->cy);
3645 return TRUE;
3648 /*************************************************************
3649 * WineEngGetFontData
3652 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3653 DWORD cbData)
3655 FT_Face ft_face = font->ft_face;
3656 DWORD len;
3657 FT_Error err;
3659 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3660 font, table, offset, buf, cbData);
3662 if(!FT_IS_SFNT(ft_face))
3663 return GDI_ERROR;
3665 if(!buf || !cbData)
3666 len = 0;
3667 else
3668 len = cbData;
3670 if(table) { /* MS tags differ in endidness from FT ones */
3671 table = table >> 24 | table << 24 |
3672 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3675 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3676 if(pFT_Load_Sfnt_Table)
3677 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3678 else { /* Do it the hard way */
3679 TT_Face tt_face = (TT_Face) ft_face;
3680 SFNT_Interface *sfnt;
3681 if (FT_Version.major==2 && FT_Version.minor==0)
3683 /* 2.0.x */
3684 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3686 else
3688 /* A field was added in the middle of the structure in 2.1.x */
3689 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3691 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3693 if(err) {
3694 TRACE("Can't find table %08lx.\n", table);
3695 return GDI_ERROR;
3697 return len;
3700 /*************************************************************
3701 * WineEngGetTextFace
3704 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3706 if(str) {
3707 lstrcpynW(str, font->name, count);
3708 return strlenW(font->name);
3709 } else
3710 return strlenW(font->name) + 1;
3713 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3715 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3716 return font->charset;
3719 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3721 GdiFont font = dc->gdiFont, linked_font;
3722 struct list *first_hfont;
3723 BOOL ret;
3725 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3726 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3727 if(font == linked_font)
3728 *new_hfont = dc->hFont;
3729 else
3731 first_hfont = list_head(&linked_font->hfontlist);
3732 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3735 return ret;
3739 /*************************************************************
3740 * FontIsLinked
3742 BOOL WINAPI FontIsLinked(HDC hdc)
3744 DC *dc = DC_GetDCPtr(hdc);
3745 BOOL ret = FALSE;
3747 if(!dc) return FALSE;
3748 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3749 ret = TRUE;
3750 GDI_ReleaseObj(hdc);
3751 TRACE("returning %d\n", ret);
3752 return ret;
3755 #else /* HAVE_FREETYPE */
3757 BOOL WineEngInit(void)
3759 return FALSE;
3761 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3763 return NULL;
3765 BOOL WineEngDestroyFontInstance(HFONT hfont)
3767 return FALSE;
3770 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3772 return 1;
3775 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3776 LPWORD pgi, DWORD flags)
3778 return GDI_ERROR;
3781 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3782 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3783 const MAT2* lpmat)
3785 ERR("called but we don't have FreeType\n");
3786 return GDI_ERROR;
3789 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3791 ERR("called but we don't have FreeType\n");
3792 return FALSE;
3795 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3796 OUTLINETEXTMETRICW *potm)
3798 ERR("called but we don't have FreeType\n");
3799 return 0;
3802 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3803 LPINT buffer)
3805 ERR("called but we don't have FreeType\n");
3806 return FALSE;
3809 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3810 LPABC buffer)
3812 ERR("called but we don't have FreeType\n");
3813 return FALSE;
3816 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3817 LPSIZE size)
3819 ERR("called but we don't have FreeType\n");
3820 return FALSE;
3823 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3824 LPSIZE size)
3826 ERR("called but we don't have FreeType\n");
3827 return FALSE;
3830 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3831 DWORD cbData)
3833 ERR("called but we don't have FreeType\n");
3834 return GDI_ERROR;
3837 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3839 ERR("called but we don't have FreeType\n");
3840 return 0;
3843 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3845 FIXME(":stub\n");
3846 return 1;
3849 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3851 FIXME(":stub\n");
3852 return TRUE;
3855 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3857 FIXME(":stub\n");
3858 return DEFAULT_CHARSET;
3861 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3863 return FALSE;
3866 BOOL WINAPI FontIsLinked(HDC hdc)
3868 return FALSE;
3870 #endif /* HAVE_FREETYPE */