msi: Add some more tests for MsiOpenDatabase.
[wine/testsucceed.git] / dlls / gdi / freetype.c
bloba664db9e26fd54733cf52aab75e7190ce849d26b
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "winternl.h"
39 #include "winerror.h"
40 #include "winreg.h"
41 #include "wingdi.h"
42 #include "gdi.h"
43 #include "gdi_private.h"
44 #include "wine/unicode.h"
45 #include "wine/debug.h"
46 #include "wine/list.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(font);
50 #ifdef HAVE_FREETYPE
52 #ifdef HAVE_FT2BUILD_H
53 #include <ft2build.h>
54 #endif
55 #ifdef HAVE_FREETYPE_FREETYPE_H
56 #include <freetype/freetype.h>
57 #endif
58 #ifdef HAVE_FREETYPE_FTGLYPH_H
59 #include <freetype/ftglyph.h>
60 #endif
61 #ifdef HAVE_FREETYPE_TTTABLES_H
62 #include <freetype/tttables.h>
63 #endif
64 #ifdef HAVE_FREETYPE_FTSNAMES_H
65 #include <freetype/ftsnames.h>
66 #else
67 # ifdef HAVE_FREETYPE_FTNAMES_H
68 # include <freetype/ftnames.h>
69 # endif
70 #endif
71 #ifdef HAVE_FREETYPE_TTNAMEID_H
72 #include <freetype/ttnameid.h>
73 #endif
74 #ifdef HAVE_FREETYPE_FTOUTLN_H
75 #include <freetype/ftoutln.h>
76 #endif
77 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
78 #include <freetype/internal/sfnt.h>
79 #endif
80 #ifdef HAVE_FREETYPE_FTTRIGON_H
81 #include <freetype/fttrigon.h>
82 #endif
83 #ifdef HAVE_FREETYPE_FTWINFNT_H
84 #include <freetype/ftwinfnt.h>
85 #endif
86 #ifdef HAVE_FREETYPE_FTMODAPI_H
87 #include <freetype/ftmodapi.h>
88 #endif
90 #ifndef SONAME_LIBFREETYPE
91 #define SONAME_LIBFREETYPE "libfreetype.so"
92 #endif
94 #ifndef HAVE_FT_TRUETYPEENGINETYPE
95 typedef enum
97 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
98 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
99 FT_TRUETYPE_ENGINE_TYPE_PATENTED
100 } FT_TrueTypeEngineType;
101 #endif
103 static FT_Library library = 0;
104 typedef struct
106 FT_Int major;
107 FT_Int minor;
108 FT_Int patch;
109 } FT_Version_t;
110 static FT_Version_t FT_Version;
111 static DWORD FT_SimpleVersion;
113 static void *ft_handle = NULL;
115 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
116 MAKE_FUNCPTR(FT_Vector_Unit);
117 MAKE_FUNCPTR(FT_Done_Face);
118 MAKE_FUNCPTR(FT_Get_Char_Index);
119 MAKE_FUNCPTR(FT_Get_Module);
120 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
121 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
122 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
123 MAKE_FUNCPTR(FT_Init_FreeType);
124 MAKE_FUNCPTR(FT_Load_Glyph);
125 MAKE_FUNCPTR(FT_Matrix_Multiply);
126 MAKE_FUNCPTR(FT_MulFix);
127 MAKE_FUNCPTR(FT_New_Face);
128 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
129 MAKE_FUNCPTR(FT_Outline_Transform);
130 MAKE_FUNCPTR(FT_Outline_Translate);
131 MAKE_FUNCPTR(FT_Select_Charmap);
132 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
133 MAKE_FUNCPTR(FT_Vector_Transform);
134 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
135 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
136 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
137 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
138 #ifdef HAVE_FREETYPE_FTWINFNT_H
139 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
140 #endif
142 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
143 #include <fontconfig/fontconfig.h>
144 MAKE_FUNCPTR(FcConfigGetCurrent);
145 MAKE_FUNCPTR(FcFontList);
146 MAKE_FUNCPTR(FcFontSetDestroy);
147 MAKE_FUNCPTR(FcInit);
148 MAKE_FUNCPTR(FcObjectSetAdd);
149 MAKE_FUNCPTR(FcObjectSetCreate);
150 MAKE_FUNCPTR(FcObjectSetDestroy);
151 MAKE_FUNCPTR(FcPatternCreate);
152 MAKE_FUNCPTR(FcPatternDestroy);
153 MAKE_FUNCPTR(FcPatternGetString);
154 #ifndef SONAME_LIBFONTCONFIG
155 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
156 #endif
157 #endif
159 #undef MAKE_FUNCPTR
161 #ifndef ft_encoding_none
162 #define FT_ENCODING_NONE ft_encoding_none
163 #endif
164 #ifndef ft_encoding_ms_symbol
165 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
166 #endif
167 #ifndef ft_encoding_unicode
168 #define FT_ENCODING_UNICODE ft_encoding_unicode
169 #endif
170 #ifndef ft_encoding_apple_roman
171 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
172 #endif
174 #ifdef WORDS_BIGENDIAN
175 #define GET_BE_WORD(x) (x)
176 #else
177 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
178 #endif
180 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
181 typedef struct {
182 FT_Short height;
183 FT_Short width;
184 FT_Pos size;
185 FT_Pos x_ppem;
186 FT_Pos y_ppem;
187 FT_Short internal_leading;
188 } Bitmap_Size;
190 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
191 So to let this compile on older versions of FreeType we'll define the
192 new structure here. */
193 typedef struct {
194 FT_Short height, width;
195 FT_Pos size, x_ppem, y_ppem;
196 } My_FT_Bitmap_Size;
198 typedef struct tagFace {
199 struct list entry;
200 WCHAR *StyleName;
201 char *file;
202 FT_Long face_index;
203 BOOL Italic;
204 BOOL Bold;
205 FONTSIGNATURE fs;
206 FONTSIGNATURE fs_links;
207 FT_Fixed font_version;
208 BOOL scalable;
209 Bitmap_Size size; /* set if face is a bitmap */
210 BOOL external; /* TRUE if we should manually add this font to the registry */
211 struct tagFamily *family;
212 } Face;
214 typedef struct tagFamily {
215 struct list entry;
216 const WCHAR *FamilyName;
217 struct list faces;
218 } Family;
220 typedef struct {
221 GLYPHMETRICS gm;
222 INT adv; /* These three hold to widths of the unrotated chars */
223 INT lsb;
224 INT bbx;
225 BOOL init;
226 } GM;
228 typedef struct {
229 FLOAT eM11, eM12;
230 FLOAT eM21, eM22;
231 } FMAT2;
233 typedef struct {
234 DWORD hash;
235 LOGFONTW lf;
236 FMAT2 matrix;
237 BOOL can_use_bitmap;
238 } FONT_DESC;
240 typedef struct tagHFONTLIST {
241 struct list entry;
242 HFONT hfont;
243 } HFONTLIST;
245 typedef struct {
246 struct list entry;
247 char *file_name;
248 INT index;
249 GdiFont font;
250 } CHILD_FONT;
252 struct tagGdiFont {
253 struct list entry;
254 FT_Face ft_face;
255 LPWSTR name;
256 int charset;
257 int codepage;
258 BOOL fake_italic;
259 BOOL fake_bold;
260 BYTE underline;
261 BYTE strikeout;
262 INT orientation;
263 GM *gm;
264 DWORD gmsize;
265 struct list hfontlist;
266 FONT_DESC font_desc;
267 LONG aveWidth;
268 SHORT yMax;
269 SHORT yMin;
270 OUTLINETEXTMETRICW *potm;
271 FONTSIGNATURE fs;
272 GdiFont base_font;
273 struct list child_fonts;
274 LONG ppem;
277 typedef struct {
278 struct list entry;
279 const WCHAR *font_name;
280 struct list links;
281 } SYSTEM_LINKS;
283 #define INIT_GM_SIZE 128
285 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
286 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
287 #define UNUSED_CACHE_SIZE 10
288 static struct list child_font_list = LIST_INIT(child_font_list);
289 static struct list system_links = LIST_INIT(system_links);
291 static struct list font_subst_list = LIST_INIT(font_subst_list);
293 static struct list font_list = LIST_INIT(font_list);
295 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
296 'R','o','m','a','n','\0'};
297 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
298 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
300 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
301 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
302 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
303 'S','e','r','i','f','\0'};
304 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
305 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
307 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
308 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
309 'W','i','n','d','o','w','s','\\',
310 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
311 'F','o','n','t','s','\0'};
313 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
314 'W','i','n','d','o','w','s',' ','N','T','\\',
315 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
316 'F','o','n','t','s','\0'};
318 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
319 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
320 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
321 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
323 static const WCHAR * const SystemFontValues[4] = {
324 System_Value,
325 OEMFont_Value,
326 FixedSys_Value,
327 NULL
330 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
331 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
333 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
334 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
335 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
336 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
337 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
338 'E','u','r','o','p','e','a','n','\0'};
339 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
340 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
341 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
342 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
343 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
344 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
345 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
346 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
347 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
348 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
349 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
350 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
352 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
353 WesternW, /*00*/
354 Central_EuropeanW,
355 CyrillicW,
356 GreekW,
357 TurkishW,
358 HebrewW,
359 ArabicW,
360 BalticW,
361 VietnameseW, /*08*/
362 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
363 ThaiW,
364 JapaneseW,
365 CHINESE_GB2312W,
366 HangulW,
367 CHINESE_BIG5W,
368 Hangul_Johab_W,
369 NULL, NULL, /*23*/
370 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
371 SymbolW /*31*/
374 typedef struct {
375 WCHAR *name;
376 INT charset;
377 } NameCs;
379 typedef struct tagFontSubst {
380 struct list entry;
381 NameCs from;
382 NameCs to;
383 } FontSubst;
385 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
387 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
390 /****************************************
391 * Notes on .fon files
393 * The fonts System, FixedSys and Terminal are special. There are typically multiple
394 * versions installed for different resolutions and codepages. Windows stores which one to use
395 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
396 * Key Meaning
397 * FIXEDFON.FON FixedSys
398 * FONTS.FON System
399 * OEMFONT.FON Terminal
400 * LogPixels Current dpi set by the display control panel applet
401 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
402 * also has a LogPixels value that appears to mirror this)
404 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
405 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
406 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
407 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
408 * so that makes sense.
410 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
411 * to be mapped into the registry on Windows 2000 at least).
412 * I have
413 * woafont=app850.fon
414 * ega80woa.fon=ega80850.fon
415 * ega40woa.fon=ega40850.fon
416 * cga80woa.fon=cga80850.fon
417 * cga40woa.fon=cga40850.fon
421 static inline BOOL is_win9x(void)
423 return GetVersion() & 0x80000000;
426 This function builds an FT_Fixed from a float. It puts the integer part
427 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
428 It fails if the integer part of the float number is greater than SHORT_MAX.
430 static inline FT_Fixed FT_FixedFromFloat(float f)
432 short value = f;
433 unsigned short fract = (f - value) * 0xFFFF;
434 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
438 This function builds an FT_Fixed from a FIXED. It simply put f.value
439 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
441 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
443 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
447 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
449 Family *family;
450 Face *face;
451 const char *file;
452 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
453 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
454 Face *ret = NULL;
456 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
457 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
459 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
461 if(face_name && strcmpiW(face_name, family->FamilyName))
462 continue;
463 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
465 file = strrchr(face->file, '/');
466 if(!file)
467 file = face->file;
468 else
469 file++;
470 if(!strcmp(file, file_nameA))
471 ret = face;
472 break;
475 HeapFree(GetProcessHeap(), 0, file_nameA);
476 return ret;
479 static Family *find_family_from_name(const WCHAR *name)
481 Family *family;
483 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
485 if(!strcmpiW(family->FamilyName, name))
486 return family;
489 return NULL;
492 static void DumpSubstList(void)
494 FontSubst *psub;
496 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
498 if(psub->from.charset != -1 || psub->to.charset != -1)
499 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
500 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
501 else
502 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
503 debugstr_w(psub->to.name));
505 return;
508 static LPWSTR strdupW(LPCWSTR p)
510 LPWSTR ret;
511 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
512 ret = HeapAlloc(GetProcessHeap(), 0, len);
513 memcpy(ret, p, len);
514 return ret;
517 static LPSTR strdupA(LPCSTR p)
519 LPSTR ret;
520 DWORD len = (strlen(p) + 1);
521 ret = HeapAlloc(GetProcessHeap(), 0, len);
522 memcpy(ret, p, len);
523 return ret;
526 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
527 INT from_charset)
529 FontSubst *element;
531 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
533 if(!strcmpiW(element->from.name, from_name) &&
534 (element->from.charset == from_charset ||
535 element->from.charset == -1))
536 return element;
539 return NULL;
542 #define ADD_FONT_SUBST_FORCE 1
544 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
546 FontSubst *from_exist, *to_exist;
548 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
550 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
552 list_remove(&from_exist->entry);
553 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
554 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
555 HeapFree(GetProcessHeap(), 0, from_exist);
556 from_exist = NULL;
559 if(!from_exist)
561 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
563 if(to_exist)
565 HeapFree(GetProcessHeap(), 0, subst->to.name);
566 subst->to.name = strdupW(to_exist->to.name);
569 list_add_tail(subst_list, &subst->entry);
571 return TRUE;
574 HeapFree(GetProcessHeap(), 0, subst->from.name);
575 HeapFree(GetProcessHeap(), 0, subst->to.name);
576 HeapFree(GetProcessHeap(), 0, subst);
577 return FALSE;
580 static void split_subst_info(NameCs *nc, LPSTR str)
582 CHAR *p = strrchr(str, ',');
583 DWORD len;
585 nc->charset = -1;
586 if(p && *(p+1)) {
587 nc->charset = strtol(p+1, NULL, 10);
588 *p = '\0';
590 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
591 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
592 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
595 static void LoadSubstList(void)
597 FontSubst *psub;
598 HKEY hkey;
599 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
600 LPSTR value;
601 LPVOID data;
603 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
604 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
605 &hkey) == ERROR_SUCCESS) {
607 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
608 &valuelen, &datalen, NULL, NULL);
610 valuelen++; /* returned value doesn't include room for '\0' */
611 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
612 data = HeapAlloc(GetProcessHeap(), 0, datalen);
614 dlen = datalen;
615 vlen = valuelen;
616 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
617 &dlen) == ERROR_SUCCESS) {
618 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
620 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
621 split_subst_info(&psub->from, value);
622 split_subst_info(&psub->to, data);
624 /* Win 2000 doesn't allow mapping between different charsets
625 or mapping of DEFAULT_CHARSET */
626 if((psub->to.charset != psub->from.charset) ||
627 psub->to.charset == DEFAULT_CHARSET) {
628 HeapFree(GetProcessHeap(), 0, psub->to.name);
629 HeapFree(GetProcessHeap(), 0, psub->from.name);
630 HeapFree(GetProcessHeap(), 0, psub);
631 } else {
632 add_font_subst(&font_subst_list, psub, 0);
634 /* reset dlen and vlen */
635 dlen = datalen;
636 vlen = valuelen;
638 HeapFree(GetProcessHeap(), 0, data);
639 HeapFree(GetProcessHeap(), 0, value);
640 RegCloseKey(hkey);
644 static WCHAR *get_familyname(FT_Face ft_face)
646 WCHAR *family = NULL;
647 FT_SfntName name;
648 FT_UInt num_names, name_index, i;
650 if(FT_IS_SFNT(ft_face))
652 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
654 for(name_index = 0; name_index < num_names; name_index++)
656 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
658 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
659 (name.language_id == GetUserDefaultLCID()) &&
660 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
661 (name.encoding_id == TT_MS_ID_UNICODE_CS))
663 /* String is not nul terminated and string_len is a byte length. */
664 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
665 for(i = 0; i < name.string_len / 2; i++)
667 WORD *tmp = (WORD *)&name.string[i * 2];
668 family[i] = GET_BE_WORD(*tmp);
670 family[i] = 0;
672 TRACE("Got localised name %s\n", debugstr_w(family));
673 return family;
679 return NULL;
683 #define ADDFONT_EXTERNAL_FONT 0x01
684 #define ADDFONT_FORCE_BITMAP 0x02
685 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
687 FT_Face ft_face;
688 TT_OS2 *pOS2;
689 TT_Header *pHeader = NULL;
690 WCHAR *english_family, *localised_family, *StyleW;
691 DWORD len;
692 Family *family;
693 Face *face;
694 struct list *family_elem_ptr, *face_elem_ptr;
695 FT_Error err;
696 FT_Long face_index = 0, num_faces;
697 #ifdef HAVE_FREETYPE_FTWINFNT_H
698 FT_WinFNT_HeaderRec winfnt_header;
699 #endif
700 int i, bitmap_num, internal_leading;
701 FONTSIGNATURE fs;
703 do {
704 char *family_name = fake_family;
706 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
707 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
708 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
709 return FALSE;
712 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*/
713 WARN("Ignoring font %s\n", debugstr_a(file));
714 pFT_Done_Face(ft_face);
715 return FALSE;
718 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
719 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
720 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
721 pFT_Done_Face(ft_face);
722 return FALSE;
725 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
726 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
727 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
728 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
729 "Skipping this font.\n", debugstr_a(file));
730 pFT_Done_Face(ft_face);
731 return FALSE;
734 if(!ft_face->family_name || !ft_face->style_name) {
735 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
736 pFT_Done_Face(ft_face);
737 return FALSE;
740 if(!family_name)
741 family_name = ft_face->family_name;
743 bitmap_num = 0;
744 do {
745 My_FT_Bitmap_Size *size = NULL;
747 if(!FT_IS_SCALABLE(ft_face))
748 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
750 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
751 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
752 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
754 localised_family = NULL;
755 if(!fake_family) {
756 localised_family = get_familyname(ft_face);
757 if(localised_family && !strcmpW(localised_family, english_family)) {
758 HeapFree(GetProcessHeap(), 0, localised_family);
759 localised_family = NULL;
763 family = NULL;
764 LIST_FOR_EACH(family_elem_ptr, &font_list) {
765 family = LIST_ENTRY(family_elem_ptr, Family, entry);
766 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
767 break;
768 family = NULL;
770 if(!family) {
771 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
772 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
773 list_init(&family->faces);
774 list_add_tail(&font_list, &family->entry);
776 if(localised_family) {
777 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
778 subst->from.name = strdupW(english_family);
779 subst->from.charset = -1;
780 subst->to.name = strdupW(localised_family);
781 subst->to.charset = -1;
782 add_font_subst(&font_subst_list, subst, 0);
785 HeapFree(GetProcessHeap(), 0, localised_family);
786 HeapFree(GetProcessHeap(), 0, english_family);
788 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
789 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
790 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
792 internal_leading = 0;
793 memset(&fs, 0, sizeof(fs));
795 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
796 if(pOS2) {
797 fs.fsCsb[0] = pOS2->ulCodePageRange1;
798 fs.fsCsb[1] = pOS2->ulCodePageRange2;
799 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
800 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
801 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
802 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
803 if(pOS2->version == 0) {
804 FT_UInt dummy;
806 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
807 fs.fsCsb[0] |= 1;
808 else
809 fs.fsCsb[0] |= 1L << 31;
812 #ifdef HAVE_FREETYPE_FTWINFNT_H
813 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
814 CHARSETINFO csi;
815 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
816 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
817 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
818 memcpy(&fs, &csi.fs, sizeof(csi.fs));
819 internal_leading = winfnt_header.internal_leading;
821 #endif
823 face_elem_ptr = list_head(&family->faces);
824 while(face_elem_ptr) {
825 face = LIST_ENTRY(face_elem_ptr, Face, entry);
826 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
827 if(!strcmpW(face->StyleName, StyleW) &&
828 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
829 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
830 debugstr_w(family->FamilyName), debugstr_w(StyleW),
831 face->font_version, pHeader ? pHeader->Font_Revision : 0);
833 if(fake_family) {
834 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
835 HeapFree(GetProcessHeap(), 0, StyleW);
836 pFT_Done_Face(ft_face);
837 return FALSE;
839 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
840 TRACE("Original font is newer so skipping this one\n");
841 HeapFree(GetProcessHeap(), 0, StyleW);
842 pFT_Done_Face(ft_face);
843 return FALSE;
844 } else {
845 TRACE("Replacing original with this one\n");
846 list_remove(&face->entry);
847 HeapFree(GetProcessHeap(), 0, face->file);
848 HeapFree(GetProcessHeap(), 0, face->StyleName);
849 HeapFree(GetProcessHeap(), 0, face);
850 break;
854 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
855 list_add_tail(&family->faces, &face->entry);
856 face->StyleName = StyleW;
857 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
858 strcpy(face->file, file);
859 face->face_index = face_index;
860 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
861 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
862 face->font_version = pHeader ? pHeader->Font_Revision : 0;
863 face->family = family;
864 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
865 memcpy(&face->fs, &fs, sizeof(face->fs));
866 memset(&face->fs_links, 0, sizeof(face->fs_links));
868 if(FT_IS_SCALABLE(ft_face)) {
869 memset(&face->size, 0, sizeof(face->size));
870 face->scalable = TRUE;
871 } else {
872 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
873 size->height, size->width, size->size >> 6,
874 size->x_ppem >> 6, size->y_ppem >> 6);
875 face->size.height = size->height;
876 face->size.width = size->width;
877 face->size.size = size->size;
878 face->size.x_ppem = size->x_ppem;
879 face->size.y_ppem = size->y_ppem;
880 face->size.internal_leading = internal_leading;
881 face->scalable = FALSE;
884 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
885 face->fs.fsCsb[0], face->fs.fsCsb[1],
886 face->fs.fsUsb[0], face->fs.fsUsb[1],
887 face->fs.fsUsb[2], face->fs.fsUsb[3]);
890 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
891 for(i = 0; i < ft_face->num_charmaps; i++) {
892 switch(ft_face->charmaps[i]->encoding) {
893 case FT_ENCODING_UNICODE:
894 case FT_ENCODING_APPLE_ROMAN:
895 face->fs.fsCsb[0] |= 1;
896 break;
897 case FT_ENCODING_MS_SYMBOL:
898 face->fs.fsCsb[0] |= 1L << 31;
899 break;
900 default:
901 break;
906 if(face->fs.fsCsb[0] & ~(1L << 31))
907 have_installed_roman_font = TRUE;
908 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
910 num_faces = ft_face->num_faces;
911 pFT_Done_Face(ft_face);
912 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
913 debugstr_w(StyleW));
914 } while(num_faces > ++face_index);
915 return TRUE;
918 static void DumpFontList(void)
920 Family *family;
921 Face *face;
922 struct list *family_elem_ptr, *face_elem_ptr;
924 LIST_FOR_EACH(family_elem_ptr, &font_list) {
925 family = LIST_ENTRY(family_elem_ptr, Family, entry);
926 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
927 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
928 face = LIST_ENTRY(face_elem_ptr, Face, entry);
929 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
930 if(!face->scalable)
931 TRACE(" %d", face->size.height);
932 TRACE("\n");
935 return;
938 /***********************************************************
939 * The replacement list is a way to map an entire font
940 * family onto another family. For example adding
942 * [HKCU\Software\Wine\Fonts\Replacements]
943 * "Wingdings"="Winedings"
945 * would enumerate the Winedings font both as Winedings and
946 * Wingdings. However if a real Wingdings font is present the
947 * replacement does not take place.
950 static void LoadReplaceList(void)
952 HKEY hkey;
953 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
954 LPSTR value;
955 LPVOID data;
956 Family *family;
957 Face *face;
958 struct list *family_elem_ptr, *face_elem_ptr;
959 WCHAR old_nameW[200];
961 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
962 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
964 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
965 &valuelen, &datalen, NULL, NULL);
967 valuelen++; /* returned value doesn't include room for '\0' */
968 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
969 data = HeapAlloc(GetProcessHeap(), 0, datalen);
971 dlen = datalen;
972 vlen = valuelen;
973 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
974 &dlen) == ERROR_SUCCESS) {
975 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
976 /* "NewName"="Oldname" */
977 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
978 break;
980 /* Find the old family and hence all of the font files
981 in that family */
982 LIST_FOR_EACH(family_elem_ptr, &font_list) {
983 family = LIST_ENTRY(family_elem_ptr, Family, entry);
984 if(!strcmpiW(family->FamilyName, old_nameW)) {
985 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
986 face = LIST_ENTRY(face_elem_ptr, Face, entry);
987 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
988 debugstr_w(face->StyleName), value);
989 /* Now add a new entry with the new family name */
990 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
992 break;
995 /* reset dlen and vlen */
996 dlen = datalen;
997 vlen = valuelen;
999 HeapFree(GetProcessHeap(), 0, data);
1000 HeapFree(GetProcessHeap(), 0, value);
1001 RegCloseKey(hkey);
1005 /*************************************************************
1006 * init_system_links
1008 static BOOL init_system_links(void)
1010 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1011 'W','i','n','d','o','w','s',' ','N','T','\\',
1012 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1013 'S','y','s','t','e','m','L','i','n','k',0};
1014 HKEY hkey;
1015 BOOL ret = FALSE;
1016 DWORD type, max_val, max_data, val_len, data_len, index;
1017 WCHAR *value, *data;
1018 WCHAR *entry, *next;
1019 SYSTEM_LINKS *font_link, *system_font_link;
1020 CHILD_FONT *child_font;
1021 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1022 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1023 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1024 FONTSIGNATURE fs;
1025 Family *family;
1026 Face *face;
1028 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1030 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1031 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1032 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1033 val_len = max_val + 1;
1034 data_len = max_data;
1035 index = 0;
1036 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1038 TRACE("%s:\n", debugstr_w(value));
1040 memset(&fs, 0, sizeof(fs));
1041 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1042 font_link->font_name = strdupW(value);
1043 list_init(&font_link->links);
1044 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1046 WCHAR *face_name;
1047 CHILD_FONT *child_font;
1049 TRACE("\t%s\n", debugstr_w(entry));
1051 next = entry + strlenW(entry) + 1;
1053 face_name = strchrW(entry, ',');
1054 if(face_name)
1056 *face_name++ = 0;
1057 while(isspaceW(*face_name))
1058 face_name++;
1060 face = find_face_from_filename(entry, face_name);
1061 if(!face)
1063 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1064 continue;
1067 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1068 child_font->file_name = strdupA(face->file);
1069 child_font->index = face->face_index;
1070 child_font->font = NULL;
1071 fs.fsCsb[0] |= face->fs.fsCsb[0];
1072 fs.fsCsb[1] |= face->fs.fsCsb[1];
1073 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1074 list_add_tail(&font_link->links, &child_font->entry);
1076 family = find_family_from_name(font_link->font_name);
1077 if(family)
1079 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1081 memcpy(&face->fs_links, &fs, sizeof(fs));
1084 list_add_tail(&system_links, &font_link->entry);
1085 val_len = max_val + 1;
1086 data_len = max_data;
1089 HeapFree(GetProcessHeap(), 0, value);
1090 HeapFree(GetProcessHeap(), 0, data);
1091 RegCloseKey(hkey);
1094 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1095 that Tahoma has */
1097 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1098 system_font_link->font_name = strdupW(System);
1099 list_init(&system_font_link->links);
1101 face = find_face_from_filename(tahoma_ttf, Tahoma);
1102 if(face)
1104 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1105 child_font->file_name = strdupA(face->file);
1106 child_font->index = face->face_index;
1107 child_font->font = NULL;
1108 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1109 list_add_tail(&system_font_link->links, &child_font->entry);
1111 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1113 if(!strcmpiW(font_link->font_name, Tahoma))
1115 CHILD_FONT *font_link_entry;
1116 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1118 CHILD_FONT *new_child;
1119 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1120 new_child->file_name = strdupA(font_link_entry->file_name);
1121 new_child->index = font_link_entry->index;
1122 new_child->font = NULL;
1123 list_add_tail(&system_font_link->links, &new_child->entry);
1125 break;
1128 list_add_tail(&system_links, &system_font_link->entry);
1129 return ret;
1132 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1134 DIR *dir;
1135 struct dirent *dent;
1136 char path[MAX_PATH];
1138 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1140 dir = opendir(dirname);
1141 if(!dir) {
1142 WARN("Can't open directory %s\n", debugstr_a(dirname));
1143 return FALSE;
1145 while((dent = readdir(dir)) != NULL) {
1146 struct stat statbuf;
1148 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1149 continue;
1151 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1153 sprintf(path, "%s/%s", dirname, dent->d_name);
1155 if(stat(path, &statbuf) == -1)
1157 WARN("Can't stat %s\n", debugstr_a(path));
1158 continue;
1160 if(S_ISDIR(statbuf.st_mode))
1161 ReadFontDir(path, external_fonts);
1162 else
1163 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1165 closedir(dir);
1166 return TRUE;
1169 static void load_fontconfig_fonts(void)
1171 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1172 void *fc_handle = NULL;
1173 FcConfig *config;
1174 FcPattern *pat;
1175 FcObjectSet *os;
1176 FcFontSet *fontset;
1177 int i, len;
1178 const char *file, *ext;
1180 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1181 if(!fc_handle) {
1182 TRACE("Wine cannot find the fontconfig library (%s).\n",
1183 SONAME_LIBFONTCONFIG);
1184 return;
1186 #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;}
1187 LOAD_FUNCPTR(FcConfigGetCurrent);
1188 LOAD_FUNCPTR(FcFontList);
1189 LOAD_FUNCPTR(FcFontSetDestroy);
1190 LOAD_FUNCPTR(FcInit);
1191 LOAD_FUNCPTR(FcObjectSetAdd);
1192 LOAD_FUNCPTR(FcObjectSetCreate);
1193 LOAD_FUNCPTR(FcObjectSetDestroy);
1194 LOAD_FUNCPTR(FcPatternCreate);
1195 LOAD_FUNCPTR(FcPatternDestroy);
1196 LOAD_FUNCPTR(FcPatternGetString);
1197 #undef LOAD_FUNCPTR
1199 if(!pFcInit()) return;
1201 config = pFcConfigGetCurrent();
1202 pat = pFcPatternCreate();
1203 os = pFcObjectSetCreate();
1204 pFcObjectSetAdd(os, FC_FILE);
1205 fontset = pFcFontList(config, pat, os);
1206 if(!fontset) return;
1207 for(i = 0; i < fontset->nfont; i++) {
1208 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1209 continue;
1210 TRACE("fontconfig: %s\n", file);
1212 /* We're just interested in OT/TT fonts for now, so this hack just
1213 picks up the standard extensions to save time loading every other
1214 font */
1215 len = strlen( file );
1216 if(len < 4) continue;
1217 ext = &file[ len - 3 ];
1218 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1219 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1221 pFcFontSetDestroy(fontset);
1222 pFcObjectSetDestroy(os);
1223 pFcPatternDestroy(pat);
1224 sym_not_found:
1225 #endif
1226 return;
1229 static BOOL load_font_from_data_dir(LPCWSTR file)
1231 BOOL ret = FALSE;
1232 const char *data_dir = wine_get_data_dir();
1234 if (!data_dir) data_dir = wine_get_build_dir();
1236 if (data_dir)
1238 INT len;
1239 char *unix_name;
1241 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1243 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1245 strcpy(unix_name, data_dir);
1246 strcat(unix_name, "/fonts/");
1248 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1250 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1251 HeapFree(GetProcessHeap(), 0, unix_name);
1253 return ret;
1256 static void load_system_fonts(void)
1258 HKEY hkey;
1259 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1260 const WCHAR * const *value;
1261 DWORD dlen, type;
1262 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1263 char *unixname;
1265 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1266 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1267 strcatW(windowsdir, fontsW);
1268 for(value = SystemFontValues; *value; value++) {
1269 dlen = sizeof(data);
1270 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1271 type == REG_SZ) {
1272 BOOL added = FALSE;
1274 sprintfW(pathW, fmtW, windowsdir, data);
1275 if((unixname = wine_get_unix_file_name(pathW))) {
1276 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1277 HeapFree(GetProcessHeap(), 0, unixname);
1279 if (!added)
1280 load_font_from_data_dir(data);
1283 RegCloseKey(hkey);
1287 /*************************************************************
1289 * This adds registry entries for any externally loaded fonts
1290 * (fonts from fontconfig or FontDirs). It also deletes entries
1291 * of no longer existing fonts.
1294 static void update_reg_entries(void)
1296 HKEY winkey = 0, externalkey = 0;
1297 LPWSTR valueW;
1298 LPVOID data;
1299 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1300 Family *family;
1301 Face *face;
1302 struct list *family_elem_ptr, *face_elem_ptr;
1303 WCHAR *file;
1304 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1305 static const WCHAR spaceW[] = {' ', '\0'};
1306 char *path;
1308 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1309 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1310 ERR("Can't create Windows font reg key\n");
1311 goto end;
1313 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1314 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1315 ERR("Can't create external font reg key\n");
1316 goto end;
1319 /* Delete all external fonts added last time */
1321 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1322 &valuelen, &datalen, NULL, NULL);
1323 valuelen++; /* returned value doesn't include room for '\0' */
1324 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1325 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1327 dlen = datalen * sizeof(WCHAR);
1328 vlen = valuelen;
1329 i = 0;
1330 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1331 &dlen) == ERROR_SUCCESS) {
1333 RegDeleteValueW(winkey, valueW);
1334 /* reset dlen and vlen */
1335 dlen = datalen;
1336 vlen = valuelen;
1338 HeapFree(GetProcessHeap(), 0, data);
1339 HeapFree(GetProcessHeap(), 0, valueW);
1341 /* Delete the old external fonts key */
1342 RegCloseKey(externalkey);
1343 externalkey = 0;
1344 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1346 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1347 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1348 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1349 ERR("Can't create external font reg key\n");
1350 goto end;
1353 /* enumerate the fonts and add external ones to the two keys */
1355 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1356 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1357 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1358 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1359 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1360 if(!face->external) continue;
1361 len = len_fam;
1362 if(strcmpiW(face->StyleName, RegularW))
1363 len = len_fam + strlenW(face->StyleName) + 1;
1364 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1365 strcpyW(valueW, family->FamilyName);
1366 if(len != len_fam) {
1367 strcatW(valueW, spaceW);
1368 strcatW(valueW, face->StyleName);
1370 strcatW(valueW, TrueType);
1371 if((path = strrchr(face->file, '/')) == NULL)
1372 path = face->file;
1373 else
1374 path++;
1375 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1377 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1378 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1379 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1380 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1382 HeapFree(GetProcessHeap(), 0, file);
1383 HeapFree(GetProcessHeap(), 0, valueW);
1386 end:
1387 if(externalkey)
1388 RegCloseKey(externalkey);
1389 if(winkey)
1390 RegCloseKey(winkey);
1391 return;
1395 /*************************************************************
1396 * WineEngAddFontResourceEx
1399 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1401 if (ft_handle) /* do it only if we have freetype up and running */
1403 char *unixname;
1405 if(flags)
1406 FIXME("Ignoring flags %lx\n", flags);
1408 if((unixname = wine_get_unix_file_name(file)))
1410 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1411 HeapFree(GetProcessHeap(), 0, unixname);
1414 return 1;
1417 /*************************************************************
1418 * WineEngRemoveFontResourceEx
1421 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1423 FIXME(":stub\n");
1424 return TRUE;
1427 static const struct nls_update_font_list
1429 UINT ansi_cp, oem_cp;
1430 const char *oem, *fixed, *system;
1431 const char *courier, *serif, *small, *sserif;
1432 } nls_update_font_list[] =
1434 /* Latin 1 (United States) */
1435 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1436 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1438 /* Latin 1 (Multilingual) */
1439 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1440 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1442 /* Eastern Europe */
1443 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1444 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1446 /* Cyrillic */
1447 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1448 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1450 /* Greek */
1451 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1452 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1454 /* Turkish */
1455 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1456 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1458 /* Hebrew */
1459 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1460 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1462 /* Arabic */
1463 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1464 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1466 /* Baltic */
1467 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1468 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1470 /* Vietnamese */
1471 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1472 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1474 /* Thai */
1475 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1476 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1478 /* Japanese */
1479 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1480 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1482 /* Chinese Simplified */
1483 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1484 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1486 /* Korean */
1487 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1488 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1490 /* Chinese Traditional */
1491 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1492 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1496 inline static HKEY create_fonts_NT_registry_key(void)
1498 HKEY hkey = 0;
1500 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1501 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1502 return hkey;
1505 inline static HKEY create_fonts_9x_registry_key(void)
1507 HKEY hkey = 0;
1509 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1510 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1511 return hkey;
1514 inline static HKEY create_config_fonts_registry_key(void)
1516 HKEY hkey = 0;
1518 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1519 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1520 return hkey;
1523 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1525 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1526 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1527 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1528 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1531 static void update_font_info(void)
1533 char buf[80];
1534 DWORD len, type;
1535 HKEY hkey = 0;
1536 UINT i, ansi_cp = 0, oem_cp = 0;
1537 LCID lcid = GetUserDefaultLCID();
1539 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1540 return;
1542 len = sizeof(buf);
1543 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1545 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1547 RegCloseKey(hkey);
1548 return;
1550 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1552 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1554 sprintf(buf, "%08lx", lcid);
1555 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1556 RegCloseKey(hkey);
1558 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1559 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1560 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1561 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1563 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1565 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1566 nls_update_font_list[i].oem_cp == oem_cp)
1568 HKEY hkey;
1570 hkey = create_config_fonts_registry_key();
1571 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1572 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1573 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1574 RegCloseKey(hkey);
1576 hkey = create_fonts_NT_registry_key();
1577 add_font_list(hkey, &nls_update_font_list[i]);
1578 RegCloseKey(hkey);
1580 hkey = create_fonts_9x_registry_key();
1581 add_font_list(hkey, &nls_update_font_list[i]);
1582 RegCloseKey(hkey);
1584 return;
1587 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1590 /*************************************************************
1591 * WineEngInit
1593 * Initialize FreeType library and create a list of available faces
1595 BOOL WineEngInit(void)
1597 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1598 static const WCHAR pathW[] = {'P','a','t','h',0};
1599 HKEY hkey;
1600 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1601 LPVOID data;
1602 WCHAR windowsdir[MAX_PATH];
1603 char *unixname;
1604 HANDLE font_mutex;
1605 const char *data_dir;
1607 TRACE("\n");
1609 /* update locale dependent font info in registry */
1610 update_font_info();
1612 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1613 if(!ft_handle) {
1614 WINE_MESSAGE(
1615 "Wine cannot find the FreeType font library. To enable Wine to\n"
1616 "use TrueType fonts please install a version of FreeType greater than\n"
1617 "or equal to 2.0.5.\n"
1618 "http://www.freetype.org\n");
1619 return FALSE;
1622 #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;}
1624 LOAD_FUNCPTR(FT_Vector_Unit)
1625 LOAD_FUNCPTR(FT_Done_Face)
1626 LOAD_FUNCPTR(FT_Get_Char_Index)
1627 LOAD_FUNCPTR(FT_Get_Module)
1628 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1629 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1630 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1631 LOAD_FUNCPTR(FT_Init_FreeType)
1632 LOAD_FUNCPTR(FT_Load_Glyph)
1633 LOAD_FUNCPTR(FT_Matrix_Multiply)
1634 LOAD_FUNCPTR(FT_MulFix)
1635 LOAD_FUNCPTR(FT_New_Face)
1636 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1637 LOAD_FUNCPTR(FT_Outline_Transform)
1638 LOAD_FUNCPTR(FT_Outline_Translate)
1639 LOAD_FUNCPTR(FT_Select_Charmap)
1640 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1641 LOAD_FUNCPTR(FT_Vector_Transform)
1643 #undef LOAD_FUNCPTR
1644 /* Don't warn if this one is missing */
1645 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1646 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1647 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1648 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1649 #ifdef HAVE_FREETYPE_FTWINFNT_H
1650 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1651 #endif
1652 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1653 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1654 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1655 <= 2.0.3 has FT_Sqrt64 */
1656 goto sym_not_found;
1659 if(pFT_Init_FreeType(&library) != 0) {
1660 ERR("Can't init FreeType library\n");
1661 wine_dlclose(ft_handle, NULL, 0);
1662 ft_handle = NULL;
1663 return FALSE;
1665 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1666 if (pFT_Library_Version)
1668 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1670 if (FT_Version.major<=0)
1672 FT_Version.major=2;
1673 FT_Version.minor=0;
1674 FT_Version.patch=5;
1676 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1677 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1678 ((FT_Version.minor << 8) & 0x00ff00) |
1679 ((FT_Version.patch ) & 0x0000ff);
1681 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1682 ERR("Failed to create font mutex\n");
1683 return FALSE;
1685 WaitForSingleObject(font_mutex, INFINITE);
1687 /* load the system bitmap fonts */
1688 load_system_fonts();
1690 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1691 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1692 strcatW(windowsdir, fontsW);
1693 if((unixname = wine_get_unix_file_name(windowsdir)))
1695 ReadFontDir(unixname, FALSE);
1696 HeapFree(GetProcessHeap(), 0, unixname);
1699 /* load the system truetype fonts */
1700 data_dir = wine_get_data_dir();
1701 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1702 strcpy(unixname, data_dir);
1703 strcat(unixname, "/fonts/");
1704 ReadFontDir(unixname, FALSE);
1705 HeapFree(GetProcessHeap(), 0, unixname);
1708 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1709 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1710 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1711 will skip these. */
1712 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1713 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1714 &hkey) == ERROR_SUCCESS) {
1715 LPWSTR valueW;
1716 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1717 &valuelen, &datalen, NULL, NULL);
1719 valuelen++; /* returned value doesn't include room for '\0' */
1720 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1721 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1722 if (valueW && data)
1724 dlen = datalen * sizeof(WCHAR);
1725 vlen = valuelen;
1726 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1727 &dlen) == ERROR_SUCCESS) {
1728 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1730 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1732 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1733 HeapFree(GetProcessHeap(), 0, unixname);
1736 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1738 WCHAR pathW[MAX_PATH];
1739 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1740 BOOL added = FALSE;
1742 sprintfW(pathW, fmtW, windowsdir, data);
1743 if((unixname = wine_get_unix_file_name(pathW)))
1745 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1746 HeapFree(GetProcessHeap(), 0, unixname);
1748 if (!added)
1749 load_font_from_data_dir(data);
1751 /* reset dlen and vlen */
1752 dlen = datalen;
1753 vlen = valuelen;
1756 HeapFree(GetProcessHeap(), 0, data);
1757 HeapFree(GetProcessHeap(), 0, valueW);
1758 RegCloseKey(hkey);
1761 load_fontconfig_fonts();
1763 /* then look in any directories that we've specified in the config file */
1764 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1765 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1767 DWORD len;
1768 LPWSTR valueW;
1769 LPSTR valueA, ptr;
1771 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1773 len += sizeof(WCHAR);
1774 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1775 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1777 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1778 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1779 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1780 TRACE( "got font path %s\n", debugstr_a(valueA) );
1781 ptr = valueA;
1782 while (ptr)
1784 LPSTR next = strchr( ptr, ':' );
1785 if (next) *next++ = 0;
1786 ReadFontDir( ptr, TRUE );
1787 ptr = next;
1789 HeapFree( GetProcessHeap(), 0, valueA );
1791 HeapFree( GetProcessHeap(), 0, valueW );
1793 RegCloseKey(hkey);
1796 DumpFontList();
1797 LoadSubstList();
1798 DumpSubstList();
1799 LoadReplaceList();
1800 update_reg_entries();
1802 init_system_links();
1804 ReleaseMutex(font_mutex);
1805 return TRUE;
1806 sym_not_found:
1807 WINE_MESSAGE(
1808 "Wine cannot find certain functions that it needs inside the FreeType\n"
1809 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1810 "FreeType to at least version 2.0.5.\n"
1811 "http://www.freetype.org\n");
1812 wine_dlclose(ft_handle, NULL, 0);
1813 ft_handle = NULL;
1814 return FALSE;
1818 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1820 TT_OS2 *pOS2;
1821 TT_HoriHeader *pHori;
1823 LONG ppem;
1825 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1826 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1828 if(height == 0) height = 16;
1830 /* Calc. height of EM square:
1832 * For +ve lfHeight we have
1833 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1834 * Re-arranging gives:
1835 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1837 * For -ve lfHeight we have
1838 * |lfHeight| = ppem
1839 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1840 * with il = winAscent + winDescent - units_per_em]
1844 if(height > 0) {
1845 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1846 ppem = ft_face->units_per_EM * height /
1847 (pHori->Ascender - pHori->Descender);
1848 else
1849 ppem = ft_face->units_per_EM * height /
1850 (pOS2->usWinAscent + pOS2->usWinDescent);
1852 else
1853 ppem = -height;
1855 return ppem;
1858 static LONG load_VDMX(GdiFont, LONG);
1860 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1862 FT_Error err;
1863 FT_Face ft_face;
1865 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1866 err = pFT_New_Face(library, file, face_index, &ft_face);
1867 if(err) {
1868 ERR("FT_New_Face rets %d\n", err);
1869 return 0;
1872 /* set it here, as load_VDMX needs it */
1873 font->ft_face = ft_face;
1875 if(FT_IS_SCALABLE(ft_face)) {
1876 /* load the VDMX table if we have one */
1877 font->ppem = load_VDMX(font, height);
1878 if(font->ppem == 0)
1879 font->ppem = calc_ppem_for_height(ft_face, height);
1881 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1882 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1883 } else {
1884 font->ppem = height;
1885 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1886 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1888 return ft_face;
1892 static int get_nearest_charset(Face *face, int *cp)
1894 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1895 a single face with the requested charset. The idea is to check if
1896 the selected font supports the current ANSI codepage, if it does
1897 return the corresponding charset, else return the first charset */
1899 CHARSETINFO csi;
1900 int acp = GetACP(), i;
1901 DWORD fs0;
1903 *cp = acp;
1904 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
1905 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1906 return csi.ciCharset;
1908 for(i = 0; i < 32; i++) {
1909 fs0 = 1L << i;
1910 if(face->fs.fsCsb[0] & fs0) {
1911 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1912 *cp = csi.ciACP;
1913 return csi.ciCharset;
1915 else
1916 FIXME("TCI failing on %lx\n", fs0);
1920 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1921 face->fs.fsCsb[0], face->file);
1922 *cp = acp;
1923 return DEFAULT_CHARSET;
1926 static GdiFont alloc_font(void)
1928 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1929 ret->gmsize = INIT_GM_SIZE;
1930 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1931 ret->gmsize * sizeof(*ret->gm));
1932 ret->potm = NULL;
1933 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1934 list_init(&ret->hfontlist);
1935 list_init(&ret->child_fonts);
1936 return ret;
1939 static void free_font(GdiFont font)
1941 struct list *cursor, *cursor2;
1943 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1945 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1946 struct list *first_hfont;
1947 HFONTLIST *hfontlist;
1948 list_remove(cursor);
1949 if(child->font)
1951 first_hfont = list_head(&child->font->hfontlist);
1952 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1953 DeleteObject(hfontlist->hfont);
1954 HeapFree(GetProcessHeap(), 0, hfontlist);
1955 free_font(child->font);
1957 HeapFree(GetProcessHeap(), 0, child->file_name);
1958 HeapFree(GetProcessHeap(), 0, child);
1961 if (font->ft_face) pFT_Done_Face(font->ft_face);
1962 HeapFree(GetProcessHeap(), 0, font->potm);
1963 HeapFree(GetProcessHeap(), 0, font->name);
1964 HeapFree(GetProcessHeap(), 0, font->gm);
1965 HeapFree(GetProcessHeap(), 0, font);
1969 /*************************************************************
1970 * load_VDMX
1972 * load the vdmx entry for the specified height
1975 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1976 ( ( (FT_ULong)_x4 << 24 ) | \
1977 ( (FT_ULong)_x3 << 16 ) | \
1978 ( (FT_ULong)_x2 << 8 ) | \
1979 (FT_ULong)_x1 )
1981 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1983 typedef struct {
1984 BYTE bCharSet;
1985 BYTE xRatio;
1986 BYTE yStartRatio;
1987 BYTE yEndRatio;
1988 } Ratios;
1990 typedef struct {
1991 WORD recs;
1992 BYTE startsz;
1993 BYTE endsz;
1994 } VDMX_group;
1996 static LONG load_VDMX(GdiFont font, LONG height)
1998 WORD hdr[3], tmp;
1999 VDMX_group group;
2000 BYTE devXRatio, devYRatio;
2001 USHORT numRecs, numRatios;
2002 DWORD result, offset = -1;
2003 LONG ppem = 0;
2004 int i;
2006 /* For documentation on VDMX records, see
2007 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2010 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2012 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2013 return ppem;
2015 /* FIXME: need the real device aspect ratio */
2016 devXRatio = 1;
2017 devYRatio = 1;
2019 numRecs = GET_BE_WORD(hdr[1]);
2020 numRatios = GET_BE_WORD(hdr[2]);
2022 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2023 for(i = 0; i < numRatios; i++) {
2024 Ratios ratio;
2026 offset = (3 * 2) + (i * sizeof(Ratios));
2027 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2028 offset = -1;
2030 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2032 if((ratio.xRatio == 0 &&
2033 ratio.yStartRatio == 0 &&
2034 ratio.yEndRatio == 0) ||
2035 (devXRatio == ratio.xRatio &&
2036 devYRatio >= ratio.yStartRatio &&
2037 devYRatio <= ratio.yEndRatio))
2039 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2040 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2041 offset = GET_BE_WORD(tmp);
2042 break;
2046 if(offset == -1) {
2047 FIXME("No suitable ratio found\n");
2048 return ppem;
2051 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2052 USHORT recs;
2053 BYTE startsz, endsz;
2054 WORD *vTable;
2056 recs = GET_BE_WORD(group.recs);
2057 startsz = group.startsz;
2058 endsz = group.endsz;
2060 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2062 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2063 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2064 if(result == GDI_ERROR) {
2065 FIXME("Failed to retrieve vTable\n");
2066 goto end;
2069 if(height > 0) {
2070 for(i = 0; i < recs; i++) {
2071 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2072 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2073 ppem = GET_BE_WORD(vTable[i * 3]);
2075 if(yMax + -yMin == height) {
2076 font->yMax = yMax;
2077 font->yMin = yMin;
2078 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2079 break;
2081 if(yMax + -yMin > height) {
2082 if(--i < 0) {
2083 ppem = 0;
2084 goto end; /* failed */
2086 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2087 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2088 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2089 break;
2092 if(!font->yMax) {
2093 ppem = 0;
2094 TRACE("ppem not found for height %ld\n", height);
2096 } else {
2097 ppem = -height;
2098 if(ppem < startsz || ppem > endsz)
2099 goto end;
2101 for(i = 0; i < recs; i++) {
2102 USHORT yPelHeight;
2103 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2105 if(yPelHeight > ppem)
2106 break; /* failed */
2108 if(yPelHeight == ppem) {
2109 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2110 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2111 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2112 break;
2116 end:
2117 HeapFree(GetProcessHeap(), 0, vTable);
2120 return ppem;
2123 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
2125 if(font->font_desc.hash != fd->hash) return TRUE;
2126 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2127 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2128 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2129 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2132 static void calc_hash(FONT_DESC *pfd)
2134 DWORD hash = 0, *ptr, two_chars;
2135 WORD *pwc;
2136 unsigned int i;
2138 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2139 hash ^= *ptr;
2140 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2141 hash ^= *ptr;
2142 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2143 two_chars = *ptr;
2144 pwc = (WCHAR *)&two_chars;
2145 if(!*pwc) break;
2146 *pwc = toupperW(*pwc);
2147 pwc++;
2148 *pwc = toupperW(*pwc);
2149 hash ^= two_chars;
2150 if(!*pwc) break;
2152 hash ^= !pfd->can_use_bitmap;
2153 pfd->hash = hash;
2154 return;
2157 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2159 GdiFont ret;
2160 FONT_DESC fd;
2161 HFONTLIST *hflist;
2162 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2164 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2165 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2166 fd.can_use_bitmap = can_use_bitmap;
2167 calc_hash(&fd);
2169 /* try the in-use list */
2170 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2171 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2172 if(!fontcmp(ret, &fd)) {
2173 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2174 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2175 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2176 if(hflist->hfont == hfont)
2177 return ret;
2179 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2180 hflist->hfont = hfont;
2181 list_add_head(&ret->hfontlist, &hflist->entry);
2182 return ret;
2186 /* then the unused list */
2187 font_elem_ptr = list_head(&unused_gdi_font_list);
2188 while(font_elem_ptr) {
2189 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2190 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2191 if(!fontcmp(ret, &fd)) {
2192 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2193 assert(list_empty(&ret->hfontlist));
2194 TRACE("Found %p in unused list\n", ret);
2195 list_remove(&ret->entry);
2196 list_add_head(&gdi_font_list, &ret->entry);
2197 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2198 hflist->hfont = hfont;
2199 list_add_head(&ret->hfontlist, &hflist->entry);
2200 return ret;
2203 return NULL;
2207 /*************************************************************
2208 * create_child_font_list
2210 static BOOL create_child_font_list(GdiFont font)
2212 BOOL ret = FALSE;
2213 SYSTEM_LINKS *font_link;
2214 CHILD_FONT *font_link_entry, *new_child;
2216 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2218 if(!strcmpW(font_link->font_name, font->name))
2220 TRACE("found entry in system list\n");
2221 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2223 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2224 new_child->file_name = strdupA(font_link_entry->file_name);
2225 new_child->index = font_link_entry->index;
2226 new_child->font = NULL;
2227 list_add_tail(&font->child_fonts, &new_child->entry);
2228 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2230 ret = TRUE;
2231 break;
2235 return ret;
2238 /*************************************************************
2239 * WineEngCreateFontInstance
2242 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2244 GdiFont ret;
2245 Face *face, *best, *best_bitmap;
2246 Family *family, *last_resort_family;
2247 struct list *family_elem_ptr, *face_elem_ptr;
2248 INT height, width = 0;
2249 unsigned int score = 0, new_score;
2250 signed int diff = 0, newdiff;
2251 BOOL bd, it, can_use_bitmap;
2252 LOGFONTW lf;
2253 CHARSETINFO csi;
2254 HFONTLIST *hflist;
2256 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2258 struct list *first_hfont = list_head(&ret->hfontlist);
2259 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2260 if(hflist->hfont == hfont)
2261 return ret;
2264 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2265 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2267 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2268 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2269 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2270 lf.lfEscapement);
2272 /* check the cache first */
2273 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2274 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2275 return ret;
2278 TRACE("not in cache\n");
2279 if(list_empty(&font_list)) /* No fonts installed */
2281 TRACE("No fonts installed\n");
2282 return NULL;
2284 if(!have_installed_roman_font)
2286 TRACE("No roman font installed\n");
2287 return NULL;
2290 ret = alloc_font();
2292 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2293 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2294 ret->font_desc.can_use_bitmap = can_use_bitmap;
2295 calc_hash(&ret->font_desc);
2296 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2297 hflist->hfont = hfont;
2298 list_add_head(&ret->hfontlist, &hflist->entry);
2301 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2302 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2303 original value lfCharSet. Note this is a special case for
2304 Symbol and doesn't happen at least for "Wingdings*" */
2306 if(!strcmpiW(lf.lfFaceName, SymbolW))
2307 lf.lfCharSet = SYMBOL_CHARSET;
2309 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2310 switch(lf.lfCharSet) {
2311 case DEFAULT_CHARSET:
2312 csi.fs.fsCsb[0] = 0;
2313 break;
2314 default:
2315 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2316 csi.fs.fsCsb[0] = 0;
2317 break;
2321 family = NULL;
2322 if(lf.lfFaceName[0] != '\0') {
2323 FontSubst *psub;
2324 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2326 if(psub) {
2327 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2328 debugstr_w(psub->to.name));
2329 strcpyW(lf.lfFaceName, psub->to.name);
2332 /* We want a match on name and charset or just name if
2333 charset was DEFAULT_CHARSET. If the latter then
2334 we fixup the returned charset later in get_nearest_charset
2335 where we'll either use the charset of the current ansi codepage
2336 or if that's unavailable the first charset that the font supports.
2338 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2339 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2340 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2341 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2342 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2343 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2344 if(face->scalable || can_use_bitmap)
2345 goto found;
2351 /* If requested charset was DEFAULT_CHARSET then try using charset
2352 corresponding to the current ansi codepage */
2353 if(!csi.fs.fsCsb[0]) {
2354 INT acp = GetACP();
2355 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2356 FIXME("TCI failed on codepage %d\n", acp);
2357 csi.fs.fsCsb[0] = 0;
2358 } else
2359 lf.lfCharSet = csi.ciCharset;
2362 /* Face families are in the top 4 bits of lfPitchAndFamily,
2363 so mask with 0xF0 before testing */
2365 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2366 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2367 strcpyW(lf.lfFaceName, defFixed);
2368 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2369 strcpyW(lf.lfFaceName, defSerif);
2370 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2371 strcpyW(lf.lfFaceName, defSans);
2372 else
2373 strcpyW(lf.lfFaceName, defSans);
2374 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2375 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2376 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2377 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2378 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2379 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2380 if(face->scalable || can_use_bitmap)
2381 goto found;
2386 last_resort_family = NULL;
2387 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2388 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2389 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2390 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2391 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2392 if(face->scalable)
2393 goto found;
2394 if(can_use_bitmap && !last_resort_family)
2395 last_resort_family = family;
2400 if(last_resort_family) {
2401 family = last_resort_family;
2402 csi.fs.fsCsb[0] = 0;
2403 goto found;
2406 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2407 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2408 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2409 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2410 if(face->scalable) {
2411 csi.fs.fsCsb[0] = 0;
2412 FIXME("just using first face for now\n");
2413 goto found;
2415 if(can_use_bitmap && !last_resort_family)
2416 last_resort_family = family;
2419 if(!last_resort_family) {
2420 FIXME("can't find a single appropriate font - bailing\n");
2421 free_font(ret);
2422 return NULL;
2425 WARN("could only find a bitmap font - this will probably look awful!\n");
2426 family = last_resort_family;
2427 csi.fs.fsCsb[0] = 0;
2429 found:
2430 it = lf.lfItalic ? 1 : 0;
2431 bd = lf.lfWeight > 550 ? 1 : 0;
2433 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2434 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2436 face = best = best_bitmap = NULL;
2437 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2439 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2441 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2442 if(!best || new_score <= score)
2444 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2445 face->Italic, face->Bold, it, bd);
2446 score = new_score;
2447 best = face;
2448 if(best->scalable && score == 0) break;
2449 if(!best->scalable)
2451 if(height > 0)
2452 newdiff = height - (signed int)(best->size.height);
2453 else
2454 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2455 if(!best_bitmap || new_score < score ||
2456 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2458 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2459 diff = newdiff;
2460 best_bitmap = best;
2461 if(score == 0 && diff == 0) break;
2467 if(best)
2468 face = best->scalable ? best : best_bitmap;
2469 ret->fake_italic = (it && !face->Italic);
2470 ret->fake_bold = (bd && !face->Bold);
2472 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2474 if(csi.fs.fsCsb[0]) {
2475 ret->charset = lf.lfCharSet;
2476 ret->codepage = csi.ciACP;
2478 else
2479 ret->charset = get_nearest_charset(face, &ret->codepage);
2481 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2482 debugstr_w(face->StyleName), face->file, face->face_index);
2484 if(!face->scalable) {
2485 width = face->size.x_ppem >> 6;
2486 height = face->size.y_ppem >> 6;
2488 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2490 if (!ret->ft_face)
2492 free_font( ret );
2493 return 0;
2496 if (ret->charset == SYMBOL_CHARSET &&
2497 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2498 /* No ops */
2500 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2501 /* No ops */
2503 else {
2504 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2507 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2508 ret->name = strdupW(family->FamilyName);
2509 ret->underline = lf.lfUnderline ? 0xff : 0;
2510 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2511 create_child_font_list(ret);
2513 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2515 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2516 list_add_head(&gdi_font_list, &ret->entry);
2517 return ret;
2520 static void dump_gdi_font_list(void)
2522 GdiFont gdiFont;
2523 struct list *elem_ptr;
2525 TRACE("---------- gdiFont Cache ----------\n");
2526 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2527 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2528 TRACE("gdiFont=%p %s %ld\n",
2529 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2532 TRACE("---------- Unused gdiFont Cache ----------\n");
2533 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2534 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2535 TRACE("gdiFont=%p %s %ld\n",
2536 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2540 /*************************************************************
2541 * WineEngDestroyFontInstance
2543 * free the gdiFont associated with this handle
2546 BOOL WineEngDestroyFontInstance(HFONT handle)
2548 GdiFont gdiFont;
2549 HFONTLIST *hflist;
2550 BOOL ret = FALSE;
2551 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2552 int i = 0;
2554 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2556 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2557 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2558 if(hflist->hfont == handle)
2560 TRACE("removing child font %p from child list\n", gdiFont);
2561 list_remove(&gdiFont->entry);
2562 return TRUE;
2566 TRACE("destroying hfont=%p\n", handle);
2567 if(TRACE_ON(font))
2568 dump_gdi_font_list();
2570 font_elem_ptr = list_head(&gdi_font_list);
2571 while(font_elem_ptr) {
2572 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2573 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2575 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2576 while(hfontlist_elem_ptr) {
2577 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2578 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2579 if(hflist->hfont == handle) {
2580 list_remove(&hflist->entry);
2581 HeapFree(GetProcessHeap(), 0, hflist);
2582 ret = TRUE;
2585 if(list_empty(&gdiFont->hfontlist)) {
2586 TRACE("Moving to Unused list\n");
2587 list_remove(&gdiFont->entry);
2588 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2593 font_elem_ptr = list_head(&unused_gdi_font_list);
2594 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2595 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2596 while(font_elem_ptr) {
2597 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2598 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2599 TRACE("freeing %p\n", gdiFont);
2600 list_remove(&gdiFont->entry);
2601 free_font(gdiFont);
2603 return ret;
2606 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2607 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2609 OUTLINETEXTMETRICW *potm = NULL;
2610 UINT size;
2611 TEXTMETRICW tm, *ptm;
2612 GdiFont font = alloc_font();
2613 LONG width, height;
2615 if(face->scalable) {
2616 height = 100;
2617 width = 0;
2618 } else {
2619 height = face->size.y_ppem >> 6;
2620 width = face->size.x_ppem >> 6;
2623 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2625 free_font(font);
2626 return;
2629 font->name = strdupW(face->family->FamilyName);
2631 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2633 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2634 if(size) {
2635 potm = HeapAlloc(GetProcessHeap(), 0, size);
2636 WineEngGetOutlineTextMetrics(font, size, potm);
2637 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2638 } else {
2639 WineEngGetTextMetrics(font, &tm);
2640 ptm = &tm;
2643 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2644 pntm->ntmTm.tmAscent = ptm->tmAscent;
2645 pntm->ntmTm.tmDescent = ptm->tmDescent;
2646 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2647 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2648 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2649 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2650 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2651 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2652 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2653 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2654 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2655 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2656 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2657 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2658 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2659 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2660 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2661 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2662 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2663 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2664 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2665 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2666 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2668 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2669 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2670 *ptype |= RASTER_FONTTYPE;
2672 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2673 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2674 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2676 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2677 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2678 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2680 if(potm) {
2681 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2683 lstrcpynW(pelf->elfLogFont.lfFaceName,
2684 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2685 LF_FACESIZE);
2686 lstrcpynW(pelf->elfFullName,
2687 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2688 LF_FULLFACESIZE);
2689 lstrcpynW(pelf->elfStyle,
2690 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2691 LF_FACESIZE);
2693 HeapFree(GetProcessHeap(), 0, potm);
2694 } else {
2695 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2697 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2698 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2699 pelf->elfStyle[0] = '\0';
2702 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2704 free_font(font);
2707 /*************************************************************
2708 * WineEngEnumFonts
2711 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2713 Family *family;
2714 Face *face;
2715 struct list *family_elem_ptr, *face_elem_ptr;
2716 ENUMLOGFONTEXW elf;
2717 NEWTEXTMETRICEXW ntm;
2718 DWORD type, ret = 1;
2719 FONTSIGNATURE fs;
2720 CHARSETINFO csi;
2721 LOGFONTW lf;
2722 int i;
2724 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2726 if(plf->lfFaceName[0]) {
2727 FontSubst *psub;
2728 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2730 if(psub) {
2731 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2732 debugstr_w(psub->to.name));
2733 memcpy(&lf, plf, sizeof(lf));
2734 strcpyW(lf.lfFaceName, psub->to.name);
2735 plf = &lf;
2738 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2739 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2740 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2741 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2742 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2743 GetEnumStructs(face, &elf, &ntm, &type);
2744 for(i = 0; i < 32; i++) {
2745 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2746 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2747 strcpyW(elf.elfScript, OEM_DOSW);
2748 i = 32; /* break out of loop */
2749 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2750 continue;
2751 else {
2752 fs.fsCsb[0] = 1L << i;
2753 fs.fsCsb[1] = 0;
2754 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2755 TCI_SRCFONTSIG))
2756 csi.ciCharset = DEFAULT_CHARSET;
2757 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2758 if(csi.ciCharset != DEFAULT_CHARSET) {
2759 elf.elfLogFont.lfCharSet =
2760 ntm.ntmTm.tmCharSet = csi.ciCharset;
2761 if(ElfScriptsW[i])
2762 strcpyW(elf.elfScript, ElfScriptsW[i]);
2763 else
2764 FIXME("Unknown elfscript for bit %d\n", i);
2767 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2768 debugstr_w(elf.elfLogFont.lfFaceName),
2769 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2770 csi.ciCharset, type, debugstr_w(elf.elfScript),
2771 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2772 ntm.ntmTm.ntmFlags);
2773 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2774 if(!ret) goto end;
2779 } else {
2780 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2781 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2782 face_elem_ptr = list_head(&family->faces);
2783 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2784 GetEnumStructs(face, &elf, &ntm, &type);
2785 for(i = 0; i < 32; i++) {
2786 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2787 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2788 strcpyW(elf.elfScript, OEM_DOSW);
2789 i = 32; /* break out of loop */
2790 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2791 continue;
2792 else {
2793 fs.fsCsb[0] = 1L << i;
2794 fs.fsCsb[1] = 0;
2795 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2796 TCI_SRCFONTSIG))
2797 csi.ciCharset = DEFAULT_CHARSET;
2798 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2799 if(csi.ciCharset != DEFAULT_CHARSET) {
2800 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2801 csi.ciCharset;
2802 if(ElfScriptsW[i])
2803 strcpyW(elf.elfScript, ElfScriptsW[i]);
2804 else
2805 FIXME("Unknown elfscript for bit %d\n", i);
2808 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2809 debugstr_w(elf.elfLogFont.lfFaceName),
2810 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2811 csi.ciCharset, type, debugstr_w(elf.elfScript),
2812 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2813 ntm.ntmTm.ntmFlags);
2814 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2815 if(!ret) goto end;
2819 end:
2820 return ret;
2823 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2825 pt->x.value = vec->x >> 6;
2826 pt->x.fract = (vec->x & 0x3f) << 10;
2827 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2828 pt->y.value = vec->y >> 6;
2829 pt->y.fract = (vec->y & 0x3f) << 10;
2830 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2831 return;
2834 /***************************************************
2835 * According to the MSDN documentation on WideCharToMultiByte,
2836 * certain codepages cannot set the default_used parameter.
2837 * This returns TRUE if the codepage can set that parameter, false else
2838 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2840 static BOOL codepage_sets_default_used(UINT codepage)
2842 switch (codepage)
2844 case CP_UTF7:
2845 case CP_UTF8:
2846 case CP_SYMBOL:
2847 return FALSE;
2848 default:
2849 return TRUE;
2853 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2855 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2856 WCHAR wc = (WCHAR)glyph;
2857 BOOL default_used;
2858 BOOL *default_used_pointer;
2859 FT_UInt ret;
2860 char buf;
2861 default_used_pointer = NULL;
2862 default_used = FALSE;
2863 if (codepage_sets_default_used(font->codepage))
2864 default_used_pointer = &default_used;
2865 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2866 ret = 0;
2867 else
2868 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2869 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2870 return ret;
2873 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2874 glyph = glyph + 0xf000;
2875 return pFT_Get_Char_Index(font->ft_face, glyph);
2878 /*************************************************************
2879 * WineEngGetGlyphIndices
2881 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2883 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2884 LPWORD pgi, DWORD flags)
2886 int i;
2887 WCHAR default_char = 0;
2888 TEXTMETRICW textm;
2890 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
2892 for(i = 0; i < count; i++)
2894 pgi[i] = get_glyph_index(font, lpstr[i]);
2895 if (pgi[i] == 0)
2897 if (!default_char)
2899 WineEngGetTextMetrics(font, &textm);
2900 default_char = textm.tmDefaultChar;
2902 pgi[i] = default_char;
2905 return count;
2908 /*************************************************************
2909 * WineEngGetGlyphOutline
2911 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2912 * except that the first parameter is the HWINEENGFONT of the font in
2913 * question rather than an HDC.
2916 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2917 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2918 const MAT2* lpmat)
2920 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2921 FT_Face ft_face = font->ft_face;
2922 FT_UInt glyph_index;
2923 DWORD width, height, pitch, needed = 0;
2924 FT_Bitmap ft_bitmap;
2925 FT_Error err;
2926 INT left, right, top = 0, bottom = 0;
2927 FT_Angle angle = 0;
2928 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2929 float widthRatio = 1.0;
2930 FT_Matrix transMat = identityMat;
2931 BOOL needsTransform = FALSE;
2934 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2935 buflen, buf, lpmat);
2937 if(format & GGO_GLYPH_INDEX) {
2938 glyph_index = glyph;
2939 format &= ~GGO_GLYPH_INDEX;
2940 } else
2941 glyph_index = get_glyph_index(font, glyph);
2943 if(glyph_index >= font->gmsize) {
2944 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2945 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2946 font->gmsize * sizeof(*font->gm));
2947 } else {
2948 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2949 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2950 return 1; /* FIXME */
2954 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2955 load_flags |= FT_LOAD_NO_BITMAP;
2957 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2959 if(err) {
2960 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2961 return GDI_ERROR;
2964 /* Scaling factor */
2965 if (font->aveWidth && font->potm) {
2966 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2969 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2970 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2972 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2973 font->gm[glyph_index].lsb = left >> 6;
2974 font->gm[glyph_index].bbx = (right - left) >> 6;
2976 /* Scaling transform */
2977 if(font->aveWidth) {
2978 FT_Matrix scaleMat;
2979 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2980 scaleMat.xy = 0;
2981 scaleMat.yx = 0;
2982 scaleMat.yy = (1 << 16);
2984 pFT_Matrix_Multiply(&scaleMat, &transMat);
2985 needsTransform = TRUE;
2988 /* Slant transform */
2989 if (font->fake_italic) {
2990 FT_Matrix slantMat;
2992 slantMat.xx = (1 << 16);
2993 slantMat.xy = ((1 << 16) >> 2);
2994 slantMat.yx = 0;
2995 slantMat.yy = (1 << 16);
2996 pFT_Matrix_Multiply(&slantMat, &transMat);
2997 needsTransform = TRUE;
3000 /* Rotation transform */
3001 if(font->orientation) {
3002 FT_Matrix rotationMat;
3003 FT_Vector vecAngle;
3004 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3005 pFT_Vector_Unit(&vecAngle, angle);
3006 rotationMat.xx = vecAngle.x;
3007 rotationMat.xy = -vecAngle.y;
3008 rotationMat.yx = -rotationMat.xy;
3009 rotationMat.yy = rotationMat.xx;
3011 pFT_Matrix_Multiply(&rotationMat, &transMat);
3012 needsTransform = TRUE;
3015 /* Extra transformation specified by caller */
3016 if (lpmat) {
3017 FT_Matrix extraMat;
3018 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3019 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3020 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3021 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3022 pFT_Matrix_Multiply(&extraMat, &transMat);
3023 needsTransform = TRUE;
3026 if(!needsTransform) {
3027 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3028 bottom = (ft_face->glyph->metrics.horiBearingY -
3029 ft_face->glyph->metrics.height) & -64;
3030 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3031 lpgm->gmCellIncY = 0;
3032 } else {
3033 INT xc, yc;
3034 FT_Vector vec;
3035 for(xc = 0; xc < 2; xc++) {
3036 for(yc = 0; yc < 2; yc++) {
3037 vec.x = (ft_face->glyph->metrics.horiBearingX +
3038 xc * ft_face->glyph->metrics.width);
3039 vec.y = ft_face->glyph->metrics.horiBearingY -
3040 yc * ft_face->glyph->metrics.height;
3041 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3042 pFT_Vector_Transform(&vec, &transMat);
3043 if(xc == 0 && yc == 0) {
3044 left = right = vec.x;
3045 top = bottom = vec.y;
3046 } else {
3047 if(vec.x < left) left = vec.x;
3048 else if(vec.x > right) right = vec.x;
3049 if(vec.y < bottom) bottom = vec.y;
3050 else if(vec.y > top) top = vec.y;
3054 left = left & -64;
3055 right = (right + 63) & -64;
3056 bottom = bottom & -64;
3057 top = (top + 63) & -64;
3059 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3060 vec.x = ft_face->glyph->metrics.horiAdvance;
3061 vec.y = 0;
3062 pFT_Vector_Transform(&vec, &transMat);
3063 lpgm->gmCellIncX = (vec.x+63) >> 6;
3064 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3066 lpgm->gmBlackBoxX = (right - left) >> 6;
3067 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3068 lpgm->gmptGlyphOrigin.x = left >> 6;
3069 lpgm->gmptGlyphOrigin.y = top >> 6;
3071 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3072 font->gm[glyph_index].init = TRUE;
3074 if(format == GGO_METRICS)
3075 return 1; /* FIXME */
3077 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3078 TRACE("loaded a bitmap\n");
3079 return GDI_ERROR;
3082 switch(format) {
3083 case GGO_BITMAP:
3084 width = lpgm->gmBlackBoxX;
3085 height = lpgm->gmBlackBoxY;
3086 pitch = ((width + 31) >> 5) << 2;
3087 needed = pitch * height;
3089 if(!buf || !buflen) break;
3091 switch(ft_face->glyph->format) {
3092 case ft_glyph_format_bitmap:
3094 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3095 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3096 INT h = ft_face->glyph->bitmap.rows;
3097 while(h--) {
3098 memcpy(dst, src, w);
3099 src += ft_face->glyph->bitmap.pitch;
3100 dst += pitch;
3102 break;
3105 case ft_glyph_format_outline:
3106 ft_bitmap.width = width;
3107 ft_bitmap.rows = height;
3108 ft_bitmap.pitch = pitch;
3109 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3110 ft_bitmap.buffer = buf;
3112 if(needsTransform) {
3113 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3116 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3118 /* Note: FreeType will only set 'black' bits for us. */
3119 memset(buf, 0, needed);
3120 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3121 break;
3123 default:
3124 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3125 return GDI_ERROR;
3127 break;
3129 case GGO_GRAY2_BITMAP:
3130 case GGO_GRAY4_BITMAP:
3131 case GGO_GRAY8_BITMAP:
3132 case WINE_GGO_GRAY16_BITMAP:
3134 unsigned int mult, row, col;
3135 BYTE *start, *ptr;
3137 width = lpgm->gmBlackBoxX;
3138 height = lpgm->gmBlackBoxY;
3139 pitch = (width + 3) / 4 * 4;
3140 needed = pitch * height;
3142 if(!buf || !buflen) break;
3143 ft_bitmap.width = width;
3144 ft_bitmap.rows = height;
3145 ft_bitmap.pitch = pitch;
3146 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3147 ft_bitmap.buffer = buf;
3149 if(needsTransform) {
3150 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3153 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3155 memset(ft_bitmap.buffer, 0, buflen);
3157 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3159 if(format == GGO_GRAY2_BITMAP)
3160 mult = 4;
3161 else if(format == GGO_GRAY4_BITMAP)
3162 mult = 16;
3163 else if(format == GGO_GRAY8_BITMAP)
3164 mult = 64;
3165 else if(format == WINE_GGO_GRAY16_BITMAP)
3166 break;
3167 else {
3168 assert(0);
3169 break;
3172 start = buf;
3173 for(row = 0; row < height; row++) {
3174 ptr = start;
3175 for(col = 0; col < width; col++, ptr++) {
3176 *ptr = (((int)*ptr) * mult + 128) / 256;
3178 start += pitch;
3180 break;
3183 case GGO_NATIVE:
3185 int contour, point = 0, first_pt;
3186 FT_Outline *outline = &ft_face->glyph->outline;
3187 TTPOLYGONHEADER *pph;
3188 TTPOLYCURVE *ppc;
3189 DWORD pph_start, cpfx, type;
3191 if(buflen == 0) buf = NULL;
3193 if (needsTransform && buf) {
3194 pFT_Outline_Transform(outline, &transMat);
3197 for(contour = 0; contour < outline->n_contours; contour++) {
3198 pph_start = needed;
3199 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3200 first_pt = point;
3201 if(buf) {
3202 pph->dwType = TT_POLYGON_TYPE;
3203 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3205 needed += sizeof(*pph);
3206 point++;
3207 while(point <= outline->contours[contour]) {
3208 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3209 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3210 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3211 cpfx = 0;
3212 do {
3213 if(buf)
3214 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3215 cpfx++;
3216 point++;
3217 } while(point <= outline->contours[contour] &&
3218 (outline->tags[point] & FT_Curve_Tag_On) ==
3219 (outline->tags[point-1] & FT_Curve_Tag_On));
3220 /* At the end of a contour Windows adds the start point, but
3221 only for Beziers */
3222 if(point > outline->contours[contour] &&
3223 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3224 if(buf)
3225 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3226 cpfx++;
3227 } else if(point <= outline->contours[contour] &&
3228 outline->tags[point] & FT_Curve_Tag_On) {
3229 /* add closing pt for bezier */
3230 if(buf)
3231 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3232 cpfx++;
3233 point++;
3235 if(buf) {
3236 ppc->wType = type;
3237 ppc->cpfx = cpfx;
3239 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3241 if(buf)
3242 pph->cb = needed - pph_start;
3244 break;
3246 case GGO_BEZIER:
3248 /* Convert the quadratic Beziers to cubic Beziers.
3249 The parametric eqn for a cubic Bezier is, from PLRM:
3250 r(t) = at^3 + bt^2 + ct + r0
3251 with the control points:
3252 r1 = r0 + c/3
3253 r2 = r1 + (c + b)/3
3254 r3 = r0 + c + b + a
3256 A quadratic Beizer has the form:
3257 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3259 So equating powers of t leads to:
3260 r1 = 2/3 p1 + 1/3 p0
3261 r2 = 2/3 p1 + 1/3 p2
3262 and of course r0 = p0, r3 = p2
3265 int contour, point = 0, first_pt;
3266 FT_Outline *outline = &ft_face->glyph->outline;
3267 TTPOLYGONHEADER *pph;
3268 TTPOLYCURVE *ppc;
3269 DWORD pph_start, cpfx, type;
3270 FT_Vector cubic_control[4];
3271 if(buflen == 0) buf = NULL;
3273 if (needsTransform && buf) {
3274 pFT_Outline_Transform(outline, &transMat);
3277 for(contour = 0; contour < outline->n_contours; contour++) {
3278 pph_start = needed;
3279 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3280 first_pt = point;
3281 if(buf) {
3282 pph->dwType = TT_POLYGON_TYPE;
3283 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3285 needed += sizeof(*pph);
3286 point++;
3287 while(point <= outline->contours[contour]) {
3288 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3289 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3290 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3291 cpfx = 0;
3292 do {
3293 if(type == TT_PRIM_LINE) {
3294 if(buf)
3295 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3296 cpfx++;
3297 point++;
3298 } else {
3299 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3300 so cpfx = 3n */
3302 /* FIXME: Possible optimization in endpoint calculation
3303 if there are two consecutive curves */
3304 cubic_control[0] = outline->points[point-1];
3305 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3306 cubic_control[0].x += outline->points[point].x + 1;
3307 cubic_control[0].y += outline->points[point].y + 1;
3308 cubic_control[0].x >>= 1;
3309 cubic_control[0].y >>= 1;
3311 if(point+1 > outline->contours[contour])
3312 cubic_control[3] = outline->points[first_pt];
3313 else {
3314 cubic_control[3] = outline->points[point+1];
3315 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3316 cubic_control[3].x += outline->points[point].x + 1;
3317 cubic_control[3].y += outline->points[point].y + 1;
3318 cubic_control[3].x >>= 1;
3319 cubic_control[3].y >>= 1;
3322 /* r1 = 1/3 p0 + 2/3 p1
3323 r2 = 1/3 p2 + 2/3 p1 */
3324 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3325 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3326 cubic_control[2] = cubic_control[1];
3327 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3328 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3329 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3330 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3331 if(buf) {
3332 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3333 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3334 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3336 cpfx += 3;
3337 point++;
3339 } while(point <= outline->contours[contour] &&
3340 (outline->tags[point] & FT_Curve_Tag_On) ==
3341 (outline->tags[point-1] & FT_Curve_Tag_On));
3342 /* At the end of a contour Windows adds the start point,
3343 but only for Beziers and we've already done that.
3345 if(point <= outline->contours[contour] &&
3346 outline->tags[point] & FT_Curve_Tag_On) {
3347 /* This is the closing pt of a bezier, but we've already
3348 added it, so just inc point and carry on */
3349 point++;
3351 if(buf) {
3352 ppc->wType = type;
3353 ppc->cpfx = cpfx;
3355 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3357 if(buf)
3358 pph->cb = needed - pph_start;
3360 break;
3363 default:
3364 FIXME("Unsupported format %d\n", format);
3365 return GDI_ERROR;
3367 return needed;
3370 static BOOL get_bitmap_text_metrics(GdiFont font)
3372 FT_Face ft_face = font->ft_face;
3373 #ifdef HAVE_FREETYPE_FTWINFNT_H
3374 FT_WinFNT_HeaderRec winfnt_header;
3375 #endif
3376 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3377 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3378 font->potm->otmSize = size;
3380 #define TM font->potm->otmTextMetrics
3381 #ifdef HAVE_FREETYPE_FTWINFNT_H
3382 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3384 TM.tmHeight = winfnt_header.pixel_height;
3385 TM.tmAscent = winfnt_header.ascent;
3386 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3387 TM.tmInternalLeading = winfnt_header.internal_leading;
3388 TM.tmExternalLeading = winfnt_header.external_leading;
3389 TM.tmAveCharWidth = winfnt_header.avg_width;
3390 TM.tmMaxCharWidth = winfnt_header.max_width;
3391 TM.tmWeight = winfnt_header.weight;
3392 TM.tmOverhang = 0;
3393 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3394 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3395 TM.tmFirstChar = winfnt_header.first_char;
3396 TM.tmLastChar = winfnt_header.last_char;
3397 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3398 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3399 TM.tmItalic = winfnt_header.italic;
3400 TM.tmUnderlined = font->underline;
3401 TM.tmStruckOut = font->strikeout;
3402 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3403 TM.tmCharSet = winfnt_header.charset;
3405 else
3406 #endif
3408 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3409 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3410 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3411 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3412 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3413 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3414 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3415 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3416 TM.tmOverhang = 0;
3417 TM.tmDigitizedAspectX = 96; /* FIXME */
3418 TM.tmDigitizedAspectY = 96; /* FIXME */
3419 TM.tmFirstChar = 1;
3420 TM.tmLastChar = 255;
3421 TM.tmDefaultChar = 32;
3422 TM.tmBreakChar = 32;
3423 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3424 TM.tmUnderlined = font->underline;
3425 TM.tmStruckOut = font->strikeout;
3426 /* NB inverted meaning of TMPF_FIXED_PITCH */
3427 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3428 TM.tmCharSet = font->charset;
3430 #undef TM
3432 return TRUE;
3435 /*************************************************************
3436 * WineEngGetTextMetrics
3439 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3441 if(!font->potm) {
3442 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3443 if(!get_bitmap_text_metrics(font))
3444 return FALSE;
3446 if(!font->potm) return FALSE;
3447 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3449 if (font->aveWidth) {
3450 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3452 return TRUE;
3456 /*************************************************************
3457 * WineEngGetOutlineTextMetrics
3460 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3461 OUTLINETEXTMETRICW *potm)
3463 FT_Face ft_face = font->ft_face;
3464 UINT needed, lenfam, lensty, ret;
3465 TT_OS2 *pOS2;
3466 TT_HoriHeader *pHori;
3467 TT_Postscript *pPost;
3468 FT_Fixed x_scale, y_scale;
3469 WCHAR *family_nameW, *style_nameW;
3470 static const WCHAR spaceW[] = {' ', '\0'};
3471 char *cp;
3472 INT ascent, descent;
3474 TRACE("font=%p\n", font);
3476 if(!FT_IS_SCALABLE(ft_face))
3477 return 0;
3479 if(font->potm) {
3480 if(cbSize >= font->potm->otmSize)
3481 memcpy(potm, font->potm, font->potm->otmSize);
3482 return font->potm->otmSize;
3486 needed = sizeof(*potm);
3488 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3489 family_nameW = strdupW(font->name);
3491 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3492 * sizeof(WCHAR);
3493 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3494 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3495 style_nameW, lensty/sizeof(WCHAR));
3497 /* These names should be read from the TT name table */
3499 /* length of otmpFamilyName */
3500 needed += lenfam;
3502 /* length of otmpFaceName */
3503 if(!strcasecmp(ft_face->style_name, "regular")) {
3504 needed += lenfam; /* just the family name */
3505 } else {
3506 needed += lenfam + lensty; /* family + " " + style */
3509 /* length of otmpStyleName */
3510 needed += lensty;
3512 /* length of otmpFullName */
3513 needed += lenfam + lensty;
3516 x_scale = ft_face->size->metrics.x_scale;
3517 y_scale = ft_face->size->metrics.y_scale;
3519 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3520 if(!pOS2) {
3521 FIXME("Can't find OS/2 table - not TT font?\n");
3522 ret = 0;
3523 goto end;
3526 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3527 if(!pHori) {
3528 FIXME("Can't find HHEA table - not TT font?\n");
3529 ret = 0;
3530 goto end;
3533 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3535 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",
3536 pOS2->usWinAscent, pOS2->usWinDescent,
3537 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3538 ft_face->ascender, ft_face->descender, ft_face->height,
3539 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3540 ft_face->bbox.yMax, ft_face->bbox.yMin);
3542 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3543 font->potm->otmSize = needed;
3545 #define TM font->potm->otmTextMetrics
3547 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3548 ascent = pHori->Ascender;
3549 descent = -pHori->Descender;
3550 } else {
3551 ascent = pOS2->usWinAscent;
3552 descent = pOS2->usWinDescent;
3555 if(font->yMax) {
3556 TM.tmAscent = font->yMax;
3557 TM.tmDescent = -font->yMin;
3558 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3559 } else {
3560 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3561 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3562 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3563 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3566 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3568 /* MSDN says:
3569 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3571 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3572 ((ascent + descent) -
3573 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3575 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3576 if (TM.tmAveCharWidth == 0) {
3577 TM.tmAveCharWidth = 1;
3579 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3580 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3581 TM.tmOverhang = 0;
3582 TM.tmDigitizedAspectX = 300;
3583 TM.tmDigitizedAspectY = 300;
3584 TM.tmFirstChar = pOS2->usFirstCharIndex;
3585 TM.tmLastChar = pOS2->usLastCharIndex;
3586 TM.tmDefaultChar = pOS2->usDefaultChar;
3587 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3588 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3589 TM.tmUnderlined = font->underline;
3590 TM.tmStruckOut = font->strikeout;
3592 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3593 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3594 (pOS2->version == 0xFFFFU ||
3595 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3596 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3597 else
3598 TM.tmPitchAndFamily = 0;
3600 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3601 case PAN_FAMILY_SCRIPT:
3602 TM.tmPitchAndFamily |= FF_SCRIPT;
3603 break;
3604 case PAN_FAMILY_DECORATIVE:
3605 case PAN_FAMILY_PICTORIAL:
3606 TM.tmPitchAndFamily |= FF_DECORATIVE;
3607 break;
3608 case PAN_FAMILY_TEXT_DISPLAY:
3609 if(TM.tmPitchAndFamily == 0) /* fixed */
3610 TM.tmPitchAndFamily = FF_MODERN;
3611 else {
3612 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3613 case PAN_SERIF_NORMAL_SANS:
3614 case PAN_SERIF_OBTUSE_SANS:
3615 case PAN_SERIF_PERP_SANS:
3616 TM.tmPitchAndFamily |= FF_SWISS;
3617 break;
3618 default:
3619 TM.tmPitchAndFamily |= FF_ROMAN;
3622 break;
3623 default:
3624 TM.tmPitchAndFamily |= FF_DONTCARE;
3627 if(FT_IS_SCALABLE(ft_face))
3628 TM.tmPitchAndFamily |= TMPF_VECTOR;
3629 if(FT_IS_SFNT(ft_face))
3630 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3632 TM.tmCharSet = font->charset;
3633 #undef TM
3635 font->potm->otmFiller = 0;
3636 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3637 font->potm->otmfsSelection = pOS2->fsSelection;
3638 font->potm->otmfsType = pOS2->fsType;
3639 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3640 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3641 font->potm->otmItalicAngle = 0; /* POST table */
3642 font->potm->otmEMSquare = ft_face->units_per_EM;
3643 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3644 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3645 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3646 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3647 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3648 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3649 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3650 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3651 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3652 font->potm->otmMacAscent = 0; /* where do these come from ? */
3653 font->potm->otmMacDescent = 0;
3654 font->potm->otmMacLineGap = 0;
3655 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3656 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3657 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3658 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3659 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3660 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3661 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3662 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3663 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3664 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3665 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3666 if(!pPost) {
3667 font->potm->otmsUnderscoreSize = 0;
3668 font->potm->otmsUnderscorePosition = 0;
3669 } else {
3670 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3671 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3674 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3675 cp = (char*)font->potm + sizeof(*font->potm);
3676 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3677 strcpyW((WCHAR*)cp, family_nameW);
3678 cp += lenfam;
3679 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3680 strcpyW((WCHAR*)cp, style_nameW);
3681 cp += lensty;
3682 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3683 strcpyW((WCHAR*)cp, family_nameW);
3684 if(strcasecmp(ft_face->style_name, "regular")) {
3685 strcatW((WCHAR*)cp, spaceW);
3686 strcatW((WCHAR*)cp, style_nameW);
3687 cp += lenfam + lensty;
3688 } else
3689 cp += lenfam;
3690 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3691 strcpyW((WCHAR*)cp, family_nameW);
3692 strcatW((WCHAR*)cp, spaceW);
3693 strcatW((WCHAR*)cp, style_nameW);
3694 ret = needed;
3696 if(potm && needed <= cbSize)
3697 memcpy(potm, font->potm, font->potm->otmSize);
3699 end:
3700 HeapFree(GetProcessHeap(), 0, style_nameW);
3701 HeapFree(GetProcessHeap(), 0, family_nameW);
3703 return ret;
3706 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3708 HFONTLIST *hfontlist;
3709 child->font = alloc_font();
3710 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3711 if(!child->font->ft_face)
3713 free_font(child->font);
3714 child->font = NULL;
3715 return FALSE;
3718 child->font->orientation = font->orientation;
3719 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3720 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3721 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3722 child->font->base_font = font;
3723 list_add_head(&child_font_list, &child->font->entry);
3724 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3725 return TRUE;
3728 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3730 FT_UInt g;
3731 CHILD_FONT *child_font;
3733 if(font->base_font)
3734 font = font->base_font;
3736 *linked_font = font;
3738 if((*glyph = get_glyph_index(font, c)))
3739 return TRUE;
3741 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3743 if(!child_font->font)
3744 if(!load_child_font(font, child_font))
3745 continue;
3747 if(!child_font->font->ft_face)
3748 continue;
3749 g = get_glyph_index(child_font->font, c);
3750 if(g)
3752 *glyph = g;
3753 *linked_font = child_font->font;
3754 return TRUE;
3757 return FALSE;
3760 /*************************************************************
3761 * WineEngGetCharWidth
3764 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3765 LPINT buffer)
3767 UINT c;
3768 GLYPHMETRICS gm;
3769 FT_UInt glyph_index;
3770 GdiFont linked_font;
3772 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3774 for(c = firstChar; c <= lastChar; c++) {
3775 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3776 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3777 &gm, 0, NULL, NULL);
3778 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3780 return TRUE;
3783 /*************************************************************
3784 * WineEngGetCharABCWidths
3787 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3788 LPABC buffer)
3790 UINT c;
3791 GLYPHMETRICS gm;
3792 FT_UInt glyph_index;
3793 GdiFont linked_font;
3795 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3797 if(!FT_IS_SCALABLE(font->ft_face))
3798 return FALSE;
3800 for(c = firstChar; c <= lastChar; c++) {
3801 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3802 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3803 &gm, 0, NULL, NULL);
3804 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3805 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3806 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3807 linked_font->gm[glyph_index].bbx;
3809 return TRUE;
3812 /*************************************************************
3813 * WineEngGetCharABCWidthsI
3816 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
3817 LPABC buffer)
3819 UINT c;
3820 GLYPHMETRICS gm;
3821 FT_UInt glyph_index;
3822 GdiFont linked_font;
3824 if(!FT_IS_SCALABLE(font->ft_face))
3825 return FALSE;
3827 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
3828 if (!pgi)
3829 for(c = firstChar; c < firstChar+count; c++) {
3830 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
3831 &gm, 0, NULL, NULL);
3832 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
3833 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
3834 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
3835 - linked_font->gm[c].bbx;
3837 else
3838 for(c = 0; c < count; c++) {
3839 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
3840 &gm, 0, NULL, NULL);
3841 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
3842 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
3843 buffer[c].abcC = linked_font->gm[pgi[c]].adv
3844 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
3847 return TRUE;
3850 /*************************************************************
3851 * WineEngGetTextExtentExPoint
3854 BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
3855 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
3857 INT idx;
3858 INT nfit = 0, ext;
3859 GLYPHMETRICS gm;
3860 TEXTMETRICW tm;
3861 FT_UInt glyph_index;
3862 GdiFont linked_font;
3864 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
3865 max_ext, size);
3867 size->cx = 0;
3868 WineEngGetTextMetrics(font, &tm);
3869 size->cy = tm.tmHeight;
3871 for(idx = 0; idx < count; idx++) {
3872 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3873 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3874 &gm, 0, NULL, NULL);
3875 size->cx += linked_font->gm[glyph_index].adv;
3876 ext = size->cx;
3877 if (! pnfit || ext <= max_ext) {
3878 ++nfit;
3879 if (dxs)
3880 dxs[idx] = ext;
3884 if (pnfit)
3885 *pnfit = nfit;
3887 TRACE("return %ld, %ld, %d\n", size->cx, size->cy, nfit);
3888 return TRUE;
3891 /*************************************************************
3892 * WineEngGetTextExtentPointI
3895 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3896 LPSIZE size)
3898 INT idx;
3899 GLYPHMETRICS gm;
3900 TEXTMETRICW tm;
3902 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3904 size->cx = 0;
3905 WineEngGetTextMetrics(font, &tm);
3906 size->cy = tm.tmHeight;
3908 for(idx = 0; idx < count; idx++) {
3909 WineEngGetGlyphOutline(font, indices[idx],
3910 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3911 NULL);
3912 size->cx += font->gm[indices[idx]].adv;
3914 TRACE("return %ld,%ld\n", size->cx, size->cy);
3915 return TRUE;
3918 /*************************************************************
3919 * WineEngGetFontData
3922 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3923 DWORD cbData)
3925 FT_Face ft_face = font->ft_face;
3926 FT_ULong len;
3927 FT_Error err;
3929 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3930 font, table, offset, buf, cbData);
3932 if(!FT_IS_SFNT(ft_face))
3933 return GDI_ERROR;
3935 if(!buf || !cbData)
3936 len = 0;
3937 else
3938 len = cbData;
3940 if(table) { /* MS tags differ in endidness from FT ones */
3941 table = table >> 24 | table << 24 |
3942 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3945 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3946 if(pFT_Load_Sfnt_Table) {
3947 /* make sure value of len is the value freetype says it needs */
3948 if( buf && len) {
3949 FT_ULong needed = 0;
3950 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3951 if( !err && needed < len) len = needed;
3953 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3955 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3956 else { /* Do it the hard way */
3957 TT_Face tt_face = (TT_Face) ft_face;
3958 SFNT_Interface *sfnt;
3959 if (FT_Version.major==2 && FT_Version.minor==0)
3961 /* 2.0.x */
3962 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3964 else
3966 /* A field was added in the middle of the structure in 2.1.x */
3967 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3969 /* make sure value of len is the value freetype says it needs */
3970 if( buf && len) {
3971 FT_ULong needed = 0;
3972 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3973 if( !err && needed < len) len = needed;
3975 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3977 #else
3978 else {
3979 static int msg;
3980 if(!msg) {
3981 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3982 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3983 "Please upgrade your freetype library.\n");
3984 msg++;
3986 err = FT_Err_Unimplemented_Feature;
3988 #endif
3989 if(err) {
3990 TRACE("Can't find table %08lx.\n", table);
3991 return GDI_ERROR;
3993 return len;
3996 /*************************************************************
3997 * WineEngGetTextFace
4000 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4002 if(str) {
4003 lstrcpynW(str, font->name, count);
4004 return strlenW(font->name);
4005 } else
4006 return strlenW(font->name) + 1;
4009 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4011 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4012 return font->charset;
4015 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4017 GdiFont font = dc->gdiFont, linked_font;
4018 struct list *first_hfont;
4019 BOOL ret;
4021 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4022 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4023 if(font == linked_font)
4024 *new_hfont = dc->hFont;
4025 else
4027 first_hfont = list_head(&linked_font->hfontlist);
4028 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4031 return ret;
4035 /*************************************************************
4036 * FontIsLinked
4038 BOOL WINAPI FontIsLinked(HDC hdc)
4040 DC *dc = DC_GetDCPtr(hdc);
4041 BOOL ret = FALSE;
4043 if(!dc) return FALSE;
4044 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4045 ret = TRUE;
4046 GDI_ReleaseObj(hdc);
4047 TRACE("returning %d\n", ret);
4048 return ret;
4051 static BOOL is_hinting_enabled(void)
4053 /* Use the >= 2.2.0 function if available */
4054 if(pFT_Get_TrueType_Engine_Type)
4056 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4057 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4059 #ifdef FT_DRIVER_HAS_HINTER
4060 else
4062 FT_Module mod;
4064 /* otherwise if we've been compiled with < 2.2.0 headers
4065 use the internal macro */
4066 mod = pFT_Get_Module(library, "truetype");
4067 if(mod && FT_DRIVER_HAS_HINTER(mod))
4068 return TRUE;
4070 #endif
4072 return FALSE;
4075 /*************************************************************************
4076 * GetRasterizerCaps (GDI32.@)
4078 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4080 static int hinting = -1;
4082 if(hinting == -1)
4083 hinting = is_hinting_enabled();
4085 lprs->nSize = sizeof(RASTERIZER_STATUS);
4086 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4087 lprs->nLanguageID = 0;
4088 return TRUE;
4092 #else /* HAVE_FREETYPE */
4094 /*************************************************************************/
4096 BOOL WineEngInit(void)
4098 return FALSE;
4100 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
4102 return NULL;
4104 BOOL WineEngDestroyFontInstance(HFONT hfont)
4106 return FALSE;
4109 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4111 return 1;
4114 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
4115 LPWORD pgi, DWORD flags)
4117 return GDI_ERROR;
4120 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
4121 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4122 const MAT2* lpmat)
4124 ERR("called but we don't have FreeType\n");
4125 return GDI_ERROR;
4128 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
4130 ERR("called but we don't have FreeType\n");
4131 return FALSE;
4134 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
4135 OUTLINETEXTMETRICW *potm)
4137 ERR("called but we don't have FreeType\n");
4138 return 0;
4141 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
4142 LPINT buffer)
4144 ERR("called but we don't have FreeType\n");
4145 return FALSE;
4148 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
4149 LPABC buffer)
4151 ERR("called but we don't have FreeType\n");
4152 return FALSE;
4155 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
4156 LPABC buffer)
4158 ERR("called but we don't have FreeType\n");
4159 return FALSE;
4162 BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
4163 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4165 ERR("called but we don't have FreeType\n");
4166 return FALSE;
4169 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
4170 LPSIZE size)
4172 ERR("called but we don't have FreeType\n");
4173 return FALSE;
4176 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
4177 DWORD cbData)
4179 ERR("called but we don't have FreeType\n");
4180 return GDI_ERROR;
4183 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4185 ERR("called but we don't have FreeType\n");
4186 return 0;
4189 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4191 FIXME(":stub\n");
4192 return 1;
4195 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4197 FIXME(":stub\n");
4198 return TRUE;
4201 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4203 FIXME(":stub\n");
4204 return DEFAULT_CHARSET;
4207 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4209 return FALSE;
4212 BOOL WINAPI FontIsLinked(HDC hdc)
4214 return FALSE;
4217 /*************************************************************************
4218 * GetRasterizerCaps (GDI32.@)
4220 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4222 lprs->nSize = sizeof(RASTERIZER_STATUS);
4223 lprs->wFlags = 0;
4224 lprs->nLanguageID = 0;
4225 return TRUE;
4228 #endif /* HAVE_FREETYPE */