Release 0.9.25.
[wine/dibdrv.git] / dlls / gdi32 / freetype.c
blobf7bc28f0b418220aabbf92f1360d11b12b7f2ed3
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.h"
44 #include "gdi_private.h"
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
47 #include "wine/list.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(font);
51 #ifdef HAVE_FREETYPE
53 #ifdef HAVE_FT2BUILD_H
54 #include <ft2build.h>
55 #endif
56 #ifdef HAVE_FREETYPE_FREETYPE_H
57 #include <freetype/freetype.h>
58 #endif
59 #ifdef HAVE_FREETYPE_FTGLYPH_H
60 #include <freetype/ftglyph.h>
61 #endif
62 #ifdef HAVE_FREETYPE_TTTABLES_H
63 #include <freetype/tttables.h>
64 #endif
65 #ifdef HAVE_FREETYPE_FTSNAMES_H
66 #include <freetype/ftsnames.h>
67 #else
68 # ifdef HAVE_FREETYPE_FTNAMES_H
69 # include <freetype/ftnames.h>
70 # endif
71 #endif
72 #ifdef HAVE_FREETYPE_TTNAMEID_H
73 #include <freetype/ttnameid.h>
74 #endif
75 #ifdef HAVE_FREETYPE_FTOUTLN_H
76 #include <freetype/ftoutln.h>
77 #endif
78 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
79 #include <freetype/internal/sfnt.h>
80 #endif
81 #ifdef HAVE_FREETYPE_FTTRIGON_H
82 #include <freetype/fttrigon.h>
83 #endif
84 #ifdef HAVE_FREETYPE_FTWINFNT_H
85 #include <freetype/ftwinfnt.h>
86 #endif
87 #ifdef HAVE_FREETYPE_FTMODAPI_H
88 #include <freetype/ftmodapi.h>
89 #endif
91 #ifndef SONAME_LIBFREETYPE
92 #define SONAME_LIBFREETYPE "libfreetype.so"
93 #endif
95 #ifndef HAVE_FT_TRUETYPEENGINETYPE
96 typedef enum
98 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
99 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
100 FT_TRUETYPE_ENGINE_TYPE_PATENTED
101 } FT_TrueTypeEngineType;
102 #endif
104 static FT_Library library = 0;
105 typedef struct
107 FT_Int major;
108 FT_Int minor;
109 FT_Int patch;
110 } FT_Version_t;
111 static FT_Version_t FT_Version;
112 static DWORD FT_SimpleVersion;
114 static void *ft_handle = NULL;
116 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
117 MAKE_FUNCPTR(FT_Vector_Unit);
118 MAKE_FUNCPTR(FT_Done_Face);
119 MAKE_FUNCPTR(FT_Get_Char_Index);
120 MAKE_FUNCPTR(FT_Get_Module);
121 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
122 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
123 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
124 MAKE_FUNCPTR(FT_Init_FreeType);
125 MAKE_FUNCPTR(FT_Load_Glyph);
126 MAKE_FUNCPTR(FT_Matrix_Multiply);
127 MAKE_FUNCPTR(FT_MulFix);
128 MAKE_FUNCPTR(FT_New_Face);
129 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
130 MAKE_FUNCPTR(FT_Outline_Transform);
131 MAKE_FUNCPTR(FT_Outline_Translate);
132 MAKE_FUNCPTR(FT_Select_Charmap);
133 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
134 MAKE_FUNCPTR(FT_Vector_Transform);
135 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
136 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
137 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
138 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
139 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
140 #ifdef HAVE_FREETYPE_FTWINFNT_H
141 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
142 #endif
144 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
145 #include <fontconfig/fontconfig.h>
146 MAKE_FUNCPTR(FcConfigGetCurrent);
147 MAKE_FUNCPTR(FcFontList);
148 MAKE_FUNCPTR(FcFontSetDestroy);
149 MAKE_FUNCPTR(FcInit);
150 MAKE_FUNCPTR(FcObjectSetAdd);
151 MAKE_FUNCPTR(FcObjectSetCreate);
152 MAKE_FUNCPTR(FcObjectSetDestroy);
153 MAKE_FUNCPTR(FcPatternCreate);
154 MAKE_FUNCPTR(FcPatternDestroy);
155 MAKE_FUNCPTR(FcPatternGetString);
156 #ifndef SONAME_LIBFONTCONFIG
157 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
158 #endif
159 #endif
161 #undef MAKE_FUNCPTR
163 #ifndef ft_encoding_none
164 #define FT_ENCODING_NONE ft_encoding_none
165 #endif
166 #ifndef ft_encoding_ms_symbol
167 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
168 #endif
169 #ifndef ft_encoding_unicode
170 #define FT_ENCODING_UNICODE ft_encoding_unicode
171 #endif
172 #ifndef ft_encoding_apple_roman
173 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
174 #endif
176 #ifdef WORDS_BIGENDIAN
177 #define GET_BE_WORD(x) (x)
178 #else
179 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
180 #endif
182 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
183 typedef struct {
184 FT_Short height;
185 FT_Short width;
186 FT_Pos size;
187 FT_Pos x_ppem;
188 FT_Pos y_ppem;
189 FT_Short internal_leading;
190 } Bitmap_Size;
192 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
193 So to let this compile on older versions of FreeType we'll define the
194 new structure here. */
195 typedef struct {
196 FT_Short height, width;
197 FT_Pos size, x_ppem, y_ppem;
198 } My_FT_Bitmap_Size;
200 typedef struct tagFace {
201 struct list entry;
202 WCHAR *StyleName;
203 char *file;
204 FT_Long face_index;
205 BOOL Italic;
206 BOOL Bold;
207 FONTSIGNATURE fs;
208 FONTSIGNATURE fs_links;
209 FT_Fixed font_version;
210 BOOL scalable;
211 Bitmap_Size size; /* set if face is a bitmap */
212 BOOL external; /* TRUE if we should manually add this font to the registry */
213 struct tagFamily *family;
214 } Face;
216 typedef struct tagFamily {
217 struct list entry;
218 const WCHAR *FamilyName;
219 struct list faces;
220 } Family;
222 typedef struct {
223 GLYPHMETRICS gm;
224 INT adv; /* These three hold to widths of the unrotated chars */
225 INT lsb;
226 INT bbx;
227 BOOL init;
228 } GM;
230 typedef struct {
231 FLOAT eM11, eM12;
232 FLOAT eM21, eM22;
233 } FMAT2;
235 typedef struct {
236 DWORD hash;
237 LOGFONTW lf;
238 FMAT2 matrix;
239 BOOL can_use_bitmap;
240 } FONT_DESC;
242 typedef struct tagHFONTLIST {
243 struct list entry;
244 HFONT hfont;
245 } HFONTLIST;
247 typedef struct {
248 struct list entry;
249 char *file_name;
250 INT index;
251 GdiFont *font;
252 } CHILD_FONT;
254 struct tagGdiFont {
255 struct list entry;
256 FT_Face ft_face;
257 LPWSTR name;
258 int charset;
259 int codepage;
260 BOOL fake_italic;
261 BOOL fake_bold;
262 BYTE underline;
263 BYTE strikeout;
264 INT orientation;
265 GM *gm;
266 DWORD gmsize;
267 struct list hfontlist;
268 FONT_DESC font_desc;
269 LONG aveWidth;
270 SHORT yMax;
271 SHORT yMin;
272 OUTLINETEXTMETRICW *potm;
273 DWORD total_kern_pairs;
274 KERNINGPAIR *kern_pairs;
275 FONTSIGNATURE fs;
276 GdiFont *base_font;
277 struct list child_fonts;
278 LONG ppem;
281 typedef struct {
282 struct list entry;
283 const WCHAR *font_name;
284 struct list links;
285 } SYSTEM_LINKS;
287 #define INIT_GM_SIZE 128
289 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
290 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
291 #define UNUSED_CACHE_SIZE 10
292 static struct list child_font_list = LIST_INIT(child_font_list);
293 static struct list system_links = LIST_INIT(system_links);
295 static struct list font_subst_list = LIST_INIT(font_subst_list);
297 static struct list font_list = LIST_INIT(font_list);
299 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
300 'R','o','m','a','n','\0'};
301 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
302 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
304 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
305 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
306 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
307 'S','e','r','i','f','\0'};
308 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
309 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
311 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
312 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
313 'W','i','n','d','o','w','s','\\',
314 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
315 'F','o','n','t','s','\0'};
317 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
318 'W','i','n','d','o','w','s',' ','N','T','\\',
319 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
320 'F','o','n','t','s','\0'};
322 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
323 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
324 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
325 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
327 static const WCHAR * const SystemFontValues[4] = {
328 System_Value,
329 OEMFont_Value,
330 FixedSys_Value,
331 NULL
334 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
335 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
337 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
338 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
339 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
340 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
341 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
342 'E','u','r','o','p','e','a','n','\0'};
343 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
344 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
345 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
346 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
347 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
348 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
349 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
350 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
351 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
352 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
353 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
354 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
356 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
357 WesternW, /*00*/
358 Central_EuropeanW,
359 CyrillicW,
360 GreekW,
361 TurkishW,
362 HebrewW,
363 ArabicW,
364 BalticW,
365 VietnameseW, /*08*/
366 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
367 ThaiW,
368 JapaneseW,
369 CHINESE_GB2312W,
370 HangulW,
371 CHINESE_BIG5W,
372 Hangul_Johab_W,
373 NULL, NULL, /*23*/
374 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
375 SymbolW /*31*/
378 typedef struct {
379 WCHAR *name;
380 INT charset;
381 } NameCs;
383 typedef struct tagFontSubst {
384 struct list entry;
385 NameCs from;
386 NameCs to;
387 } FontSubst;
389 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
391 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
394 /****************************************
395 * Notes on .fon files
397 * The fonts System, FixedSys and Terminal are special. There are typically multiple
398 * versions installed for different resolutions and codepages. Windows stores which one to use
399 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
400 * Key Meaning
401 * FIXEDFON.FON FixedSys
402 * FONTS.FON System
403 * OEMFONT.FON Terminal
404 * LogPixels Current dpi set by the display control panel applet
405 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
406 * also has a LogPixels value that appears to mirror this)
408 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
409 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
410 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
411 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
412 * so that makes sense.
414 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
415 * to be mapped into the registry on Windows 2000 at least).
416 * I have
417 * woafont=app850.fon
418 * ega80woa.fon=ega80850.fon
419 * ega40woa.fon=ega40850.fon
420 * cga80woa.fon=cga80850.fon
421 * cga40woa.fon=cga40850.fon
425 static inline BOOL is_win9x(void)
427 return GetVersion() & 0x80000000;
430 This function builds an FT_Fixed from a float. It puts the integer part
431 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
432 It fails if the integer part of the float number is greater than SHORT_MAX.
434 static inline FT_Fixed FT_FixedFromFloat(float f)
436 short value = f;
437 unsigned short fract = (f - value) * 0xFFFF;
438 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
442 This function builds an FT_Fixed from a FIXED. It simply put f.value
443 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
445 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
447 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
451 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
453 Family *family;
454 Face *face;
455 const char *file;
456 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
457 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
459 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
460 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
462 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
464 if(face_name && strcmpiW(face_name, family->FamilyName))
465 continue;
466 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
468 file = strrchr(face->file, '/');
469 if(!file)
470 file = face->file;
471 else
472 file++;
473 if(!strcasecmp(file, file_nameA))
475 HeapFree(GetProcessHeap(), 0, file_nameA);
476 return face;
480 HeapFree(GetProcessHeap(), 0, file_nameA);
481 return NULL;
484 static Family *find_family_from_name(const WCHAR *name)
486 Family *family;
488 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
490 if(!strcmpiW(family->FamilyName, name))
491 return family;
494 return NULL;
497 static void DumpSubstList(void)
499 FontSubst *psub;
501 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
503 if(psub->from.charset != -1 || psub->to.charset != -1)
504 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
505 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
506 else
507 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
508 debugstr_w(psub->to.name));
510 return;
513 static LPWSTR strdupW(LPCWSTR p)
515 LPWSTR ret;
516 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
517 ret = HeapAlloc(GetProcessHeap(), 0, len);
518 memcpy(ret, p, len);
519 return ret;
522 static LPSTR strdupA(LPCSTR p)
524 LPSTR ret;
525 DWORD len = (strlen(p) + 1);
526 ret = HeapAlloc(GetProcessHeap(), 0, len);
527 memcpy(ret, p, len);
528 return ret;
531 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
532 INT from_charset)
534 FontSubst *element;
536 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
538 if(!strcmpiW(element->from.name, from_name) &&
539 (element->from.charset == from_charset ||
540 element->from.charset == -1))
541 return element;
544 return NULL;
547 #define ADD_FONT_SUBST_FORCE 1
549 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
551 FontSubst *from_exist, *to_exist;
553 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
555 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
557 list_remove(&from_exist->entry);
558 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
559 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
560 HeapFree(GetProcessHeap(), 0, from_exist);
561 from_exist = NULL;
564 if(!from_exist)
566 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
568 if(to_exist)
570 HeapFree(GetProcessHeap(), 0, subst->to.name);
571 subst->to.name = strdupW(to_exist->to.name);
574 list_add_tail(subst_list, &subst->entry);
576 return TRUE;
579 HeapFree(GetProcessHeap(), 0, subst->from.name);
580 HeapFree(GetProcessHeap(), 0, subst->to.name);
581 HeapFree(GetProcessHeap(), 0, subst);
582 return FALSE;
585 static void split_subst_info(NameCs *nc, LPSTR str)
587 CHAR *p = strrchr(str, ',');
588 DWORD len;
590 nc->charset = -1;
591 if(p && *(p+1)) {
592 nc->charset = strtol(p+1, NULL, 10);
593 *p = '\0';
595 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
596 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
597 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
600 static void LoadSubstList(void)
602 FontSubst *psub;
603 HKEY hkey;
604 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
605 LPSTR value;
606 LPVOID data;
608 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
609 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
610 &hkey) == ERROR_SUCCESS) {
612 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
613 &valuelen, &datalen, NULL, NULL);
615 valuelen++; /* returned value doesn't include room for '\0' */
616 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
617 data = HeapAlloc(GetProcessHeap(), 0, datalen);
619 dlen = datalen;
620 vlen = valuelen;
621 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
622 &dlen) == ERROR_SUCCESS) {
623 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
625 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
626 split_subst_info(&psub->from, value);
627 split_subst_info(&psub->to, data);
629 /* Win 2000 doesn't allow mapping between different charsets
630 or mapping of DEFAULT_CHARSET */
631 if((psub->to.charset != psub->from.charset) ||
632 psub->to.charset == DEFAULT_CHARSET) {
633 HeapFree(GetProcessHeap(), 0, psub->to.name);
634 HeapFree(GetProcessHeap(), 0, psub->from.name);
635 HeapFree(GetProcessHeap(), 0, psub);
636 } else {
637 add_font_subst(&font_subst_list, psub, 0);
639 /* reset dlen and vlen */
640 dlen = datalen;
641 vlen = valuelen;
643 HeapFree(GetProcessHeap(), 0, data);
644 HeapFree(GetProcessHeap(), 0, value);
645 RegCloseKey(hkey);
649 static WCHAR *get_familyname(FT_Face ft_face)
651 WCHAR *family = NULL;
652 FT_SfntName name;
653 FT_UInt num_names, name_index, i;
655 if(FT_IS_SFNT(ft_face))
657 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
659 for(name_index = 0; name_index < num_names; name_index++)
661 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
663 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
664 (name.language_id == GetUserDefaultLCID()) &&
665 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
666 (name.encoding_id == TT_MS_ID_UNICODE_CS))
668 /* String is not nul terminated and string_len is a byte length. */
669 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
670 for(i = 0; i < name.string_len / 2; i++)
672 WORD *tmp = (WORD *)&name.string[i * 2];
673 family[i] = GET_BE_WORD(*tmp);
675 family[i] = 0;
677 TRACE("Got localised name %s\n", debugstr_w(family));
678 return family;
684 return NULL;
688 #define ADDFONT_EXTERNAL_FONT 0x01
689 #define ADDFONT_FORCE_BITMAP 0x02
690 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
692 FT_Face ft_face;
693 TT_OS2 *pOS2;
694 TT_Header *pHeader = NULL;
695 WCHAR *english_family, *localised_family, *StyleW;
696 DWORD len;
697 Family *family;
698 Face *face;
699 struct list *family_elem_ptr, *face_elem_ptr;
700 FT_Error err;
701 FT_Long face_index = 0, num_faces;
702 #ifdef HAVE_FREETYPE_FTWINFNT_H
703 FT_WinFNT_HeaderRec winfnt_header;
704 #endif
705 int i, bitmap_num, internal_leading;
706 FONTSIGNATURE fs;
708 do {
709 char *family_name = fake_family;
711 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
712 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
713 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
714 return FALSE;
717 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*/
718 WARN("Ignoring font %s\n", debugstr_a(file));
719 pFT_Done_Face(ft_face);
720 return FALSE;
723 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
724 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
725 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
726 pFT_Done_Face(ft_face);
727 return FALSE;
730 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
731 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
732 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
733 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
734 "Skipping this font.\n", debugstr_a(file));
735 pFT_Done_Face(ft_face);
736 return FALSE;
739 if(!ft_face->family_name || !ft_face->style_name) {
740 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
741 pFT_Done_Face(ft_face);
742 return FALSE;
745 if(!family_name)
746 family_name = ft_face->family_name;
748 bitmap_num = 0;
749 do {
750 My_FT_Bitmap_Size *size = NULL;
752 if(!FT_IS_SCALABLE(ft_face))
753 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
755 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
756 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
757 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
759 localised_family = NULL;
760 if(!fake_family) {
761 localised_family = get_familyname(ft_face);
762 if(localised_family && !strcmpW(localised_family, english_family)) {
763 HeapFree(GetProcessHeap(), 0, localised_family);
764 localised_family = NULL;
768 family = NULL;
769 LIST_FOR_EACH(family_elem_ptr, &font_list) {
770 family = LIST_ENTRY(family_elem_ptr, Family, entry);
771 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
772 break;
773 family = NULL;
775 if(!family) {
776 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
777 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
778 list_init(&family->faces);
779 list_add_tail(&font_list, &family->entry);
781 if(localised_family) {
782 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
783 subst->from.name = strdupW(english_family);
784 subst->from.charset = -1;
785 subst->to.name = strdupW(localised_family);
786 subst->to.charset = -1;
787 add_font_subst(&font_subst_list, subst, 0);
790 HeapFree(GetProcessHeap(), 0, localised_family);
791 HeapFree(GetProcessHeap(), 0, english_family);
793 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
794 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
795 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
797 internal_leading = 0;
798 memset(&fs, 0, sizeof(fs));
800 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
801 if(pOS2) {
802 fs.fsCsb[0] = pOS2->ulCodePageRange1;
803 fs.fsCsb[1] = pOS2->ulCodePageRange2;
804 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
805 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
806 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
807 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
808 if(pOS2->version == 0) {
809 FT_UInt dummy;
811 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
812 fs.fsCsb[0] |= 1;
813 else
814 fs.fsCsb[0] |= 1L << 31;
817 #ifdef HAVE_FREETYPE_FTWINFNT_H
818 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
819 CHARSETINFO csi;
820 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
821 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
822 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
823 memcpy(&fs, &csi.fs, sizeof(csi.fs));
824 internal_leading = winfnt_header.internal_leading;
826 #endif
828 face_elem_ptr = list_head(&family->faces);
829 while(face_elem_ptr) {
830 face = LIST_ENTRY(face_elem_ptr, Face, entry);
831 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
832 if(!strcmpW(face->StyleName, StyleW) &&
833 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
834 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
835 debugstr_w(family->FamilyName), debugstr_w(StyleW),
836 face->font_version, pHeader ? pHeader->Font_Revision : 0);
838 if(fake_family) {
839 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
840 HeapFree(GetProcessHeap(), 0, StyleW);
841 pFT_Done_Face(ft_face);
842 return FALSE;
844 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
845 TRACE("Original font is newer so skipping this one\n");
846 HeapFree(GetProcessHeap(), 0, StyleW);
847 pFT_Done_Face(ft_face);
848 return FALSE;
849 } else {
850 TRACE("Replacing original with this one\n");
851 list_remove(&face->entry);
852 HeapFree(GetProcessHeap(), 0, face->file);
853 HeapFree(GetProcessHeap(), 0, face->StyleName);
854 HeapFree(GetProcessHeap(), 0, face);
855 break;
859 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
860 list_add_tail(&family->faces, &face->entry);
861 face->StyleName = StyleW;
862 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
863 strcpy(face->file, file);
864 face->face_index = face_index;
865 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
866 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
867 face->font_version = pHeader ? pHeader->Font_Revision : 0;
868 face->family = family;
869 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
870 memcpy(&face->fs, &fs, sizeof(face->fs));
871 memset(&face->fs_links, 0, sizeof(face->fs_links));
873 if(FT_IS_SCALABLE(ft_face)) {
874 memset(&face->size, 0, sizeof(face->size));
875 face->scalable = TRUE;
876 } else {
877 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
878 size->height, size->width, size->size >> 6,
879 size->x_ppem >> 6, size->y_ppem >> 6);
880 face->size.height = size->height;
881 face->size.width = size->width;
882 face->size.size = size->size;
883 face->size.x_ppem = size->x_ppem;
884 face->size.y_ppem = size->y_ppem;
885 face->size.internal_leading = internal_leading;
886 face->scalable = FALSE;
889 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
890 face->fs.fsCsb[0], face->fs.fsCsb[1],
891 face->fs.fsUsb[0], face->fs.fsUsb[1],
892 face->fs.fsUsb[2], face->fs.fsUsb[3]);
895 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
896 for(i = 0; i < ft_face->num_charmaps; i++) {
897 switch(ft_face->charmaps[i]->encoding) {
898 case FT_ENCODING_UNICODE:
899 case FT_ENCODING_APPLE_ROMAN:
900 face->fs.fsCsb[0] |= 1;
901 break;
902 case FT_ENCODING_MS_SYMBOL:
903 face->fs.fsCsb[0] |= 1L << 31;
904 break;
905 default:
906 break;
911 if(face->fs.fsCsb[0] & ~(1L << 31))
912 have_installed_roman_font = TRUE;
913 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
915 num_faces = ft_face->num_faces;
916 pFT_Done_Face(ft_face);
917 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
918 debugstr_w(StyleW));
919 } while(num_faces > ++face_index);
920 return TRUE;
923 static void DumpFontList(void)
925 Family *family;
926 Face *face;
927 struct list *family_elem_ptr, *face_elem_ptr;
929 LIST_FOR_EACH(family_elem_ptr, &font_list) {
930 family = LIST_ENTRY(family_elem_ptr, Family, entry);
931 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
932 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
933 face = LIST_ENTRY(face_elem_ptr, Face, entry);
934 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
935 if(!face->scalable)
936 TRACE(" %d", face->size.height);
937 TRACE("\n");
940 return;
943 /***********************************************************
944 * The replacement list is a way to map an entire font
945 * family onto another family. For example adding
947 * [HKCU\Software\Wine\Fonts\Replacements]
948 * "Wingdings"="Winedings"
950 * would enumerate the Winedings font both as Winedings and
951 * Wingdings. However if a real Wingdings font is present the
952 * replacement does not take place.
955 static void LoadReplaceList(void)
957 HKEY hkey;
958 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
959 LPSTR value;
960 LPVOID data;
961 Family *family;
962 Face *face;
963 struct list *family_elem_ptr, *face_elem_ptr;
964 WCHAR old_nameW[200];
966 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
967 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
969 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
970 &valuelen, &datalen, NULL, NULL);
972 valuelen++; /* returned value doesn't include room for '\0' */
973 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
974 data = HeapAlloc(GetProcessHeap(), 0, datalen);
976 dlen = datalen;
977 vlen = valuelen;
978 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
979 &dlen) == ERROR_SUCCESS) {
980 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
981 /* "NewName"="Oldname" */
982 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
983 break;
985 /* Find the old family and hence all of the font files
986 in that family */
987 LIST_FOR_EACH(family_elem_ptr, &font_list) {
988 family = LIST_ENTRY(family_elem_ptr, Family, entry);
989 if(!strcmpiW(family->FamilyName, old_nameW)) {
990 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
991 face = LIST_ENTRY(face_elem_ptr, Face, entry);
992 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
993 debugstr_w(face->StyleName), value);
994 /* Now add a new entry with the new family name */
995 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
997 break;
1000 /* reset dlen and vlen */
1001 dlen = datalen;
1002 vlen = valuelen;
1004 HeapFree(GetProcessHeap(), 0, data);
1005 HeapFree(GetProcessHeap(), 0, value);
1006 RegCloseKey(hkey);
1010 /*************************************************************
1011 * init_system_links
1013 static BOOL init_system_links(void)
1015 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1016 'W','i','n','d','o','w','s',' ','N','T','\\',
1017 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1018 'S','y','s','t','e','m','L','i','n','k',0};
1019 HKEY hkey;
1020 BOOL ret = FALSE;
1021 DWORD type, max_val, max_data, val_len, data_len, index;
1022 WCHAR *value, *data;
1023 WCHAR *entry, *next;
1024 SYSTEM_LINKS *font_link, *system_font_link;
1025 CHILD_FONT *child_font;
1026 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1027 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1028 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1029 FONTSIGNATURE fs;
1030 Family *family;
1031 Face *face;
1032 FontSubst *psub;
1034 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1036 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1037 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1038 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1039 val_len = max_val + 1;
1040 data_len = max_data;
1041 index = 0;
1042 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1044 TRACE("%s:\n", debugstr_w(value));
1046 memset(&fs, 0, sizeof(fs));
1047 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1048 psub = get_font_subst(&font_subst_list, value, -1);
1049 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1050 list_init(&font_link->links);
1051 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1053 WCHAR *face_name;
1054 CHILD_FONT *child_font;
1056 TRACE("\t%s\n", debugstr_w(entry));
1058 next = entry + strlenW(entry) + 1;
1060 face_name = strchrW(entry, ',');
1061 if(face_name)
1063 *face_name++ = 0;
1064 while(isspaceW(*face_name))
1065 face_name++;
1067 psub = get_font_subst(&font_subst_list, face_name, -1);
1068 if(psub)
1069 face_name = psub->to.name;
1071 face = find_face_from_filename(entry, face_name);
1072 if(!face)
1074 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1075 continue;
1078 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1079 child_font->file_name = strdupA(face->file);
1080 child_font->index = face->face_index;
1081 child_font->font = NULL;
1082 fs.fsCsb[0] |= face->fs.fsCsb[0];
1083 fs.fsCsb[1] |= face->fs.fsCsb[1];
1084 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1085 list_add_tail(&font_link->links, &child_font->entry);
1087 family = find_family_from_name(font_link->font_name);
1088 if(family)
1090 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1092 memcpy(&face->fs_links, &fs, sizeof(fs));
1095 list_add_tail(&system_links, &font_link->entry);
1096 val_len = max_val + 1;
1097 data_len = max_data;
1100 HeapFree(GetProcessHeap(), 0, value);
1101 HeapFree(GetProcessHeap(), 0, data);
1102 RegCloseKey(hkey);
1105 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1106 that Tahoma has */
1108 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1109 system_font_link->font_name = strdupW(System);
1110 list_init(&system_font_link->links);
1112 face = find_face_from_filename(tahoma_ttf, Tahoma);
1113 if(face)
1115 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1116 child_font->file_name = strdupA(face->file);
1117 child_font->index = face->face_index;
1118 child_font->font = NULL;
1119 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1120 list_add_tail(&system_font_link->links, &child_font->entry);
1122 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1124 if(!strcmpiW(font_link->font_name, Tahoma))
1126 CHILD_FONT *font_link_entry;
1127 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1129 CHILD_FONT *new_child;
1130 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1131 new_child->file_name = strdupA(font_link_entry->file_name);
1132 new_child->index = font_link_entry->index;
1133 new_child->font = NULL;
1134 list_add_tail(&system_font_link->links, &new_child->entry);
1136 break;
1139 list_add_tail(&system_links, &system_font_link->entry);
1140 return ret;
1143 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1145 DIR *dir;
1146 struct dirent *dent;
1147 char path[MAX_PATH];
1149 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1151 dir = opendir(dirname);
1152 if(!dir) {
1153 WARN("Can't open directory %s\n", debugstr_a(dirname));
1154 return FALSE;
1156 while((dent = readdir(dir)) != NULL) {
1157 struct stat statbuf;
1159 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1160 continue;
1162 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1164 sprintf(path, "%s/%s", dirname, dent->d_name);
1166 if(stat(path, &statbuf) == -1)
1168 WARN("Can't stat %s\n", debugstr_a(path));
1169 continue;
1171 if(S_ISDIR(statbuf.st_mode))
1172 ReadFontDir(path, external_fonts);
1173 else
1174 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1176 closedir(dir);
1177 return TRUE;
1180 static void load_fontconfig_fonts(void)
1182 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1183 void *fc_handle = NULL;
1184 FcConfig *config;
1185 FcPattern *pat;
1186 FcObjectSet *os;
1187 FcFontSet *fontset;
1188 int i, len;
1189 char *file;
1190 const char *ext;
1192 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1193 if(!fc_handle) {
1194 TRACE("Wine cannot find the fontconfig library (%s).\n",
1195 SONAME_LIBFONTCONFIG);
1196 return;
1198 #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;}
1199 LOAD_FUNCPTR(FcConfigGetCurrent);
1200 LOAD_FUNCPTR(FcFontList);
1201 LOAD_FUNCPTR(FcFontSetDestroy);
1202 LOAD_FUNCPTR(FcInit);
1203 LOAD_FUNCPTR(FcObjectSetAdd);
1204 LOAD_FUNCPTR(FcObjectSetCreate);
1205 LOAD_FUNCPTR(FcObjectSetDestroy);
1206 LOAD_FUNCPTR(FcPatternCreate);
1207 LOAD_FUNCPTR(FcPatternDestroy);
1208 LOAD_FUNCPTR(FcPatternGetString);
1209 #undef LOAD_FUNCPTR
1211 if(!pFcInit()) return;
1213 config = pFcConfigGetCurrent();
1214 pat = pFcPatternCreate();
1215 os = pFcObjectSetCreate();
1216 pFcObjectSetAdd(os, FC_FILE);
1217 fontset = pFcFontList(config, pat, os);
1218 if(!fontset) return;
1219 for(i = 0; i < fontset->nfont; i++) {
1220 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1221 continue;
1222 TRACE("fontconfig: %s\n", file);
1224 /* We're just interested in OT/TT fonts for now, so this hack just
1225 picks up the standard extensions to save time loading every other
1226 font */
1227 len = strlen( file );
1228 if(len < 4) continue;
1229 ext = &file[ len - 3 ];
1230 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1231 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1233 pFcFontSetDestroy(fontset);
1234 pFcObjectSetDestroy(os);
1235 pFcPatternDestroy(pat);
1236 sym_not_found:
1237 #endif
1238 return;
1241 static BOOL load_font_from_data_dir(LPCWSTR file)
1243 BOOL ret = FALSE;
1244 const char *data_dir = wine_get_data_dir();
1246 if (!data_dir) data_dir = wine_get_build_dir();
1248 if (data_dir)
1250 INT len;
1251 char *unix_name;
1253 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1255 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1257 strcpy(unix_name, data_dir);
1258 strcat(unix_name, "/fonts/");
1260 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1262 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1263 HeapFree(GetProcessHeap(), 0, unix_name);
1265 return ret;
1268 static void load_system_fonts(void)
1270 HKEY hkey;
1271 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1272 const WCHAR * const *value;
1273 DWORD dlen, type;
1274 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1275 char *unixname;
1277 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1278 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1279 strcatW(windowsdir, fontsW);
1280 for(value = SystemFontValues; *value; value++) {
1281 dlen = sizeof(data);
1282 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1283 type == REG_SZ) {
1284 BOOL added = FALSE;
1286 sprintfW(pathW, fmtW, windowsdir, data);
1287 if((unixname = wine_get_unix_file_name(pathW))) {
1288 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1289 HeapFree(GetProcessHeap(), 0, unixname);
1291 if (!added)
1292 load_font_from_data_dir(data);
1295 RegCloseKey(hkey);
1299 /*************************************************************
1301 * This adds registry entries for any externally loaded fonts
1302 * (fonts from fontconfig or FontDirs). It also deletes entries
1303 * of no longer existing fonts.
1306 static void update_reg_entries(void)
1308 HKEY winkey = 0, externalkey = 0;
1309 LPWSTR valueW;
1310 LPVOID data;
1311 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1312 Family *family;
1313 Face *face;
1314 struct list *family_elem_ptr, *face_elem_ptr;
1315 WCHAR *file;
1316 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1317 static const WCHAR spaceW[] = {' ', '\0'};
1318 char *path;
1320 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1321 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1322 ERR("Can't create Windows font reg key\n");
1323 goto end;
1325 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1326 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1327 ERR("Can't create external font reg key\n");
1328 goto end;
1331 /* Delete all external fonts added last time */
1333 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1334 &valuelen, &datalen, NULL, NULL);
1335 valuelen++; /* returned value doesn't include room for '\0' */
1336 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1337 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1339 dlen = datalen * sizeof(WCHAR);
1340 vlen = valuelen;
1341 i = 0;
1342 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1343 &dlen) == ERROR_SUCCESS) {
1345 RegDeleteValueW(winkey, valueW);
1346 /* reset dlen and vlen */
1347 dlen = datalen;
1348 vlen = valuelen;
1350 HeapFree(GetProcessHeap(), 0, data);
1351 HeapFree(GetProcessHeap(), 0, valueW);
1353 /* Delete the old external fonts key */
1354 RegCloseKey(externalkey);
1355 externalkey = 0;
1356 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1358 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1359 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1360 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1361 ERR("Can't create external font reg key\n");
1362 goto end;
1365 /* enumerate the fonts and add external ones to the two keys */
1367 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1368 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1369 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1370 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1371 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1372 if(!face->external) continue;
1373 len = len_fam;
1374 if(strcmpiW(face->StyleName, RegularW))
1375 len = len_fam + strlenW(face->StyleName) + 1;
1376 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1377 strcpyW(valueW, family->FamilyName);
1378 if(len != len_fam) {
1379 strcatW(valueW, spaceW);
1380 strcatW(valueW, face->StyleName);
1382 strcatW(valueW, TrueType);
1383 if((path = strrchr(face->file, '/')) == NULL)
1384 path = face->file;
1385 else
1386 path++;
1387 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1389 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1390 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1391 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1392 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1394 HeapFree(GetProcessHeap(), 0, file);
1395 HeapFree(GetProcessHeap(), 0, valueW);
1398 end:
1399 if(externalkey)
1400 RegCloseKey(externalkey);
1401 if(winkey)
1402 RegCloseKey(winkey);
1403 return;
1407 /*************************************************************
1408 * WineEngAddFontResourceEx
1411 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1413 if (ft_handle) /* do it only if we have freetype up and running */
1415 char *unixname;
1417 if(flags)
1418 FIXME("Ignoring flags %x\n", flags);
1420 if((unixname = wine_get_unix_file_name(file)))
1422 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1423 HeapFree(GetProcessHeap(), 0, unixname);
1426 return 1;
1429 /*************************************************************
1430 * WineEngRemoveFontResourceEx
1433 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1435 FIXME(":stub\n");
1436 return TRUE;
1439 static const struct nls_update_font_list
1441 UINT ansi_cp, oem_cp;
1442 const char *oem, *fixed, *system;
1443 const char *courier, *serif, *small, *sserif;
1444 } nls_update_font_list[] =
1446 /* Latin 1 (United States) */
1447 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1450 /* Latin 1 (Multilingual) */
1451 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1452 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1454 /* Eastern Europe */
1455 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1456 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1458 /* Cyrillic */
1459 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1460 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1462 /* Greek */
1463 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1464 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1466 /* Turkish */
1467 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1468 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1470 /* Hebrew */
1471 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1472 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1474 /* Arabic */
1475 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1476 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1478 /* Baltic */
1479 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1480 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1482 /* Vietnamese */
1483 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1484 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1486 /* Thai */
1487 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1488 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1490 /* Japanese */
1491 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1492 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1494 /* Chinese Simplified */
1495 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1496 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1498 /* Korean */
1499 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1500 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1502 /* Chinese Traditional */
1503 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1504 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1508 inline static HKEY create_fonts_NT_registry_key(void)
1510 HKEY hkey = 0;
1512 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1513 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1514 return hkey;
1517 inline static HKEY create_fonts_9x_registry_key(void)
1519 HKEY hkey = 0;
1521 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1522 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1523 return hkey;
1526 inline static HKEY create_config_fonts_registry_key(void)
1528 HKEY hkey = 0;
1530 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1531 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1532 return hkey;
1535 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1537 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1538 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1539 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1540 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1543 static void update_font_info(void)
1545 char buf[80];
1546 DWORD len, type;
1547 HKEY hkey = 0;
1548 UINT i, ansi_cp = 0, oem_cp = 0;
1549 LCID lcid = GetUserDefaultLCID();
1551 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1552 return;
1554 len = sizeof(buf);
1555 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1557 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1559 RegCloseKey(hkey);
1560 return;
1562 TRACE("updating registry, locale changed %s -> %08x\n", debugstr_a(buf), lcid);
1564 else TRACE("updating registry, locale changed none -> %08x\n", lcid);
1566 sprintf(buf, "%08x", lcid);
1567 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1568 RegCloseKey(hkey);
1570 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1571 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1572 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1573 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1575 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1577 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1578 nls_update_font_list[i].oem_cp == oem_cp)
1580 HKEY hkey;
1582 hkey = create_config_fonts_registry_key();
1583 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1584 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1585 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1586 RegCloseKey(hkey);
1588 hkey = create_fonts_NT_registry_key();
1589 add_font_list(hkey, &nls_update_font_list[i]);
1590 RegCloseKey(hkey);
1592 hkey = create_fonts_9x_registry_key();
1593 add_font_list(hkey, &nls_update_font_list[i]);
1594 RegCloseKey(hkey);
1596 return;
1599 FIXME("there is no font defaults for lcid %04x/ansi_cp %u\n", lcid, ansi_cp);
1602 /*************************************************************
1603 * WineEngInit
1605 * Initialize FreeType library and create a list of available faces
1607 BOOL WineEngInit(void)
1609 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1610 static const WCHAR pathW[] = {'P','a','t','h',0};
1611 HKEY hkey;
1612 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1613 LPVOID data;
1614 WCHAR windowsdir[MAX_PATH];
1615 char *unixname;
1616 HANDLE font_mutex;
1617 const char *data_dir;
1619 TRACE("\n");
1621 /* update locale dependent font info in registry */
1622 update_font_info();
1624 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1625 if(!ft_handle) {
1626 WINE_MESSAGE(
1627 "Wine cannot find the FreeType font library. To enable Wine to\n"
1628 "use TrueType fonts please install a version of FreeType greater than\n"
1629 "or equal to 2.0.5.\n"
1630 "http://www.freetype.org\n");
1631 return FALSE;
1634 #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;}
1636 LOAD_FUNCPTR(FT_Vector_Unit)
1637 LOAD_FUNCPTR(FT_Done_Face)
1638 LOAD_FUNCPTR(FT_Get_Char_Index)
1639 LOAD_FUNCPTR(FT_Get_Module)
1640 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1641 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1642 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1643 LOAD_FUNCPTR(FT_Init_FreeType)
1644 LOAD_FUNCPTR(FT_Load_Glyph)
1645 LOAD_FUNCPTR(FT_Matrix_Multiply)
1646 LOAD_FUNCPTR(FT_MulFix)
1647 LOAD_FUNCPTR(FT_New_Face)
1648 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1649 LOAD_FUNCPTR(FT_Outline_Transform)
1650 LOAD_FUNCPTR(FT_Outline_Translate)
1651 LOAD_FUNCPTR(FT_Select_Charmap)
1652 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1653 LOAD_FUNCPTR(FT_Vector_Transform)
1655 #undef LOAD_FUNCPTR
1656 /* Don't warn if this one is missing */
1657 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1658 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1659 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1660 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1661 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1662 #ifdef HAVE_FREETYPE_FTWINFNT_H
1663 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1664 #endif
1665 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1666 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1667 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1668 <= 2.0.3 has FT_Sqrt64 */
1669 goto sym_not_found;
1672 if(pFT_Init_FreeType(&library) != 0) {
1673 ERR("Can't init FreeType library\n");
1674 wine_dlclose(ft_handle, NULL, 0);
1675 ft_handle = NULL;
1676 return FALSE;
1678 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1679 if (pFT_Library_Version)
1681 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1683 if (FT_Version.major<=0)
1685 FT_Version.major=2;
1686 FT_Version.minor=0;
1687 FT_Version.patch=5;
1689 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1690 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1691 ((FT_Version.minor << 8) & 0x00ff00) |
1692 ((FT_Version.patch ) & 0x0000ff);
1694 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1695 ERR("Failed to create font mutex\n");
1696 return FALSE;
1698 WaitForSingleObject(font_mutex, INFINITE);
1700 /* load the system bitmap fonts */
1701 load_system_fonts();
1703 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1704 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1705 strcatW(windowsdir, fontsW);
1706 if((unixname = wine_get_unix_file_name(windowsdir)))
1708 ReadFontDir(unixname, FALSE);
1709 HeapFree(GetProcessHeap(), 0, unixname);
1712 /* load the system truetype fonts */
1713 data_dir = wine_get_data_dir();
1714 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1715 strcpy(unixname, data_dir);
1716 strcat(unixname, "/fonts/");
1717 ReadFontDir(unixname, FALSE);
1718 HeapFree(GetProcessHeap(), 0, unixname);
1721 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1722 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1723 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1724 will skip these. */
1725 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1726 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1727 &hkey) == ERROR_SUCCESS) {
1728 LPWSTR valueW;
1729 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1730 &valuelen, &datalen, NULL, NULL);
1732 valuelen++; /* returned value doesn't include room for '\0' */
1733 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1734 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1735 if (valueW && data)
1737 dlen = datalen * sizeof(WCHAR);
1738 vlen = valuelen;
1739 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1740 &dlen) == ERROR_SUCCESS) {
1741 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1743 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1745 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1746 HeapFree(GetProcessHeap(), 0, unixname);
1749 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1751 WCHAR pathW[MAX_PATH];
1752 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1753 BOOL added = FALSE;
1755 sprintfW(pathW, fmtW, windowsdir, data);
1756 if((unixname = wine_get_unix_file_name(pathW)))
1758 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1759 HeapFree(GetProcessHeap(), 0, unixname);
1761 if (!added)
1762 load_font_from_data_dir(data);
1764 /* reset dlen and vlen */
1765 dlen = datalen;
1766 vlen = valuelen;
1769 HeapFree(GetProcessHeap(), 0, data);
1770 HeapFree(GetProcessHeap(), 0, valueW);
1771 RegCloseKey(hkey);
1774 load_fontconfig_fonts();
1776 /* then look in any directories that we've specified in the config file */
1777 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1778 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1780 DWORD len;
1781 LPWSTR valueW;
1782 LPSTR valueA, ptr;
1784 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1786 len += sizeof(WCHAR);
1787 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1788 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1790 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1791 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1792 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1793 TRACE( "got font path %s\n", debugstr_a(valueA) );
1794 ptr = valueA;
1795 while (ptr)
1797 LPSTR next = strchr( ptr, ':' );
1798 if (next) *next++ = 0;
1799 ReadFontDir( ptr, TRUE );
1800 ptr = next;
1802 HeapFree( GetProcessHeap(), 0, valueA );
1804 HeapFree( GetProcessHeap(), 0, valueW );
1806 RegCloseKey(hkey);
1809 DumpFontList();
1810 LoadSubstList();
1811 DumpSubstList();
1812 LoadReplaceList();
1813 update_reg_entries();
1815 init_system_links();
1817 ReleaseMutex(font_mutex);
1818 return TRUE;
1819 sym_not_found:
1820 WINE_MESSAGE(
1821 "Wine cannot find certain functions that it needs inside the FreeType\n"
1822 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1823 "FreeType to at least version 2.0.5.\n"
1824 "http://www.freetype.org\n");
1825 wine_dlclose(ft_handle, NULL, 0);
1826 ft_handle = NULL;
1827 return FALSE;
1831 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1833 TT_OS2 *pOS2;
1834 TT_HoriHeader *pHori;
1836 LONG ppem;
1838 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1839 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1841 if(height == 0) height = 16;
1843 /* Calc. height of EM square:
1845 * For +ve lfHeight we have
1846 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1847 * Re-arranging gives:
1848 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1850 * For -ve lfHeight we have
1851 * |lfHeight| = ppem
1852 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1853 * with il = winAscent + winDescent - units_per_em]
1857 if(height > 0) {
1858 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1859 ppem = ft_face->units_per_EM * height /
1860 (pHori->Ascender - pHori->Descender);
1861 else
1862 ppem = ft_face->units_per_EM * height /
1863 (pOS2->usWinAscent + pOS2->usWinDescent);
1865 else
1866 ppem = -height;
1868 return ppem;
1871 static LONG load_VDMX(GdiFont*, LONG);
1873 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
1875 FT_Error err;
1876 FT_Face ft_face;
1878 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
1879 err = pFT_New_Face(library, file, face_index, &ft_face);
1880 if(err) {
1881 ERR("FT_New_Face rets %d\n", err);
1882 return 0;
1885 /* set it here, as load_VDMX needs it */
1886 font->ft_face = ft_face;
1888 if(FT_IS_SCALABLE(ft_face)) {
1889 /* load the VDMX table if we have one */
1890 font->ppem = load_VDMX(font, height);
1891 if(font->ppem == 0)
1892 font->ppem = calc_ppem_for_height(ft_face, height);
1894 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1895 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
1896 } else {
1897 font->ppem = height;
1898 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1899 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
1901 return ft_face;
1905 static int get_nearest_charset(Face *face, int *cp)
1907 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1908 a single face with the requested charset. The idea is to check if
1909 the selected font supports the current ANSI codepage, if it does
1910 return the corresponding charset, else return the first charset */
1912 CHARSETINFO csi;
1913 int acp = GetACP(), i;
1914 DWORD fs0;
1916 *cp = acp;
1917 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
1918 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
1919 return csi.ciCharset;
1921 for(i = 0; i < 32; i++) {
1922 fs0 = 1L << i;
1923 if(face->fs.fsCsb[0] & fs0) {
1924 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1925 *cp = csi.ciACP;
1926 return csi.ciCharset;
1928 else
1929 FIXME("TCI failing on %x\n", fs0);
1933 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
1934 face->fs.fsCsb[0], face->file);
1935 *cp = acp;
1936 return DEFAULT_CHARSET;
1939 static GdiFont *alloc_font(void)
1941 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1942 ret->gmsize = INIT_GM_SIZE;
1943 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1944 ret->gmsize * sizeof(*ret->gm));
1945 ret->potm = NULL;
1946 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1947 ret->total_kern_pairs = (DWORD)-1;
1948 ret->kern_pairs = NULL;
1949 list_init(&ret->hfontlist);
1950 list_init(&ret->child_fonts);
1951 return ret;
1954 static void free_font(GdiFont *font)
1956 struct list *cursor, *cursor2;
1958 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1960 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1961 struct list *first_hfont;
1962 HFONTLIST *hfontlist;
1963 list_remove(cursor);
1964 if(child->font)
1966 first_hfont = list_head(&child->font->hfontlist);
1967 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1968 DeleteObject(hfontlist->hfont);
1969 HeapFree(GetProcessHeap(), 0, hfontlist);
1970 free_font(child->font);
1972 HeapFree(GetProcessHeap(), 0, child->file_name);
1973 HeapFree(GetProcessHeap(), 0, child);
1976 if (font->ft_face) pFT_Done_Face(font->ft_face);
1977 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
1978 HeapFree(GetProcessHeap(), 0, font->potm);
1979 HeapFree(GetProcessHeap(), 0, font->name);
1980 HeapFree(GetProcessHeap(), 0, font->gm);
1981 HeapFree(GetProcessHeap(), 0, font);
1985 /*************************************************************
1986 * load_VDMX
1988 * load the vdmx entry for the specified height
1991 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1992 ( ( (FT_ULong)_x4 << 24 ) | \
1993 ( (FT_ULong)_x3 << 16 ) | \
1994 ( (FT_ULong)_x2 << 8 ) | \
1995 (FT_ULong)_x1 )
1997 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1999 typedef struct {
2000 BYTE bCharSet;
2001 BYTE xRatio;
2002 BYTE yStartRatio;
2003 BYTE yEndRatio;
2004 } Ratios;
2006 typedef struct {
2007 WORD recs;
2008 BYTE startsz;
2009 BYTE endsz;
2010 } VDMX_group;
2012 static LONG load_VDMX(GdiFont *font, LONG height)
2014 WORD hdr[3], tmp;
2015 VDMX_group group;
2016 BYTE devXRatio, devYRatio;
2017 USHORT numRecs, numRatios;
2018 DWORD result, offset = -1;
2019 LONG ppem = 0;
2020 int i;
2022 /* For documentation on VDMX records, see
2023 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2026 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2028 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2029 return ppem;
2031 /* FIXME: need the real device aspect ratio */
2032 devXRatio = 1;
2033 devYRatio = 1;
2035 numRecs = GET_BE_WORD(hdr[1]);
2036 numRatios = GET_BE_WORD(hdr[2]);
2038 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2039 for(i = 0; i < numRatios; i++) {
2040 Ratios ratio;
2042 offset = (3 * 2) + (i * sizeof(Ratios));
2043 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2044 offset = -1;
2046 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2048 if((ratio.xRatio == 0 &&
2049 ratio.yStartRatio == 0 &&
2050 ratio.yEndRatio == 0) ||
2051 (devXRatio == ratio.xRatio &&
2052 devYRatio >= ratio.yStartRatio &&
2053 devYRatio <= ratio.yEndRatio))
2055 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2056 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2057 offset = GET_BE_WORD(tmp);
2058 break;
2062 if(offset == -1) {
2063 FIXME("No suitable ratio found\n");
2064 return ppem;
2067 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2068 USHORT recs;
2069 BYTE startsz, endsz;
2070 WORD *vTable;
2072 recs = GET_BE_WORD(group.recs);
2073 startsz = group.startsz;
2074 endsz = group.endsz;
2076 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2078 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2079 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2080 if(result == GDI_ERROR) {
2081 FIXME("Failed to retrieve vTable\n");
2082 goto end;
2085 if(height > 0) {
2086 for(i = 0; i < recs; i++) {
2087 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2088 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2089 ppem = GET_BE_WORD(vTable[i * 3]);
2091 if(yMax + -yMin == height) {
2092 font->yMax = yMax;
2093 font->yMin = yMin;
2094 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2095 break;
2097 if(yMax + -yMin > height) {
2098 if(--i < 0) {
2099 ppem = 0;
2100 goto end; /* failed */
2102 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2103 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2104 ppem = GET_BE_WORD(vTable[i * 3]);
2105 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2106 break;
2109 if(!font->yMax) {
2110 ppem = 0;
2111 TRACE("ppem not found for height %d\n", height);
2113 } else {
2114 ppem = -height;
2115 if(ppem < startsz || ppem > endsz)
2116 goto end;
2118 for(i = 0; i < recs; i++) {
2119 USHORT yPelHeight;
2120 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2122 if(yPelHeight > ppem)
2123 break; /* failed */
2125 if(yPelHeight == ppem) {
2126 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2127 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2128 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2129 break;
2133 end:
2134 HeapFree(GetProcessHeap(), 0, vTable);
2137 return ppem;
2140 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2142 if(font->font_desc.hash != fd->hash) return TRUE;
2143 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2144 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2145 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2146 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2149 static void calc_hash(FONT_DESC *pfd)
2151 DWORD hash = 0, *ptr, two_chars;
2152 WORD *pwc;
2153 unsigned int i;
2155 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2156 hash ^= *ptr;
2157 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2158 hash ^= *ptr;
2159 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2160 two_chars = *ptr;
2161 pwc = (WCHAR *)&two_chars;
2162 if(!*pwc) break;
2163 *pwc = toupperW(*pwc);
2164 pwc++;
2165 *pwc = toupperW(*pwc);
2166 hash ^= two_chars;
2167 if(!*pwc) break;
2169 hash ^= !pfd->can_use_bitmap;
2170 pfd->hash = hash;
2171 return;
2174 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2176 GdiFont *ret;
2177 FONT_DESC fd;
2178 HFONTLIST *hflist;
2179 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2181 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2182 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2183 fd.can_use_bitmap = can_use_bitmap;
2184 calc_hash(&fd);
2186 /* try the in-use list */
2187 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2188 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2189 if(!fontcmp(ret, &fd)) {
2190 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2191 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2192 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2193 if(hflist->hfont == hfont)
2194 return ret;
2196 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2197 hflist->hfont = hfont;
2198 list_add_head(&ret->hfontlist, &hflist->entry);
2199 return ret;
2203 /* then the unused list */
2204 font_elem_ptr = list_head(&unused_gdi_font_list);
2205 while(font_elem_ptr) {
2206 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2207 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2208 if(!fontcmp(ret, &fd)) {
2209 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2210 assert(list_empty(&ret->hfontlist));
2211 TRACE("Found %p in unused list\n", ret);
2212 list_remove(&ret->entry);
2213 list_add_head(&gdi_font_list, &ret->entry);
2214 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2215 hflist->hfont = hfont;
2216 list_add_head(&ret->hfontlist, &hflist->entry);
2217 return ret;
2220 return NULL;
2224 /*************************************************************
2225 * create_child_font_list
2227 static BOOL create_child_font_list(GdiFont *font)
2229 BOOL ret = FALSE;
2230 SYSTEM_LINKS *font_link;
2231 CHILD_FONT *font_link_entry, *new_child;
2233 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2235 if(!strcmpW(font_link->font_name, font->name))
2237 TRACE("found entry in system list\n");
2238 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2240 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2241 new_child->file_name = strdupA(font_link_entry->file_name);
2242 new_child->index = font_link_entry->index;
2243 new_child->font = NULL;
2244 list_add_tail(&font->child_fonts, &new_child->entry);
2245 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2247 ret = TRUE;
2248 break;
2252 return ret;
2255 /*************************************************************
2256 * WineEngCreateFontInstance
2259 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2261 GdiFont *ret;
2262 Face *face, *best, *best_bitmap;
2263 Family *family, *last_resort_family;
2264 struct list *family_elem_ptr, *face_elem_ptr;
2265 INT height, width = 0;
2266 unsigned int score = 0, new_score;
2267 signed int diff = 0, newdiff;
2268 BOOL bd, it, can_use_bitmap;
2269 LOGFONTW lf;
2270 CHARSETINFO csi;
2271 HFONTLIST *hflist;
2273 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2275 struct list *first_hfont = list_head(&ret->hfontlist);
2276 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2277 if(hflist->hfont == hfont)
2278 return ret;
2281 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2282 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2284 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2285 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2286 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2287 lf.lfEscapement);
2289 /* check the cache first */
2290 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2291 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2292 return ret;
2295 TRACE("not in cache\n");
2296 if(list_empty(&font_list)) /* No fonts installed */
2298 TRACE("No fonts installed\n");
2299 return NULL;
2301 if(!have_installed_roman_font)
2303 TRACE("No roman font installed\n");
2304 return NULL;
2307 ret = alloc_font();
2309 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2310 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2311 ret->font_desc.can_use_bitmap = can_use_bitmap;
2312 calc_hash(&ret->font_desc);
2313 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2314 hflist->hfont = hfont;
2315 list_add_head(&ret->hfontlist, &hflist->entry);
2318 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2319 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2320 original value lfCharSet. Note this is a special case for
2321 Symbol and doesn't happen at least for "Wingdings*" */
2323 if(!strcmpiW(lf.lfFaceName, SymbolW))
2324 lf.lfCharSet = SYMBOL_CHARSET;
2326 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2327 switch(lf.lfCharSet) {
2328 case DEFAULT_CHARSET:
2329 csi.fs.fsCsb[0] = 0;
2330 break;
2331 default:
2332 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2333 csi.fs.fsCsb[0] = 0;
2334 break;
2338 family = NULL;
2339 if(lf.lfFaceName[0] != '\0') {
2340 FontSubst *psub;
2341 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2343 if(psub) {
2344 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2345 debugstr_w(psub->to.name));
2346 strcpyW(lf.lfFaceName, psub->to.name);
2349 /* We want a match on name and charset or just name if
2350 charset was DEFAULT_CHARSET. If the latter then
2351 we fixup the returned charset later in get_nearest_charset
2352 where we'll either use the charset of the current ansi codepage
2353 or if that's unavailable the first charset that the font supports.
2355 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2356 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2357 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2358 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2359 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2360 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2361 if(face->scalable || can_use_bitmap)
2362 goto found;
2368 /* If requested charset was DEFAULT_CHARSET then try using charset
2369 corresponding to the current ansi codepage */
2370 if(!csi.fs.fsCsb[0]) {
2371 INT acp = GetACP();
2372 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2373 FIXME("TCI failed on codepage %d\n", acp);
2374 csi.fs.fsCsb[0] = 0;
2375 } else
2376 lf.lfCharSet = csi.ciCharset;
2379 /* Face families are in the top 4 bits of lfPitchAndFamily,
2380 so mask with 0xF0 before testing */
2382 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2383 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2384 strcpyW(lf.lfFaceName, defFixed);
2385 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2386 strcpyW(lf.lfFaceName, defSerif);
2387 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2388 strcpyW(lf.lfFaceName, defSans);
2389 else
2390 strcpyW(lf.lfFaceName, defSans);
2391 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2392 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2393 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2394 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2395 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2396 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2397 if(face->scalable || can_use_bitmap)
2398 goto found;
2403 last_resort_family = NULL;
2404 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2405 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2406 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2407 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2408 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2409 if(face->scalable)
2410 goto found;
2411 if(can_use_bitmap && !last_resort_family)
2412 last_resort_family = family;
2417 if(last_resort_family) {
2418 family = last_resort_family;
2419 csi.fs.fsCsb[0] = 0;
2420 goto found;
2423 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2424 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2425 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2426 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2427 if(face->scalable) {
2428 csi.fs.fsCsb[0] = 0;
2429 WARN("just using first face for now\n");
2430 goto found;
2432 if(can_use_bitmap && !last_resort_family)
2433 last_resort_family = family;
2436 if(!last_resort_family) {
2437 FIXME("can't find a single appropriate font - bailing\n");
2438 free_font(ret);
2439 return NULL;
2442 WARN("could only find a bitmap font - this will probably look awful!\n");
2443 family = last_resort_family;
2444 csi.fs.fsCsb[0] = 0;
2446 found:
2447 it = lf.lfItalic ? 1 : 0;
2448 bd = lf.lfWeight > 550 ? 1 : 0;
2450 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2451 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2453 face = best = best_bitmap = NULL;
2454 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2456 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2458 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2459 if(!best || new_score <= score)
2461 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2462 face->Italic, face->Bold, it, bd);
2463 score = new_score;
2464 best = face;
2465 if(best->scalable && score == 0) break;
2466 if(!best->scalable)
2468 if(height > 0)
2469 newdiff = height - (signed int)(best->size.height);
2470 else
2471 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2472 if(!best_bitmap || new_score < score ||
2473 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2475 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2476 diff = newdiff;
2477 best_bitmap = best;
2478 if(score == 0 && diff == 0) break;
2484 if(best)
2485 face = best->scalable ? best : best_bitmap;
2486 ret->fake_italic = (it && !face->Italic);
2487 ret->fake_bold = (bd && !face->Bold);
2489 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2491 if(csi.fs.fsCsb[0]) {
2492 ret->charset = lf.lfCharSet;
2493 ret->codepage = csi.ciACP;
2495 else
2496 ret->charset = get_nearest_charset(face, &ret->codepage);
2498 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2499 debugstr_w(face->StyleName), face->file, face->face_index);
2501 if(!face->scalable) {
2502 width = face->size.x_ppem >> 6;
2503 height = face->size.y_ppem >> 6;
2505 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2507 if (!ret->ft_face)
2509 free_font( ret );
2510 return 0;
2513 if (ret->charset == SYMBOL_CHARSET &&
2514 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2515 /* No ops */
2517 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2518 /* No ops */
2520 else {
2521 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2524 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2525 ret->name = strdupW(family->FamilyName);
2526 ret->underline = lf.lfUnderline ? 0xff : 0;
2527 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2528 create_child_font_list(ret);
2530 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2532 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2533 list_add_head(&gdi_font_list, &ret->entry);
2534 return ret;
2537 static void dump_gdi_font_list(void)
2539 GdiFont *gdiFont;
2540 struct list *elem_ptr;
2542 TRACE("---------- gdiFont Cache ----------\n");
2543 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2544 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2545 TRACE("gdiFont=%p %s %d\n",
2546 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2549 TRACE("---------- Unused gdiFont Cache ----------\n");
2550 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2551 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2552 TRACE("gdiFont=%p %s %d\n",
2553 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2557 /*************************************************************
2558 * WineEngDestroyFontInstance
2560 * free the gdiFont associated with this handle
2563 BOOL WineEngDestroyFontInstance(HFONT handle)
2565 GdiFont *gdiFont;
2566 HFONTLIST *hflist;
2567 BOOL ret = FALSE;
2568 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2569 int i = 0;
2571 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2573 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2574 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2575 if(hflist->hfont == handle)
2577 TRACE("removing child font %p from child list\n", gdiFont);
2578 list_remove(&gdiFont->entry);
2579 return TRUE;
2583 TRACE("destroying hfont=%p\n", handle);
2584 if(TRACE_ON(font))
2585 dump_gdi_font_list();
2587 font_elem_ptr = list_head(&gdi_font_list);
2588 while(font_elem_ptr) {
2589 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2590 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2592 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2593 while(hfontlist_elem_ptr) {
2594 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2595 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2596 if(hflist->hfont == handle) {
2597 list_remove(&hflist->entry);
2598 HeapFree(GetProcessHeap(), 0, hflist);
2599 ret = TRUE;
2602 if(list_empty(&gdiFont->hfontlist)) {
2603 TRACE("Moving to Unused list\n");
2604 list_remove(&gdiFont->entry);
2605 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2610 font_elem_ptr = list_head(&unused_gdi_font_list);
2611 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2612 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2613 while(font_elem_ptr) {
2614 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2615 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2616 TRACE("freeing %p\n", gdiFont);
2617 list_remove(&gdiFont->entry);
2618 free_font(gdiFont);
2620 return ret;
2623 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2624 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2626 OUTLINETEXTMETRICW *potm = NULL;
2627 UINT size;
2628 TEXTMETRICW tm, *ptm;
2629 GdiFont *font = alloc_font();
2630 LONG width, height;
2632 if(face->scalable) {
2633 height = 100;
2634 width = 0;
2635 } else {
2636 height = face->size.y_ppem >> 6;
2637 width = face->size.x_ppem >> 6;
2640 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2642 free_font(font);
2643 return;
2646 font->name = strdupW(face->family->FamilyName);
2648 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2650 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2651 if(size) {
2652 potm = HeapAlloc(GetProcessHeap(), 0, size);
2653 WineEngGetOutlineTextMetrics(font, size, potm);
2654 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2655 } else {
2656 WineEngGetTextMetrics(font, &tm);
2657 ptm = &tm;
2660 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2661 pntm->ntmTm.tmAscent = ptm->tmAscent;
2662 pntm->ntmTm.tmDescent = ptm->tmDescent;
2663 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2664 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2665 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2666 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2667 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2668 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2669 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2670 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2671 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2672 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2673 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2674 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2675 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2676 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2677 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2678 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2679 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2680 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2681 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2682 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2683 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2685 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2686 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2687 *ptype |= RASTER_FONTTYPE;
2689 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2690 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2691 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2693 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2694 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2695 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2697 if(potm) {
2698 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2700 lstrcpynW(pelf->elfLogFont.lfFaceName,
2701 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2702 LF_FACESIZE);
2703 lstrcpynW(pelf->elfFullName,
2704 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2705 LF_FULLFACESIZE);
2706 lstrcpynW(pelf->elfStyle,
2707 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2708 LF_FACESIZE);
2710 HeapFree(GetProcessHeap(), 0, potm);
2711 } else {
2712 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2714 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2715 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2716 pelf->elfStyle[0] = '\0';
2719 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2721 free_font(font);
2724 /*************************************************************
2725 * WineEngEnumFonts
2728 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2730 Family *family;
2731 Face *face;
2732 struct list *family_elem_ptr, *face_elem_ptr;
2733 ENUMLOGFONTEXW elf;
2734 NEWTEXTMETRICEXW ntm;
2735 DWORD type, ret = 1;
2736 FONTSIGNATURE fs;
2737 CHARSETINFO csi;
2738 LOGFONTW lf;
2739 int i;
2741 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2743 if(plf->lfFaceName[0]) {
2744 FontSubst *psub;
2745 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2747 if(psub) {
2748 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2749 debugstr_w(psub->to.name));
2750 memcpy(&lf, plf, sizeof(lf));
2751 strcpyW(lf.lfFaceName, psub->to.name);
2752 plf = &lf;
2755 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2756 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2757 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2758 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2759 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2760 GetEnumStructs(face, &elf, &ntm, &type);
2761 for(i = 0; i < 32; i++) {
2762 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2763 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2764 strcpyW(elf.elfScript, OEM_DOSW);
2765 i = 32; /* break out of loop */
2766 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2767 continue;
2768 else {
2769 fs.fsCsb[0] = 1L << i;
2770 fs.fsCsb[1] = 0;
2771 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2772 TCI_SRCFONTSIG))
2773 csi.ciCharset = DEFAULT_CHARSET;
2774 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2775 if(csi.ciCharset != DEFAULT_CHARSET) {
2776 elf.elfLogFont.lfCharSet =
2777 ntm.ntmTm.tmCharSet = csi.ciCharset;
2778 if(ElfScriptsW[i])
2779 strcpyW(elf.elfScript, ElfScriptsW[i]);
2780 else
2781 FIXME("Unknown elfscript for bit %d\n", i);
2784 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
2785 debugstr_w(elf.elfLogFont.lfFaceName),
2786 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2787 csi.ciCharset, type, debugstr_w(elf.elfScript),
2788 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2789 ntm.ntmTm.ntmFlags);
2790 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2791 if(!ret) goto end;
2796 } else {
2797 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2798 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2799 face_elem_ptr = list_head(&family->faces);
2800 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2801 GetEnumStructs(face, &elf, &ntm, &type);
2802 for(i = 0; i < 32; i++) {
2803 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2804 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2805 strcpyW(elf.elfScript, OEM_DOSW);
2806 i = 32; /* break out of loop */
2807 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2808 continue;
2809 else {
2810 fs.fsCsb[0] = 1L << i;
2811 fs.fsCsb[1] = 0;
2812 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2813 TCI_SRCFONTSIG))
2814 csi.ciCharset = DEFAULT_CHARSET;
2815 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2816 if(csi.ciCharset != DEFAULT_CHARSET) {
2817 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2818 csi.ciCharset;
2819 if(ElfScriptsW[i])
2820 strcpyW(elf.elfScript, ElfScriptsW[i]);
2821 else
2822 FIXME("Unknown elfscript for bit %d\n", i);
2825 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2826 debugstr_w(elf.elfLogFont.lfFaceName),
2827 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2828 csi.ciCharset, type, debugstr_w(elf.elfScript),
2829 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2830 ntm.ntmTm.ntmFlags);
2831 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2832 if(!ret) goto end;
2836 end:
2837 return ret;
2840 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2842 pt->x.value = vec->x >> 6;
2843 pt->x.fract = (vec->x & 0x3f) << 10;
2844 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2845 pt->y.value = vec->y >> 6;
2846 pt->y.fract = (vec->y & 0x3f) << 10;
2847 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2848 return;
2851 /***************************************************
2852 * According to the MSDN documentation on WideCharToMultiByte,
2853 * certain codepages cannot set the default_used parameter.
2854 * This returns TRUE if the codepage can set that parameter, false else
2855 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2857 static BOOL codepage_sets_default_used(UINT codepage)
2859 switch (codepage)
2861 case CP_UTF7:
2862 case CP_UTF8:
2863 case CP_SYMBOL:
2864 return FALSE;
2865 default:
2866 return TRUE;
2870 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
2872 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2873 WCHAR wc = (WCHAR)glyph;
2874 BOOL default_used;
2875 BOOL *default_used_pointer;
2876 FT_UInt ret;
2877 char buf;
2878 default_used_pointer = NULL;
2879 default_used = FALSE;
2880 if (codepage_sets_default_used(font->codepage))
2881 default_used_pointer = &default_used;
2882 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2883 ret = 0;
2884 else
2885 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2886 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2887 return ret;
2890 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2891 glyph = glyph + 0xf000;
2892 return pFT_Get_Char_Index(font->ft_face, glyph);
2895 /*************************************************************
2896 * WineEngGetGlyphIndices
2898 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2900 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
2901 LPWORD pgi, DWORD flags)
2903 int i;
2904 WCHAR default_char = 0;
2905 TEXTMETRICW textm;
2907 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
2909 for(i = 0; i < count; i++)
2911 pgi[i] = get_glyph_index(font, lpstr[i]);
2912 if (pgi[i] == 0)
2914 if (!default_char)
2916 WineEngGetTextMetrics(font, &textm);
2917 default_char = textm.tmDefaultChar;
2919 pgi[i] = default_char;
2922 return count;
2925 /*************************************************************
2926 * WineEngGetGlyphOutline
2928 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2929 * except that the first parameter is the HWINEENGFONT of the font in
2930 * question rather than an HDC.
2933 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
2934 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2935 const MAT2* lpmat)
2937 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2938 FT_Face ft_face = font->ft_face;
2939 FT_UInt glyph_index;
2940 DWORD width, height, pitch, needed = 0;
2941 FT_Bitmap ft_bitmap;
2942 FT_Error err;
2943 INT left, right, top = 0, bottom = 0;
2944 FT_Angle angle = 0;
2945 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2946 float widthRatio = 1.0;
2947 FT_Matrix transMat = identityMat;
2948 BOOL needsTransform = FALSE;
2951 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
2952 buflen, buf, lpmat);
2954 if(format & GGO_GLYPH_INDEX) {
2955 glyph_index = glyph;
2956 format &= ~GGO_GLYPH_INDEX;
2957 } else
2958 glyph_index = get_glyph_index(font, glyph);
2960 if(glyph_index >= font->gmsize) {
2961 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2962 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2963 font->gmsize * sizeof(*font->gm));
2964 } else {
2965 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2966 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2967 return 1; /* FIXME */
2971 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2972 load_flags |= FT_LOAD_NO_BITMAP;
2974 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2976 if(err) {
2977 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2978 return GDI_ERROR;
2981 /* Scaling factor */
2982 if (font->aveWidth && font->potm) {
2983 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2986 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2987 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2989 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2990 font->gm[glyph_index].lsb = left >> 6;
2991 font->gm[glyph_index].bbx = (right - left) >> 6;
2993 /* Scaling transform */
2994 if(font->aveWidth) {
2995 FT_Matrix scaleMat;
2996 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2997 scaleMat.xy = 0;
2998 scaleMat.yx = 0;
2999 scaleMat.yy = (1 << 16);
3001 pFT_Matrix_Multiply(&scaleMat, &transMat);
3002 needsTransform = TRUE;
3005 /* Slant transform */
3006 if (font->fake_italic) {
3007 FT_Matrix slantMat;
3009 slantMat.xx = (1 << 16);
3010 slantMat.xy = ((1 << 16) >> 2);
3011 slantMat.yx = 0;
3012 slantMat.yy = (1 << 16);
3013 pFT_Matrix_Multiply(&slantMat, &transMat);
3014 needsTransform = TRUE;
3017 /* Rotation transform */
3018 if(font->orientation) {
3019 FT_Matrix rotationMat;
3020 FT_Vector vecAngle;
3021 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3022 pFT_Vector_Unit(&vecAngle, angle);
3023 rotationMat.xx = vecAngle.x;
3024 rotationMat.xy = -vecAngle.y;
3025 rotationMat.yx = -rotationMat.xy;
3026 rotationMat.yy = rotationMat.xx;
3028 pFT_Matrix_Multiply(&rotationMat, &transMat);
3029 needsTransform = TRUE;
3032 /* Extra transformation specified by caller */
3033 if (lpmat) {
3034 FT_Matrix extraMat;
3035 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3036 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3037 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3038 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3039 pFT_Matrix_Multiply(&extraMat, &transMat);
3040 needsTransform = TRUE;
3043 if(!needsTransform) {
3044 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3045 bottom = (ft_face->glyph->metrics.horiBearingY -
3046 ft_face->glyph->metrics.height) & -64;
3047 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3048 lpgm->gmCellIncY = 0;
3049 } else {
3050 INT xc, yc;
3051 FT_Vector vec;
3052 for(xc = 0; xc < 2; xc++) {
3053 for(yc = 0; yc < 2; yc++) {
3054 vec.x = (ft_face->glyph->metrics.horiBearingX +
3055 xc * ft_face->glyph->metrics.width);
3056 vec.y = ft_face->glyph->metrics.horiBearingY -
3057 yc * ft_face->glyph->metrics.height;
3058 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3059 pFT_Vector_Transform(&vec, &transMat);
3060 if(xc == 0 && yc == 0) {
3061 left = right = vec.x;
3062 top = bottom = vec.y;
3063 } else {
3064 if(vec.x < left) left = vec.x;
3065 else if(vec.x > right) right = vec.x;
3066 if(vec.y < bottom) bottom = vec.y;
3067 else if(vec.y > top) top = vec.y;
3071 left = left & -64;
3072 right = (right + 63) & -64;
3073 bottom = bottom & -64;
3074 top = (top + 63) & -64;
3076 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3077 vec.x = ft_face->glyph->metrics.horiAdvance;
3078 vec.y = 0;
3079 pFT_Vector_Transform(&vec, &transMat);
3080 lpgm->gmCellIncX = (vec.x+63) >> 6;
3081 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3083 lpgm->gmBlackBoxX = (right - left) >> 6;
3084 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3085 lpgm->gmptGlyphOrigin.x = left >> 6;
3086 lpgm->gmptGlyphOrigin.y = top >> 6;
3088 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3089 font->gm[glyph_index].init = TRUE;
3091 if(format == GGO_METRICS)
3092 return 1; /* FIXME */
3094 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3095 TRACE("loaded a bitmap\n");
3096 return GDI_ERROR;
3099 switch(format) {
3100 case GGO_BITMAP:
3101 width = lpgm->gmBlackBoxX;
3102 height = lpgm->gmBlackBoxY;
3103 pitch = ((width + 31) >> 5) << 2;
3104 needed = pitch * height;
3106 if(!buf || !buflen) break;
3108 switch(ft_face->glyph->format) {
3109 case ft_glyph_format_bitmap:
3111 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3112 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3113 INT h = ft_face->glyph->bitmap.rows;
3114 while(h--) {
3115 memcpy(dst, src, w);
3116 src += ft_face->glyph->bitmap.pitch;
3117 dst += pitch;
3119 break;
3122 case ft_glyph_format_outline:
3123 ft_bitmap.width = width;
3124 ft_bitmap.rows = height;
3125 ft_bitmap.pitch = pitch;
3126 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3127 ft_bitmap.buffer = buf;
3129 if(needsTransform) {
3130 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3133 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3135 /* Note: FreeType will only set 'black' bits for us. */
3136 memset(buf, 0, needed);
3137 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3138 break;
3140 default:
3141 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3142 return GDI_ERROR;
3144 break;
3146 case GGO_GRAY2_BITMAP:
3147 case GGO_GRAY4_BITMAP:
3148 case GGO_GRAY8_BITMAP:
3149 case WINE_GGO_GRAY16_BITMAP:
3151 unsigned int mult, row, col;
3152 BYTE *start, *ptr;
3154 width = lpgm->gmBlackBoxX;
3155 height = lpgm->gmBlackBoxY;
3156 pitch = (width + 3) / 4 * 4;
3157 needed = pitch * height;
3159 if(!buf || !buflen) break;
3160 ft_bitmap.width = width;
3161 ft_bitmap.rows = height;
3162 ft_bitmap.pitch = pitch;
3163 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3164 ft_bitmap.buffer = buf;
3166 if(needsTransform) {
3167 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3170 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3172 memset(ft_bitmap.buffer, 0, buflen);
3174 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3176 if(format == GGO_GRAY2_BITMAP)
3177 mult = 4;
3178 else if(format == GGO_GRAY4_BITMAP)
3179 mult = 16;
3180 else if(format == GGO_GRAY8_BITMAP)
3181 mult = 64;
3182 else if(format == WINE_GGO_GRAY16_BITMAP)
3183 break;
3184 else {
3185 assert(0);
3186 break;
3189 start = buf;
3190 for(row = 0; row < height; row++) {
3191 ptr = start;
3192 for(col = 0; col < width; col++, ptr++) {
3193 *ptr = (((int)*ptr) * mult + 128) / 256;
3195 start += pitch;
3197 break;
3200 case GGO_NATIVE:
3202 int contour, point = 0, first_pt;
3203 FT_Outline *outline = &ft_face->glyph->outline;
3204 TTPOLYGONHEADER *pph;
3205 TTPOLYCURVE *ppc;
3206 DWORD pph_start, cpfx, type;
3208 if(buflen == 0) buf = NULL;
3210 if (needsTransform && buf) {
3211 pFT_Outline_Transform(outline, &transMat);
3214 for(contour = 0; contour < outline->n_contours; contour++) {
3215 pph_start = needed;
3216 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3217 first_pt = point;
3218 if(buf) {
3219 pph->dwType = TT_POLYGON_TYPE;
3220 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3222 needed += sizeof(*pph);
3223 point++;
3224 while(point <= outline->contours[contour]) {
3225 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3226 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3227 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3228 cpfx = 0;
3229 do {
3230 if(buf)
3231 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3232 cpfx++;
3233 point++;
3234 } while(point <= outline->contours[contour] &&
3235 (outline->tags[point] & FT_Curve_Tag_On) ==
3236 (outline->tags[point-1] & FT_Curve_Tag_On));
3237 /* At the end of a contour Windows adds the start point, but
3238 only for Beziers */
3239 if(point > outline->contours[contour] &&
3240 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3241 if(buf)
3242 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3243 cpfx++;
3244 } else if(point <= outline->contours[contour] &&
3245 outline->tags[point] & FT_Curve_Tag_On) {
3246 /* add closing pt for bezier */
3247 if(buf)
3248 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3249 cpfx++;
3250 point++;
3252 if(buf) {
3253 ppc->wType = type;
3254 ppc->cpfx = cpfx;
3256 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3258 if(buf)
3259 pph->cb = needed - pph_start;
3261 break;
3263 case GGO_BEZIER:
3265 /* Convert the quadratic Beziers to cubic Beziers.
3266 The parametric eqn for a cubic Bezier is, from PLRM:
3267 r(t) = at^3 + bt^2 + ct + r0
3268 with the control points:
3269 r1 = r0 + c/3
3270 r2 = r1 + (c + b)/3
3271 r3 = r0 + c + b + a
3273 A quadratic Beizer has the form:
3274 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3276 So equating powers of t leads to:
3277 r1 = 2/3 p1 + 1/3 p0
3278 r2 = 2/3 p1 + 1/3 p2
3279 and of course r0 = p0, r3 = p2
3282 int contour, point = 0, first_pt;
3283 FT_Outline *outline = &ft_face->glyph->outline;
3284 TTPOLYGONHEADER *pph;
3285 TTPOLYCURVE *ppc;
3286 DWORD pph_start, cpfx, type;
3287 FT_Vector cubic_control[4];
3288 if(buflen == 0) buf = NULL;
3290 if (needsTransform && buf) {
3291 pFT_Outline_Transform(outline, &transMat);
3294 for(contour = 0; contour < outline->n_contours; contour++) {
3295 pph_start = needed;
3296 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3297 first_pt = point;
3298 if(buf) {
3299 pph->dwType = TT_POLYGON_TYPE;
3300 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3302 needed += sizeof(*pph);
3303 point++;
3304 while(point <= outline->contours[contour]) {
3305 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3306 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3307 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3308 cpfx = 0;
3309 do {
3310 if(type == TT_PRIM_LINE) {
3311 if(buf)
3312 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3313 cpfx++;
3314 point++;
3315 } else {
3316 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3317 so cpfx = 3n */
3319 /* FIXME: Possible optimization in endpoint calculation
3320 if there are two consecutive curves */
3321 cubic_control[0] = outline->points[point-1];
3322 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3323 cubic_control[0].x += outline->points[point].x + 1;
3324 cubic_control[0].y += outline->points[point].y + 1;
3325 cubic_control[0].x >>= 1;
3326 cubic_control[0].y >>= 1;
3328 if(point+1 > outline->contours[contour])
3329 cubic_control[3] = outline->points[first_pt];
3330 else {
3331 cubic_control[3] = outline->points[point+1];
3332 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3333 cubic_control[3].x += outline->points[point].x + 1;
3334 cubic_control[3].y += outline->points[point].y + 1;
3335 cubic_control[3].x >>= 1;
3336 cubic_control[3].y >>= 1;
3339 /* r1 = 1/3 p0 + 2/3 p1
3340 r2 = 1/3 p2 + 2/3 p1 */
3341 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3342 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3343 cubic_control[2] = cubic_control[1];
3344 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3345 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3346 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3347 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3348 if(buf) {
3349 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3350 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3351 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3353 cpfx += 3;
3354 point++;
3356 } while(point <= outline->contours[contour] &&
3357 (outline->tags[point] & FT_Curve_Tag_On) ==
3358 (outline->tags[point-1] & FT_Curve_Tag_On));
3359 /* At the end of a contour Windows adds the start point,
3360 but only for Beziers and we've already done that.
3362 if(point <= outline->contours[contour] &&
3363 outline->tags[point] & FT_Curve_Tag_On) {
3364 /* This is the closing pt of a bezier, but we've already
3365 added it, so just inc point and carry on */
3366 point++;
3368 if(buf) {
3369 ppc->wType = type;
3370 ppc->cpfx = cpfx;
3372 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3374 if(buf)
3375 pph->cb = needed - pph_start;
3377 break;
3380 default:
3381 FIXME("Unsupported format %d\n", format);
3382 return GDI_ERROR;
3384 return needed;
3387 static BOOL get_bitmap_text_metrics(GdiFont *font)
3389 FT_Face ft_face = font->ft_face;
3390 #ifdef HAVE_FREETYPE_FTWINFNT_H
3391 FT_WinFNT_HeaderRec winfnt_header;
3392 #endif
3393 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3394 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3395 font->potm->otmSize = size;
3397 #define TM font->potm->otmTextMetrics
3398 #ifdef HAVE_FREETYPE_FTWINFNT_H
3399 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3401 TM.tmHeight = winfnt_header.pixel_height;
3402 TM.tmAscent = winfnt_header.ascent;
3403 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3404 TM.tmInternalLeading = winfnt_header.internal_leading;
3405 TM.tmExternalLeading = winfnt_header.external_leading;
3406 TM.tmAveCharWidth = winfnt_header.avg_width;
3407 TM.tmMaxCharWidth = winfnt_header.max_width;
3408 TM.tmWeight = winfnt_header.weight;
3409 TM.tmOverhang = 0;
3410 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3411 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3412 TM.tmFirstChar = winfnt_header.first_char;
3413 TM.tmLastChar = winfnt_header.last_char;
3414 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3415 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3416 TM.tmItalic = winfnt_header.italic;
3417 TM.tmUnderlined = font->underline;
3418 TM.tmStruckOut = font->strikeout;
3419 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3420 TM.tmCharSet = winfnt_header.charset;
3422 else
3423 #endif
3425 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3426 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3427 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3428 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3429 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3430 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3431 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3432 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3433 TM.tmOverhang = 0;
3434 TM.tmDigitizedAspectX = 96; /* FIXME */
3435 TM.tmDigitizedAspectY = 96; /* FIXME */
3436 TM.tmFirstChar = 1;
3437 TM.tmLastChar = 255;
3438 TM.tmDefaultChar = 32;
3439 TM.tmBreakChar = 32;
3440 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3441 TM.tmUnderlined = font->underline;
3442 TM.tmStruckOut = font->strikeout;
3443 /* NB inverted meaning of TMPF_FIXED_PITCH */
3444 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3445 TM.tmCharSet = font->charset;
3447 #undef TM
3449 return TRUE;
3452 /*************************************************************
3453 * WineEngGetTextMetrics
3456 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3458 if(!font->potm) {
3459 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3460 if(!get_bitmap_text_metrics(font))
3461 return FALSE;
3463 if(!font->potm) return FALSE;
3464 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3466 if (font->aveWidth) {
3467 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3469 return TRUE;
3473 /*************************************************************
3474 * WineEngGetOutlineTextMetrics
3477 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3478 OUTLINETEXTMETRICW *potm)
3480 FT_Face ft_face = font->ft_face;
3481 UINT needed, lenfam, lensty, ret;
3482 TT_OS2 *pOS2;
3483 TT_HoriHeader *pHori;
3484 TT_Postscript *pPost;
3485 FT_Fixed x_scale, y_scale;
3486 WCHAR *family_nameW, *style_nameW;
3487 static const WCHAR spaceW[] = {' ', '\0'};
3488 char *cp;
3489 INT ascent, descent;
3491 TRACE("font=%p\n", font);
3493 if(!FT_IS_SCALABLE(ft_face))
3494 return 0;
3496 if(font->potm) {
3497 if(cbSize >= font->potm->otmSize)
3498 memcpy(potm, font->potm, font->potm->otmSize);
3499 return font->potm->otmSize;
3503 needed = sizeof(*potm);
3505 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3506 family_nameW = strdupW(font->name);
3508 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3509 * sizeof(WCHAR);
3510 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3511 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3512 style_nameW, lensty/sizeof(WCHAR));
3514 /* These names should be read from the TT name table */
3516 /* length of otmpFamilyName */
3517 needed += lenfam;
3519 /* length of otmpFaceName */
3520 if(!strcasecmp(ft_face->style_name, "regular")) {
3521 needed += lenfam; /* just the family name */
3522 } else {
3523 needed += lenfam + lensty; /* family + " " + style */
3526 /* length of otmpStyleName */
3527 needed += lensty;
3529 /* length of otmpFullName */
3530 needed += lenfam + lensty;
3533 x_scale = ft_face->size->metrics.x_scale;
3534 y_scale = ft_face->size->metrics.y_scale;
3536 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3537 if(!pOS2) {
3538 FIXME("Can't find OS/2 table - not TT font?\n");
3539 ret = 0;
3540 goto end;
3543 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3544 if(!pHori) {
3545 FIXME("Can't find HHEA table - not TT font?\n");
3546 ret = 0;
3547 goto end;
3550 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3552 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",
3553 pOS2->usWinAscent, pOS2->usWinDescent,
3554 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3555 ft_face->ascender, ft_face->descender, ft_face->height,
3556 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3557 ft_face->bbox.yMax, ft_face->bbox.yMin);
3559 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3560 font->potm->otmSize = needed;
3562 #define TM font->potm->otmTextMetrics
3564 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3565 ascent = pHori->Ascender;
3566 descent = -pHori->Descender;
3567 } else {
3568 ascent = pOS2->usWinAscent;
3569 descent = pOS2->usWinDescent;
3572 if(font->yMax) {
3573 TM.tmAscent = font->yMax;
3574 TM.tmDescent = -font->yMin;
3575 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3576 } else {
3577 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3578 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3579 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3580 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3583 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3585 /* MSDN says:
3586 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3588 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3589 ((ascent + descent) -
3590 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3592 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3593 if (TM.tmAveCharWidth == 0) {
3594 TM.tmAveCharWidth = 1;
3596 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3597 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3598 TM.tmOverhang = 0;
3599 TM.tmDigitizedAspectX = 300;
3600 TM.tmDigitizedAspectY = 300;
3601 TM.tmFirstChar = pOS2->usFirstCharIndex;
3602 TM.tmLastChar = pOS2->usLastCharIndex;
3603 TM.tmDefaultChar = pOS2->usDefaultChar;
3604 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3605 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3606 TM.tmUnderlined = font->underline;
3607 TM.tmStruckOut = font->strikeout;
3609 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3610 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3611 (pOS2->version == 0xFFFFU ||
3612 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3613 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3614 else
3615 TM.tmPitchAndFamily = 0;
3617 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3618 case PAN_FAMILY_SCRIPT:
3619 TM.tmPitchAndFamily |= FF_SCRIPT;
3620 break;
3621 case PAN_FAMILY_DECORATIVE:
3622 case PAN_FAMILY_PICTORIAL:
3623 TM.tmPitchAndFamily |= FF_DECORATIVE;
3624 break;
3625 case PAN_FAMILY_TEXT_DISPLAY:
3626 if(TM.tmPitchAndFamily == 0) /* fixed */
3627 TM.tmPitchAndFamily = FF_MODERN;
3628 else {
3629 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3630 case PAN_SERIF_NORMAL_SANS:
3631 case PAN_SERIF_OBTUSE_SANS:
3632 case PAN_SERIF_PERP_SANS:
3633 TM.tmPitchAndFamily |= FF_SWISS;
3634 break;
3635 default:
3636 TM.tmPitchAndFamily |= FF_ROMAN;
3639 break;
3640 default:
3641 TM.tmPitchAndFamily |= FF_DONTCARE;
3644 if(FT_IS_SCALABLE(ft_face))
3645 TM.tmPitchAndFamily |= TMPF_VECTOR;
3646 if(FT_IS_SFNT(ft_face))
3647 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3649 TM.tmCharSet = font->charset;
3650 #undef TM
3652 font->potm->otmFiller = 0;
3653 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3654 font->potm->otmfsSelection = pOS2->fsSelection;
3655 font->potm->otmfsType = pOS2->fsType;
3656 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3657 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3658 font->potm->otmItalicAngle = 0; /* POST table */
3659 font->potm->otmEMSquare = ft_face->units_per_EM;
3660 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3661 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3662 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3663 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3664 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3665 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3666 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3667 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3668 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3669 font->potm->otmMacAscent = 0; /* where do these come from ? */
3670 font->potm->otmMacDescent = 0;
3671 font->potm->otmMacLineGap = 0;
3672 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3673 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3674 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3675 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3676 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3677 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3678 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3679 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3680 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3681 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3682 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3683 if(!pPost) {
3684 font->potm->otmsUnderscoreSize = 0;
3685 font->potm->otmsUnderscorePosition = 0;
3686 } else {
3687 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3688 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3691 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3692 cp = (char*)font->potm + sizeof(*font->potm);
3693 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3694 strcpyW((WCHAR*)cp, family_nameW);
3695 cp += lenfam;
3696 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3697 strcpyW((WCHAR*)cp, style_nameW);
3698 cp += lensty;
3699 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3700 strcpyW((WCHAR*)cp, family_nameW);
3701 if(strcasecmp(ft_face->style_name, "regular")) {
3702 strcatW((WCHAR*)cp, spaceW);
3703 strcatW((WCHAR*)cp, style_nameW);
3704 cp += lenfam + lensty;
3705 } else
3706 cp += lenfam;
3707 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3708 strcpyW((WCHAR*)cp, family_nameW);
3709 strcatW((WCHAR*)cp, spaceW);
3710 strcatW((WCHAR*)cp, style_nameW);
3711 ret = needed;
3713 if(potm && needed <= cbSize)
3714 memcpy(potm, font->potm, font->potm->otmSize);
3716 end:
3717 HeapFree(GetProcessHeap(), 0, style_nameW);
3718 HeapFree(GetProcessHeap(), 0, family_nameW);
3720 return ret;
3723 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
3725 HFONTLIST *hfontlist;
3726 child->font = alloc_font();
3727 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3728 if(!child->font->ft_face)
3730 free_font(child->font);
3731 child->font = NULL;
3732 return FALSE;
3735 child->font->orientation = font->orientation;
3736 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3737 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3738 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3739 child->font->base_font = font;
3740 list_add_head(&child_font_list, &child->font->entry);
3741 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3742 return TRUE;
3745 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
3747 FT_UInt g;
3748 CHILD_FONT *child_font;
3750 if(font->base_font)
3751 font = font->base_font;
3753 *linked_font = font;
3755 if((*glyph = get_glyph_index(font, c)))
3756 return TRUE;
3758 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3760 if(!child_font->font)
3761 if(!load_child_font(font, child_font))
3762 continue;
3764 if(!child_font->font->ft_face)
3765 continue;
3766 g = get_glyph_index(child_font->font, c);
3767 if(g)
3769 *glyph = g;
3770 *linked_font = child_font->font;
3771 return TRUE;
3774 return FALSE;
3777 /*************************************************************
3778 * WineEngGetCharWidth
3781 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
3782 LPINT buffer)
3784 UINT c;
3785 GLYPHMETRICS gm;
3786 FT_UInt glyph_index;
3787 GdiFont *linked_font;
3789 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3791 for(c = firstChar; c <= lastChar; c++) {
3792 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3793 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3794 &gm, 0, NULL, NULL);
3795 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3797 return TRUE;
3800 /*************************************************************
3801 * WineEngGetCharABCWidths
3804 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
3805 LPABC buffer)
3807 UINT c;
3808 GLYPHMETRICS gm;
3809 FT_UInt glyph_index;
3810 GdiFont *linked_font;
3812 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3814 if(!FT_IS_SCALABLE(font->ft_face))
3815 return FALSE;
3817 for(c = firstChar; c <= lastChar; c++) {
3818 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3819 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3820 &gm, 0, NULL, NULL);
3821 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3822 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3823 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3824 linked_font->gm[glyph_index].bbx;
3826 return TRUE;
3829 /*************************************************************
3830 * WineEngGetCharABCWidthsI
3833 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
3834 LPABC buffer)
3836 UINT c;
3837 GLYPHMETRICS gm;
3838 FT_UInt glyph_index;
3839 GdiFont *linked_font;
3841 if(!FT_IS_SCALABLE(font->ft_face))
3842 return FALSE;
3844 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
3845 if (!pgi)
3846 for(c = firstChar; c < firstChar+count; c++) {
3847 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
3848 &gm, 0, NULL, NULL);
3849 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
3850 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
3851 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
3852 - linked_font->gm[c].bbx;
3854 else
3855 for(c = 0; c < count; c++) {
3856 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
3857 &gm, 0, NULL, NULL);
3858 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
3859 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
3860 buffer[c].abcC = linked_font->gm[pgi[c]].adv
3861 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
3864 return TRUE;
3867 /*************************************************************
3868 * WineEngGetTextExtentExPoint
3871 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
3872 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
3874 INT idx;
3875 INT nfit = 0, ext;
3876 GLYPHMETRICS gm;
3877 TEXTMETRICW tm;
3878 FT_UInt glyph_index;
3879 GdiFont *linked_font;
3881 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
3882 max_ext, size);
3884 size->cx = 0;
3885 WineEngGetTextMetrics(font, &tm);
3886 size->cy = tm.tmHeight;
3888 for(idx = 0; idx < count; idx++) {
3889 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3890 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3891 &gm, 0, NULL, NULL);
3892 size->cx += linked_font->gm[glyph_index].adv;
3893 ext = size->cx;
3894 if (! pnfit || ext <= max_ext) {
3895 ++nfit;
3896 if (dxs)
3897 dxs[idx] = ext;
3901 if (pnfit)
3902 *pnfit = nfit;
3904 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
3905 return TRUE;
3908 /*************************************************************
3909 * WineEngGetTextExtentPointI
3912 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
3913 LPSIZE size)
3915 INT idx;
3916 GLYPHMETRICS gm;
3917 TEXTMETRICW tm;
3919 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3921 size->cx = 0;
3922 WineEngGetTextMetrics(font, &tm);
3923 size->cy = tm.tmHeight;
3925 for(idx = 0; idx < count; idx++) {
3926 WineEngGetGlyphOutline(font, indices[idx],
3927 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3928 NULL);
3929 size->cx += font->gm[indices[idx]].adv;
3931 TRACE("return %d,%d\n", size->cx, size->cy);
3932 return TRUE;
3935 /*************************************************************
3936 * WineEngGetFontData
3939 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
3940 DWORD cbData)
3942 FT_Face ft_face = font->ft_face;
3943 FT_ULong len;
3944 FT_Error err;
3946 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
3947 font, table, offset, buf, cbData);
3949 if(!FT_IS_SFNT(ft_face))
3950 return GDI_ERROR;
3952 if(!buf || !cbData)
3953 len = 0;
3954 else
3955 len = cbData;
3957 if(table) { /* MS tags differ in endidness from FT ones */
3958 table = table >> 24 | table << 24 |
3959 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3962 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3963 if(pFT_Load_Sfnt_Table) {
3964 /* make sure value of len is the value freetype says it needs */
3965 if( buf && len) {
3966 FT_ULong needed = 0;
3967 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3968 if( !err && needed < len) len = needed;
3970 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3972 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3973 else { /* Do it the hard way */
3974 TT_Face tt_face = (TT_Face) ft_face;
3975 SFNT_Interface *sfnt;
3976 if (FT_Version.major==2 && FT_Version.minor==0)
3978 /* 2.0.x */
3979 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3981 else
3983 /* A field was added in the middle of the structure in 2.1.x */
3984 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3986 /* make sure value of len is the value freetype says it needs */
3987 if( buf && len) {
3988 FT_ULong needed = 0;
3989 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3990 if( !err && needed < len) len = needed;
3992 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3994 #else
3995 else {
3996 static int msg;
3997 if(!msg) {
3998 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3999 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4000 "Please upgrade your freetype library.\n");
4001 msg++;
4003 err = FT_Err_Unimplemented_Feature;
4005 #endif
4006 if(err) {
4007 TRACE("Can't find table %08x.\n", table);
4008 return GDI_ERROR;
4010 return len;
4013 /*************************************************************
4014 * WineEngGetTextFace
4017 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4019 if(str) {
4020 lstrcpynW(str, font->name, count);
4021 return strlenW(font->name);
4022 } else
4023 return strlenW(font->name) + 1;
4026 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4028 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4029 return font->charset;
4032 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4034 GdiFont *font = dc->gdiFont, *linked_font;
4035 struct list *first_hfont;
4036 BOOL ret;
4038 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4039 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4040 if(font == linked_font)
4041 *new_hfont = dc->hFont;
4042 else
4044 first_hfont = list_head(&linked_font->hfontlist);
4045 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4048 return ret;
4052 /*************************************************************
4053 * FontIsLinked
4055 BOOL WINAPI FontIsLinked(HDC hdc)
4057 DC *dc = DC_GetDCPtr(hdc);
4058 BOOL ret = FALSE;
4060 if(!dc) return FALSE;
4061 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4062 ret = TRUE;
4063 GDI_ReleaseObj(hdc);
4064 TRACE("returning %d\n", ret);
4065 return ret;
4068 static BOOL is_hinting_enabled(void)
4070 /* Use the >= 2.2.0 function if available */
4071 if(pFT_Get_TrueType_Engine_Type)
4073 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4074 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4076 #ifdef FT_DRIVER_HAS_HINTER
4077 else
4079 FT_Module mod;
4081 /* otherwise if we've been compiled with < 2.2.0 headers
4082 use the internal macro */
4083 mod = pFT_Get_Module(library, "truetype");
4084 if(mod && FT_DRIVER_HAS_HINTER(mod))
4085 return TRUE;
4087 #endif
4089 return FALSE;
4092 /*************************************************************************
4093 * GetRasterizerCaps (GDI32.@)
4095 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4097 static int hinting = -1;
4099 if(hinting == -1)
4100 hinting = is_hinting_enabled();
4102 lprs->nSize = sizeof(RASTERIZER_STATUS);
4103 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4104 lprs->nLanguageID = 0;
4105 return TRUE;
4108 /*************************************************************************
4109 * Kerning support for TrueType fonts
4111 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4113 struct TT_kern_table
4115 USHORT version;
4116 USHORT nTables;
4119 struct TT_kern_subtable
4121 USHORT version;
4122 USHORT length;
4123 union
4125 USHORT word;
4126 struct
4128 USHORT horizontal : 1;
4129 USHORT minimum : 1;
4130 USHORT cross_stream: 1;
4131 USHORT override : 1;
4132 USHORT reserved1 : 4;
4133 USHORT format : 8;
4134 } bits;
4135 } coverage;
4138 struct TT_format0_kern_subtable
4140 USHORT nPairs;
4141 USHORT searchRange;
4142 USHORT entrySelector;
4143 USHORT rangeShift;
4146 struct TT_kern_pair
4148 USHORT left;
4149 USHORT right;
4150 short value;
4153 static DWORD parse_format0_kern_subtable(GdiFont *font,
4154 const struct TT_format0_kern_subtable *tt_f0_ks,
4155 const USHORT *glyph_to_char,
4156 KERNINGPAIR *kern_pair, DWORD cPairs)
4158 USHORT i, nPairs;
4159 const struct TT_kern_pair *tt_kern_pair;
4161 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4163 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4165 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4166 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4167 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4169 if (!kern_pair || !cPairs)
4170 return nPairs;
4172 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4174 nPairs = min(nPairs, cPairs);
4176 for (i = 0; i < nPairs; i++)
4178 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4179 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4180 /* this algorithm appears to better match what Windows does */
4181 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4182 if (kern_pair->iKernAmount < 0)
4184 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4185 kern_pair->iKernAmount -= font->ppem;
4187 else if (kern_pair->iKernAmount > 0)
4189 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4190 kern_pair->iKernAmount += font->ppem;
4192 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4194 TRACE("left %u right %u value %d\n",
4195 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4197 kern_pair++;
4199 TRACE("copied %u entries\n", nPairs);
4200 return nPairs;
4203 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4205 DWORD length;
4206 void *buf;
4207 const struct TT_kern_table *tt_kern_table;
4208 const struct TT_kern_subtable *tt_kern_subtable;
4209 USHORT i, nTables;
4210 USHORT *glyph_to_char;
4212 if (font->total_kern_pairs != (DWORD)-1)
4214 if (cPairs && kern_pair)
4216 cPairs = min(cPairs, font->total_kern_pairs);
4217 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4218 return cPairs;
4220 return font->total_kern_pairs;
4223 font->total_kern_pairs = 0;
4225 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4227 if (length == GDI_ERROR)
4229 TRACE("no kerning data in the font\n");
4230 return 0;
4233 buf = HeapAlloc(GetProcessHeap(), 0, length);
4234 if (!buf)
4236 WARN("Out of memory\n");
4237 return 0;
4240 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4242 /* build a glyph index to char code map */
4243 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4244 if (!glyph_to_char)
4246 WARN("Out of memory allocating a glyph index to char code map\n");
4247 HeapFree(GetProcessHeap(), 0, buf);
4248 return 0;
4251 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4253 FT_UInt glyph_code;
4254 FT_ULong char_code;
4256 glyph_code = 0;
4257 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4259 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4260 font->ft_face->num_glyphs, glyph_code, char_code);
4262 while (glyph_code)
4264 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4266 /* FIXME: This doesn't match what Windows does: it does some fancy
4267 * things with duplicate glyph index to char code mappings, while
4268 * we just avoid overriding existing entries.
4270 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4271 glyph_to_char[glyph_code] = (USHORT)char_code;
4273 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4276 else
4278 ULONG n;
4280 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4281 for (n = 0; n <= 65535; n++)
4282 glyph_to_char[n] = (USHORT)n;
4285 tt_kern_table = buf;
4286 nTables = GET_BE_WORD(tt_kern_table->nTables);
4287 TRACE("version %u, nTables %u\n",
4288 GET_BE_WORD(tt_kern_table->version), nTables);
4290 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4292 for (i = 0; i < nTables; i++)
4294 struct TT_kern_subtable tt_kern_subtable_copy;
4296 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4297 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4298 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4300 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4301 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4302 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4304 /* According to the TrueType specification this is the only format
4305 * that will be properly interpreted by Windows and OS/2
4307 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4309 DWORD new_chunk, old_total = font->total_kern_pairs;
4311 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4312 glyph_to_char, NULL, 0);
4313 font->total_kern_pairs += new_chunk;
4315 if (!font->kern_pairs)
4316 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4317 font->total_kern_pairs * sizeof(*font->kern_pairs));
4318 else
4319 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4320 font->total_kern_pairs * sizeof(*font->kern_pairs));
4322 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4323 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4325 else
4326 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4328 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4331 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4332 HeapFree(GetProcessHeap(), 0, buf);
4334 if (cPairs && kern_pair)
4336 cPairs = min(cPairs, font->total_kern_pairs);
4337 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4338 return cPairs;
4340 return font->total_kern_pairs;
4343 #else /* HAVE_FREETYPE */
4345 /*************************************************************************/
4347 BOOL WineEngInit(void)
4349 return FALSE;
4351 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4353 return NULL;
4355 BOOL WineEngDestroyFontInstance(HFONT hfont)
4357 return FALSE;
4360 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4362 return 1;
4365 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4366 LPWORD pgi, DWORD flags)
4368 return GDI_ERROR;
4371 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4372 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4373 const MAT2* lpmat)
4375 ERR("called but we don't have FreeType\n");
4376 return GDI_ERROR;
4379 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4381 ERR("called but we don't have FreeType\n");
4382 return FALSE;
4385 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4386 OUTLINETEXTMETRICW *potm)
4388 ERR("called but we don't have FreeType\n");
4389 return 0;
4392 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4393 LPINT buffer)
4395 ERR("called but we don't have FreeType\n");
4396 return FALSE;
4399 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4400 LPABC buffer)
4402 ERR("called but we don't have FreeType\n");
4403 return FALSE;
4406 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4407 LPABC buffer)
4409 ERR("called but we don't have FreeType\n");
4410 return FALSE;
4413 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4414 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4416 ERR("called but we don't have FreeType\n");
4417 return FALSE;
4420 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4421 LPSIZE size)
4423 ERR("called but we don't have FreeType\n");
4424 return FALSE;
4427 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4428 DWORD cbData)
4430 ERR("called but we don't have FreeType\n");
4431 return GDI_ERROR;
4434 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4436 ERR("called but we don't have FreeType\n");
4437 return 0;
4440 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4442 FIXME(":stub\n");
4443 return 1;
4446 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4448 FIXME(":stub\n");
4449 return TRUE;
4452 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4454 FIXME(":stub\n");
4455 return DEFAULT_CHARSET;
4458 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4460 return FALSE;
4463 BOOL WINAPI FontIsLinked(HDC hdc)
4465 return FALSE;
4468 /*************************************************************************
4469 * GetRasterizerCaps (GDI32.@)
4471 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4473 lprs->nSize = sizeof(RASTERIZER_STATUS);
4474 lprs->wFlags = 0;
4475 lprs->nLanguageID = 0;
4476 return TRUE;
4479 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4481 ERR("called but we don't have FreeType\n");
4482 return 0;
4485 #endif /* HAVE_FREETYPE */