winecfg: Add ability to change colors and non-client sizes.
[wine.git] / dlls / gdi32 / freetype.c
blobf77047e5d6517b52d4405926ff30d61b3414880e
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #include <string.h>
33 #include <dirent.h>
34 #include <stdio.h>
35 #include <assert.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winternl.h"
40 #include "winerror.h"
41 #include "winreg.h"
42 #include "wingdi.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_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
138 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
139 #ifdef HAVE_FREETYPE_FTWINFNT_H
140 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
141 #endif
143 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
144 #include <fontconfig/fontconfig.h>
145 MAKE_FUNCPTR(FcConfigGetCurrent);
146 MAKE_FUNCPTR(FcFontList);
147 MAKE_FUNCPTR(FcFontSetDestroy);
148 MAKE_FUNCPTR(FcInit);
149 MAKE_FUNCPTR(FcObjectSetAdd);
150 MAKE_FUNCPTR(FcObjectSetCreate);
151 MAKE_FUNCPTR(FcObjectSetDestroy);
152 MAKE_FUNCPTR(FcPatternCreate);
153 MAKE_FUNCPTR(FcPatternDestroy);
154 MAKE_FUNCPTR(FcPatternGetString);
155 #ifndef SONAME_LIBFONTCONFIG
156 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
157 #endif
158 #endif
160 #undef MAKE_FUNCPTR
162 #ifndef ft_encoding_none
163 #define FT_ENCODING_NONE ft_encoding_none
164 #endif
165 #ifndef ft_encoding_ms_symbol
166 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
167 #endif
168 #ifndef ft_encoding_unicode
169 #define FT_ENCODING_UNICODE ft_encoding_unicode
170 #endif
171 #ifndef ft_encoding_apple_roman
172 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
173 #endif
175 #ifdef WORDS_BIGENDIAN
176 #define GET_BE_WORD(x) (x)
177 #else
178 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
179 #endif
181 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
182 typedef struct {
183 FT_Short height;
184 FT_Short width;
185 FT_Pos size;
186 FT_Pos x_ppem;
187 FT_Pos y_ppem;
188 FT_Short internal_leading;
189 } Bitmap_Size;
191 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
192 So to let this compile on older versions of FreeType we'll define the
193 new structure here. */
194 typedef struct {
195 FT_Short height, width;
196 FT_Pos size, x_ppem, y_ppem;
197 } My_FT_Bitmap_Size;
199 typedef struct tagFace {
200 struct list entry;
201 WCHAR *StyleName;
202 char *file;
203 FT_Long face_index;
204 BOOL Italic;
205 BOOL Bold;
206 FONTSIGNATURE fs;
207 FONTSIGNATURE fs_links;
208 FT_Fixed font_version;
209 BOOL scalable;
210 Bitmap_Size size; /* set if face is a bitmap */
211 BOOL external; /* TRUE if we should manually add this font to the registry */
212 struct tagFamily *family;
213 } Face;
215 typedef struct tagFamily {
216 struct list entry;
217 const WCHAR *FamilyName;
218 struct list faces;
219 } Family;
221 typedef struct {
222 GLYPHMETRICS gm;
223 INT adv; /* These three hold to widths of the unrotated chars */
224 INT lsb;
225 INT bbx;
226 BOOL init;
227 } GM;
229 typedef struct {
230 FLOAT eM11, eM12;
231 FLOAT eM21, eM22;
232 } FMAT2;
234 typedef struct {
235 DWORD hash;
236 LOGFONTW lf;
237 FMAT2 matrix;
238 BOOL can_use_bitmap;
239 } FONT_DESC;
241 typedef struct tagHFONTLIST {
242 struct list entry;
243 HFONT hfont;
244 } HFONTLIST;
246 typedef struct {
247 struct list entry;
248 char *file_name;
249 INT index;
250 GdiFont *font;
251 } CHILD_FONT;
253 struct tagGdiFont {
254 struct list entry;
255 FT_Face ft_face;
256 LPWSTR name;
257 int charset;
258 int codepage;
259 BOOL fake_italic;
260 BOOL fake_bold;
261 BYTE underline;
262 BYTE strikeout;
263 INT orientation;
264 GM *gm;
265 DWORD gmsize;
266 struct list hfontlist;
267 FONT_DESC font_desc;
268 LONG aveWidth;
269 SHORT yMax;
270 SHORT yMin;
271 OUTLINETEXTMETRICW *potm;
272 DWORD total_kern_pairs;
273 KERNINGPAIR *kern_pairs;
274 FONTSIGNATURE fs;
275 GdiFont *base_font;
276 struct list child_fonts;
277 LONG ppem;
280 typedef struct {
281 struct list entry;
282 const WCHAR *font_name;
283 struct list links;
284 } SYSTEM_LINKS;
286 #define INIT_GM_SIZE 128
288 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
289 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
290 #define UNUSED_CACHE_SIZE 10
291 static struct list child_font_list = LIST_INIT(child_font_list);
292 static struct list system_links = LIST_INIT(system_links);
294 static struct list font_subst_list = LIST_INIT(font_subst_list);
296 static struct list font_list = LIST_INIT(font_list);
298 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
299 'R','o','m','a','n','\0'};
300 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
301 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
303 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
304 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
305 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
306 'S','e','r','i','f','\0'};
307 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
308 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
310 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
311 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
312 'W','i','n','d','o','w','s','\\',
313 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
314 'F','o','n','t','s','\0'};
316 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
317 'W','i','n','d','o','w','s',' ','N','T','\\',
318 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
319 'F','o','n','t','s','\0'};
321 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
322 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
323 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
324 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
326 static const WCHAR * const SystemFontValues[4] = {
327 System_Value,
328 OEMFont_Value,
329 FixedSys_Value,
330 NULL
333 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
334 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
336 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
337 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
338 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
339 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
340 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
341 'E','u','r','o','p','e','a','n','\0'};
342 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
343 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
344 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
345 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
346 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
347 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
348 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
349 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
350 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
351 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
352 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
353 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
355 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
356 WesternW, /*00*/
357 Central_EuropeanW,
358 CyrillicW,
359 GreekW,
360 TurkishW,
361 HebrewW,
362 ArabicW,
363 BalticW,
364 VietnameseW, /*08*/
365 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
366 ThaiW,
367 JapaneseW,
368 CHINESE_GB2312W,
369 HangulW,
370 CHINESE_BIG5W,
371 Hangul_Johab_W,
372 NULL, NULL, /*23*/
373 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
374 SymbolW /*31*/
377 typedef struct {
378 WCHAR *name;
379 INT charset;
380 } NameCs;
382 typedef struct tagFontSubst {
383 struct list entry;
384 NameCs from;
385 NameCs to;
386 } FontSubst;
388 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
390 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
393 /****************************************
394 * Notes on .fon files
396 * The fonts System, FixedSys and Terminal are special. There are typically multiple
397 * versions installed for different resolutions and codepages. Windows stores which one to use
398 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
399 * Key Meaning
400 * FIXEDFON.FON FixedSys
401 * FONTS.FON System
402 * OEMFONT.FON Terminal
403 * LogPixels Current dpi set by the display control panel applet
404 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
405 * also has a LogPixels value that appears to mirror this)
407 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
408 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
409 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
410 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
411 * so that makes sense.
413 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
414 * to be mapped into the registry on Windows 2000 at least).
415 * I have
416 * woafont=app850.fon
417 * ega80woa.fon=ega80850.fon
418 * ega40woa.fon=ega40850.fon
419 * cga80woa.fon=cga80850.fon
420 * cga40woa.fon=cga40850.fon
424 static inline BOOL is_win9x(void)
426 return GetVersion() & 0x80000000;
429 This function builds an FT_Fixed from a float. It puts the integer part
430 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
431 It fails if the integer part of the float number is greater than SHORT_MAX.
433 static inline FT_Fixed FT_FixedFromFloat(float f)
435 short value = f;
436 unsigned short fract = (f - value) * 0xFFFF;
437 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
441 This function builds an FT_Fixed from a FIXED. It simply put f.value
442 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
444 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
446 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
450 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
452 Family *family;
453 Face *face;
454 const char *file;
455 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
456 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
458 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
459 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
461 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
463 if(face_name && strcmpiW(face_name, family->FamilyName))
464 continue;
465 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
467 file = strrchr(face->file, '/');
468 if(!file)
469 file = face->file;
470 else
471 file++;
472 if(!strcasecmp(file, file_nameA))
474 HeapFree(GetProcessHeap(), 0, file_nameA);
475 return face;
479 HeapFree(GetProcessHeap(), 0, file_nameA);
480 return NULL;
483 static Family *find_family_from_name(const WCHAR *name)
485 Family *family;
487 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
489 if(!strcmpiW(family->FamilyName, name))
490 return family;
493 return NULL;
496 static void DumpSubstList(void)
498 FontSubst *psub;
500 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
502 if(psub->from.charset != -1 || psub->to.charset != -1)
503 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
504 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
505 else
506 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
507 debugstr_w(psub->to.name));
509 return;
512 static LPWSTR strdupW(LPCWSTR p)
514 LPWSTR ret;
515 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
516 ret = HeapAlloc(GetProcessHeap(), 0, len);
517 memcpy(ret, p, len);
518 return ret;
521 static LPSTR strdupA(LPCSTR p)
523 LPSTR ret;
524 DWORD len = (strlen(p) + 1);
525 ret = HeapAlloc(GetProcessHeap(), 0, len);
526 memcpy(ret, p, len);
527 return ret;
530 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
531 INT from_charset)
533 FontSubst *element;
535 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
537 if(!strcmpiW(element->from.name, from_name) &&
538 (element->from.charset == from_charset ||
539 element->from.charset == -1))
540 return element;
543 return NULL;
546 #define ADD_FONT_SUBST_FORCE 1
548 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
550 FontSubst *from_exist, *to_exist;
552 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
554 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
556 list_remove(&from_exist->entry);
557 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
558 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
559 HeapFree(GetProcessHeap(), 0, from_exist);
560 from_exist = NULL;
563 if(!from_exist)
565 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
567 if(to_exist)
569 HeapFree(GetProcessHeap(), 0, subst->to.name);
570 subst->to.name = strdupW(to_exist->to.name);
573 list_add_tail(subst_list, &subst->entry);
575 return TRUE;
578 HeapFree(GetProcessHeap(), 0, subst->from.name);
579 HeapFree(GetProcessHeap(), 0, subst->to.name);
580 HeapFree(GetProcessHeap(), 0, subst);
581 return FALSE;
584 static void split_subst_info(NameCs *nc, LPSTR str)
586 CHAR *p = strrchr(str, ',');
587 DWORD len;
589 nc->charset = -1;
590 if(p && *(p+1)) {
591 nc->charset = strtol(p+1, NULL, 10);
592 *p = '\0';
594 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
595 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
596 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
599 static void LoadSubstList(void)
601 FontSubst *psub;
602 HKEY hkey;
603 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
604 LPSTR value;
605 LPVOID data;
607 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
608 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
609 &hkey) == ERROR_SUCCESS) {
611 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
612 &valuelen, &datalen, NULL, NULL);
614 valuelen++; /* returned value doesn't include room for '\0' */
615 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
616 data = HeapAlloc(GetProcessHeap(), 0, datalen);
618 dlen = datalen;
619 vlen = valuelen;
620 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
621 &dlen) == ERROR_SUCCESS) {
622 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
624 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
625 split_subst_info(&psub->from, value);
626 split_subst_info(&psub->to, data);
628 /* Win 2000 doesn't allow mapping between different charsets
629 or mapping of DEFAULT_CHARSET */
630 if((psub->to.charset != psub->from.charset) ||
631 psub->to.charset == DEFAULT_CHARSET) {
632 HeapFree(GetProcessHeap(), 0, psub->to.name);
633 HeapFree(GetProcessHeap(), 0, psub->from.name);
634 HeapFree(GetProcessHeap(), 0, psub);
635 } else {
636 add_font_subst(&font_subst_list, psub, 0);
638 /* reset dlen and vlen */
639 dlen = datalen;
640 vlen = valuelen;
642 HeapFree(GetProcessHeap(), 0, data);
643 HeapFree(GetProcessHeap(), 0, value);
644 RegCloseKey(hkey);
648 static WCHAR *get_familyname(FT_Face ft_face)
650 WCHAR *family = NULL;
651 FT_SfntName name;
652 FT_UInt num_names, name_index, i;
654 if(FT_IS_SFNT(ft_face))
656 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
658 for(name_index = 0; name_index < num_names; name_index++)
660 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
662 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
663 (name.language_id == GetUserDefaultLCID()) &&
664 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
665 (name.encoding_id == TT_MS_ID_UNICODE_CS))
667 /* String is not nul terminated and string_len is a byte length. */
668 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
669 for(i = 0; i < name.string_len / 2; i++)
671 WORD *tmp = (WORD *)&name.string[i * 2];
672 family[i] = GET_BE_WORD(*tmp);
674 family[i] = 0;
676 TRACE("Got localised name %s\n", debugstr_w(family));
677 return family;
683 return NULL;
687 #define ADDFONT_EXTERNAL_FONT 0x01
688 #define ADDFONT_FORCE_BITMAP 0x02
689 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
691 FT_Face ft_face;
692 TT_OS2 *pOS2;
693 TT_Header *pHeader = NULL;
694 WCHAR *english_family, *localised_family, *StyleW;
695 DWORD len;
696 Family *family;
697 Face *face;
698 struct list *family_elem_ptr, *face_elem_ptr;
699 FT_Error err;
700 FT_Long face_index = 0, num_faces;
701 #ifdef HAVE_FREETYPE_FTWINFNT_H
702 FT_WinFNT_HeaderRec winfnt_header;
703 #endif
704 int i, bitmap_num, internal_leading;
705 FONTSIGNATURE fs;
707 do {
708 char *family_name = fake_family;
710 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
711 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
712 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
713 return FALSE;
716 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*/
717 WARN("Ignoring font %s\n", debugstr_a(file));
718 pFT_Done_Face(ft_face);
719 return FALSE;
722 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
723 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
724 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
725 pFT_Done_Face(ft_face);
726 return FALSE;
729 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
730 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
731 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
732 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
733 "Skipping this font.\n", debugstr_a(file));
734 pFT_Done_Face(ft_face);
735 return FALSE;
738 if(!ft_face->family_name || !ft_face->style_name) {
739 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
740 pFT_Done_Face(ft_face);
741 return FALSE;
744 if(!family_name)
745 family_name = ft_face->family_name;
747 bitmap_num = 0;
748 do {
749 My_FT_Bitmap_Size *size = NULL;
751 if(!FT_IS_SCALABLE(ft_face))
752 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
754 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
755 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
756 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
758 localised_family = NULL;
759 if(!fake_family) {
760 localised_family = get_familyname(ft_face);
761 if(localised_family && !strcmpW(localised_family, english_family)) {
762 HeapFree(GetProcessHeap(), 0, localised_family);
763 localised_family = NULL;
767 family = NULL;
768 LIST_FOR_EACH(family_elem_ptr, &font_list) {
769 family = LIST_ENTRY(family_elem_ptr, Family, entry);
770 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
771 break;
772 family = NULL;
774 if(!family) {
775 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
776 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
777 list_init(&family->faces);
778 list_add_tail(&font_list, &family->entry);
780 if(localised_family) {
781 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
782 subst->from.name = strdupW(english_family);
783 subst->from.charset = -1;
784 subst->to.name = strdupW(localised_family);
785 subst->to.charset = -1;
786 add_font_subst(&font_subst_list, subst, 0);
789 HeapFree(GetProcessHeap(), 0, localised_family);
790 HeapFree(GetProcessHeap(), 0, english_family);
792 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
793 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
794 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
796 internal_leading = 0;
797 memset(&fs, 0, sizeof(fs));
799 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
800 if(pOS2) {
801 fs.fsCsb[0] = pOS2->ulCodePageRange1;
802 fs.fsCsb[1] = pOS2->ulCodePageRange2;
803 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
804 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
805 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
806 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
807 if(pOS2->version == 0) {
808 FT_UInt dummy;
810 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
811 fs.fsCsb[0] |= 1;
812 else
813 fs.fsCsb[0] |= 1L << 31;
816 #ifdef HAVE_FREETYPE_FTWINFNT_H
817 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
818 CHARSETINFO csi;
819 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
820 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
821 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
822 memcpy(&fs, &csi.fs, sizeof(csi.fs));
823 internal_leading = winfnt_header.internal_leading;
825 #endif
827 face_elem_ptr = list_head(&family->faces);
828 while(face_elem_ptr) {
829 face = LIST_ENTRY(face_elem_ptr, Face, entry);
830 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
831 if(!strcmpW(face->StyleName, StyleW) &&
832 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
833 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
834 debugstr_w(family->FamilyName), debugstr_w(StyleW),
835 face->font_version, pHeader ? pHeader->Font_Revision : 0);
837 if(fake_family) {
838 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
839 HeapFree(GetProcessHeap(), 0, StyleW);
840 pFT_Done_Face(ft_face);
841 return FALSE;
843 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
844 TRACE("Original font is newer so skipping this one\n");
845 HeapFree(GetProcessHeap(), 0, StyleW);
846 pFT_Done_Face(ft_face);
847 return FALSE;
848 } else {
849 TRACE("Replacing original with this one\n");
850 list_remove(&face->entry);
851 HeapFree(GetProcessHeap(), 0, face->file);
852 HeapFree(GetProcessHeap(), 0, face->StyleName);
853 HeapFree(GetProcessHeap(), 0, face);
854 break;
858 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
859 list_add_tail(&family->faces, &face->entry);
860 face->StyleName = StyleW;
861 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
862 strcpy(face->file, file);
863 face->face_index = face_index;
864 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
865 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
866 face->font_version = pHeader ? pHeader->Font_Revision : 0;
867 face->family = family;
868 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
869 memcpy(&face->fs, &fs, sizeof(face->fs));
870 memset(&face->fs_links, 0, sizeof(face->fs_links));
872 if(FT_IS_SCALABLE(ft_face)) {
873 memset(&face->size, 0, sizeof(face->size));
874 face->scalable = TRUE;
875 } else {
876 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
877 size->height, size->width, size->size >> 6,
878 size->x_ppem >> 6, size->y_ppem >> 6);
879 face->size.height = size->height;
880 face->size.width = size->width;
881 face->size.size = size->size;
882 face->size.x_ppem = size->x_ppem;
883 face->size.y_ppem = size->y_ppem;
884 face->size.internal_leading = internal_leading;
885 face->scalable = FALSE;
888 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
889 face->fs.fsCsb[0], face->fs.fsCsb[1],
890 face->fs.fsUsb[0], face->fs.fsUsb[1],
891 face->fs.fsUsb[2], face->fs.fsUsb[3]);
894 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
895 for(i = 0; i < ft_face->num_charmaps; i++) {
896 switch(ft_face->charmaps[i]->encoding) {
897 case FT_ENCODING_UNICODE:
898 case FT_ENCODING_APPLE_ROMAN:
899 face->fs.fsCsb[0] |= 1;
900 break;
901 case FT_ENCODING_MS_SYMBOL:
902 face->fs.fsCsb[0] |= 1L << 31;
903 break;
904 default:
905 break;
910 if(face->fs.fsCsb[0] & ~(1L << 31))
911 have_installed_roman_font = TRUE;
912 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
914 num_faces = ft_face->num_faces;
915 pFT_Done_Face(ft_face);
916 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
917 debugstr_w(StyleW));
918 } while(num_faces > ++face_index);
919 return TRUE;
922 static void DumpFontList(void)
924 Family *family;
925 Face *face;
926 struct list *family_elem_ptr, *face_elem_ptr;
928 LIST_FOR_EACH(family_elem_ptr, &font_list) {
929 family = LIST_ENTRY(family_elem_ptr, Family, entry);
930 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
931 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
932 face = LIST_ENTRY(face_elem_ptr, Face, entry);
933 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
934 if(!face->scalable)
935 TRACE(" %d", face->size.height);
936 TRACE("\n");
939 return;
942 /***********************************************************
943 * The replacement list is a way to map an entire font
944 * family onto another family. For example adding
946 * [HKCU\Software\Wine\Fonts\Replacements]
947 * "Wingdings"="Winedings"
949 * would enumerate the Winedings font both as Winedings and
950 * Wingdings. However if a real Wingdings font is present the
951 * replacement does not take place.
954 static void LoadReplaceList(void)
956 HKEY hkey;
957 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
958 LPSTR value;
959 LPVOID data;
960 Family *family;
961 Face *face;
962 struct list *family_elem_ptr, *face_elem_ptr;
963 WCHAR old_nameW[200];
965 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
966 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
968 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
969 &valuelen, &datalen, NULL, NULL);
971 valuelen++; /* returned value doesn't include room for '\0' */
972 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
973 data = HeapAlloc(GetProcessHeap(), 0, datalen);
975 dlen = datalen;
976 vlen = valuelen;
977 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
978 &dlen) == ERROR_SUCCESS) {
979 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
980 /* "NewName"="Oldname" */
981 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
982 break;
984 /* Find the old family and hence all of the font files
985 in that family */
986 LIST_FOR_EACH(family_elem_ptr, &font_list) {
987 family = LIST_ENTRY(family_elem_ptr, Family, entry);
988 if(!strcmpiW(family->FamilyName, old_nameW)) {
989 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
990 face = LIST_ENTRY(face_elem_ptr, Face, entry);
991 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
992 debugstr_w(face->StyleName), value);
993 /* Now add a new entry with the new family name */
994 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
996 break;
999 /* reset dlen and vlen */
1000 dlen = datalen;
1001 vlen = valuelen;
1003 HeapFree(GetProcessHeap(), 0, data);
1004 HeapFree(GetProcessHeap(), 0, value);
1005 RegCloseKey(hkey);
1009 /*************************************************************
1010 * init_system_links
1012 static BOOL init_system_links(void)
1014 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1015 'W','i','n','d','o','w','s',' ','N','T','\\',
1016 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1017 'S','y','s','t','e','m','L','i','n','k',0};
1018 HKEY hkey;
1019 BOOL ret = FALSE;
1020 DWORD type, max_val, max_data, val_len, data_len, index;
1021 WCHAR *value, *data;
1022 WCHAR *entry, *next;
1023 SYSTEM_LINKS *font_link, *system_font_link;
1024 CHILD_FONT *child_font;
1025 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1026 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1027 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1028 FONTSIGNATURE fs;
1029 Family *family;
1030 Face *face;
1031 FontSubst *psub;
1033 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1035 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1036 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1037 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1038 val_len = max_val + 1;
1039 data_len = max_data;
1040 index = 0;
1041 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1043 TRACE("%s:\n", debugstr_w(value));
1045 memset(&fs, 0, sizeof(fs));
1046 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1047 psub = get_font_subst(&font_subst_list, value, -1);
1048 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1049 list_init(&font_link->links);
1050 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1052 WCHAR *face_name;
1053 CHILD_FONT *child_font;
1055 TRACE("\t%s\n", debugstr_w(entry));
1057 next = entry + strlenW(entry) + 1;
1059 face_name = strchrW(entry, ',');
1060 if(face_name)
1062 *face_name++ = 0;
1063 while(isspaceW(*face_name))
1064 face_name++;
1066 psub = get_font_subst(&font_subst_list, face_name, -1);
1067 if(psub)
1068 face_name = psub->to.name;
1070 face = find_face_from_filename(entry, face_name);
1071 if(!face)
1073 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1074 continue;
1077 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1078 child_font->file_name = strdupA(face->file);
1079 child_font->index = face->face_index;
1080 child_font->font = NULL;
1081 fs.fsCsb[0] |= face->fs.fsCsb[0];
1082 fs.fsCsb[1] |= face->fs.fsCsb[1];
1083 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1084 list_add_tail(&font_link->links, &child_font->entry);
1086 family = find_family_from_name(font_link->font_name);
1087 if(family)
1089 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1091 memcpy(&face->fs_links, &fs, sizeof(fs));
1094 list_add_tail(&system_links, &font_link->entry);
1095 val_len = max_val + 1;
1096 data_len = max_data;
1099 HeapFree(GetProcessHeap(), 0, value);
1100 HeapFree(GetProcessHeap(), 0, data);
1101 RegCloseKey(hkey);
1104 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1105 that Tahoma has */
1107 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1108 system_font_link->font_name = strdupW(System);
1109 list_init(&system_font_link->links);
1111 face = find_face_from_filename(tahoma_ttf, Tahoma);
1112 if(face)
1114 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1115 child_font->file_name = strdupA(face->file);
1116 child_font->index = face->face_index;
1117 child_font->font = NULL;
1118 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1119 list_add_tail(&system_font_link->links, &child_font->entry);
1121 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1123 if(!strcmpiW(font_link->font_name, Tahoma))
1125 CHILD_FONT *font_link_entry;
1126 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1128 CHILD_FONT *new_child;
1129 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1130 new_child->file_name = strdupA(font_link_entry->file_name);
1131 new_child->index = font_link_entry->index;
1132 new_child->font = NULL;
1133 list_add_tail(&system_font_link->links, &new_child->entry);
1135 break;
1138 list_add_tail(&system_links, &system_font_link->entry);
1139 return ret;
1142 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1144 DIR *dir;
1145 struct dirent *dent;
1146 char path[MAX_PATH];
1148 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1150 dir = opendir(dirname);
1151 if(!dir) {
1152 WARN("Can't open directory %s\n", debugstr_a(dirname));
1153 return FALSE;
1155 while((dent = readdir(dir)) != NULL) {
1156 struct stat statbuf;
1158 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1159 continue;
1161 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1163 sprintf(path, "%s/%s", dirname, dent->d_name);
1165 if(stat(path, &statbuf) == -1)
1167 WARN("Can't stat %s\n", debugstr_a(path));
1168 continue;
1170 if(S_ISDIR(statbuf.st_mode))
1171 ReadFontDir(path, external_fonts);
1172 else
1173 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1175 closedir(dir);
1176 return TRUE;
1179 static void load_fontconfig_fonts(void)
1181 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1182 void *fc_handle = NULL;
1183 FcConfig *config;
1184 FcPattern *pat;
1185 FcObjectSet *os;
1186 FcFontSet *fontset;
1187 int i, len;
1188 char *file;
1189 const char *ext;
1191 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1192 if(!fc_handle) {
1193 TRACE("Wine cannot find the fontconfig library (%s).\n",
1194 SONAME_LIBFONTCONFIG);
1195 return;
1197 #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;}
1198 LOAD_FUNCPTR(FcConfigGetCurrent);
1199 LOAD_FUNCPTR(FcFontList);
1200 LOAD_FUNCPTR(FcFontSetDestroy);
1201 LOAD_FUNCPTR(FcInit);
1202 LOAD_FUNCPTR(FcObjectSetAdd);
1203 LOAD_FUNCPTR(FcObjectSetCreate);
1204 LOAD_FUNCPTR(FcObjectSetDestroy);
1205 LOAD_FUNCPTR(FcPatternCreate);
1206 LOAD_FUNCPTR(FcPatternDestroy);
1207 LOAD_FUNCPTR(FcPatternGetString);
1208 #undef LOAD_FUNCPTR
1210 if(!pFcInit()) return;
1212 config = pFcConfigGetCurrent();
1213 pat = pFcPatternCreate();
1214 os = pFcObjectSetCreate();
1215 pFcObjectSetAdd(os, FC_FILE);
1216 fontset = pFcFontList(config, pat, os);
1217 if(!fontset) return;
1218 for(i = 0; i < fontset->nfont; i++) {
1219 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1220 continue;
1221 TRACE("fontconfig: %s\n", file);
1223 /* We're just interested in OT/TT fonts for now, so this hack just
1224 picks up the standard extensions to save time loading every other
1225 font */
1226 len = strlen( file );
1227 if(len < 4) continue;
1228 ext = &file[ len - 3 ];
1229 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1230 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1232 pFcFontSetDestroy(fontset);
1233 pFcObjectSetDestroy(os);
1234 pFcPatternDestroy(pat);
1235 sym_not_found:
1236 #endif
1237 return;
1240 static BOOL load_font_from_data_dir(LPCWSTR file)
1242 BOOL ret = FALSE;
1243 const char *data_dir = wine_get_data_dir();
1245 if (!data_dir) data_dir = wine_get_build_dir();
1247 if (data_dir)
1249 INT len;
1250 char *unix_name;
1252 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1254 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1256 strcpy(unix_name, data_dir);
1257 strcat(unix_name, "/fonts/");
1259 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1261 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1262 HeapFree(GetProcessHeap(), 0, unix_name);
1264 return ret;
1267 static void load_system_fonts(void)
1269 HKEY hkey;
1270 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1271 const WCHAR * const *value;
1272 DWORD dlen, type;
1273 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1274 char *unixname;
1276 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1277 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1278 strcatW(windowsdir, fontsW);
1279 for(value = SystemFontValues; *value; value++) {
1280 dlen = sizeof(data);
1281 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1282 type == REG_SZ) {
1283 BOOL added = FALSE;
1285 sprintfW(pathW, fmtW, windowsdir, data);
1286 if((unixname = wine_get_unix_file_name(pathW))) {
1287 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1288 HeapFree(GetProcessHeap(), 0, unixname);
1290 if (!added)
1291 load_font_from_data_dir(data);
1294 RegCloseKey(hkey);
1298 /*************************************************************
1300 * This adds registry entries for any externally loaded fonts
1301 * (fonts from fontconfig or FontDirs). It also deletes entries
1302 * of no longer existing fonts.
1305 static void update_reg_entries(void)
1307 HKEY winkey = 0, externalkey = 0;
1308 LPWSTR valueW;
1309 LPVOID data;
1310 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1311 Family *family;
1312 Face *face;
1313 struct list *family_elem_ptr, *face_elem_ptr;
1314 WCHAR *file;
1315 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1316 static const WCHAR spaceW[] = {' ', '\0'};
1317 char *path;
1319 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1320 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1321 ERR("Can't create Windows font reg key\n");
1322 goto end;
1324 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1325 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1326 ERR("Can't create external font reg key\n");
1327 goto end;
1330 /* Delete all external fonts added last time */
1332 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1333 &valuelen, &datalen, NULL, NULL);
1334 valuelen++; /* returned value doesn't include room for '\0' */
1335 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1336 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1338 dlen = datalen * sizeof(WCHAR);
1339 vlen = valuelen;
1340 i = 0;
1341 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1342 &dlen) == ERROR_SUCCESS) {
1344 RegDeleteValueW(winkey, valueW);
1345 /* reset dlen and vlen */
1346 dlen = datalen;
1347 vlen = valuelen;
1349 HeapFree(GetProcessHeap(), 0, data);
1350 HeapFree(GetProcessHeap(), 0, valueW);
1352 /* Delete the old external fonts key */
1353 RegCloseKey(externalkey);
1354 externalkey = 0;
1355 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1357 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1358 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1359 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1360 ERR("Can't create external font reg key\n");
1361 goto end;
1364 /* enumerate the fonts and add external ones to the two keys */
1366 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1367 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1368 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1369 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1370 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1371 if(!face->external) continue;
1372 len = len_fam;
1373 if(strcmpiW(face->StyleName, RegularW))
1374 len = len_fam + strlenW(face->StyleName) + 1;
1375 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1376 strcpyW(valueW, family->FamilyName);
1377 if(len != len_fam) {
1378 strcatW(valueW, spaceW);
1379 strcatW(valueW, face->StyleName);
1381 strcatW(valueW, TrueType);
1382 if((path = strrchr(face->file, '/')) == NULL)
1383 path = face->file;
1384 else
1385 path++;
1386 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1388 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1389 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1390 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1391 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1393 HeapFree(GetProcessHeap(), 0, file);
1394 HeapFree(GetProcessHeap(), 0, valueW);
1397 end:
1398 if(externalkey)
1399 RegCloseKey(externalkey);
1400 if(winkey)
1401 RegCloseKey(winkey);
1402 return;
1406 /*************************************************************
1407 * WineEngAddFontResourceEx
1410 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1412 if (ft_handle) /* do it only if we have freetype up and running */
1414 char *unixname;
1416 if(flags)
1417 FIXME("Ignoring flags %x\n", flags);
1419 if((unixname = wine_get_unix_file_name(file)))
1421 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1422 HeapFree(GetProcessHeap(), 0, unixname);
1425 return 1;
1428 /*************************************************************
1429 * WineEngRemoveFontResourceEx
1432 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1434 FIXME(":stub\n");
1435 return TRUE;
1438 static const struct nls_update_font_list
1440 UINT ansi_cp, oem_cp;
1441 const char *oem, *fixed, *system;
1442 const char *courier, *serif, *small, *sserif;
1443 } nls_update_font_list[] =
1445 /* Latin 1 (United States) */
1446 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1447 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1449 /* Latin 1 (Multilingual) */
1450 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1451 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1453 /* Eastern Europe */
1454 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1455 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1457 /* Cyrillic */
1458 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1459 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1461 /* Greek */
1462 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1463 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1465 /* Turkish */
1466 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1467 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1469 /* Hebrew */
1470 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1471 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1473 /* Arabic */
1474 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1475 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1477 /* Baltic */
1478 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1479 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1481 /* Vietnamese */
1482 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1483 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1485 /* Thai */
1486 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1487 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1489 /* Japanese */
1490 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1491 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1493 /* Chinese Simplified */
1494 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1495 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1497 /* Korean */
1498 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1499 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1501 /* Chinese Traditional */
1502 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1503 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1507 inline static HKEY create_fonts_NT_registry_key(void)
1509 HKEY hkey = 0;
1511 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1512 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1513 return hkey;
1516 inline static HKEY create_fonts_9x_registry_key(void)
1518 HKEY hkey = 0;
1520 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1521 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1522 return hkey;
1525 inline static HKEY create_config_fonts_registry_key(void)
1527 HKEY hkey = 0;
1529 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1530 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1531 return hkey;
1534 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1536 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1537 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1538 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1539 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1542 static void update_font_info(void)
1544 char buf[80];
1545 DWORD len, type;
1546 HKEY hkey = 0;
1547 UINT i, ansi_cp = 0, oem_cp = 0;
1548 LCID lcid = GetUserDefaultLCID();
1550 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1551 return;
1553 len = sizeof(buf);
1554 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1556 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1558 RegCloseKey(hkey);
1559 return;
1561 TRACE("updating registry, locale changed %s -> %08x\n", debugstr_a(buf), lcid);
1563 else TRACE("updating registry, locale changed none -> %08x\n", lcid);
1565 sprintf(buf, "%08x", lcid);
1566 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1567 RegCloseKey(hkey);
1569 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1570 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1571 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1572 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1574 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1576 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1577 nls_update_font_list[i].oem_cp == oem_cp)
1579 HKEY hkey;
1581 hkey = create_config_fonts_registry_key();
1582 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1583 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1584 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1585 RegCloseKey(hkey);
1587 hkey = create_fonts_NT_registry_key();
1588 add_font_list(hkey, &nls_update_font_list[i]);
1589 RegCloseKey(hkey);
1591 hkey = create_fonts_9x_registry_key();
1592 add_font_list(hkey, &nls_update_font_list[i]);
1593 RegCloseKey(hkey);
1595 return;
1598 FIXME("there is no font defaults for lcid %04x/ansi_cp %u\n", lcid, ansi_cp);
1601 /*************************************************************
1602 * WineEngInit
1604 * Initialize FreeType library and create a list of available faces
1606 BOOL WineEngInit(void)
1608 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1609 static const WCHAR pathW[] = {'P','a','t','h',0};
1610 HKEY hkey;
1611 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1612 LPVOID data;
1613 WCHAR windowsdir[MAX_PATH];
1614 char *unixname;
1615 HANDLE font_mutex;
1616 const char *data_dir;
1618 TRACE("\n");
1620 /* update locale dependent font info in registry */
1621 update_font_info();
1623 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1624 if(!ft_handle) {
1625 WINE_MESSAGE(
1626 "Wine cannot find the FreeType font library. To enable Wine to\n"
1627 "use TrueType fonts please install a version of FreeType greater than\n"
1628 "or equal to 2.0.5.\n"
1629 "http://www.freetype.org\n");
1630 return FALSE;
1633 #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;}
1635 LOAD_FUNCPTR(FT_Vector_Unit)
1636 LOAD_FUNCPTR(FT_Done_Face)
1637 LOAD_FUNCPTR(FT_Get_Char_Index)
1638 LOAD_FUNCPTR(FT_Get_Module)
1639 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1640 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1641 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1642 LOAD_FUNCPTR(FT_Init_FreeType)
1643 LOAD_FUNCPTR(FT_Load_Glyph)
1644 LOAD_FUNCPTR(FT_Matrix_Multiply)
1645 LOAD_FUNCPTR(FT_MulFix)
1646 LOAD_FUNCPTR(FT_New_Face)
1647 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1648 LOAD_FUNCPTR(FT_Outline_Transform)
1649 LOAD_FUNCPTR(FT_Outline_Translate)
1650 LOAD_FUNCPTR(FT_Select_Charmap)
1651 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1652 LOAD_FUNCPTR(FT_Vector_Transform)
1654 #undef LOAD_FUNCPTR
1655 /* Don't warn if this one is missing */
1656 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1657 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1658 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1659 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1660 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1661 #ifdef HAVE_FREETYPE_FTWINFNT_H
1662 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1663 #endif
1664 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1665 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1666 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1667 <= 2.0.3 has FT_Sqrt64 */
1668 goto sym_not_found;
1671 if(pFT_Init_FreeType(&library) != 0) {
1672 ERR("Can't init FreeType library\n");
1673 wine_dlclose(ft_handle, NULL, 0);
1674 ft_handle = NULL;
1675 return FALSE;
1677 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1678 if (pFT_Library_Version)
1680 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1682 if (FT_Version.major<=0)
1684 FT_Version.major=2;
1685 FT_Version.minor=0;
1686 FT_Version.patch=5;
1688 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1689 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1690 ((FT_Version.minor << 8) & 0x00ff00) |
1691 ((FT_Version.patch ) & 0x0000ff);
1693 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1694 ERR("Failed to create font mutex\n");
1695 return FALSE;
1697 WaitForSingleObject(font_mutex, INFINITE);
1699 /* load the system bitmap fonts */
1700 load_system_fonts();
1702 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1703 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1704 strcatW(windowsdir, fontsW);
1705 if((unixname = wine_get_unix_file_name(windowsdir)))
1707 ReadFontDir(unixname, FALSE);
1708 HeapFree(GetProcessHeap(), 0, unixname);
1711 /* load the system truetype fonts */
1712 data_dir = wine_get_data_dir();
1713 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1714 strcpy(unixname, data_dir);
1715 strcat(unixname, "/fonts/");
1716 ReadFontDir(unixname, FALSE);
1717 HeapFree(GetProcessHeap(), 0, unixname);
1720 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1721 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1722 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1723 will skip these. */
1724 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1725 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1726 &hkey) == ERROR_SUCCESS) {
1727 LPWSTR valueW;
1728 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1729 &valuelen, &datalen, NULL, NULL);
1731 valuelen++; /* returned value doesn't include room for '\0' */
1732 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1733 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1734 if (valueW && data)
1736 dlen = datalen * sizeof(WCHAR);
1737 vlen = valuelen;
1738 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1739 &dlen) == ERROR_SUCCESS) {
1740 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1742 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1744 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1745 HeapFree(GetProcessHeap(), 0, unixname);
1748 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1750 WCHAR pathW[MAX_PATH];
1751 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1752 BOOL added = FALSE;
1754 sprintfW(pathW, fmtW, windowsdir, data);
1755 if((unixname = wine_get_unix_file_name(pathW)))
1757 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1758 HeapFree(GetProcessHeap(), 0, unixname);
1760 if (!added)
1761 load_font_from_data_dir(data);
1763 /* reset dlen and vlen */
1764 dlen = datalen;
1765 vlen = valuelen;
1768 HeapFree(GetProcessHeap(), 0, data);
1769 HeapFree(GetProcessHeap(), 0, valueW);
1770 RegCloseKey(hkey);
1773 load_fontconfig_fonts();
1775 /* then look in any directories that we've specified in the config file */
1776 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1777 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1779 DWORD len;
1780 LPWSTR valueW;
1781 LPSTR valueA, ptr;
1783 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1785 len += sizeof(WCHAR);
1786 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1787 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1789 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1790 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1791 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1792 TRACE( "got font path %s\n", debugstr_a(valueA) );
1793 ptr = valueA;
1794 while (ptr)
1796 LPSTR next = strchr( ptr, ':' );
1797 if (next) *next++ = 0;
1798 ReadFontDir( ptr, TRUE );
1799 ptr = next;
1801 HeapFree( GetProcessHeap(), 0, valueA );
1803 HeapFree( GetProcessHeap(), 0, valueW );
1805 RegCloseKey(hkey);
1808 DumpFontList();
1809 LoadSubstList();
1810 DumpSubstList();
1811 LoadReplaceList();
1812 update_reg_entries();
1814 init_system_links();
1816 ReleaseMutex(font_mutex);
1817 return TRUE;
1818 sym_not_found:
1819 WINE_MESSAGE(
1820 "Wine cannot find certain functions that it needs inside the FreeType\n"
1821 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1822 "FreeType to at least version 2.0.5.\n"
1823 "http://www.freetype.org\n");
1824 wine_dlclose(ft_handle, NULL, 0);
1825 ft_handle = NULL;
1826 return FALSE;
1830 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1832 TT_OS2 *pOS2;
1833 TT_HoriHeader *pHori;
1835 LONG ppem;
1837 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1838 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1840 if(height == 0) height = 16;
1842 /* Calc. height of EM square:
1844 * For +ve lfHeight we have
1845 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1846 * Re-arranging gives:
1847 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1849 * For -ve lfHeight we have
1850 * |lfHeight| = ppem
1851 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1852 * with il = winAscent + winDescent - units_per_em]
1856 if(height > 0) {
1857 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1858 ppem = ft_face->units_per_EM * height /
1859 (pHori->Ascender - pHori->Descender);
1860 else
1861 ppem = ft_face->units_per_EM * height /
1862 (pOS2->usWinAscent + pOS2->usWinDescent);
1864 else
1865 ppem = -height;
1867 return ppem;
1870 static LONG load_VDMX(GdiFont*, LONG);
1872 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
1874 FT_Error err;
1875 FT_Face ft_face;
1877 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
1878 err = pFT_New_Face(library, file, face_index, &ft_face);
1879 if(err) {
1880 ERR("FT_New_Face rets %d\n", err);
1881 return 0;
1884 /* set it here, as load_VDMX needs it */
1885 font->ft_face = ft_face;
1887 if(FT_IS_SCALABLE(ft_face)) {
1888 /* load the VDMX table if we have one */
1889 font->ppem = load_VDMX(font, height);
1890 if(font->ppem == 0)
1891 font->ppem = calc_ppem_for_height(ft_face, height);
1893 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1894 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
1895 } else {
1896 font->ppem = height;
1897 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1898 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
1900 return ft_face;
1904 static int get_nearest_charset(Face *face, int *cp)
1906 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1907 a single face with the requested charset. The idea is to check if
1908 the selected font supports the current ANSI codepage, if it does
1909 return the corresponding charset, else return the first charset */
1911 CHARSETINFO csi;
1912 int acp = GetACP(), i;
1913 DWORD fs0;
1915 *cp = acp;
1916 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
1917 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
1918 return csi.ciCharset;
1920 for(i = 0; i < 32; i++) {
1921 fs0 = 1L << i;
1922 if(face->fs.fsCsb[0] & fs0) {
1923 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1924 *cp = csi.ciACP;
1925 return csi.ciCharset;
1927 else
1928 FIXME("TCI failing on %x\n", fs0);
1932 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
1933 face->fs.fsCsb[0], face->file);
1934 *cp = acp;
1935 return DEFAULT_CHARSET;
1938 static GdiFont *alloc_font(void)
1940 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1941 ret->gmsize = INIT_GM_SIZE;
1942 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1943 ret->gmsize * sizeof(*ret->gm));
1944 ret->potm = NULL;
1945 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1946 ret->total_kern_pairs = (DWORD)-1;
1947 ret->kern_pairs = NULL;
1948 list_init(&ret->hfontlist);
1949 list_init(&ret->child_fonts);
1950 return ret;
1953 static void free_font(GdiFont *font)
1955 struct list *cursor, *cursor2;
1957 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1959 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1960 struct list *first_hfont;
1961 HFONTLIST *hfontlist;
1962 list_remove(cursor);
1963 if(child->font)
1965 first_hfont = list_head(&child->font->hfontlist);
1966 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1967 DeleteObject(hfontlist->hfont);
1968 HeapFree(GetProcessHeap(), 0, hfontlist);
1969 free_font(child->font);
1971 HeapFree(GetProcessHeap(), 0, child->file_name);
1972 HeapFree(GetProcessHeap(), 0, child);
1975 if (font->ft_face) pFT_Done_Face(font->ft_face);
1976 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
1977 HeapFree(GetProcessHeap(), 0, font->potm);
1978 HeapFree(GetProcessHeap(), 0, font->name);
1979 HeapFree(GetProcessHeap(), 0, font->gm);
1980 HeapFree(GetProcessHeap(), 0, font);
1984 /*************************************************************
1985 * load_VDMX
1987 * load the vdmx entry for the specified height
1990 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1991 ( ( (FT_ULong)_x4 << 24 ) | \
1992 ( (FT_ULong)_x3 << 16 ) | \
1993 ( (FT_ULong)_x2 << 8 ) | \
1994 (FT_ULong)_x1 )
1996 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1998 typedef struct {
1999 BYTE bCharSet;
2000 BYTE xRatio;
2001 BYTE yStartRatio;
2002 BYTE yEndRatio;
2003 } Ratios;
2005 typedef struct {
2006 WORD recs;
2007 BYTE startsz;
2008 BYTE endsz;
2009 } VDMX_group;
2011 static LONG load_VDMX(GdiFont *font, LONG height)
2013 WORD hdr[3], tmp;
2014 VDMX_group group;
2015 BYTE devXRatio, devYRatio;
2016 USHORT numRecs, numRatios;
2017 DWORD result, offset = -1;
2018 LONG ppem = 0;
2019 int i;
2021 /* For documentation on VDMX records, see
2022 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2025 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2027 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2028 return ppem;
2030 /* FIXME: need the real device aspect ratio */
2031 devXRatio = 1;
2032 devYRatio = 1;
2034 numRecs = GET_BE_WORD(hdr[1]);
2035 numRatios = GET_BE_WORD(hdr[2]);
2037 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2038 for(i = 0; i < numRatios; i++) {
2039 Ratios ratio;
2041 offset = (3 * 2) + (i * sizeof(Ratios));
2042 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2043 offset = -1;
2045 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2047 if((ratio.xRatio == 0 &&
2048 ratio.yStartRatio == 0 &&
2049 ratio.yEndRatio == 0) ||
2050 (devXRatio == ratio.xRatio &&
2051 devYRatio >= ratio.yStartRatio &&
2052 devYRatio <= ratio.yEndRatio))
2054 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2055 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2056 offset = GET_BE_WORD(tmp);
2057 break;
2061 if(offset == -1) {
2062 FIXME("No suitable ratio found\n");
2063 return ppem;
2066 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2067 USHORT recs;
2068 BYTE startsz, endsz;
2069 WORD *vTable;
2071 recs = GET_BE_WORD(group.recs);
2072 startsz = group.startsz;
2073 endsz = group.endsz;
2075 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2077 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2078 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2079 if(result == GDI_ERROR) {
2080 FIXME("Failed to retrieve vTable\n");
2081 goto end;
2084 if(height > 0) {
2085 for(i = 0; i < recs; i++) {
2086 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2087 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2088 ppem = GET_BE_WORD(vTable[i * 3]);
2090 if(yMax + -yMin == height) {
2091 font->yMax = yMax;
2092 font->yMin = yMin;
2093 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2094 break;
2096 if(yMax + -yMin > height) {
2097 if(--i < 0) {
2098 ppem = 0;
2099 goto end; /* failed */
2101 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2102 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2103 ppem = GET_BE_WORD(vTable[i * 3]);
2104 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2105 break;
2108 if(!font->yMax) {
2109 ppem = 0;
2110 TRACE("ppem not found for height %d\n", height);
2112 } else {
2113 ppem = -height;
2114 if(ppem < startsz || ppem > endsz)
2115 goto end;
2117 for(i = 0; i < recs; i++) {
2118 USHORT yPelHeight;
2119 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2121 if(yPelHeight > ppem)
2122 break; /* failed */
2124 if(yPelHeight == ppem) {
2125 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2126 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2127 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2128 break;
2132 end:
2133 HeapFree(GetProcessHeap(), 0, vTable);
2136 return ppem;
2139 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2141 if(font->font_desc.hash != fd->hash) return TRUE;
2142 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2143 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2144 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2145 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2148 static void calc_hash(FONT_DESC *pfd)
2150 DWORD hash = 0, *ptr, two_chars;
2151 WORD *pwc;
2152 unsigned int i;
2154 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2155 hash ^= *ptr;
2156 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2157 hash ^= *ptr;
2158 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2159 two_chars = *ptr;
2160 pwc = (WCHAR *)&two_chars;
2161 if(!*pwc) break;
2162 *pwc = toupperW(*pwc);
2163 pwc++;
2164 *pwc = toupperW(*pwc);
2165 hash ^= two_chars;
2166 if(!*pwc) break;
2168 hash ^= !pfd->can_use_bitmap;
2169 pfd->hash = hash;
2170 return;
2173 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2175 GdiFont *ret;
2176 FONT_DESC fd;
2177 HFONTLIST *hflist;
2178 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2180 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2181 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2182 fd.can_use_bitmap = can_use_bitmap;
2183 calc_hash(&fd);
2185 /* try the in-use list */
2186 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2187 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2188 if(!fontcmp(ret, &fd)) {
2189 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2190 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2191 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2192 if(hflist->hfont == hfont)
2193 return ret;
2195 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2196 hflist->hfont = hfont;
2197 list_add_head(&ret->hfontlist, &hflist->entry);
2198 return ret;
2202 /* then the unused list */
2203 font_elem_ptr = list_head(&unused_gdi_font_list);
2204 while(font_elem_ptr) {
2205 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2206 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2207 if(!fontcmp(ret, &fd)) {
2208 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2209 assert(list_empty(&ret->hfontlist));
2210 TRACE("Found %p in unused list\n", ret);
2211 list_remove(&ret->entry);
2212 list_add_head(&gdi_font_list, &ret->entry);
2213 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2214 hflist->hfont = hfont;
2215 list_add_head(&ret->hfontlist, &hflist->entry);
2216 return ret;
2219 return NULL;
2223 /*************************************************************
2224 * create_child_font_list
2226 static BOOL create_child_font_list(GdiFont *font)
2228 BOOL ret = FALSE;
2229 SYSTEM_LINKS *font_link;
2230 CHILD_FONT *font_link_entry, *new_child;
2232 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2234 if(!strcmpW(font_link->font_name, font->name))
2236 TRACE("found entry in system list\n");
2237 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2239 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2240 new_child->file_name = strdupA(font_link_entry->file_name);
2241 new_child->index = font_link_entry->index;
2242 new_child->font = NULL;
2243 list_add_tail(&font->child_fonts, &new_child->entry);
2244 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2246 ret = TRUE;
2247 break;
2251 return ret;
2254 /*************************************************************
2255 * WineEngCreateFontInstance
2258 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2260 GdiFont *ret;
2261 Face *face, *best, *best_bitmap;
2262 Family *family, *last_resort_family;
2263 struct list *family_elem_ptr, *face_elem_ptr;
2264 INT height, width = 0;
2265 unsigned int score = 0, new_score;
2266 signed int diff = 0, newdiff;
2267 BOOL bd, it, can_use_bitmap;
2268 LOGFONTW lf;
2269 CHARSETINFO csi;
2270 HFONTLIST *hflist;
2272 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2274 struct list *first_hfont = list_head(&ret->hfontlist);
2275 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2276 if(hflist->hfont == hfont)
2277 return ret;
2280 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2281 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2283 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2284 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2285 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2286 lf.lfEscapement);
2288 /* check the cache first */
2289 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2290 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2291 return ret;
2294 TRACE("not in cache\n");
2295 if(list_empty(&font_list)) /* No fonts installed */
2297 TRACE("No fonts installed\n");
2298 return NULL;
2300 if(!have_installed_roman_font)
2302 TRACE("No roman font installed\n");
2303 return NULL;
2306 ret = alloc_font();
2308 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2309 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2310 ret->font_desc.can_use_bitmap = can_use_bitmap;
2311 calc_hash(&ret->font_desc);
2312 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2313 hflist->hfont = hfont;
2314 list_add_head(&ret->hfontlist, &hflist->entry);
2317 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2318 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2319 original value lfCharSet. Note this is a special case for
2320 Symbol and doesn't happen at least for "Wingdings*" */
2322 if(!strcmpiW(lf.lfFaceName, SymbolW))
2323 lf.lfCharSet = SYMBOL_CHARSET;
2325 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2326 switch(lf.lfCharSet) {
2327 case DEFAULT_CHARSET:
2328 csi.fs.fsCsb[0] = 0;
2329 break;
2330 default:
2331 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2332 csi.fs.fsCsb[0] = 0;
2333 break;
2337 family = NULL;
2338 if(lf.lfFaceName[0] != '\0') {
2339 FontSubst *psub;
2340 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2342 if(psub) {
2343 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2344 debugstr_w(psub->to.name));
2345 strcpyW(lf.lfFaceName, psub->to.name);
2348 /* We want a match on name and charset or just name if
2349 charset was DEFAULT_CHARSET. If the latter then
2350 we fixup the returned charset later in get_nearest_charset
2351 where we'll either use the charset of the current ansi codepage
2352 or if that's unavailable the first charset that the font supports.
2354 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2355 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2356 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2357 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2358 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2359 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2360 if(face->scalable || can_use_bitmap)
2361 goto found;
2367 /* If requested charset was DEFAULT_CHARSET then try using charset
2368 corresponding to the current ansi codepage */
2369 if(!csi.fs.fsCsb[0]) {
2370 INT acp = GetACP();
2371 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2372 FIXME("TCI failed on codepage %d\n", acp);
2373 csi.fs.fsCsb[0] = 0;
2374 } else
2375 lf.lfCharSet = csi.ciCharset;
2378 /* Face families are in the top 4 bits of lfPitchAndFamily,
2379 so mask with 0xF0 before testing */
2381 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2382 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2383 strcpyW(lf.lfFaceName, defFixed);
2384 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2385 strcpyW(lf.lfFaceName, defSerif);
2386 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2387 strcpyW(lf.lfFaceName, defSans);
2388 else
2389 strcpyW(lf.lfFaceName, defSans);
2390 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2391 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2392 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2393 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2394 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2395 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2396 if(face->scalable || can_use_bitmap)
2397 goto found;
2402 last_resort_family = NULL;
2403 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2404 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2405 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2406 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2407 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2408 if(face->scalable)
2409 goto found;
2410 if(can_use_bitmap && !last_resort_family)
2411 last_resort_family = family;
2416 if(last_resort_family) {
2417 family = last_resort_family;
2418 csi.fs.fsCsb[0] = 0;
2419 goto found;
2422 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2423 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2424 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2425 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2426 if(face->scalable) {
2427 csi.fs.fsCsb[0] = 0;
2428 WARN("just using first face for now\n");
2429 goto found;
2431 if(can_use_bitmap && !last_resort_family)
2432 last_resort_family = family;
2435 if(!last_resort_family) {
2436 FIXME("can't find a single appropriate font - bailing\n");
2437 free_font(ret);
2438 return NULL;
2441 WARN("could only find a bitmap font - this will probably look awful!\n");
2442 family = last_resort_family;
2443 csi.fs.fsCsb[0] = 0;
2445 found:
2446 it = lf.lfItalic ? 1 : 0;
2447 bd = lf.lfWeight > 550 ? 1 : 0;
2449 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2450 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2452 face = best = best_bitmap = NULL;
2453 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2455 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2457 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2458 if(!best || new_score <= score)
2460 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2461 face->Italic, face->Bold, it, bd);
2462 score = new_score;
2463 best = face;
2464 if(best->scalable && score == 0) break;
2465 if(!best->scalable)
2467 if(height > 0)
2468 newdiff = height - (signed int)(best->size.height);
2469 else
2470 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2471 if(!best_bitmap || new_score < score ||
2472 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2474 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2475 diff = newdiff;
2476 best_bitmap = best;
2477 if(score == 0 && diff == 0) break;
2483 if(best)
2484 face = best->scalable ? best : best_bitmap;
2485 ret->fake_italic = (it && !face->Italic);
2486 ret->fake_bold = (bd && !face->Bold);
2488 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2490 if(csi.fs.fsCsb[0]) {
2491 ret->charset = lf.lfCharSet;
2492 ret->codepage = csi.ciACP;
2494 else
2495 ret->charset = get_nearest_charset(face, &ret->codepage);
2497 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2498 debugstr_w(face->StyleName), face->file, face->face_index);
2500 if(!face->scalable) {
2501 width = face->size.x_ppem >> 6;
2502 height = face->size.y_ppem >> 6;
2504 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2506 if (!ret->ft_face)
2508 free_font( ret );
2509 return 0;
2512 if (ret->charset == SYMBOL_CHARSET &&
2513 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2514 /* No ops */
2516 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2517 /* No ops */
2519 else {
2520 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2523 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2524 ret->name = strdupW(family->FamilyName);
2525 ret->underline = lf.lfUnderline ? 0xff : 0;
2526 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2527 create_child_font_list(ret);
2529 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2531 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2532 list_add_head(&gdi_font_list, &ret->entry);
2533 return ret;
2536 static void dump_gdi_font_list(void)
2538 GdiFont *gdiFont;
2539 struct list *elem_ptr;
2541 TRACE("---------- gdiFont Cache ----------\n");
2542 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2543 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2544 TRACE("gdiFont=%p %s %d\n",
2545 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2548 TRACE("---------- Unused gdiFont Cache ----------\n");
2549 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2550 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2551 TRACE("gdiFont=%p %s %d\n",
2552 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2556 /*************************************************************
2557 * WineEngDestroyFontInstance
2559 * free the gdiFont associated with this handle
2562 BOOL WineEngDestroyFontInstance(HFONT handle)
2564 GdiFont *gdiFont;
2565 HFONTLIST *hflist;
2566 BOOL ret = FALSE;
2567 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2568 int i = 0;
2570 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2572 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2573 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2574 if(hflist->hfont == handle)
2576 TRACE("removing child font %p from child list\n", gdiFont);
2577 list_remove(&gdiFont->entry);
2578 return TRUE;
2582 TRACE("destroying hfont=%p\n", handle);
2583 if(TRACE_ON(font))
2584 dump_gdi_font_list();
2586 font_elem_ptr = list_head(&gdi_font_list);
2587 while(font_elem_ptr) {
2588 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2589 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2591 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2592 while(hfontlist_elem_ptr) {
2593 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2594 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2595 if(hflist->hfont == handle) {
2596 list_remove(&hflist->entry);
2597 HeapFree(GetProcessHeap(), 0, hflist);
2598 ret = TRUE;
2601 if(list_empty(&gdiFont->hfontlist)) {
2602 TRACE("Moving to Unused list\n");
2603 list_remove(&gdiFont->entry);
2604 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2609 font_elem_ptr = list_head(&unused_gdi_font_list);
2610 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2611 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2612 while(font_elem_ptr) {
2613 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2614 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2615 TRACE("freeing %p\n", gdiFont);
2616 list_remove(&gdiFont->entry);
2617 free_font(gdiFont);
2619 return ret;
2622 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2623 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2625 OUTLINETEXTMETRICW *potm = NULL;
2626 UINT size;
2627 TEXTMETRICW tm, *ptm;
2628 GdiFont *font = alloc_font();
2629 LONG width, height;
2631 if(face->scalable) {
2632 height = 100;
2633 width = 0;
2634 } else {
2635 height = face->size.y_ppem >> 6;
2636 width = face->size.x_ppem >> 6;
2639 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2641 free_font(font);
2642 return;
2645 font->name = strdupW(face->family->FamilyName);
2647 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2649 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2650 if(size) {
2651 potm = HeapAlloc(GetProcessHeap(), 0, size);
2652 WineEngGetOutlineTextMetrics(font, size, potm);
2653 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2654 } else {
2655 WineEngGetTextMetrics(font, &tm);
2656 ptm = &tm;
2659 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2660 pntm->ntmTm.tmAscent = ptm->tmAscent;
2661 pntm->ntmTm.tmDescent = ptm->tmDescent;
2662 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2663 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2664 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2665 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2666 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2667 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2668 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2669 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2670 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2671 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2672 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2673 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2674 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2675 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2676 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2677 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2678 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2679 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2680 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2681 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2682 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2684 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2685 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2686 *ptype |= RASTER_FONTTYPE;
2688 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2689 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2690 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2692 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2693 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2694 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2696 if(potm) {
2697 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2699 lstrcpynW(pelf->elfLogFont.lfFaceName,
2700 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2701 LF_FACESIZE);
2702 lstrcpynW(pelf->elfFullName,
2703 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2704 LF_FULLFACESIZE);
2705 lstrcpynW(pelf->elfStyle,
2706 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2707 LF_FACESIZE);
2709 HeapFree(GetProcessHeap(), 0, potm);
2710 } else {
2711 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2713 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2714 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2715 pelf->elfStyle[0] = '\0';
2718 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2720 free_font(font);
2723 /*************************************************************
2724 * WineEngEnumFonts
2727 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2729 Family *family;
2730 Face *face;
2731 struct list *family_elem_ptr, *face_elem_ptr;
2732 ENUMLOGFONTEXW elf;
2733 NEWTEXTMETRICEXW ntm;
2734 DWORD type, ret = 1;
2735 FONTSIGNATURE fs;
2736 CHARSETINFO csi;
2737 LOGFONTW lf;
2738 int i;
2740 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2742 if(plf->lfFaceName[0]) {
2743 FontSubst *psub;
2744 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2746 if(psub) {
2747 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2748 debugstr_w(psub->to.name));
2749 memcpy(&lf, plf, sizeof(lf));
2750 strcpyW(lf.lfFaceName, psub->to.name);
2751 plf = &lf;
2754 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2755 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2756 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2757 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2758 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2759 GetEnumStructs(face, &elf, &ntm, &type);
2760 for(i = 0; i < 32; i++) {
2761 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2762 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2763 strcpyW(elf.elfScript, OEM_DOSW);
2764 i = 32; /* break out of loop */
2765 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2766 continue;
2767 else {
2768 fs.fsCsb[0] = 1L << i;
2769 fs.fsCsb[1] = 0;
2770 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2771 TCI_SRCFONTSIG))
2772 csi.ciCharset = DEFAULT_CHARSET;
2773 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2774 if(csi.ciCharset != DEFAULT_CHARSET) {
2775 elf.elfLogFont.lfCharSet =
2776 ntm.ntmTm.tmCharSet = csi.ciCharset;
2777 if(ElfScriptsW[i])
2778 strcpyW(elf.elfScript, ElfScriptsW[i]);
2779 else
2780 FIXME("Unknown elfscript for bit %d\n", i);
2783 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
2784 debugstr_w(elf.elfLogFont.lfFaceName),
2785 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2786 csi.ciCharset, type, debugstr_w(elf.elfScript),
2787 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2788 ntm.ntmTm.ntmFlags);
2789 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2790 if(!ret) goto end;
2795 } else {
2796 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2797 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2798 face_elem_ptr = list_head(&family->faces);
2799 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2800 GetEnumStructs(face, &elf, &ntm, &type);
2801 for(i = 0; i < 32; i++) {
2802 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2803 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2804 strcpyW(elf.elfScript, OEM_DOSW);
2805 i = 32; /* break out of loop */
2806 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2807 continue;
2808 else {
2809 fs.fsCsb[0] = 1L << i;
2810 fs.fsCsb[1] = 0;
2811 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2812 TCI_SRCFONTSIG))
2813 csi.ciCharset = DEFAULT_CHARSET;
2814 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2815 if(csi.ciCharset != DEFAULT_CHARSET) {
2816 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2817 csi.ciCharset;
2818 if(ElfScriptsW[i])
2819 strcpyW(elf.elfScript, ElfScriptsW[i]);
2820 else
2821 FIXME("Unknown elfscript for bit %d\n", i);
2824 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2825 debugstr_w(elf.elfLogFont.lfFaceName),
2826 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2827 csi.ciCharset, type, debugstr_w(elf.elfScript),
2828 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2829 ntm.ntmTm.ntmFlags);
2830 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2831 if(!ret) goto end;
2835 end:
2836 return ret;
2839 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2841 pt->x.value = vec->x >> 6;
2842 pt->x.fract = (vec->x & 0x3f) << 10;
2843 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2844 pt->y.value = vec->y >> 6;
2845 pt->y.fract = (vec->y & 0x3f) << 10;
2846 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2847 return;
2850 /***************************************************
2851 * According to the MSDN documentation on WideCharToMultiByte,
2852 * certain codepages cannot set the default_used parameter.
2853 * This returns TRUE if the codepage can set that parameter, false else
2854 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2856 static BOOL codepage_sets_default_used(UINT codepage)
2858 switch (codepage)
2860 case CP_UTF7:
2861 case CP_UTF8:
2862 case CP_SYMBOL:
2863 return FALSE;
2864 default:
2865 return TRUE;
2869 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
2871 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2872 WCHAR wc = (WCHAR)glyph;
2873 BOOL default_used;
2874 BOOL *default_used_pointer;
2875 FT_UInt ret;
2876 char buf;
2877 default_used_pointer = NULL;
2878 default_used = FALSE;
2879 if (codepage_sets_default_used(font->codepage))
2880 default_used_pointer = &default_used;
2881 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2882 ret = 0;
2883 else
2884 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2885 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2886 return ret;
2889 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2890 glyph = glyph + 0xf000;
2891 return pFT_Get_Char_Index(font->ft_face, glyph);
2894 /*************************************************************
2895 * WineEngGetGlyphIndices
2897 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2899 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
2900 LPWORD pgi, DWORD flags)
2902 int i;
2903 WCHAR default_char = 0;
2904 TEXTMETRICW textm;
2906 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
2908 for(i = 0; i < count; i++)
2910 pgi[i] = get_glyph_index(font, lpstr[i]);
2911 if (pgi[i] == 0)
2913 if (!default_char)
2915 WineEngGetTextMetrics(font, &textm);
2916 default_char = textm.tmDefaultChar;
2918 pgi[i] = default_char;
2921 return count;
2924 /*************************************************************
2925 * WineEngGetGlyphOutline
2927 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2928 * except that the first parameter is the HWINEENGFONT of the font in
2929 * question rather than an HDC.
2932 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
2933 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2934 const MAT2* lpmat)
2936 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2937 FT_Face ft_face = font->ft_face;
2938 FT_UInt glyph_index;
2939 DWORD width, height, pitch, needed = 0;
2940 FT_Bitmap ft_bitmap;
2941 FT_Error err;
2942 INT left, right, top = 0, bottom = 0;
2943 FT_Angle angle = 0;
2944 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2945 float widthRatio = 1.0;
2946 FT_Matrix transMat = identityMat;
2947 BOOL needsTransform = FALSE;
2950 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
2951 buflen, buf, lpmat);
2953 if(format & GGO_GLYPH_INDEX) {
2954 glyph_index = glyph;
2955 format &= ~GGO_GLYPH_INDEX;
2956 } else
2957 glyph_index = get_glyph_index(font, glyph);
2959 if(glyph_index >= font->gmsize) {
2960 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2961 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2962 font->gmsize * sizeof(*font->gm));
2963 } else {
2964 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2965 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2966 return 1; /* FIXME */
2970 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2971 load_flags |= FT_LOAD_NO_BITMAP;
2973 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2975 if(err) {
2976 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2977 return GDI_ERROR;
2980 /* Scaling factor */
2981 if (font->aveWidth && font->potm) {
2982 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2985 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2986 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2988 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2989 font->gm[glyph_index].lsb = left >> 6;
2990 font->gm[glyph_index].bbx = (right - left) >> 6;
2992 /* Scaling transform */
2993 if(font->aveWidth) {
2994 FT_Matrix scaleMat;
2995 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2996 scaleMat.xy = 0;
2997 scaleMat.yx = 0;
2998 scaleMat.yy = (1 << 16);
3000 pFT_Matrix_Multiply(&scaleMat, &transMat);
3001 needsTransform = TRUE;
3004 /* Slant transform */
3005 if (font->fake_italic) {
3006 FT_Matrix slantMat;
3008 slantMat.xx = (1 << 16);
3009 slantMat.xy = ((1 << 16) >> 2);
3010 slantMat.yx = 0;
3011 slantMat.yy = (1 << 16);
3012 pFT_Matrix_Multiply(&slantMat, &transMat);
3013 needsTransform = TRUE;
3016 /* Rotation transform */
3017 if(font->orientation) {
3018 FT_Matrix rotationMat;
3019 FT_Vector vecAngle;
3020 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3021 pFT_Vector_Unit(&vecAngle, angle);
3022 rotationMat.xx = vecAngle.x;
3023 rotationMat.xy = -vecAngle.y;
3024 rotationMat.yx = -rotationMat.xy;
3025 rotationMat.yy = rotationMat.xx;
3027 pFT_Matrix_Multiply(&rotationMat, &transMat);
3028 needsTransform = TRUE;
3031 /* Extra transformation specified by caller */
3032 if (lpmat) {
3033 FT_Matrix extraMat;
3034 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3035 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3036 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3037 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3038 pFT_Matrix_Multiply(&extraMat, &transMat);
3039 needsTransform = TRUE;
3042 if(!needsTransform) {
3043 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3044 bottom = (ft_face->glyph->metrics.horiBearingY -
3045 ft_face->glyph->metrics.height) & -64;
3046 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3047 lpgm->gmCellIncY = 0;
3048 } else {
3049 INT xc, yc;
3050 FT_Vector vec;
3051 for(xc = 0; xc < 2; xc++) {
3052 for(yc = 0; yc < 2; yc++) {
3053 vec.x = (ft_face->glyph->metrics.horiBearingX +
3054 xc * ft_face->glyph->metrics.width);
3055 vec.y = ft_face->glyph->metrics.horiBearingY -
3056 yc * ft_face->glyph->metrics.height;
3057 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3058 pFT_Vector_Transform(&vec, &transMat);
3059 if(xc == 0 && yc == 0) {
3060 left = right = vec.x;
3061 top = bottom = vec.y;
3062 } else {
3063 if(vec.x < left) left = vec.x;
3064 else if(vec.x > right) right = vec.x;
3065 if(vec.y < bottom) bottom = vec.y;
3066 else if(vec.y > top) top = vec.y;
3070 left = left & -64;
3071 right = (right + 63) & -64;
3072 bottom = bottom & -64;
3073 top = (top + 63) & -64;
3075 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3076 vec.x = ft_face->glyph->metrics.horiAdvance;
3077 vec.y = 0;
3078 pFT_Vector_Transform(&vec, &transMat);
3079 lpgm->gmCellIncX = (vec.x+63) >> 6;
3080 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3082 lpgm->gmBlackBoxX = (right - left) >> 6;
3083 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3084 lpgm->gmptGlyphOrigin.x = left >> 6;
3085 lpgm->gmptGlyphOrigin.y = top >> 6;
3087 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3088 font->gm[glyph_index].init = TRUE;
3090 if(format == GGO_METRICS)
3091 return 1; /* FIXME */
3093 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3094 TRACE("loaded a bitmap\n");
3095 return GDI_ERROR;
3098 switch(format) {
3099 case GGO_BITMAP:
3100 width = lpgm->gmBlackBoxX;
3101 height = lpgm->gmBlackBoxY;
3102 pitch = ((width + 31) >> 5) << 2;
3103 needed = pitch * height;
3105 if(!buf || !buflen) break;
3107 switch(ft_face->glyph->format) {
3108 case ft_glyph_format_bitmap:
3110 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3111 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3112 INT h = ft_face->glyph->bitmap.rows;
3113 while(h--) {
3114 memcpy(dst, src, w);
3115 src += ft_face->glyph->bitmap.pitch;
3116 dst += pitch;
3118 break;
3121 case ft_glyph_format_outline:
3122 ft_bitmap.width = width;
3123 ft_bitmap.rows = height;
3124 ft_bitmap.pitch = pitch;
3125 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3126 ft_bitmap.buffer = buf;
3128 if(needsTransform) {
3129 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3132 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3134 /* Note: FreeType will only set 'black' bits for us. */
3135 memset(buf, 0, needed);
3136 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3137 break;
3139 default:
3140 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3141 return GDI_ERROR;
3143 break;
3145 case GGO_GRAY2_BITMAP:
3146 case GGO_GRAY4_BITMAP:
3147 case GGO_GRAY8_BITMAP:
3148 case WINE_GGO_GRAY16_BITMAP:
3150 unsigned int mult, row, col;
3151 BYTE *start, *ptr;
3153 width = lpgm->gmBlackBoxX;
3154 height = lpgm->gmBlackBoxY;
3155 pitch = (width + 3) / 4 * 4;
3156 needed = pitch * height;
3158 if(!buf || !buflen) break;
3159 ft_bitmap.width = width;
3160 ft_bitmap.rows = height;
3161 ft_bitmap.pitch = pitch;
3162 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3163 ft_bitmap.buffer = buf;
3165 if(needsTransform) {
3166 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3169 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3171 memset(ft_bitmap.buffer, 0, buflen);
3173 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3175 if(format == GGO_GRAY2_BITMAP)
3176 mult = 4;
3177 else if(format == GGO_GRAY4_BITMAP)
3178 mult = 16;
3179 else if(format == GGO_GRAY8_BITMAP)
3180 mult = 64;
3181 else if(format == WINE_GGO_GRAY16_BITMAP)
3182 break;
3183 else {
3184 assert(0);
3185 break;
3188 start = buf;
3189 for(row = 0; row < height; row++) {
3190 ptr = start;
3191 for(col = 0; col < width; col++, ptr++) {
3192 *ptr = (((int)*ptr) * mult + 128) / 256;
3194 start += pitch;
3196 break;
3199 case GGO_NATIVE:
3201 int contour, point = 0, first_pt;
3202 FT_Outline *outline = &ft_face->glyph->outline;
3203 TTPOLYGONHEADER *pph;
3204 TTPOLYCURVE *ppc;
3205 DWORD pph_start, cpfx, type;
3207 if(buflen == 0) buf = NULL;
3209 if (needsTransform && buf) {
3210 pFT_Outline_Transform(outline, &transMat);
3213 for(contour = 0; contour < outline->n_contours; contour++) {
3214 pph_start = needed;
3215 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3216 first_pt = point;
3217 if(buf) {
3218 pph->dwType = TT_POLYGON_TYPE;
3219 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3221 needed += sizeof(*pph);
3222 point++;
3223 while(point <= outline->contours[contour]) {
3224 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3225 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3226 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3227 cpfx = 0;
3228 do {
3229 if(buf)
3230 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3231 cpfx++;
3232 point++;
3233 } while(point <= outline->contours[contour] &&
3234 (outline->tags[point] & FT_Curve_Tag_On) ==
3235 (outline->tags[point-1] & FT_Curve_Tag_On));
3236 /* At the end of a contour Windows adds the start point, but
3237 only for Beziers */
3238 if(point > outline->contours[contour] &&
3239 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3240 if(buf)
3241 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3242 cpfx++;
3243 } else if(point <= outline->contours[contour] &&
3244 outline->tags[point] & FT_Curve_Tag_On) {
3245 /* add closing pt for bezier */
3246 if(buf)
3247 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3248 cpfx++;
3249 point++;
3251 if(buf) {
3252 ppc->wType = type;
3253 ppc->cpfx = cpfx;
3255 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3257 if(buf)
3258 pph->cb = needed - pph_start;
3260 break;
3262 case GGO_BEZIER:
3264 /* Convert the quadratic Beziers to cubic Beziers.
3265 The parametric eqn for a cubic Bezier is, from PLRM:
3266 r(t) = at^3 + bt^2 + ct + r0
3267 with the control points:
3268 r1 = r0 + c/3
3269 r2 = r1 + (c + b)/3
3270 r3 = r0 + c + b + a
3272 A quadratic Beizer has the form:
3273 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3275 So equating powers of t leads to:
3276 r1 = 2/3 p1 + 1/3 p0
3277 r2 = 2/3 p1 + 1/3 p2
3278 and of course r0 = p0, r3 = p2
3281 int contour, point = 0, first_pt;
3282 FT_Outline *outline = &ft_face->glyph->outline;
3283 TTPOLYGONHEADER *pph;
3284 TTPOLYCURVE *ppc;
3285 DWORD pph_start, cpfx, type;
3286 FT_Vector cubic_control[4];
3287 if(buflen == 0) buf = NULL;
3289 if (needsTransform && buf) {
3290 pFT_Outline_Transform(outline, &transMat);
3293 for(contour = 0; contour < outline->n_contours; contour++) {
3294 pph_start = needed;
3295 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3296 first_pt = point;
3297 if(buf) {
3298 pph->dwType = TT_POLYGON_TYPE;
3299 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3301 needed += sizeof(*pph);
3302 point++;
3303 while(point <= outline->contours[contour]) {
3304 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3305 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3306 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3307 cpfx = 0;
3308 do {
3309 if(type == TT_PRIM_LINE) {
3310 if(buf)
3311 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3312 cpfx++;
3313 point++;
3314 } else {
3315 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3316 so cpfx = 3n */
3318 /* FIXME: Possible optimization in endpoint calculation
3319 if there are two consecutive curves */
3320 cubic_control[0] = outline->points[point-1];
3321 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3322 cubic_control[0].x += outline->points[point].x + 1;
3323 cubic_control[0].y += outline->points[point].y + 1;
3324 cubic_control[0].x >>= 1;
3325 cubic_control[0].y >>= 1;
3327 if(point+1 > outline->contours[contour])
3328 cubic_control[3] = outline->points[first_pt];
3329 else {
3330 cubic_control[3] = outline->points[point+1];
3331 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3332 cubic_control[3].x += outline->points[point].x + 1;
3333 cubic_control[3].y += outline->points[point].y + 1;
3334 cubic_control[3].x >>= 1;
3335 cubic_control[3].y >>= 1;
3338 /* r1 = 1/3 p0 + 2/3 p1
3339 r2 = 1/3 p2 + 2/3 p1 */
3340 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3341 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3342 cubic_control[2] = cubic_control[1];
3343 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3344 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3345 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3346 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3347 if(buf) {
3348 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3349 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3350 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3352 cpfx += 3;
3353 point++;
3355 } while(point <= outline->contours[contour] &&
3356 (outline->tags[point] & FT_Curve_Tag_On) ==
3357 (outline->tags[point-1] & FT_Curve_Tag_On));
3358 /* At the end of a contour Windows adds the start point,
3359 but only for Beziers and we've already done that.
3361 if(point <= outline->contours[contour] &&
3362 outline->tags[point] & FT_Curve_Tag_On) {
3363 /* This is the closing pt of a bezier, but we've already
3364 added it, so just inc point and carry on */
3365 point++;
3367 if(buf) {
3368 ppc->wType = type;
3369 ppc->cpfx = cpfx;
3371 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3373 if(buf)
3374 pph->cb = needed - pph_start;
3376 break;
3379 default:
3380 FIXME("Unsupported format %d\n", format);
3381 return GDI_ERROR;
3383 return needed;
3386 static BOOL get_bitmap_text_metrics(GdiFont *font)
3388 FT_Face ft_face = font->ft_face;
3389 #ifdef HAVE_FREETYPE_FTWINFNT_H
3390 FT_WinFNT_HeaderRec winfnt_header;
3391 #endif
3392 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3393 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3394 font->potm->otmSize = size;
3396 #define TM font->potm->otmTextMetrics
3397 #ifdef HAVE_FREETYPE_FTWINFNT_H
3398 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3400 TM.tmHeight = winfnt_header.pixel_height;
3401 TM.tmAscent = winfnt_header.ascent;
3402 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3403 TM.tmInternalLeading = winfnt_header.internal_leading;
3404 TM.tmExternalLeading = winfnt_header.external_leading;
3405 TM.tmAveCharWidth = winfnt_header.avg_width;
3406 TM.tmMaxCharWidth = winfnt_header.max_width;
3407 TM.tmWeight = winfnt_header.weight;
3408 TM.tmOverhang = 0;
3409 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3410 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3411 TM.tmFirstChar = winfnt_header.first_char;
3412 TM.tmLastChar = winfnt_header.last_char;
3413 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3414 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3415 TM.tmItalic = winfnt_header.italic;
3416 TM.tmUnderlined = font->underline;
3417 TM.tmStruckOut = font->strikeout;
3418 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3419 TM.tmCharSet = winfnt_header.charset;
3421 else
3422 #endif
3424 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3425 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3426 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3427 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3428 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3429 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3430 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3431 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3432 TM.tmOverhang = 0;
3433 TM.tmDigitizedAspectX = 96; /* FIXME */
3434 TM.tmDigitizedAspectY = 96; /* FIXME */
3435 TM.tmFirstChar = 1;
3436 TM.tmLastChar = 255;
3437 TM.tmDefaultChar = 32;
3438 TM.tmBreakChar = 32;
3439 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3440 TM.tmUnderlined = font->underline;
3441 TM.tmStruckOut = font->strikeout;
3442 /* NB inverted meaning of TMPF_FIXED_PITCH */
3443 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3444 TM.tmCharSet = font->charset;
3446 #undef TM
3448 return TRUE;
3451 /*************************************************************
3452 * WineEngGetTextMetrics
3455 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3457 if(!font->potm) {
3458 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3459 if(!get_bitmap_text_metrics(font))
3460 return FALSE;
3462 if(!font->potm) return FALSE;
3463 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3465 if (font->aveWidth) {
3466 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3468 return TRUE;
3472 /*************************************************************
3473 * WineEngGetOutlineTextMetrics
3476 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3477 OUTLINETEXTMETRICW *potm)
3479 FT_Face ft_face = font->ft_face;
3480 UINT needed, lenfam, lensty, ret;
3481 TT_OS2 *pOS2;
3482 TT_HoriHeader *pHori;
3483 TT_Postscript *pPost;
3484 FT_Fixed x_scale, y_scale;
3485 WCHAR *family_nameW, *style_nameW;
3486 static const WCHAR spaceW[] = {' ', '\0'};
3487 char *cp;
3488 INT ascent, descent;
3490 TRACE("font=%p\n", font);
3492 if(!FT_IS_SCALABLE(ft_face))
3493 return 0;
3495 if(font->potm) {
3496 if(cbSize >= font->potm->otmSize)
3497 memcpy(potm, font->potm, font->potm->otmSize);
3498 return font->potm->otmSize;
3502 needed = sizeof(*potm);
3504 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3505 family_nameW = strdupW(font->name);
3507 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3508 * sizeof(WCHAR);
3509 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3510 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3511 style_nameW, lensty/sizeof(WCHAR));
3513 /* These names should be read from the TT name table */
3515 /* length of otmpFamilyName */
3516 needed += lenfam;
3518 /* length of otmpFaceName */
3519 if(!strcasecmp(ft_face->style_name, "regular")) {
3520 needed += lenfam; /* just the family name */
3521 } else {
3522 needed += lenfam + lensty; /* family + " " + style */
3525 /* length of otmpStyleName */
3526 needed += lensty;
3528 /* length of otmpFullName */
3529 needed += lenfam + lensty;
3532 x_scale = ft_face->size->metrics.x_scale;
3533 y_scale = ft_face->size->metrics.y_scale;
3535 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3536 if(!pOS2) {
3537 FIXME("Can't find OS/2 table - not TT font?\n");
3538 ret = 0;
3539 goto end;
3542 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3543 if(!pHori) {
3544 FIXME("Can't find HHEA table - not TT font?\n");
3545 ret = 0;
3546 goto end;
3549 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3551 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",
3552 pOS2->usWinAscent, pOS2->usWinDescent,
3553 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3554 ft_face->ascender, ft_face->descender, ft_face->height,
3555 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3556 ft_face->bbox.yMax, ft_face->bbox.yMin);
3558 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3559 font->potm->otmSize = needed;
3561 #define TM font->potm->otmTextMetrics
3563 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3564 ascent = pHori->Ascender;
3565 descent = -pHori->Descender;
3566 } else {
3567 ascent = pOS2->usWinAscent;
3568 descent = pOS2->usWinDescent;
3571 if(font->yMax) {
3572 TM.tmAscent = font->yMax;
3573 TM.tmDescent = -font->yMin;
3574 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3575 } else {
3576 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3577 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3578 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3579 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3582 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3584 /* MSDN says:
3585 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3587 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3588 ((ascent + descent) -
3589 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3591 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3592 if (TM.tmAveCharWidth == 0) {
3593 TM.tmAveCharWidth = 1;
3595 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3596 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3597 TM.tmOverhang = 0;
3598 TM.tmDigitizedAspectX = 300;
3599 TM.tmDigitizedAspectY = 300;
3600 TM.tmFirstChar = pOS2->usFirstCharIndex;
3601 TM.tmLastChar = pOS2->usLastCharIndex;
3602 TM.tmDefaultChar = pOS2->usDefaultChar;
3603 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3604 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3605 TM.tmUnderlined = font->underline;
3606 TM.tmStruckOut = font->strikeout;
3608 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3609 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3610 (pOS2->version == 0xFFFFU ||
3611 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3612 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3613 else
3614 TM.tmPitchAndFamily = 0;
3616 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3617 case PAN_FAMILY_SCRIPT:
3618 TM.tmPitchAndFamily |= FF_SCRIPT;
3619 break;
3620 case PAN_FAMILY_DECORATIVE:
3621 case PAN_FAMILY_PICTORIAL:
3622 TM.tmPitchAndFamily |= FF_DECORATIVE;
3623 break;
3624 case PAN_FAMILY_TEXT_DISPLAY:
3625 if(TM.tmPitchAndFamily == 0) /* fixed */
3626 TM.tmPitchAndFamily = FF_MODERN;
3627 else {
3628 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3629 case PAN_SERIF_NORMAL_SANS:
3630 case PAN_SERIF_OBTUSE_SANS:
3631 case PAN_SERIF_PERP_SANS:
3632 TM.tmPitchAndFamily |= FF_SWISS;
3633 break;
3634 default:
3635 TM.tmPitchAndFamily |= FF_ROMAN;
3638 break;
3639 default:
3640 TM.tmPitchAndFamily |= FF_DONTCARE;
3643 if(FT_IS_SCALABLE(ft_face))
3644 TM.tmPitchAndFamily |= TMPF_VECTOR;
3645 if(FT_IS_SFNT(ft_face))
3646 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3648 TM.tmCharSet = font->charset;
3649 #undef TM
3651 font->potm->otmFiller = 0;
3652 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3653 font->potm->otmfsSelection = pOS2->fsSelection;
3654 font->potm->otmfsType = pOS2->fsType;
3655 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3656 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3657 font->potm->otmItalicAngle = 0; /* POST table */
3658 font->potm->otmEMSquare = ft_face->units_per_EM;
3659 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3660 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3661 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3662 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3663 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3664 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3665 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3666 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3667 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3668 font->potm->otmMacAscent = 0; /* where do these come from ? */
3669 font->potm->otmMacDescent = 0;
3670 font->potm->otmMacLineGap = 0;
3671 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3672 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3673 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3674 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3675 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3676 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3677 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3678 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3679 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3680 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3681 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3682 if(!pPost) {
3683 font->potm->otmsUnderscoreSize = 0;
3684 font->potm->otmsUnderscorePosition = 0;
3685 } else {
3686 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3687 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3690 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3691 cp = (char*)font->potm + sizeof(*font->potm);
3692 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3693 strcpyW((WCHAR*)cp, family_nameW);
3694 cp += lenfam;
3695 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3696 strcpyW((WCHAR*)cp, style_nameW);
3697 cp += lensty;
3698 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3699 strcpyW((WCHAR*)cp, family_nameW);
3700 if(strcasecmp(ft_face->style_name, "regular")) {
3701 strcatW((WCHAR*)cp, spaceW);
3702 strcatW((WCHAR*)cp, style_nameW);
3703 cp += lenfam + lensty;
3704 } else
3705 cp += lenfam;
3706 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3707 strcpyW((WCHAR*)cp, family_nameW);
3708 strcatW((WCHAR*)cp, spaceW);
3709 strcatW((WCHAR*)cp, style_nameW);
3710 ret = needed;
3712 if(potm && needed <= cbSize)
3713 memcpy(potm, font->potm, font->potm->otmSize);
3715 end:
3716 HeapFree(GetProcessHeap(), 0, style_nameW);
3717 HeapFree(GetProcessHeap(), 0, family_nameW);
3719 return ret;
3722 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
3724 HFONTLIST *hfontlist;
3725 child->font = alloc_font();
3726 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3727 if(!child->font->ft_face)
3729 free_font(child->font);
3730 child->font = NULL;
3731 return FALSE;
3734 child->font->orientation = font->orientation;
3735 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3736 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3737 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3738 child->font->base_font = font;
3739 list_add_head(&child_font_list, &child->font->entry);
3740 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3741 return TRUE;
3744 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
3746 FT_UInt g;
3747 CHILD_FONT *child_font;
3749 if(font->base_font)
3750 font = font->base_font;
3752 *linked_font = font;
3754 if((*glyph = get_glyph_index(font, c)))
3755 return TRUE;
3757 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3759 if(!child_font->font)
3760 if(!load_child_font(font, child_font))
3761 continue;
3763 if(!child_font->font->ft_face)
3764 continue;
3765 g = get_glyph_index(child_font->font, c);
3766 if(g)
3768 *glyph = g;
3769 *linked_font = child_font->font;
3770 return TRUE;
3773 return FALSE;
3776 /*************************************************************
3777 * WineEngGetCharWidth
3780 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
3781 LPINT buffer)
3783 UINT c;
3784 GLYPHMETRICS gm;
3785 FT_UInt glyph_index;
3786 GdiFont *linked_font;
3788 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3790 for(c = firstChar; c <= lastChar; c++) {
3791 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3792 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3793 &gm, 0, NULL, NULL);
3794 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3796 return TRUE;
3799 /*************************************************************
3800 * WineEngGetCharABCWidths
3803 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
3804 LPABC buffer)
3806 UINT c;
3807 GLYPHMETRICS gm;
3808 FT_UInt glyph_index;
3809 GdiFont *linked_font;
3811 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3813 if(!FT_IS_SCALABLE(font->ft_face))
3814 return FALSE;
3816 for(c = firstChar; c <= lastChar; c++) {
3817 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3818 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3819 &gm, 0, NULL, NULL);
3820 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3821 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3822 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3823 linked_font->gm[glyph_index].bbx;
3825 return TRUE;
3828 /*************************************************************
3829 * WineEngGetCharABCWidthsI
3832 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
3833 LPABC buffer)
3835 UINT c;
3836 GLYPHMETRICS gm;
3837 FT_UInt glyph_index;
3838 GdiFont *linked_font;
3840 if(!FT_IS_SCALABLE(font->ft_face))
3841 return FALSE;
3843 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
3844 if (!pgi)
3845 for(c = firstChar; c < firstChar+count; c++) {
3846 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
3847 &gm, 0, NULL, NULL);
3848 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
3849 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
3850 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
3851 - linked_font->gm[c].bbx;
3853 else
3854 for(c = 0; c < count; c++) {
3855 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
3856 &gm, 0, NULL, NULL);
3857 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
3858 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
3859 buffer[c].abcC = linked_font->gm[pgi[c]].adv
3860 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
3863 return TRUE;
3866 /*************************************************************
3867 * WineEngGetTextExtentExPoint
3870 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
3871 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
3873 INT idx;
3874 INT nfit = 0, ext;
3875 GLYPHMETRICS gm;
3876 TEXTMETRICW tm;
3877 FT_UInt glyph_index;
3878 GdiFont *linked_font;
3880 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
3881 max_ext, size);
3883 size->cx = 0;
3884 WineEngGetTextMetrics(font, &tm);
3885 size->cy = tm.tmHeight;
3887 for(idx = 0; idx < count; idx++) {
3888 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3889 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3890 &gm, 0, NULL, NULL);
3891 size->cx += linked_font->gm[glyph_index].adv;
3892 ext = size->cx;
3893 if (! pnfit || ext <= max_ext) {
3894 ++nfit;
3895 if (dxs)
3896 dxs[idx] = ext;
3900 if (pnfit)
3901 *pnfit = nfit;
3903 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
3904 return TRUE;
3907 /*************************************************************
3908 * WineEngGetTextExtentPointI
3911 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
3912 LPSIZE size)
3914 INT idx;
3915 GLYPHMETRICS gm;
3916 TEXTMETRICW tm;
3918 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3920 size->cx = 0;
3921 WineEngGetTextMetrics(font, &tm);
3922 size->cy = tm.tmHeight;
3924 for(idx = 0; idx < count; idx++) {
3925 WineEngGetGlyphOutline(font, indices[idx],
3926 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3927 NULL);
3928 size->cx += font->gm[indices[idx]].adv;
3930 TRACE("return %d,%d\n", size->cx, size->cy);
3931 return TRUE;
3934 /*************************************************************
3935 * WineEngGetFontData
3938 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
3939 DWORD cbData)
3941 FT_Face ft_face = font->ft_face;
3942 FT_ULong len;
3943 FT_Error err;
3945 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
3946 font, table, offset, buf, cbData);
3948 if(!FT_IS_SFNT(ft_face))
3949 return GDI_ERROR;
3951 if(!buf || !cbData)
3952 len = 0;
3953 else
3954 len = cbData;
3956 if(table) { /* MS tags differ in endidness from FT ones */
3957 table = table >> 24 | table << 24 |
3958 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3961 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3962 if(pFT_Load_Sfnt_Table) {
3963 /* make sure value of len is the value freetype says it needs */
3964 if( buf && len) {
3965 FT_ULong needed = 0;
3966 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3967 if( !err && needed < len) len = needed;
3969 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3971 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3972 else { /* Do it the hard way */
3973 TT_Face tt_face = (TT_Face) ft_face;
3974 SFNT_Interface *sfnt;
3975 if (FT_Version.major==2 && FT_Version.minor==0)
3977 /* 2.0.x */
3978 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3980 else
3982 /* A field was added in the middle of the structure in 2.1.x */
3983 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3985 /* make sure value of len is the value freetype says it needs */
3986 if( buf && len) {
3987 FT_ULong needed = 0;
3988 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3989 if( !err && needed < len) len = needed;
3991 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3993 #else
3994 else {
3995 static int msg;
3996 if(!msg) {
3997 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3998 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3999 "Please upgrade your freetype library.\n");
4000 msg++;
4002 err = FT_Err_Unimplemented_Feature;
4004 #endif
4005 if(err) {
4006 TRACE("Can't find table %08x.\n", table);
4007 return GDI_ERROR;
4009 return len;
4012 /*************************************************************
4013 * WineEngGetTextFace
4016 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4018 if(str) {
4019 lstrcpynW(str, font->name, count);
4020 return strlenW(font->name);
4021 } else
4022 return strlenW(font->name) + 1;
4025 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4027 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4028 return font->charset;
4031 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4033 GdiFont *font = dc->gdiFont, *linked_font;
4034 struct list *first_hfont;
4035 BOOL ret;
4037 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4038 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4039 if(font == linked_font)
4040 *new_hfont = dc->hFont;
4041 else
4043 first_hfont = list_head(&linked_font->hfontlist);
4044 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4047 return ret;
4051 /*************************************************************
4052 * FontIsLinked
4054 BOOL WINAPI FontIsLinked(HDC hdc)
4056 DC *dc = DC_GetDCPtr(hdc);
4057 BOOL ret = FALSE;
4059 if(!dc) return FALSE;
4060 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4061 ret = TRUE;
4062 GDI_ReleaseObj(hdc);
4063 TRACE("returning %d\n", ret);
4064 return ret;
4067 static BOOL is_hinting_enabled(void)
4069 /* Use the >= 2.2.0 function if available */
4070 if(pFT_Get_TrueType_Engine_Type)
4072 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4073 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4075 #ifdef FT_DRIVER_HAS_HINTER
4076 else
4078 FT_Module mod;
4080 /* otherwise if we've been compiled with < 2.2.0 headers
4081 use the internal macro */
4082 mod = pFT_Get_Module(library, "truetype");
4083 if(mod && FT_DRIVER_HAS_HINTER(mod))
4084 return TRUE;
4086 #endif
4088 return FALSE;
4091 /*************************************************************************
4092 * GetRasterizerCaps (GDI32.@)
4094 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4096 static int hinting = -1;
4098 if(hinting == -1)
4099 hinting = is_hinting_enabled();
4101 lprs->nSize = sizeof(RASTERIZER_STATUS);
4102 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4103 lprs->nLanguageID = 0;
4104 return TRUE;
4107 /*************************************************************************
4108 * Kerning support for TrueType fonts
4110 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4112 struct TT_kern_table
4114 USHORT version;
4115 USHORT nTables;
4118 struct TT_kern_subtable
4120 USHORT version;
4121 USHORT length;
4122 union
4124 USHORT word;
4125 struct
4127 USHORT horizontal : 1;
4128 USHORT minimum : 1;
4129 USHORT cross_stream: 1;
4130 USHORT override : 1;
4131 USHORT reserved1 : 4;
4132 USHORT format : 8;
4133 } bits;
4134 } coverage;
4137 struct TT_format0_kern_subtable
4139 USHORT nPairs;
4140 USHORT searchRange;
4141 USHORT entrySelector;
4142 USHORT rangeShift;
4145 struct TT_kern_pair
4147 USHORT left;
4148 USHORT right;
4149 short value;
4152 static DWORD parse_format0_kern_subtable(GdiFont *font,
4153 const struct TT_format0_kern_subtable *tt_f0_ks,
4154 const USHORT *glyph_to_char,
4155 KERNINGPAIR *kern_pair, DWORD cPairs)
4157 USHORT i, nPairs;
4158 const struct TT_kern_pair *tt_kern_pair;
4160 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4162 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4164 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4165 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4166 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4168 if (!kern_pair || !cPairs)
4169 return nPairs;
4171 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4173 nPairs = min(nPairs, cPairs);
4175 for (i = 0; i < nPairs; i++)
4177 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4178 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4179 /* this algorithm appears to better match what Windows does */
4180 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4181 if (kern_pair->iKernAmount < 0)
4183 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4184 kern_pair->iKernAmount -= font->ppem;
4186 else if (kern_pair->iKernAmount > 0)
4188 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4189 kern_pair->iKernAmount += font->ppem;
4191 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4193 TRACE("left %u right %u value %d\n",
4194 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4196 kern_pair++;
4198 TRACE("copied %u entries\n", nPairs);
4199 return nPairs;
4202 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4204 DWORD length;
4205 void *buf;
4206 const struct TT_kern_table *tt_kern_table;
4207 const struct TT_kern_subtable *tt_kern_subtable;
4208 USHORT i, nTables;
4209 USHORT *glyph_to_char;
4211 if (font->total_kern_pairs != (DWORD)-1)
4213 if (cPairs && kern_pair)
4215 cPairs = min(cPairs, font->total_kern_pairs);
4216 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4217 return cPairs;
4219 return font->total_kern_pairs;
4222 font->total_kern_pairs = 0;
4224 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4226 if (length == GDI_ERROR)
4228 TRACE("no kerning data in the font\n");
4229 return 0;
4232 buf = HeapAlloc(GetProcessHeap(), 0, length);
4233 if (!buf)
4235 WARN("Out of memory\n");
4236 return 0;
4239 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4241 /* build a glyph index to char code map */
4242 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4243 if (!glyph_to_char)
4245 WARN("Out of memory allocating a glyph index to char code map\n");
4246 HeapFree(GetProcessHeap(), 0, buf);
4247 return 0;
4250 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4252 FT_UInt glyph_code;
4253 FT_ULong char_code;
4255 glyph_code = 0;
4256 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4258 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4259 font->ft_face->num_glyphs, glyph_code, char_code);
4261 while (glyph_code)
4263 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4265 /* FIXME: This doesn't match what Windows does: it does some fancy
4266 * things with duplicate glyph index to char code mappings, while
4267 * we just avoid overriding existing entries.
4269 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4270 glyph_to_char[glyph_code] = (USHORT)char_code;
4272 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4275 else
4277 ULONG n;
4279 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4280 for (n = 0; n <= 65535; n++)
4281 glyph_to_char[n] = (USHORT)n;
4284 tt_kern_table = buf;
4285 nTables = GET_BE_WORD(tt_kern_table->nTables);
4286 TRACE("version %u, nTables %u\n",
4287 GET_BE_WORD(tt_kern_table->version), nTables);
4289 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4291 for (i = 0; i < nTables; i++)
4293 struct TT_kern_subtable tt_kern_subtable_copy;
4295 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4296 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4297 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4299 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4300 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4301 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4303 /* According to the TrueType specification this is the only format
4304 * that will be properly interpreted by Windows and OS/2
4306 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4308 DWORD new_chunk, old_total = font->total_kern_pairs;
4310 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4311 glyph_to_char, NULL, 0);
4312 font->total_kern_pairs += new_chunk;
4314 if (!font->kern_pairs)
4315 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4316 font->total_kern_pairs * sizeof(*font->kern_pairs));
4317 else
4318 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4319 font->total_kern_pairs * sizeof(*font->kern_pairs));
4321 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4322 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4324 else
4325 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4327 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4330 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4331 HeapFree(GetProcessHeap(), 0, buf);
4333 if (cPairs && kern_pair)
4335 cPairs = min(cPairs, font->total_kern_pairs);
4336 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4337 return cPairs;
4339 return font->total_kern_pairs;
4342 #else /* HAVE_FREETYPE */
4344 /*************************************************************************/
4346 BOOL WineEngInit(void)
4348 return FALSE;
4350 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4352 return NULL;
4354 BOOL WineEngDestroyFontInstance(HFONT hfont)
4356 return FALSE;
4359 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4361 return 1;
4364 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4365 LPWORD pgi, DWORD flags)
4367 return GDI_ERROR;
4370 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4371 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4372 const MAT2* lpmat)
4374 ERR("called but we don't have FreeType\n");
4375 return GDI_ERROR;
4378 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4380 ERR("called but we don't have FreeType\n");
4381 return FALSE;
4384 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4385 OUTLINETEXTMETRICW *potm)
4387 ERR("called but we don't have FreeType\n");
4388 return 0;
4391 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4392 LPINT buffer)
4394 ERR("called but we don't have FreeType\n");
4395 return FALSE;
4398 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4399 LPABC buffer)
4401 ERR("called but we don't have FreeType\n");
4402 return FALSE;
4405 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4406 LPABC buffer)
4408 ERR("called but we don't have FreeType\n");
4409 return FALSE;
4412 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4413 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4415 ERR("called but we don't have FreeType\n");
4416 return FALSE;
4419 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4420 LPSIZE size)
4422 ERR("called but we don't have FreeType\n");
4423 return FALSE;
4426 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4427 DWORD cbData)
4429 ERR("called but we don't have FreeType\n");
4430 return GDI_ERROR;
4433 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4435 ERR("called but we don't have FreeType\n");
4436 return 0;
4439 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4441 FIXME(":stub\n");
4442 return 1;
4445 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4447 FIXME(":stub\n");
4448 return TRUE;
4451 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4453 FIXME(":stub\n");
4454 return DEFAULT_CHARSET;
4457 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4459 return FALSE;
4462 BOOL WINAPI FontIsLinked(HDC hdc)
4464 return FALSE;
4467 /*************************************************************************
4468 * GetRasterizerCaps (GDI32.@)
4470 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4472 lprs->nSize = sizeof(RASTERIZER_STATUS);
4473 lprs->wFlags = 0;
4474 lprs->nLanguageID = 0;
4475 return TRUE;
4478 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4480 ERR("called but we don't have FreeType\n");
4481 return 0;
4484 #endif /* HAVE_FREETYPE */