Store the selected ppem in the GdiFont.
[wine/hacks.git] / dlls / gdi / freetype.c
blobfc95a86afa7cecbf894f2ecfb38bde8b8eeba311
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 LONG ppem;
253 typedef struct {
254 struct list entry;
255 WCHAR *font_name;
256 struct list links;
257 } SYSTEM_LINKS;
259 #define INIT_GM_SIZE 128
261 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
262 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
263 #define UNUSED_CACHE_SIZE 10
264 static struct list system_links = LIST_INIT(system_links);
266 static struct list font_list = LIST_INIT(font_list);
268 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
269 'R','o','m','a','n','\0'};
270 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
271 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
273 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
274 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
275 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
276 'S','e','r','i','f','\0'};
277 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
278 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
280 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
281 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
282 'W','i','n','d','o','w','s','\\',
283 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
284 'F','o','n','t','s','\0'};
286 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
287 'W','i','n','d','o','w','s',' ','N','T','\\',
288 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
289 'F','o','n','t','s','\0'};
291 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
292 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
293 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
294 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
296 static const WCHAR *SystemFontValues[4] = {
297 System_Value,
298 OEMFont_Value,
299 FixedSys_Value,
300 NULL
303 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
304 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
306 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
307 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
308 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
309 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
310 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
311 'E','u','r','o','p','e','a','n','\0'};
312 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
313 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
314 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
315 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
316 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
317 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
318 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
319 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
320 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
321 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
322 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
323 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
325 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
326 WesternW, /*00*/
327 Central_EuropeanW,
328 CyrillicW,
329 GreekW,
330 TurkishW,
331 HebrewW,
332 ArabicW,
333 BalticW,
334 VietnameseW, /*08*/
335 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
336 ThaiW,
337 JapaneseW,
338 CHINESE_GB2312W,
339 HangulW,
340 CHINESE_BIG5W,
341 Hangul_Johab_W,
342 NULL, NULL, /*23*/
343 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
344 SymbolW /*31*/
347 typedef struct {
348 WCHAR *name;
349 INT charset;
350 } NameCs;
352 typedef struct tagFontSubst {
353 NameCs from;
354 NameCs to;
355 struct tagFontSubst *next;
356 } FontSubst;
358 static FontSubst *substlist = NULL;
359 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
361 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
364 /****************************************
365 * Notes on .fon files
367 * The fonts System, FixedSys and Terminal are special. There are typically multiple
368 * versions installed for different resolutions and codepages. Windows stores which one to use
369 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
370 * Key Meaning
371 * FIXEDFON.FON FixedSys
372 * FONTS.FON System
373 * OEMFONT.FON Terminal
374 * LogPixels Current dpi set by the display control panel applet
375 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
376 * also has a LogPixels value that appears to mirror this)
378 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
379 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
380 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
381 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
382 * so that makes sense.
384 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
385 * to be mapped into the registry on Windows 2000 at least).
386 * I have
387 * woafont=app850.fon
388 * ega80woa.fon=ega80850.fon
389 * ega40woa.fon=ega40850.fon
390 * cga80woa.fon=cga80850.fon
391 * cga40woa.fon=cga40850.fon
395 static inline BOOL is_win9x(void)
397 return GetVersion() & 0x80000000;
400 This function builds an FT_Fixed from a float. It puts the integer part
401 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
402 It fails if the integer part of the float number is greater than SHORT_MAX.
404 static inline FT_Fixed FT_FixedFromFloat(float f)
406 short value = f;
407 unsigned short fract = (f - value) * 0xFFFF;
408 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
412 This function builds an FT_Fixed from a FIXED. It simply put f.value
413 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
415 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
417 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
420 #define ADDFONT_EXTERNAL_FONT 0x01
421 #define ADDFONT_FORCE_BITMAP 0x02
422 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
424 FT_Face ft_face;
425 TT_OS2 *pOS2;
426 TT_Header *pHeader = NULL;
427 WCHAR *FamilyW, *StyleW;
428 DWORD len;
429 Family *family;
430 Face *face;
431 struct list *family_elem_ptr, *face_elem_ptr;
432 FT_Error err;
433 FT_Long face_index = 0, num_faces;
434 #ifdef HAVE_FREETYPE_FTWINFNT_H
435 FT_WinFNT_HeaderRec winfnt_header;
436 #endif
437 int i, bitmap_num, internal_leading;
438 FONTSIGNATURE fs;
440 do {
441 char *family_name = fake_family;
443 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
444 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
445 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
446 return FALSE;
449 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*/
450 pFT_Done_Face(ft_face);
451 return FALSE;
454 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
455 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
456 pFT_Done_Face(ft_face);
457 return FALSE;
460 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
461 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
462 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
463 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
464 "Skipping this font.\n", debugstr_a(file));
465 pFT_Done_Face(ft_face);
466 return FALSE;
469 if(!ft_face->family_name || !ft_face->style_name) {
470 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
471 pFT_Done_Face(ft_face);
472 return FALSE;
475 if(!family_name)
476 family_name = ft_face->family_name;
478 bitmap_num = 0;
479 do {
480 My_FT_Bitmap_Size *size = NULL;
482 if(!FT_IS_SCALABLE(ft_face))
483 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
485 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
486 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
487 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
489 family = NULL;
490 LIST_FOR_EACH(family_elem_ptr, &font_list) {
491 family = LIST_ENTRY(family_elem_ptr, Family, entry);
492 if(!strcmpW(family->FamilyName, FamilyW))
493 break;
494 family = NULL;
496 if(!family) {
497 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
498 family->FamilyName = FamilyW;
499 list_init(&family->faces);
500 list_add_tail(&font_list, &family->entry);
501 } else {
502 HeapFree(GetProcessHeap(), 0, FamilyW);
505 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
506 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
507 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
509 internal_leading = 0;
510 memset(&fs, 0, sizeof(fs));
512 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
513 if(pOS2) {
514 fs.fsCsb[0] = pOS2->ulCodePageRange1;
515 fs.fsCsb[1] = pOS2->ulCodePageRange2;
516 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
517 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
518 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
519 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
520 if(pOS2->version == 0) {
521 FT_UInt dummy;
523 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
524 fs.fsCsb[0] |= 1;
525 else
526 fs.fsCsb[0] |= 1L << 31;
529 #ifdef HAVE_FREETYPE_FTWINFNT_H
530 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
531 CHARSETINFO csi;
532 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
533 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
534 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
535 memcpy(&fs, &csi.fs, sizeof(csi.fs));
536 internal_leading = winfnt_header.internal_leading;
538 #endif
540 face_elem_ptr = list_head(&family->faces);
541 while(face_elem_ptr) {
542 face = LIST_ENTRY(face_elem_ptr, Face, entry);
543 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
544 if(!strcmpW(face->StyleName, StyleW) &&
545 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
546 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
547 debugstr_w(family->FamilyName), debugstr_w(StyleW),
548 face->font_version, pHeader ? pHeader->Font_Revision : 0);
550 if(fake_family) {
551 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
552 HeapFree(GetProcessHeap(), 0, StyleW);
553 pFT_Done_Face(ft_face);
554 return FALSE;
556 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
557 TRACE("Original font is newer so skipping this one\n");
558 HeapFree(GetProcessHeap(), 0, StyleW);
559 pFT_Done_Face(ft_face);
560 return FALSE;
561 } else {
562 TRACE("Replacing original with this one\n");
563 list_remove(&face->entry);
564 HeapFree(GetProcessHeap(), 0, face->file);
565 HeapFree(GetProcessHeap(), 0, face->StyleName);
566 HeapFree(GetProcessHeap(), 0, face);
567 break;
571 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
572 list_add_tail(&family->faces, &face->entry);
573 face->StyleName = StyleW;
574 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
575 strcpy(face->file, file);
576 face->face_index = face_index;
577 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
578 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
579 face->font_version = pHeader ? pHeader->Font_Revision : 0;
580 face->family = family;
581 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
582 memcpy(&face->fs, &fs, sizeof(face->fs));
583 memset(&face->fs_links, 0, sizeof(face->fs_links));
585 if(FT_IS_SCALABLE(ft_face)) {
586 memset(&face->size, 0, sizeof(face->size));
587 face->scalable = TRUE;
588 } else {
589 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
590 size->height, size->width, size->size >> 6,
591 size->x_ppem >> 6, size->y_ppem >> 6);
592 face->size.height = size->height;
593 face->size.width = size->width;
594 face->size.size = size->size;
595 face->size.x_ppem = size->x_ppem;
596 face->size.y_ppem = size->y_ppem;
597 face->size.internal_leading = internal_leading;
598 face->scalable = FALSE;
601 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
602 face->fs.fsCsb[0], face->fs.fsCsb[1],
603 face->fs.fsUsb[0], face->fs.fsUsb[1],
604 face->fs.fsUsb[2], face->fs.fsUsb[3]);
607 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
608 for(i = 0; i < ft_face->num_charmaps; i++) {
609 switch(ft_face->charmaps[i]->encoding) {
610 case FT_ENCODING_UNICODE:
611 case FT_ENCODING_APPLE_ROMAN:
612 face->fs.fsCsb[0] |= 1;
613 break;
614 case FT_ENCODING_MS_SYMBOL:
615 face->fs.fsCsb[0] |= 1L << 31;
616 break;
617 default:
618 break;
623 if(face->fs.fsCsb[0] & ~(1L << 31))
624 have_installed_roman_font = TRUE;
625 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
627 num_faces = ft_face->num_faces;
628 pFT_Done_Face(ft_face);
629 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
630 debugstr_w(StyleW));
631 } while(num_faces > ++face_index);
632 return TRUE;
635 static void DumpFontList(void)
637 Family *family;
638 Face *face;
639 struct list *family_elem_ptr, *face_elem_ptr;
641 LIST_FOR_EACH(family_elem_ptr, &font_list) {
642 family = LIST_ENTRY(family_elem_ptr, Family, entry);
643 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
644 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
645 face = LIST_ENTRY(face_elem_ptr, Face, entry);
646 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
647 if(!face->scalable)
648 TRACE(" %ld", face->size.y_ppem >> 6);
649 TRACE("\n");
652 return;
655 static Face *find_face_from_filename(WCHAR *name)
657 Family *family;
658 Face *face;
659 char *file;
660 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
661 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
662 Face *ret = NULL;
664 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
665 TRACE("looking for %s\n", debugstr_a(nameA));
667 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
669 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
671 file = strrchr(face->file, '/');
672 if(!file)
673 file = face->file;
674 else
675 file++;
676 if(!strcmp(file, nameA))
677 ret = face;
678 break;
681 HeapFree(GetProcessHeap(), 0, nameA);
682 return ret;
685 static Family *find_family_from_name(WCHAR *name)
687 Family *family;
689 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
691 if(!strcmpiW(family->FamilyName, name))
692 return family;
695 return NULL;
698 static void DumpSubstList(void)
700 FontSubst *psub;
702 for(psub = substlist; psub; psub = psub->next)
703 if(psub->from.charset != -1 || psub->to.charset != -1)
704 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
705 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
706 else
707 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
708 debugstr_w(psub->to.name));
709 return;
712 static LPWSTR strdupW(LPCWSTR p)
714 LPWSTR ret;
715 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
716 ret = HeapAlloc(GetProcessHeap(), 0, len);
717 memcpy(ret, p, len);
718 return ret;
721 static LPSTR strdupA(LPCSTR p)
723 LPSTR ret;
724 DWORD len = (strlen(p) + 1);
725 ret = HeapAlloc(GetProcessHeap(), 0, len);
726 memcpy(ret, p, len);
727 return ret;
730 static void split_subst_info(NameCs *nc, LPSTR str)
732 CHAR *p = strrchr(str, ',');
733 DWORD len;
735 nc->charset = -1;
736 if(p && *(p+1)) {
737 nc->charset = strtol(p+1, NULL, 10);
738 *p = '\0';
740 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
741 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
742 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
745 static void LoadSubstList(void)
747 FontSubst *psub, **ppsub;
748 HKEY hkey;
749 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
750 LPSTR value;
751 LPVOID data;
753 if(substlist) {
754 for(psub = substlist; psub;) {
755 FontSubst *ptmp;
756 HeapFree(GetProcessHeap(), 0, psub->to.name);
757 HeapFree(GetProcessHeap(), 0, psub->from.name);
758 ptmp = psub;
759 psub = psub->next;
760 HeapFree(GetProcessHeap(), 0, ptmp);
762 substlist = NULL;
765 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
766 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
767 &hkey) == ERROR_SUCCESS) {
769 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
770 &valuelen, &datalen, NULL, NULL);
772 valuelen++; /* returned value doesn't include room for '\0' */
773 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
774 data = HeapAlloc(GetProcessHeap(), 0, datalen);
776 dlen = datalen;
777 vlen = valuelen;
778 ppsub = &substlist;
779 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
780 &dlen) == ERROR_SUCCESS) {
781 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
783 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
784 (*ppsub)->next = NULL;
785 split_subst_info(&((*ppsub)->from), value);
786 split_subst_info(&((*ppsub)->to), data);
788 /* Win 2000 doesn't allow mapping between different charsets
789 or mapping of DEFAULT_CHARSET */
790 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
791 (*ppsub)->to.charset == DEFAULT_CHARSET) {
792 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
793 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
794 HeapFree(GetProcessHeap(), 0, *ppsub);
795 *ppsub = NULL;
796 } else {
797 ppsub = &((*ppsub)->next);
799 /* reset dlen and vlen */
800 dlen = datalen;
801 vlen = valuelen;
803 HeapFree(GetProcessHeap(), 0, data);
804 HeapFree(GetProcessHeap(), 0, value);
805 RegCloseKey(hkey);
809 /***********************************************************
810 * The replacement list is a way to map an entire font
811 * family onto another family. For example adding
813 * [HKCU\Software\Wine\Fonts\Replacements]
814 * "Wingdings"="Winedings"
816 * would enumerate the Winedings font both as Winedings and
817 * Wingdings. However if a real Wingdings font is present the
818 * replacement does not take place.
821 static void LoadReplaceList(void)
823 HKEY hkey;
824 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
825 LPSTR value;
826 LPVOID data;
827 Family *family;
828 Face *face;
829 struct list *family_elem_ptr, *face_elem_ptr;
830 WCHAR old_nameW[200];
832 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
833 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
835 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
836 &valuelen, &datalen, NULL, NULL);
838 valuelen++; /* returned value doesn't include room for '\0' */
839 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
840 data = HeapAlloc(GetProcessHeap(), 0, datalen);
842 dlen = datalen;
843 vlen = valuelen;
844 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
845 &dlen) == ERROR_SUCCESS) {
846 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
847 /* "NewName"="Oldname" */
848 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
849 break;
851 /* Find the old family and hence all of the font files
852 in that family */
853 LIST_FOR_EACH(family_elem_ptr, &font_list) {
854 family = LIST_ENTRY(family_elem_ptr, Family, entry);
855 if(!strcmpiW(family->FamilyName, old_nameW)) {
856 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
857 face = LIST_ENTRY(face_elem_ptr, Face, entry);
858 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
859 debugstr_w(face->StyleName), value);
860 /* Now add a new entry with the new family name */
861 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
863 break;
866 /* reset dlen and vlen */
867 dlen = datalen;
868 vlen = valuelen;
870 HeapFree(GetProcessHeap(), 0, data);
871 HeapFree(GetProcessHeap(), 0, value);
872 RegCloseKey(hkey);
876 /*************************************************************
877 * init_system_links
879 static BOOL init_system_links(void)
881 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
882 'W','i','n','d','o','w','s',' ','N','T','\\',
883 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
884 'S','y','s','t','e','m','L','i','n','k',0};
885 HKEY hkey;
886 BOOL ret = FALSE;
887 DWORD type, max_val, max_data, val_len, data_len, index;
888 WCHAR *value, *data;
889 WCHAR *entry, *next;
890 SYSTEM_LINKS *font_link, *system_font_link;
891 CHILD_FONT *child_font;
892 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
893 static const WCHAR System[] = {'S','y','s','t','e','m',0};
894 FONTSIGNATURE fs;
895 Family *family;
896 Face *face;
898 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
900 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
901 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
902 data = HeapAlloc(GetProcessHeap(), 0, max_data);
903 val_len = max_val + 1;
904 data_len = max_data;
905 index = 0;
906 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
908 TRACE("%s:\n", debugstr_w(value));
910 memset(&fs, 0, sizeof(fs));
911 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
912 font_link->font_name = strdupW(value);
913 list_init(&font_link->links);
914 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
916 WCHAR *face_name;
917 INT index;
918 CHILD_FONT *child_font;
920 TRACE("\t%s\n", debugstr_w(entry));
922 next = entry + strlenW(entry) + 1;
924 face_name = strchrW(entry, ',');
925 if(!face_name)
926 index = 0;
927 else
929 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
930 *face_name++ = 0;
931 while(isspaceW(*face_name))
932 face_name++;
934 index = 0;
936 face = find_face_from_filename(entry);
937 if(!face)
939 TRACE("Unable to find file %s\n", debugstr_w(entry));
940 continue;
943 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
944 child_font->file_name = strdupA(face->file);
945 child_font->index = index;
946 child_font->font = NULL;
947 fs.fsCsb[0] |= face->fs.fsCsb[0];
948 fs.fsCsb[1] |= face->fs.fsCsb[1];
949 list_add_tail(&font_link->links, &child_font->entry);
951 family = find_family_from_name(font_link->font_name);
952 if(family)
954 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
956 memcpy(&face->fs_links, &fs, sizeof(fs));
959 list_add_tail(&system_links, &font_link->entry);
960 val_len = max_val + 1;
961 data_len = max_data;
964 HeapFree(GetProcessHeap(), 0, value);
965 HeapFree(GetProcessHeap(), 0, data);
966 RegCloseKey(hkey);
969 /* Explicitly add an entry for the system font, this links to Tahoma and any links
970 that Tahoma has */
971 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
972 system_font_link->font_name = strdupW(System);
973 list_init(&system_font_link->links);
974 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
975 child_font->file_name = strdupA("Tahoma.ttf");
976 child_font->index = 0;
977 child_font->font = NULL;
978 list_add_tail(&system_font_link->links, &child_font->entry);
979 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
981 if(!strcmpW(font_link->font_name, Tahoma))
983 CHILD_FONT *font_link_entry;
984 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
986 CHILD_FONT *new_child;
987 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
988 new_child->file_name = strdupA(font_link_entry->file_name);
989 new_child->index = font_link_entry->index;
990 new_child->font = NULL;
991 list_add_tail(&system_font_link->links, &new_child->entry);
993 break;
996 list_add_tail(&system_links, &system_font_link->entry);
997 return ret;
1000 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1002 DIR *dir;
1003 struct dirent *dent;
1004 char path[MAX_PATH];
1006 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1008 dir = opendir(dirname);
1009 if(!dir) {
1010 ERR("Can't open directory %s\n", debugstr_a(dirname));
1011 return FALSE;
1013 while((dent = readdir(dir)) != NULL) {
1014 struct stat statbuf;
1016 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1017 continue;
1019 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1021 sprintf(path, "%s/%s", dirname, dent->d_name);
1023 if(stat(path, &statbuf) == -1)
1025 WARN("Can't stat %s\n", debugstr_a(path));
1026 continue;
1028 if(S_ISDIR(statbuf.st_mode))
1029 ReadFontDir(path, external_fonts);
1030 else
1031 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1033 closedir(dir);
1034 return TRUE;
1037 static void load_fontconfig_fonts(void)
1039 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1040 void *fc_handle = NULL;
1041 FcConfig *config;
1042 FcPattern *pat;
1043 FcObjectSet *os;
1044 FcFontSet *fontset;
1045 FcValue v;
1046 int i, len;
1047 const char *file, *ext;
1049 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1050 if(!fc_handle) {
1051 TRACE("Wine cannot find the fontconfig library (%s).\n",
1052 SONAME_LIBFONTCONFIG);
1053 return;
1055 #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;}
1056 LOAD_FUNCPTR(FcConfigGetCurrent);
1057 LOAD_FUNCPTR(FcFontList);
1058 LOAD_FUNCPTR(FcFontSetDestroy);
1059 LOAD_FUNCPTR(FcInit);
1060 LOAD_FUNCPTR(FcObjectSetAdd);
1061 LOAD_FUNCPTR(FcObjectSetCreate);
1062 LOAD_FUNCPTR(FcObjectSetDestroy);
1063 LOAD_FUNCPTR(FcPatternCreate);
1064 LOAD_FUNCPTR(FcPatternDestroy);
1065 LOAD_FUNCPTR(FcPatternGet);
1066 #undef LOAD_FUNCPTR
1068 if(!pFcInit()) return;
1070 config = pFcConfigGetCurrent();
1071 pat = pFcPatternCreate();
1072 os = pFcObjectSetCreate();
1073 pFcObjectSetAdd(os, FC_FILE);
1074 fontset = pFcFontList(config, pat, os);
1075 if(!fontset) return;
1076 for(i = 0; i < fontset->nfont; i++) {
1077 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1078 continue;
1079 if(v.type != FcTypeString) continue;
1080 file = (LPCSTR) v.u.s;
1081 TRACE("fontconfig: %s\n", file);
1083 /* We're just interested in OT/TT fonts for now, so this hack just
1084 picks up the standard extensions to save time loading every other
1085 font */
1086 len = strlen( file );
1087 if(len < 4) continue;
1088 ext = &file[ len - 3 ];
1089 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1090 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1092 pFcFontSetDestroy(fontset);
1093 pFcObjectSetDestroy(os);
1094 pFcPatternDestroy(pat);
1095 sym_not_found:
1096 #endif
1097 return;
1101 static void load_system_fonts(void)
1103 HKEY hkey;
1104 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1105 const WCHAR **value;
1106 DWORD dlen, type;
1107 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1108 char *unixname;
1110 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1111 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1112 strcatW(windowsdir, fontsW);
1113 for(value = SystemFontValues; *value; value++) {
1114 dlen = sizeof(data);
1115 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1116 type == REG_SZ) {
1117 sprintfW(pathW, fmtW, windowsdir, data);
1118 if((unixname = wine_get_unix_file_name(pathW))) {
1119 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1120 HeapFree(GetProcessHeap(), 0, unixname);
1124 RegCloseKey(hkey);
1128 /*************************************************************
1130 * This adds registry entries for any externally loaded fonts
1131 * (fonts from fontconfig or FontDirs). It also deletes entries
1132 * of no longer existing fonts.
1135 static void update_reg_entries(void)
1137 HKEY winkey = 0, externalkey = 0;
1138 LPWSTR valueW;
1139 LPVOID data;
1140 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1141 Family *family;
1142 Face *face;
1143 struct list *family_elem_ptr, *face_elem_ptr;
1144 WCHAR *file;
1145 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1146 static const WCHAR spaceW[] = {' ', '\0'};
1147 char *path;
1149 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1150 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1151 ERR("Can't create Windows font reg key\n");
1152 goto end;
1154 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1155 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1156 ERR("Can't create external font reg key\n");
1157 goto end;
1160 /* Delete all external fonts added last time */
1162 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1163 &valuelen, &datalen, NULL, NULL);
1164 valuelen++; /* returned value doesn't include room for '\0' */
1165 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1166 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1168 dlen = datalen * sizeof(WCHAR);
1169 vlen = valuelen;
1170 i = 0;
1171 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1172 &dlen) == ERROR_SUCCESS) {
1174 RegDeleteValueW(winkey, valueW);
1175 /* reset dlen and vlen */
1176 dlen = datalen;
1177 vlen = valuelen;
1179 HeapFree(GetProcessHeap(), 0, data);
1180 HeapFree(GetProcessHeap(), 0, valueW);
1182 /* Delete the old external fonts key */
1183 RegCloseKey(externalkey);
1184 externalkey = 0;
1185 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1187 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1188 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1189 ERR("Can't create external font reg key\n");
1190 goto end;
1193 /* enumerate the fonts and add external ones to the two keys */
1195 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1196 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1197 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1198 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1199 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1200 if(!face->external) continue;
1201 len = len_fam;
1202 if(strcmpiW(face->StyleName, RegularW))
1203 len = len_fam + strlenW(face->StyleName) + 1;
1204 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1205 strcpyW(valueW, family->FamilyName);
1206 if(len != len_fam) {
1207 strcatW(valueW, spaceW);
1208 strcatW(valueW, face->StyleName);
1210 strcatW(valueW, TrueType);
1211 if((path = strrchr(face->file, '/')) == NULL)
1212 path = face->file;
1213 else
1214 path++;
1215 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1217 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1218 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1219 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1220 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1222 HeapFree(GetProcessHeap(), 0, file);
1223 HeapFree(GetProcessHeap(), 0, valueW);
1226 end:
1227 if(externalkey)
1228 RegCloseKey(externalkey);
1229 if(winkey)
1230 RegCloseKey(winkey);
1231 return;
1235 /*************************************************************
1236 * WineEngAddFontResourceEx
1239 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1241 if (ft_handle) /* do it only if we have freetype up and running */
1243 char *unixname;
1245 if(flags)
1246 FIXME("Ignoring flags %lx\n", flags);
1248 if((unixname = wine_get_unix_file_name(file)))
1250 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1251 HeapFree(GetProcessHeap(), 0, unixname);
1254 return 1;
1257 /*************************************************************
1258 * WineEngRemoveFontResourceEx
1261 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1263 FIXME(":stub\n");
1264 return TRUE;
1267 /*************************************************************
1268 * WineEngInit
1270 * Initialize FreeType library and create a list of available faces
1272 BOOL WineEngInit(void)
1274 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1275 static const WCHAR pathW[] = {'P','a','t','h',0};
1276 HKEY hkey;
1277 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1278 LPVOID data;
1279 WCHAR windowsdir[MAX_PATH];
1280 char *unixname;
1281 HANDLE font_mutex;
1283 TRACE("\n");
1285 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1286 if(!ft_handle) {
1287 WINE_MESSAGE(
1288 "Wine cannot find the FreeType font library. To enable Wine to\n"
1289 "use TrueType fonts please install a version of FreeType greater than\n"
1290 "or equal to 2.0.5.\n"
1291 "http://www.freetype.org\n");
1292 return FALSE;
1295 #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;}
1297 LOAD_FUNCPTR(FT_Vector_Unit)
1298 LOAD_FUNCPTR(FT_Done_Face)
1299 LOAD_FUNCPTR(FT_Get_Char_Index)
1300 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1301 LOAD_FUNCPTR(FT_Init_FreeType)
1302 LOAD_FUNCPTR(FT_Load_Glyph)
1303 LOAD_FUNCPTR(FT_Matrix_Multiply)
1304 LOAD_FUNCPTR(FT_MulFix)
1305 LOAD_FUNCPTR(FT_New_Face)
1306 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1307 LOAD_FUNCPTR(FT_Outline_Transform)
1308 LOAD_FUNCPTR(FT_Outline_Translate)
1309 LOAD_FUNCPTR(FT_Select_Charmap)
1310 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1311 LOAD_FUNCPTR(FT_Vector_Transform)
1313 #undef LOAD_FUNCPTR
1314 /* Don't warn if this one is missing */
1315 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1316 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1317 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1318 #ifdef HAVE_FREETYPE_FTWINFNT_H
1319 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1320 #endif
1321 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1322 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1323 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1324 <= 2.0.3 has FT_Sqrt64 */
1325 goto sym_not_found;
1328 if(pFT_Init_FreeType(&library) != 0) {
1329 ERR("Can't init FreeType library\n");
1330 wine_dlclose(ft_handle, NULL, 0);
1331 ft_handle = NULL;
1332 return FALSE;
1334 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1335 if (pFT_Library_Version)
1337 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1339 if (FT_Version.major<=0)
1341 FT_Version.major=2;
1342 FT_Version.minor=0;
1343 FT_Version.patch=5;
1345 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1346 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1347 ((FT_Version.minor << 8) & 0x00ff00) |
1348 ((FT_Version.patch ) & 0x0000ff);
1350 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1351 ERR("Failed to create font mutex\n");
1352 return FALSE;
1354 WaitForSingleObject(font_mutex, INFINITE);
1356 /* load the system fonts */
1357 load_system_fonts();
1359 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1360 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1361 strcatW(windowsdir, fontsW);
1362 if((unixname = wine_get_unix_file_name(windowsdir)))
1364 ReadFontDir(unixname, FALSE);
1365 HeapFree(GetProcessHeap(), 0, unixname);
1368 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1369 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1370 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1371 will skip these. */
1372 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1373 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1374 &hkey) == ERROR_SUCCESS) {
1375 LPWSTR valueW;
1376 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1377 &valuelen, &datalen, NULL, NULL);
1379 valuelen++; /* returned value doesn't include room for '\0' */
1380 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1381 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1382 if (valueW && data)
1384 dlen = datalen * sizeof(WCHAR);
1385 vlen = valuelen;
1386 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1387 &dlen) == ERROR_SUCCESS) {
1388 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1390 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1392 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1393 HeapFree(GetProcessHeap(), 0, unixname);
1396 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1398 WCHAR pathW[MAX_PATH];
1399 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1400 sprintfW(pathW, fmtW, windowsdir, data);
1401 if((unixname = wine_get_unix_file_name(pathW)))
1403 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1404 HeapFree(GetProcessHeap(), 0, unixname);
1407 /* reset dlen and vlen */
1408 dlen = datalen;
1409 vlen = valuelen;
1412 HeapFree(GetProcessHeap(), 0, data);
1413 HeapFree(GetProcessHeap(), 0, valueW);
1414 RegCloseKey(hkey);
1417 load_fontconfig_fonts();
1419 /* then look in any directories that we've specified in the config file */
1420 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1421 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1423 DWORD len;
1424 LPWSTR valueW;
1425 LPSTR valueA, ptr;
1427 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1429 len += sizeof(WCHAR);
1430 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1431 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1433 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1434 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1435 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1436 TRACE( "got font path %s\n", debugstr_a(valueA) );
1437 ptr = valueA;
1438 while (ptr)
1440 LPSTR next = strchr( ptr, ':' );
1441 if (next) *next++ = 0;
1442 ReadFontDir( ptr, TRUE );
1443 ptr = next;
1445 HeapFree( GetProcessHeap(), 0, valueA );
1447 HeapFree( GetProcessHeap(), 0, valueW );
1449 RegCloseKey(hkey);
1452 DumpFontList();
1453 LoadSubstList();
1454 DumpSubstList();
1455 LoadReplaceList();
1456 update_reg_entries();
1458 init_system_links();
1460 ReleaseMutex(font_mutex);
1461 return TRUE;
1462 sym_not_found:
1463 WINE_MESSAGE(
1464 "Wine cannot find certain functions that it needs inside the FreeType\n"
1465 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1466 "FreeType to at least version 2.0.5.\n"
1467 "http://www.freetype.org\n");
1468 wine_dlclose(ft_handle, NULL, 0);
1469 ft_handle = NULL;
1470 return FALSE;
1474 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1476 TT_OS2 *pOS2;
1477 TT_HoriHeader *pHori;
1479 LONG ppem;
1481 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1482 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1484 if(height == 0) height = 16;
1486 /* Calc. height of EM square:
1488 * For +ve lfHeight we have
1489 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1490 * Re-arranging gives:
1491 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1493 * For -ve lfHeight we have
1494 * |lfHeight| = ppem
1495 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1496 * with il = winAscent + winDescent - units_per_em]
1500 if(height > 0) {
1501 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1502 ppem = ft_face->units_per_EM * height /
1503 (pHori->Ascender - pHori->Descender);
1504 else
1505 ppem = ft_face->units_per_EM * height /
1506 (pOS2->usWinAscent + pOS2->usWinDescent);
1508 else
1509 ppem = -height;
1511 return ppem;
1514 static LONG load_VDMX(GdiFont, LONG);
1516 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1518 FT_Error err;
1519 FT_Face ft_face;
1521 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1522 err = pFT_New_Face(library, file, face_index, &ft_face);
1523 if(err) {
1524 ERR("FT_New_Face rets %d\n", err);
1525 return 0;
1528 /* set it here, as load_VDMX needs it */
1529 font->ft_face = ft_face;
1531 if(FT_IS_SCALABLE(ft_face)) {
1532 /* load the VDMX table if we have one */
1533 font->ppem = load_VDMX(font, height);
1534 if(font->ppem == 0)
1535 font->ppem = calc_ppem_for_height(ft_face, height);
1537 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1538 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1539 } else {
1540 font->ppem = height;
1541 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1542 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1544 return ft_face;
1548 static int get_nearest_charset(Face *face, int *cp)
1550 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1551 a single face with the requested charset. The idea is to check if
1552 the selected font supports the current ANSI codepage, if it does
1553 return the corresponding charset, else return the first charset */
1555 CHARSETINFO csi;
1556 int acp = GetACP(), i;
1557 DWORD fs0;
1559 *cp = acp;
1560 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1561 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1562 return csi.ciCharset;
1564 for(i = 0; i < 32; i++) {
1565 fs0 = 1L << i;
1566 if(face->fs.fsCsb[0] & fs0) {
1567 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1568 *cp = csi.ciACP;
1569 return csi.ciCharset;
1571 else
1572 FIXME("TCI failing on %lx\n", fs0);
1576 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1577 face->fs.fsCsb[0], face->file);
1578 *cp = acp;
1579 return DEFAULT_CHARSET;
1582 static GdiFont alloc_font(void)
1584 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1585 ret->gmsize = INIT_GM_SIZE;
1586 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1587 ret->gmsize * sizeof(*ret->gm));
1588 ret->potm = NULL;
1589 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1590 list_init(&ret->hfontlist);
1591 return ret;
1594 static void free_font(GdiFont font)
1596 if (font->ft_face) pFT_Done_Face(font->ft_face);
1597 HeapFree(GetProcessHeap(), 0, font->potm);
1598 HeapFree(GetProcessHeap(), 0, font->name);
1599 HeapFree(GetProcessHeap(), 0, font->gm);
1600 HeapFree(GetProcessHeap(), 0, font);
1604 /*************************************************************
1605 * load_VDMX
1607 * load the vdmx entry for the specified height
1610 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1611 ( ( (FT_ULong)_x4 << 24 ) | \
1612 ( (FT_ULong)_x3 << 16 ) | \
1613 ( (FT_ULong)_x2 << 8 ) | \
1614 (FT_ULong)_x1 )
1616 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1618 typedef struct {
1619 BYTE bCharSet;
1620 BYTE xRatio;
1621 BYTE yStartRatio;
1622 BYTE yEndRatio;
1623 } Ratios;
1626 static LONG load_VDMX(GdiFont font, LONG height)
1628 BYTE hdr[6], tmp[2], group[4];
1629 BYTE devXRatio, devYRatio;
1630 USHORT numRecs, numRatios;
1631 DWORD result, offset = -1;
1632 LONG ppem = 0;
1633 int i;
1635 /* For documentation on VDMX records, see
1636 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1639 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1641 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1642 return ppem;
1644 /* FIXME: need the real device aspect ratio */
1645 devXRatio = 1;
1646 devYRatio = 1;
1648 numRecs = GET_BE_WORD(&hdr[2]);
1649 numRatios = GET_BE_WORD(&hdr[4]);
1651 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1652 for(i = 0; i < numRatios; i++) {
1653 Ratios ratio;
1655 offset = (3 * 2) + (i * sizeof(Ratios));
1656 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1657 offset = -1;
1659 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1661 if((ratio.xRatio == 0 &&
1662 ratio.yStartRatio == 0 &&
1663 ratio.yEndRatio == 0) ||
1664 (devXRatio == ratio.xRatio &&
1665 devYRatio >= ratio.yStartRatio &&
1666 devYRatio <= ratio.yEndRatio))
1668 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1669 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1670 offset = GET_BE_WORD(tmp);
1671 break;
1675 if(offset == -1) {
1676 FIXME("No suitable ratio found\n");
1677 return ppem;
1680 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1681 USHORT recs;
1682 BYTE startsz, endsz;
1683 BYTE *vTable;
1685 recs = GET_BE_WORD(group);
1686 startsz = group[2];
1687 endsz = group[3];
1689 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1691 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1692 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1693 if(result == GDI_ERROR) {
1694 FIXME("Failed to retrieve vTable\n");
1695 goto end;
1698 if(height > 0) {
1699 for(i = 0; i < recs; i++) {
1700 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1701 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1702 ppem = GET_BE_WORD(&vTable[i * 6]);
1704 if(yMax + -yMin == height) {
1705 font->yMax = yMax;
1706 font->yMin = yMin;
1707 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1708 break;
1710 if(yMax + -yMin > height) {
1711 if(--i < 0) {
1712 ppem = 0;
1713 goto end; /* failed */
1715 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1716 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1717 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1718 break;
1721 if(!font->yMax) {
1722 ppem = 0;
1723 TRACE("ppem not found for height %ld\n", height);
1725 } else {
1726 ppem = -height;
1727 if(ppem < startsz || ppem > endsz)
1728 goto end;
1730 for(i = 0; i < recs; i++) {
1731 USHORT yPelHeight;
1732 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1734 if(yPelHeight > ppem)
1735 break; /* failed */
1737 if(yPelHeight == ppem) {
1738 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1739 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1740 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1741 break;
1745 end:
1746 HeapFree(GetProcessHeap(), 0, vTable);
1749 return ppem;
1752 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1754 if(font->font_desc.hash != fd->hash) return TRUE;
1755 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1756 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1757 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1760 static void calc_hash(FONT_DESC *pfd)
1762 DWORD hash = 0, *ptr, two_chars;
1763 WORD *pwc;
1764 unsigned int i;
1766 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1767 hash ^= *ptr;
1768 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1769 hash ^= *ptr;
1770 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1771 two_chars = *ptr;
1772 pwc = (WCHAR *)&two_chars;
1773 if(!*pwc) break;
1774 *pwc = toupperW(*pwc);
1775 pwc++;
1776 *pwc = toupperW(*pwc);
1777 hash ^= two_chars;
1778 if(!*pwc) break;
1780 pfd->hash = hash;
1781 return;
1784 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1786 GdiFont ret;
1787 FONT_DESC fd;
1788 HFONTLIST *hflist;
1789 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1791 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1792 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1793 calc_hash(&fd);
1795 /* try the in-use list */
1796 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1797 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1798 if(!fontcmp(ret, &fd)) {
1799 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1800 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1801 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1802 if(hflist->hfont == hfont)
1803 return ret;
1805 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1806 hflist->hfont = hfont;
1807 list_add_head(&ret->hfontlist, &hflist->entry);
1808 return ret;
1812 /* then the unused list */
1813 font_elem_ptr = list_head(&unused_gdi_font_list);
1814 while(font_elem_ptr) {
1815 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1816 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1817 if(!fontcmp(ret, &fd)) {
1818 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1819 assert(list_empty(&ret->hfontlist));
1820 TRACE("Found %p in unused list\n", ret);
1821 list_remove(&ret->entry);
1822 list_add_head(&gdi_font_list, &ret->entry);
1823 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1824 hflist->hfont = hfont;
1825 list_add_head(&ret->hfontlist, &hflist->entry);
1826 return ret;
1829 return NULL;
1832 /*************************************************************
1833 * WineEngCreateFontInstance
1836 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1838 GdiFont ret;
1839 Face *face, *best;
1840 Family *family;
1841 struct list *family_elem_ptr, *face_elem_ptr;
1842 INT height, width = 0;
1843 signed int diff = 0, newdiff;
1844 BOOL bd, it, can_use_bitmap;
1845 LOGFONTW lf;
1846 CHARSETINFO csi;
1847 HFONTLIST *hflist;
1849 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1850 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1852 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1853 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1854 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1855 lf.lfEscapement);
1857 /* check the cache first */
1858 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1859 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1860 return ret;
1863 TRACE("not in cache\n");
1864 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1866 TRACE("No fonts installed\n");
1867 return NULL;
1870 ret = alloc_font();
1872 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1873 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1874 calc_hash(&ret->font_desc);
1875 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1876 hflist->hfont = hfont;
1877 list_add_head(&ret->hfontlist, &hflist->entry);
1880 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1881 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1882 original value lfCharSet. Note this is a special case for
1883 Symbol and doesn't happen at least for "Wingdings*" */
1885 if(!strcmpiW(lf.lfFaceName, SymbolW))
1886 lf.lfCharSet = SYMBOL_CHARSET;
1888 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1889 switch(lf.lfCharSet) {
1890 case DEFAULT_CHARSET:
1891 csi.fs.fsCsb[0] = 0;
1892 break;
1893 default:
1894 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1895 csi.fs.fsCsb[0] = 0;
1896 break;
1900 family = NULL;
1901 if(lf.lfFaceName[0] != '\0') {
1902 FontSubst *psub;
1903 for(psub = substlist; psub; psub = psub->next)
1904 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1905 (psub->from.charset == -1 ||
1906 psub->from.charset == lf.lfCharSet))
1907 break;
1908 if(psub) {
1909 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1910 debugstr_w(psub->to.name));
1911 strcpyW(lf.lfFaceName, psub->to.name);
1914 /* We want a match on name and charset or just name if
1915 charset was DEFAULT_CHARSET. If the latter then
1916 we fixup the returned charset later in get_nearest_charset
1917 where we'll either use the charset of the current ansi codepage
1918 or if that's unavailable the first charset that the font supports.
1920 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1921 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1922 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1923 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1924 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1925 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1926 if(face->scalable || can_use_bitmap)
1927 goto found;
1933 /* If requested charset was DEFAULT_CHARSET then try using charset
1934 corresponding to the current ansi codepage */
1935 if(!csi.fs.fsCsb[0]) {
1936 INT acp = GetACP();
1937 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1938 FIXME("TCI failed on codepage %d\n", acp);
1939 csi.fs.fsCsb[0] = 0;
1940 } else
1941 lf.lfCharSet = csi.ciCharset;
1944 /* Face families are in the top 4 bits of lfPitchAndFamily,
1945 so mask with 0xF0 before testing */
1947 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1948 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1949 strcpyW(lf.lfFaceName, defFixed);
1950 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1951 strcpyW(lf.lfFaceName, defSerif);
1952 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1953 strcpyW(lf.lfFaceName, defSans);
1954 else
1955 strcpyW(lf.lfFaceName, defSans);
1956 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1957 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1958 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1959 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1960 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1961 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1962 if(face->scalable || can_use_bitmap)
1963 goto found;
1968 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1969 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1970 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1971 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1972 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1973 if(face->scalable || can_use_bitmap)
1974 goto found;
1979 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1980 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1981 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1982 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1983 if(face->scalable || can_use_bitmap) {
1984 csi.fs.fsCsb[0] = 0;
1985 FIXME("just using first face for now\n");
1986 goto found;
1990 FIXME("can't find a single appropriate font - bailing\n");
1991 free_font(ret);
1992 return NULL;
1994 found:
1995 it = lf.lfItalic ? 1 : 0;
1996 bd = lf.lfWeight > 550 ? 1 : 0;
1998 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1999 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2001 face = best = NULL;
2002 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2003 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2004 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2005 ((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])) {
2006 if(face->scalable)
2007 break;
2008 if(height > 0)
2009 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2010 else
2011 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2012 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2013 (diff < 0 && newdiff > diff)) {
2014 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2015 diff = newdiff;
2016 best = face;
2017 if(diff == 0)
2018 break;
2021 face = NULL;
2023 if(!face && best)
2024 face = best;
2025 else if(!face) {
2026 best = NULL;
2027 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2028 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2029 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0]) {
2030 if(face->scalable)
2031 break;
2032 if(height > 0)
2033 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2034 else
2035 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2036 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2037 (diff < 0 && newdiff > diff)) {
2038 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2039 diff = newdiff;
2040 best = face;
2041 if(diff == 0)
2042 break;
2045 face = NULL;
2047 if(!face && best)
2048 face = best;
2049 if(it && !face->Italic) ret->fake_italic = TRUE;
2050 if(bd && !face->Bold) ret->fake_bold = TRUE;
2053 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2055 if(csi.fs.fsCsb[0]) {
2056 ret->charset = lf.lfCharSet;
2057 ret->codepage = csi.ciACP;
2059 else
2060 ret->charset = get_nearest_charset(face, &ret->codepage);
2062 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2063 debugstr_w(face->StyleName), face->file, face->face_index);
2065 if(!face->scalable) {
2066 width = face->size.x_ppem >> 6;
2067 height = face->size.y_ppem >> 6;
2069 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2071 if (!ret->ft_face)
2073 free_font( ret );
2074 return 0;
2077 if (ret->charset == SYMBOL_CHARSET &&
2078 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2079 /* No ops */
2081 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2082 /* No ops */
2084 else {
2085 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2088 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2089 ret->name = strdupW(family->FamilyName);
2090 ret->underline = lf.lfUnderline ? 0xff : 0;
2091 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2093 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2095 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2096 list_add_head(&gdi_font_list, &ret->entry);
2097 return ret;
2100 static void dump_gdi_font_list(void)
2102 GdiFont gdiFont;
2103 struct list *elem_ptr;
2105 TRACE("---------- gdiFont Cache ----------\n");
2106 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2107 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2108 TRACE("gdiFont=%p %s %ld\n",
2109 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2112 TRACE("---------- Unused gdiFont Cache ----------\n");
2113 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2114 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2115 TRACE("gdiFont=%p %s %ld\n",
2116 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2120 /*************************************************************
2121 * WineEngDestroyFontInstance
2123 * free the gdiFont associated with this handle
2126 BOOL WineEngDestroyFontInstance(HFONT handle)
2128 GdiFont gdiFont;
2129 HFONTLIST *hflist;
2130 BOOL ret = FALSE;
2131 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2132 int i = 0;
2134 TRACE("destroying hfont=%p\n", handle);
2135 if(TRACE_ON(font))
2136 dump_gdi_font_list();
2138 font_elem_ptr = list_head(&gdi_font_list);
2139 while(font_elem_ptr) {
2140 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2141 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2143 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2144 while(hfontlist_elem_ptr) {
2145 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2146 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2147 if(hflist->hfont == handle) {
2148 list_remove(&hflist->entry);
2149 HeapFree(GetProcessHeap(), 0, hflist);
2150 ret = TRUE;
2153 if(list_empty(&gdiFont->hfontlist)) {
2154 TRACE("Moving to Unused list\n");
2155 list_remove(&gdiFont->entry);
2156 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2161 font_elem_ptr = list_head(&unused_gdi_font_list);
2162 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2163 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2164 while(font_elem_ptr) {
2165 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2166 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2167 TRACE("freeing %p\n", gdiFont);
2168 list_remove(&gdiFont->entry);
2169 free_font(gdiFont);
2171 return ret;
2174 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2175 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2177 OUTLINETEXTMETRICW *potm = NULL;
2178 UINT size;
2179 TEXTMETRICW tm, *ptm;
2180 GdiFont font = alloc_font();
2181 LONG width, height;
2183 if(face->scalable) {
2184 height = 100;
2185 width = 0;
2186 } else {
2187 height = face->size.y_ppem >> 6;
2188 width = face->size.x_ppem >> 6;
2191 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2193 free_font(font);
2194 return;
2197 font->name = strdupW(face->family->FamilyName);
2199 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2201 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2202 if(size) {
2203 potm = HeapAlloc(GetProcessHeap(), 0, size);
2204 WineEngGetOutlineTextMetrics(font, size, potm);
2205 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2206 } else {
2207 WineEngGetTextMetrics(font, &tm);
2208 ptm = &tm;
2211 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2212 pntm->ntmTm.tmAscent = ptm->tmAscent;
2213 pntm->ntmTm.tmDescent = ptm->tmDescent;
2214 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2215 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2216 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2217 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2218 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2219 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2220 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2221 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2222 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2223 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2224 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2225 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2226 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2227 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2228 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2229 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2230 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2231 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2232 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2233 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2234 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2236 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2237 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2238 *ptype |= RASTER_FONTTYPE;
2240 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2241 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2242 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2244 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2245 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2246 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2248 if(potm) {
2249 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2251 lstrcpynW(pelf->elfLogFont.lfFaceName,
2252 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2253 LF_FACESIZE);
2254 lstrcpynW(pelf->elfFullName,
2255 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2256 LF_FULLFACESIZE);
2257 lstrcpynW(pelf->elfStyle,
2258 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2259 LF_FACESIZE);
2261 HeapFree(GetProcessHeap(), 0, potm);
2262 } else {
2263 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2265 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2266 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2267 pelf->elfStyle[0] = '\0';
2270 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2272 free_font(font);
2275 /*************************************************************
2276 * WineEngEnumFonts
2279 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2281 Family *family;
2282 Face *face;
2283 struct list *family_elem_ptr, *face_elem_ptr;
2284 ENUMLOGFONTEXW elf;
2285 NEWTEXTMETRICEXW ntm;
2286 DWORD type, ret = 1;
2287 FONTSIGNATURE fs;
2288 CHARSETINFO csi;
2289 LOGFONTW lf;
2290 int i;
2292 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2294 if(plf->lfFaceName[0]) {
2295 FontSubst *psub;
2296 for(psub = substlist; psub; psub = psub->next)
2297 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2298 (psub->from.charset == -1 ||
2299 psub->from.charset == plf->lfCharSet))
2300 break;
2301 if(psub) {
2302 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2303 debugstr_w(psub->to.name));
2304 memcpy(&lf, plf, sizeof(lf));
2305 strcpyW(lf.lfFaceName, psub->to.name);
2306 plf = &lf;
2309 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2310 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2311 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2312 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2313 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2314 GetEnumStructs(face, &elf, &ntm, &type);
2315 for(i = 0; i < 32; i++) {
2316 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2317 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2318 strcpyW(elf.elfScript, OEM_DOSW);
2319 i = 32; /* break out of loop */
2320 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2321 continue;
2322 else {
2323 fs.fsCsb[0] = 1L << i;
2324 fs.fsCsb[1] = 0;
2325 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2326 TCI_SRCFONTSIG))
2327 csi.ciCharset = DEFAULT_CHARSET;
2328 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2329 if(csi.ciCharset != DEFAULT_CHARSET) {
2330 elf.elfLogFont.lfCharSet =
2331 ntm.ntmTm.tmCharSet = csi.ciCharset;
2332 if(ElfScriptsW[i])
2333 strcpyW(elf.elfScript, ElfScriptsW[i]);
2334 else
2335 FIXME("Unknown elfscript for bit %d\n", i);
2338 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2339 debugstr_w(elf.elfLogFont.lfFaceName),
2340 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2341 csi.ciCharset, type, debugstr_w(elf.elfScript),
2342 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2343 ntm.ntmTm.ntmFlags);
2344 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2345 if(!ret) goto end;
2350 } else {
2351 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2352 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2353 face_elem_ptr = list_head(&family->faces);
2354 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2355 GetEnumStructs(face, &elf, &ntm, &type);
2356 for(i = 0; i < 32; i++) {
2357 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2358 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2359 strcpyW(elf.elfScript, OEM_DOSW);
2360 i = 32; /* break out of loop */
2361 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2362 continue;
2363 else {
2364 fs.fsCsb[0] = 1L << i;
2365 fs.fsCsb[1] = 0;
2366 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2367 TCI_SRCFONTSIG))
2368 csi.ciCharset = DEFAULT_CHARSET;
2369 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2370 if(csi.ciCharset != DEFAULT_CHARSET) {
2371 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2372 csi.ciCharset;
2373 if(ElfScriptsW[i])
2374 strcpyW(elf.elfScript, ElfScriptsW[i]);
2375 else
2376 FIXME("Unknown elfscript for bit %d\n", i);
2379 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2380 debugstr_w(elf.elfLogFont.lfFaceName),
2381 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2382 csi.ciCharset, type, debugstr_w(elf.elfScript),
2383 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2384 ntm.ntmTm.ntmFlags);
2385 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2386 if(!ret) goto end;
2390 end:
2391 return ret;
2394 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2396 pt->x.value = vec->x >> 6;
2397 pt->x.fract = (vec->x & 0x3f) << 10;
2398 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2399 pt->y.value = vec->y >> 6;
2400 pt->y.fract = (vec->y & 0x3f) << 10;
2401 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2402 return;
2405 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2407 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2408 WCHAR wc = (WCHAR)glyph;
2409 char buf;
2410 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2411 return pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2414 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2415 glyph = glyph + 0xf000;
2416 return pFT_Get_Char_Index(font->ft_face, glyph);
2419 /*************************************************************
2420 * WineEngGetGlyphIndices
2422 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2424 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2425 LPWORD pgi, DWORD flags)
2427 INT i;
2429 for(i = 0; i < count; i++)
2430 pgi[i] = get_glyph_index(font, lpstr[i]);
2432 return count;
2435 /*************************************************************
2436 * WineEngGetGlyphOutline
2438 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2439 * except that the first parameter is the HWINEENGFONT of the font in
2440 * question rather than an HDC.
2443 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2444 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2445 const MAT2* lpmat)
2447 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2448 FT_Face ft_face = font->ft_face;
2449 FT_UInt glyph_index;
2450 DWORD width, height, pitch, needed = 0;
2451 FT_Bitmap ft_bitmap;
2452 FT_Error err;
2453 INT left, right, top = 0, bottom = 0;
2454 FT_Angle angle = 0;
2455 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2456 float widthRatio = 1.0;
2457 FT_Matrix transMat = identityMat;
2458 BOOL needsTransform = FALSE;
2461 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2462 buflen, buf, lpmat);
2464 if(format & GGO_GLYPH_INDEX) {
2465 glyph_index = glyph;
2466 format &= ~GGO_GLYPH_INDEX;
2467 } else
2468 glyph_index = get_glyph_index(font, glyph);
2470 if(glyph_index >= font->gmsize) {
2471 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2472 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2473 font->gmsize * sizeof(*font->gm));
2474 } else {
2475 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2476 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2477 return 1; /* FIXME */
2481 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2482 load_flags |= FT_LOAD_NO_BITMAP;
2484 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2486 if(err) {
2487 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2488 return GDI_ERROR;
2491 /* Scaling factor */
2492 if (font->aveWidth && font->potm) {
2493 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2496 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2497 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2499 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2500 font->gm[glyph_index].lsb = left >> 6;
2501 font->gm[glyph_index].bbx = (right - left) >> 6;
2503 /* Scaling transform */
2504 if(font->aveWidth) {
2505 FT_Matrix scaleMat;
2506 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2507 scaleMat.xy = 0;
2508 scaleMat.yx = 0;
2509 scaleMat.yy = (1 << 16);
2511 pFT_Matrix_Multiply(&scaleMat, &transMat);
2512 needsTransform = TRUE;
2515 /* Rotation transform */
2516 if(font->orientation) {
2517 FT_Matrix rotationMat;
2518 FT_Vector vecAngle;
2519 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2520 pFT_Vector_Unit(&vecAngle, angle);
2521 rotationMat.xx = vecAngle.x;
2522 rotationMat.xy = -vecAngle.y;
2523 rotationMat.yx = -rotationMat.xy;
2524 rotationMat.yy = rotationMat.xx;
2526 pFT_Matrix_Multiply(&rotationMat, &transMat);
2527 needsTransform = TRUE;
2530 /* Extra transformation specified by caller */
2531 if (lpmat) {
2532 FT_Matrix extraMat;
2533 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2534 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2535 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2536 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2537 pFT_Matrix_Multiply(&extraMat, &transMat);
2538 needsTransform = TRUE;
2541 if(!needsTransform) {
2542 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2543 bottom = (ft_face->glyph->metrics.horiBearingY -
2544 ft_face->glyph->metrics.height) & -64;
2545 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2546 lpgm->gmCellIncY = 0;
2547 } else {
2548 INT xc, yc;
2549 FT_Vector vec;
2550 for(xc = 0; xc < 2; xc++) {
2551 for(yc = 0; yc < 2; yc++) {
2552 vec.x = (ft_face->glyph->metrics.horiBearingX +
2553 xc * ft_face->glyph->metrics.width);
2554 vec.y = ft_face->glyph->metrics.horiBearingY -
2555 yc * ft_face->glyph->metrics.height;
2556 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2557 pFT_Vector_Transform(&vec, &transMat);
2558 if(xc == 0 && yc == 0) {
2559 left = right = vec.x;
2560 top = bottom = vec.y;
2561 } else {
2562 if(vec.x < left) left = vec.x;
2563 else if(vec.x > right) right = vec.x;
2564 if(vec.y < bottom) bottom = vec.y;
2565 else if(vec.y > top) top = vec.y;
2569 left = left & -64;
2570 right = (right + 63) & -64;
2571 bottom = bottom & -64;
2572 top = (top + 63) & -64;
2574 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2575 vec.x = ft_face->glyph->metrics.horiAdvance;
2576 vec.y = 0;
2577 pFT_Vector_Transform(&vec, &transMat);
2578 lpgm->gmCellIncX = (vec.x+63) >> 6;
2579 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2581 lpgm->gmBlackBoxX = (right - left) >> 6;
2582 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2583 lpgm->gmptGlyphOrigin.x = left >> 6;
2584 lpgm->gmptGlyphOrigin.y = top >> 6;
2586 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2587 font->gm[glyph_index].init = TRUE;
2589 if(format == GGO_METRICS)
2590 return 1; /* FIXME */
2592 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2593 TRACE("loaded a bitmap\n");
2594 return GDI_ERROR;
2597 switch(format) {
2598 case GGO_BITMAP:
2599 width = lpgm->gmBlackBoxX;
2600 height = lpgm->gmBlackBoxY;
2601 pitch = ((width + 31) >> 5) << 2;
2602 needed = pitch * height;
2604 if(!buf || !buflen) break;
2606 switch(ft_face->glyph->format) {
2607 case ft_glyph_format_bitmap:
2609 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2610 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2611 INT h = ft_face->glyph->bitmap.rows;
2612 while(h--) {
2613 memcpy(dst, src, w);
2614 src += ft_face->glyph->bitmap.pitch;
2615 dst += pitch;
2617 break;
2620 case ft_glyph_format_outline:
2621 ft_bitmap.width = width;
2622 ft_bitmap.rows = height;
2623 ft_bitmap.pitch = pitch;
2624 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2625 ft_bitmap.buffer = buf;
2627 if(needsTransform) {
2628 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2631 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2633 /* Note: FreeType will only set 'black' bits for us. */
2634 memset(buf, 0, needed);
2635 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2636 break;
2638 default:
2639 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2640 return GDI_ERROR;
2642 break;
2644 case GGO_GRAY2_BITMAP:
2645 case GGO_GRAY4_BITMAP:
2646 case GGO_GRAY8_BITMAP:
2647 case WINE_GGO_GRAY16_BITMAP:
2649 unsigned int mult, row, col;
2650 BYTE *start, *ptr;
2652 width = lpgm->gmBlackBoxX;
2653 height = lpgm->gmBlackBoxY;
2654 pitch = (width + 3) / 4 * 4;
2655 needed = pitch * height;
2657 if(!buf || !buflen) break;
2658 ft_bitmap.width = width;
2659 ft_bitmap.rows = height;
2660 ft_bitmap.pitch = pitch;
2661 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2662 ft_bitmap.buffer = buf;
2664 if(needsTransform) {
2665 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2668 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2670 memset(ft_bitmap.buffer, 0, buflen);
2672 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2674 if(format == GGO_GRAY2_BITMAP)
2675 mult = 4;
2676 else if(format == GGO_GRAY4_BITMAP)
2677 mult = 16;
2678 else if(format == GGO_GRAY8_BITMAP)
2679 mult = 64;
2680 else if(format == WINE_GGO_GRAY16_BITMAP)
2681 break;
2682 else {
2683 assert(0);
2684 break;
2687 start = buf;
2688 for(row = 0; row < height; row++) {
2689 ptr = start;
2690 for(col = 0; col < width; col++, ptr++) {
2691 *ptr = (((int)*ptr) * mult + 128) / 256;
2693 start += pitch;
2695 break;
2698 case GGO_NATIVE:
2700 int contour, point = 0, first_pt;
2701 FT_Outline *outline = &ft_face->glyph->outline;
2702 TTPOLYGONHEADER *pph;
2703 TTPOLYCURVE *ppc;
2704 DWORD pph_start, cpfx, type;
2706 if(buflen == 0) buf = NULL;
2708 if (needsTransform && buf) {
2709 pFT_Outline_Transform(outline, &transMat);
2712 for(contour = 0; contour < outline->n_contours; contour++) {
2713 pph_start = needed;
2714 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2715 first_pt = point;
2716 if(buf) {
2717 pph->dwType = TT_POLYGON_TYPE;
2718 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2720 needed += sizeof(*pph);
2721 point++;
2722 while(point <= outline->contours[contour]) {
2723 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2724 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2725 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2726 cpfx = 0;
2727 do {
2728 if(buf)
2729 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2730 cpfx++;
2731 point++;
2732 } while(point <= outline->contours[contour] &&
2733 (outline->tags[point] & FT_Curve_Tag_On) ==
2734 (outline->tags[point-1] & FT_Curve_Tag_On));
2735 /* At the end of a contour Windows adds the start point, but
2736 only for Beziers */
2737 if(point > outline->contours[contour] &&
2738 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2739 if(buf)
2740 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2741 cpfx++;
2742 } else if(point <= outline->contours[contour] &&
2743 outline->tags[point] & FT_Curve_Tag_On) {
2744 /* add closing pt for bezier */
2745 if(buf)
2746 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2747 cpfx++;
2748 point++;
2750 if(buf) {
2751 ppc->wType = type;
2752 ppc->cpfx = cpfx;
2754 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2756 if(buf)
2757 pph->cb = needed - pph_start;
2759 break;
2761 case GGO_BEZIER:
2763 /* Convert the quadratic Beziers to cubic Beziers.
2764 The parametric eqn for a cubic Bezier is, from PLRM:
2765 r(t) = at^3 + bt^2 + ct + r0
2766 with the control points:
2767 r1 = r0 + c/3
2768 r2 = r1 + (c + b)/3
2769 r3 = r0 + c + b + a
2771 A quadratic Beizer has the form:
2772 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2774 So equating powers of t leads to:
2775 r1 = 2/3 p1 + 1/3 p0
2776 r2 = 2/3 p1 + 1/3 p2
2777 and of course r0 = p0, r3 = p2
2780 int contour, point = 0, first_pt;
2781 FT_Outline *outline = &ft_face->glyph->outline;
2782 TTPOLYGONHEADER *pph;
2783 TTPOLYCURVE *ppc;
2784 DWORD pph_start, cpfx, type;
2785 FT_Vector cubic_control[4];
2786 if(buflen == 0) buf = NULL;
2788 if (needsTransform && buf) {
2789 pFT_Outline_Transform(outline, &transMat);
2792 for(contour = 0; contour < outline->n_contours; contour++) {
2793 pph_start = needed;
2794 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2795 first_pt = point;
2796 if(buf) {
2797 pph->dwType = TT_POLYGON_TYPE;
2798 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2800 needed += sizeof(*pph);
2801 point++;
2802 while(point <= outline->contours[contour]) {
2803 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2804 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2805 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2806 cpfx = 0;
2807 do {
2808 if(type == TT_PRIM_LINE) {
2809 if(buf)
2810 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2811 cpfx++;
2812 point++;
2813 } else {
2814 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2815 so cpfx = 3n */
2817 /* FIXME: Possible optimization in endpoint calculation
2818 if there are two consecutive curves */
2819 cubic_control[0] = outline->points[point-1];
2820 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2821 cubic_control[0].x += outline->points[point].x + 1;
2822 cubic_control[0].y += outline->points[point].y + 1;
2823 cubic_control[0].x >>= 1;
2824 cubic_control[0].y >>= 1;
2826 if(point+1 > outline->contours[contour])
2827 cubic_control[3] = outline->points[first_pt];
2828 else {
2829 cubic_control[3] = outline->points[point+1];
2830 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2831 cubic_control[3].x += outline->points[point].x + 1;
2832 cubic_control[3].y += outline->points[point].y + 1;
2833 cubic_control[3].x >>= 1;
2834 cubic_control[3].y >>= 1;
2837 /* r1 = 1/3 p0 + 2/3 p1
2838 r2 = 1/3 p2 + 2/3 p1 */
2839 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2840 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2841 cubic_control[2] = cubic_control[1];
2842 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2843 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2844 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2845 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2846 if(buf) {
2847 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2848 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2849 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2851 cpfx += 3;
2852 point++;
2854 } while(point <= outline->contours[contour] &&
2855 (outline->tags[point] & FT_Curve_Tag_On) ==
2856 (outline->tags[point-1] & FT_Curve_Tag_On));
2857 /* At the end of a contour Windows adds the start point,
2858 but only for Beziers and we've already done that.
2860 if(point <= outline->contours[contour] &&
2861 outline->tags[point] & FT_Curve_Tag_On) {
2862 /* This is the closing pt of a bezier, but we've already
2863 added it, so just inc point and carry on */
2864 point++;
2866 if(buf) {
2867 ppc->wType = type;
2868 ppc->cpfx = cpfx;
2870 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2872 if(buf)
2873 pph->cb = needed - pph_start;
2875 break;
2878 default:
2879 FIXME("Unsupported format %d\n", format);
2880 return GDI_ERROR;
2882 return needed;
2885 static BOOL get_bitmap_text_metrics(GdiFont font)
2887 FT_Face ft_face = font->ft_face;
2888 #ifdef HAVE_FREETYPE_FTWINFNT_H
2889 FT_WinFNT_HeaderRec winfnt_header;
2890 #endif
2891 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2892 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2893 font->potm->otmSize = size;
2895 #define TM font->potm->otmTextMetrics
2896 #ifdef HAVE_FREETYPE_FTWINFNT_H
2897 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2899 TM.tmHeight = winfnt_header.pixel_height;
2900 TM.tmAscent = winfnt_header.ascent;
2901 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2902 TM.tmInternalLeading = winfnt_header.internal_leading;
2903 TM.tmExternalLeading = winfnt_header.external_leading;
2904 TM.tmAveCharWidth = winfnt_header.avg_width;
2905 TM.tmMaxCharWidth = winfnt_header.max_width;
2906 TM.tmWeight = winfnt_header.weight;
2907 TM.tmOverhang = 0;
2908 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2909 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2910 TM.tmFirstChar = winfnt_header.first_char;
2911 TM.tmLastChar = winfnt_header.last_char;
2912 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2913 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2914 TM.tmItalic = winfnt_header.italic;
2915 TM.tmUnderlined = font->underline;
2916 TM.tmStruckOut = font->strikeout;
2917 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2918 TM.tmCharSet = winfnt_header.charset;
2920 else
2921 #endif
2923 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2924 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2925 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2926 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2927 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2928 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2929 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2930 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2931 TM.tmOverhang = 0;
2932 TM.tmDigitizedAspectX = 96; /* FIXME */
2933 TM.tmDigitizedAspectY = 96; /* FIXME */
2934 TM.tmFirstChar = 1;
2935 TM.tmLastChar = 255;
2936 TM.tmDefaultChar = 32;
2937 TM.tmBreakChar = 32;
2938 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2939 TM.tmUnderlined = font->underline;
2940 TM.tmStruckOut = font->strikeout;
2941 /* NB inverted meaning of TMPF_FIXED_PITCH */
2942 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2943 TM.tmCharSet = font->charset;
2945 #undef TM
2947 return TRUE;
2950 /*************************************************************
2951 * WineEngGetTextMetrics
2954 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2956 if(!font->potm) {
2957 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2958 if(!get_bitmap_text_metrics(font))
2959 return FALSE;
2961 if(!font->potm) return FALSE;
2962 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2964 if (font->aveWidth) {
2965 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2967 return TRUE;
2971 /*************************************************************
2972 * WineEngGetOutlineTextMetrics
2975 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2976 OUTLINETEXTMETRICW *potm)
2978 FT_Face ft_face = font->ft_face;
2979 UINT needed, lenfam, lensty, ret;
2980 TT_OS2 *pOS2;
2981 TT_HoriHeader *pHori;
2982 TT_Postscript *pPost;
2983 FT_Fixed x_scale, y_scale;
2984 WCHAR *family_nameW, *style_nameW;
2985 static const WCHAR spaceW[] = {' ', '\0'};
2986 char *cp;
2987 INT ascent, descent;
2989 TRACE("font=%p\n", font);
2991 if(!FT_IS_SCALABLE(ft_face))
2992 return 0;
2994 if(font->potm) {
2995 if(cbSize >= font->potm->otmSize)
2996 memcpy(potm, font->potm, font->potm->otmSize);
2997 return font->potm->otmSize;
3001 needed = sizeof(*potm);
3003 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3004 family_nameW = strdupW(font->name);
3006 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3007 * sizeof(WCHAR);
3008 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3009 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3010 style_nameW, lensty);
3012 /* These names should be read from the TT name table */
3014 /* length of otmpFamilyName */
3015 needed += lenfam;
3017 /* length of otmpFaceName */
3018 if(!strcasecmp(ft_face->style_name, "regular")) {
3019 needed += lenfam; /* just the family name */
3020 } else {
3021 needed += lenfam + lensty; /* family + " " + style */
3024 /* length of otmpStyleName */
3025 needed += lensty;
3027 /* length of otmpFullName */
3028 needed += lenfam + lensty;
3031 x_scale = ft_face->size->metrics.x_scale;
3032 y_scale = ft_face->size->metrics.y_scale;
3034 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3035 if(!pOS2) {
3036 FIXME("Can't find OS/2 table - not TT font?\n");
3037 ret = 0;
3038 goto end;
3041 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3042 if(!pHori) {
3043 FIXME("Can't find HHEA table - not TT font?\n");
3044 ret = 0;
3045 goto end;
3048 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3050 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",
3051 pOS2->usWinAscent, pOS2->usWinDescent,
3052 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3053 ft_face->ascender, ft_face->descender, ft_face->height,
3054 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3055 ft_face->bbox.yMax, ft_face->bbox.yMin);
3057 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3058 font->potm->otmSize = needed;
3060 #define TM font->potm->otmTextMetrics
3062 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3063 ascent = pHori->Ascender;
3064 descent = -pHori->Descender;
3065 } else {
3066 ascent = pOS2->usWinAscent;
3067 descent = pOS2->usWinDescent;
3070 if(font->yMax) {
3071 TM.tmAscent = font->yMax;
3072 TM.tmDescent = -font->yMin;
3073 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3074 } else {
3075 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3076 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3077 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3078 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3081 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3083 /* MSDN says:
3084 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3086 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3087 ((ascent + descent) -
3088 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3090 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3091 if (TM.tmAveCharWidth == 0) {
3092 TM.tmAveCharWidth = 1;
3094 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3095 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3096 TM.tmOverhang = 0;
3097 TM.tmDigitizedAspectX = 300;
3098 TM.tmDigitizedAspectY = 300;
3099 TM.tmFirstChar = pOS2->usFirstCharIndex;
3100 TM.tmLastChar = pOS2->usLastCharIndex;
3101 TM.tmDefaultChar = pOS2->usDefaultChar;
3102 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3103 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3104 TM.tmUnderlined = font->underline;
3105 TM.tmStruckOut = font->strikeout;
3107 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3108 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3109 (pOS2->version == 0xFFFFU ||
3110 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3111 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3112 else
3113 TM.tmPitchAndFamily = 0;
3115 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3116 case PAN_FAMILY_SCRIPT:
3117 TM.tmPitchAndFamily |= FF_SCRIPT;
3118 break;
3119 case PAN_FAMILY_DECORATIVE:
3120 case PAN_FAMILY_PICTORIAL:
3121 TM.tmPitchAndFamily |= FF_DECORATIVE;
3122 break;
3123 case PAN_FAMILY_TEXT_DISPLAY:
3124 if(TM.tmPitchAndFamily == 0) /* fixed */
3125 TM.tmPitchAndFamily = FF_MODERN;
3126 else {
3127 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3128 case PAN_SERIF_NORMAL_SANS:
3129 case PAN_SERIF_OBTUSE_SANS:
3130 case PAN_SERIF_PERP_SANS:
3131 TM.tmPitchAndFamily |= FF_SWISS;
3132 break;
3133 default:
3134 TM.tmPitchAndFamily |= FF_ROMAN;
3137 break;
3138 default:
3139 TM.tmPitchAndFamily |= FF_DONTCARE;
3142 if(FT_IS_SCALABLE(ft_face))
3143 TM.tmPitchAndFamily |= TMPF_VECTOR;
3144 if(FT_IS_SFNT(ft_face))
3145 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3147 TM.tmCharSet = font->charset;
3148 #undef TM
3150 font->potm->otmFiller = 0;
3151 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3152 font->potm->otmfsSelection = pOS2->fsSelection;
3153 font->potm->otmfsType = pOS2->fsType;
3154 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3155 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3156 font->potm->otmItalicAngle = 0; /* POST table */
3157 font->potm->otmEMSquare = ft_face->units_per_EM;
3158 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3159 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3160 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3161 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3162 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3163 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3164 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3165 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3166 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3167 font->potm->otmMacAscent = 0; /* where do these come from ? */
3168 font->potm->otmMacDescent = 0;
3169 font->potm->otmMacLineGap = 0;
3170 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3171 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3172 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3173 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3174 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3175 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3176 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3177 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3178 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3179 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3180 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3181 if(!pPost) {
3182 font->potm->otmsUnderscoreSize = 0;
3183 font->potm->otmsUnderscorePosition = 0;
3184 } else {
3185 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3186 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3189 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3190 cp = (char*)font->potm + sizeof(*font->potm);
3191 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3192 strcpyW((WCHAR*)cp, family_nameW);
3193 cp += lenfam;
3194 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3195 strcpyW((WCHAR*)cp, style_nameW);
3196 cp += lensty;
3197 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3198 strcpyW((WCHAR*)cp, family_nameW);
3199 if(strcasecmp(ft_face->style_name, "regular")) {
3200 strcatW((WCHAR*)cp, spaceW);
3201 strcatW((WCHAR*)cp, style_nameW);
3202 cp += lenfam + lensty;
3203 } else
3204 cp += lenfam;
3205 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3206 strcpyW((WCHAR*)cp, family_nameW);
3207 strcatW((WCHAR*)cp, spaceW);
3208 strcatW((WCHAR*)cp, style_nameW);
3209 ret = needed;
3211 if(potm && needed <= cbSize)
3212 memcpy(potm, font->potm, font->potm->otmSize);
3214 end:
3215 HeapFree(GetProcessHeap(), 0, style_nameW);
3216 HeapFree(GetProcessHeap(), 0, family_nameW);
3218 return ret;
3222 /*************************************************************
3223 * WineEngGetCharWidth
3226 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3227 LPINT buffer)
3229 UINT c;
3230 GLYPHMETRICS gm;
3231 FT_UInt glyph_index;
3233 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3235 for(c = firstChar; c <= lastChar; c++) {
3236 glyph_index = get_glyph_index(font, c);
3237 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3238 &gm, 0, NULL, NULL);
3239 buffer[c - firstChar] = font->gm[glyph_index].adv;
3241 return TRUE;
3244 /*************************************************************
3245 * WineEngGetCharABCWidths
3248 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3249 LPABC buffer)
3251 UINT c;
3252 GLYPHMETRICS gm;
3253 FT_UInt glyph_index;
3255 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3257 if(!FT_IS_SCALABLE(font->ft_face))
3258 return FALSE;
3260 for(c = firstChar; c <= lastChar; c++) {
3261 glyph_index = get_glyph_index(font, c);
3262 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3263 &gm, 0, NULL, NULL);
3264 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3265 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3266 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3267 font->gm[glyph_index].bbx;
3269 return TRUE;
3272 /*************************************************************
3273 * WineEngGetTextExtentPoint
3276 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3277 LPSIZE size)
3279 INT idx;
3280 GLYPHMETRICS gm;
3281 TEXTMETRICW tm;
3282 FT_UInt glyph_index;
3284 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3285 size);
3287 size->cx = 0;
3288 WineEngGetTextMetrics(font, &tm);
3289 size->cy = tm.tmHeight;
3291 for(idx = 0; idx < count; idx++) {
3292 glyph_index = get_glyph_index(font, wstr[idx]);
3293 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3294 &gm, 0, NULL, NULL);
3295 size->cx += font->gm[glyph_index].adv;
3297 TRACE("return %ld,%ld\n", size->cx, size->cy);
3298 return TRUE;
3301 /*************************************************************
3302 * WineEngGetTextExtentPointI
3305 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3306 LPSIZE size)
3308 INT idx;
3309 GLYPHMETRICS gm;
3310 TEXTMETRICW tm;
3312 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3314 size->cx = 0;
3315 WineEngGetTextMetrics(font, &tm);
3316 size->cy = tm.tmHeight;
3318 for(idx = 0; idx < count; idx++) {
3319 WineEngGetGlyphOutline(font, indices[idx],
3320 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3321 NULL);
3322 size->cx += font->gm[indices[idx]].adv;
3324 TRACE("return %ld,%ld\n", size->cx, size->cy);
3325 return TRUE;
3328 /*************************************************************
3329 * WineEngGetFontData
3332 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3333 DWORD cbData)
3335 FT_Face ft_face = font->ft_face;
3336 DWORD len;
3337 FT_Error err;
3339 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3340 font, table, offset, buf, cbData);
3342 if(!FT_IS_SFNT(ft_face))
3343 return GDI_ERROR;
3345 if(!buf || !cbData)
3346 len = 0;
3347 else
3348 len = cbData;
3350 if(table) { /* MS tags differ in endidness from FT ones */
3351 table = table >> 24 | table << 24 |
3352 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3355 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3356 if(pFT_Load_Sfnt_Table)
3357 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3358 else { /* Do it the hard way */
3359 TT_Face tt_face = (TT_Face) ft_face;
3360 SFNT_Interface *sfnt;
3361 if (FT_Version.major==2 && FT_Version.minor==0)
3363 /* 2.0.x */
3364 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3366 else
3368 /* A field was added in the middle of the structure in 2.1.x */
3369 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3371 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3373 if(err) {
3374 TRACE("Can't find table %08lx.\n", table);
3375 return GDI_ERROR;
3377 return len;
3380 /*************************************************************
3381 * WineEngGetTextFace
3384 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3386 if(str) {
3387 lstrcpynW(str, font->name, count);
3388 return strlenW(font->name);
3389 } else
3390 return strlenW(font->name) + 1;
3393 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3395 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3396 return font->charset;
3399 #else /* HAVE_FREETYPE */
3401 BOOL WineEngInit(void)
3403 return FALSE;
3405 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3407 return NULL;
3409 BOOL WineEngDestroyFontInstance(HFONT hfont)
3411 return FALSE;
3414 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3416 return 1;
3419 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3420 LPWORD pgi, DWORD flags)
3422 return GDI_ERROR;
3425 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3426 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3427 const MAT2* lpmat)
3429 ERR("called but we don't have FreeType\n");
3430 return GDI_ERROR;
3433 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3435 ERR("called but we don't have FreeType\n");
3436 return FALSE;
3439 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3440 OUTLINETEXTMETRICW *potm)
3442 ERR("called but we don't have FreeType\n");
3443 return 0;
3446 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3447 LPINT buffer)
3449 ERR("called but we don't have FreeType\n");
3450 return FALSE;
3453 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3454 LPABC buffer)
3456 ERR("called but we don't have FreeType\n");
3457 return FALSE;
3460 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3461 LPSIZE size)
3463 ERR("called but we don't have FreeType\n");
3464 return FALSE;
3467 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3468 LPSIZE size)
3470 ERR("called but we don't have FreeType\n");
3471 return FALSE;
3474 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3475 DWORD cbData)
3477 ERR("called but we don't have FreeType\n");
3478 return GDI_ERROR;
3481 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3483 ERR("called but we don't have FreeType\n");
3484 return 0;
3487 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3489 FIXME(":stub\n");
3490 return 1;
3493 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3495 FIXME(":stub\n");
3496 return TRUE;
3499 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3501 FIXME(":stub\n");
3502 return DEFAULT_CHARSET;
3505 #endif /* HAVE_FREETYPE */