Fix an RPC server startup race introduced by me.
[wine/dcerpc.git] / dlls / gdi / freetype.c
blob3bedcc1e62d71ce6b641c91d751b8dbff744c9b2
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
30 #endif
31 #include <string.h>
32 #include <dirent.h>
33 #include <stdio.h>
34 #include <assert.h>
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winerror.h"
39 #include "winreg.h"
40 #include "wingdi.h"
41 #include "gdi.h"
42 #include "gdi_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(font);
49 #ifdef HAVE_FREETYPE
51 #ifdef HAVE_FT2BUILD_H
52 #include <ft2build.h>
53 #endif
54 #ifdef HAVE_FREETYPE_FREETYPE_H
55 #include <freetype/freetype.h>
56 #endif
57 #ifdef HAVE_FREETYPE_FTGLYPH_H
58 #include <freetype/ftglyph.h>
59 #endif
60 #ifdef HAVE_FREETYPE_TTTABLES_H
61 #include <freetype/tttables.h>
62 #endif
63 #ifdef HAVE_FREETYPE_FTSNAMES_H
64 #include <freetype/ftsnames.h>
65 #else
66 # ifdef HAVE_FREETYPE_FTNAMES_H
67 # include <freetype/ftnames.h>
68 # endif
69 #endif
70 #ifdef HAVE_FREETYPE_TTNAMEID_H
71 #include <freetype/ttnameid.h>
72 #endif
73 #ifdef HAVE_FREETYPE_FTOUTLN_H
74 #include <freetype/ftoutln.h>
75 #endif
76 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
77 #include <freetype/internal/sfnt.h>
78 #endif
79 #ifdef HAVE_FREETYPE_FTTRIGON_H
80 #include <freetype/fttrigon.h>
81 #endif
82 #ifdef HAVE_FREETYPE_FTWINFNT_H
83 #include <freetype/ftwinfnt.h>
84 #endif
86 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
88 #endif
90 static FT_Library library = 0;
91 typedef struct
93 FT_Int major;
94 FT_Int minor;
95 FT_Int patch;
96 } FT_Version_t;
97 static FT_Version_t FT_Version;
98 static DWORD FT_SimpleVersion;
100 static void *ft_handle = NULL;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
103 MAKE_FUNCPTR(FT_Vector_Unit);
104 MAKE_FUNCPTR(FT_Done_Face);
105 MAKE_FUNCPTR(FT_Get_Char_Index);
106 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
107 MAKE_FUNCPTR(FT_Init_FreeType);
108 MAKE_FUNCPTR(FT_Load_Glyph);
109 MAKE_FUNCPTR(FT_Matrix_Multiply);
110 MAKE_FUNCPTR(FT_MulFix);
111 MAKE_FUNCPTR(FT_New_Face);
112 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
113 MAKE_FUNCPTR(FT_Outline_Transform);
114 MAKE_FUNCPTR(FT_Outline_Translate);
115 MAKE_FUNCPTR(FT_Select_Charmap);
116 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
117 MAKE_FUNCPTR(FT_Vector_Transform);
118 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
119 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
120 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
121 #ifdef HAVE_FREETYPE_FTWINFNT_H
122 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
123 #endif
125 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
126 #include <fontconfig/fontconfig.h>
127 MAKE_FUNCPTR(FcConfigGetCurrent);
128 MAKE_FUNCPTR(FcFontList);
129 MAKE_FUNCPTR(FcFontSetDestroy);
130 MAKE_FUNCPTR(FcInit);
131 MAKE_FUNCPTR(FcObjectSetAdd);
132 MAKE_FUNCPTR(FcObjectSetCreate);
133 MAKE_FUNCPTR(FcObjectSetDestroy);
134 MAKE_FUNCPTR(FcPatternCreate);
135 MAKE_FUNCPTR(FcPatternDestroy);
136 MAKE_FUNCPTR(FcPatternGet);
137 #ifndef SONAME_LIBFONTCONFIG
138 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
139 #endif
140 #endif
142 #undef MAKE_FUNCPTR
144 #ifndef ft_encoding_none
145 #define FT_ENCODING_NONE ft_encoding_none
146 #endif
147 #ifndef ft_encoding_ms_symbol
148 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
149 #endif
150 #ifndef ft_encoding_unicode
151 #define FT_ENCODING_UNICODE ft_encoding_unicode
152 #endif
153 #ifndef ft_encoding_apple_roman
154 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
155 #endif
157 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
159 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
160 typedef struct {
161 FT_Short height;
162 FT_Short width;
163 FT_Pos size;
164 FT_Pos x_ppem;
165 FT_Pos y_ppem;
166 FT_Short internal_leading;
167 } Bitmap_Size;
169 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
170 So to let this compile on older versions of FreeType we'll define the
171 new structure here. */
172 typedef struct {
173 FT_Short height, width;
174 FT_Pos size, x_ppem, y_ppem;
175 } My_FT_Bitmap_Size;
177 typedef struct tagFace {
178 struct list entry;
179 WCHAR *StyleName;
180 char *file;
181 FT_Long face_index;
182 BOOL Italic;
183 BOOL Bold;
184 FONTSIGNATURE fs;
185 FT_Fixed font_version;
186 BOOL scalable;
187 Bitmap_Size size; /* set if face is a bitmap */
188 BOOL external; /* TRUE if we should manually add this font to the registry */
189 struct tagFamily *family;
190 } Face;
192 typedef struct tagFamily {
193 struct list entry;
194 WCHAR *FamilyName;
195 struct list faces;
196 } Family;
198 typedef struct {
199 GLYPHMETRICS gm;
200 INT adv; /* These three hold to widths of the unrotated chars */
201 INT lsb;
202 INT bbx;
203 BOOL init;
204 } GM;
206 typedef struct {
207 FLOAT eM11, eM12;
208 FLOAT eM21, eM22;
209 } FMAT2;
211 typedef struct {
212 DWORD hash;
213 LOGFONTW lf;
214 FMAT2 matrix;
215 } FONT_DESC;
217 typedef struct tagHFONTLIST {
218 struct list entry;
219 HFONT hfont;
220 } HFONTLIST;
222 struct tagGdiFont {
223 struct list entry;
224 FT_Face ft_face;
225 LPWSTR name;
226 int charset;
227 int codepage;
228 BOOL fake_italic;
229 BOOL fake_bold;
230 BYTE underline;
231 BYTE strikeout;
232 INT orientation;
233 GM *gm;
234 DWORD gmsize;
235 struct list hfontlist;
236 FONT_DESC font_desc;
237 LONG aveWidth;
238 SHORT yMax;
239 SHORT yMin;
240 OUTLINETEXTMETRICW *potm;
241 FONTSIGNATURE fs;
244 #define INIT_GM_SIZE 128
246 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
247 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
248 #define UNUSED_CACHE_SIZE 10
250 static struct list font_list = LIST_INIT(font_list);
252 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
253 'R','o','m','a','n','\0'};
254 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
255 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
257 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
258 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
259 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
260 'S','e','r','i','f','\0'};
261 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
262 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
264 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
265 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
266 'W','i','n','d','o','w','s','\\',
267 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
268 'F','o','n','t','s','\0'};
270 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
271 'W','i','n','d','o','w','s',' ','N','T','\\',
272 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
273 'F','o','n','t','s','\0'};
275 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
276 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
277 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
278 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
280 static const WCHAR *SystemFontValues[4] = {
281 System_Value,
282 OEMFont_Value,
283 FixedSys_Value,
284 NULL
287 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
288 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
290 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
291 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
292 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
293 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
294 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
295 'E','u','r','o','p','e','a','n','\0'};
296 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
297 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
298 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
299 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
300 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
301 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
302 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
303 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
304 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
305 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
306 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
307 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
309 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
310 WesternW, /*00*/
311 Central_EuropeanW,
312 CyrillicW,
313 GreekW,
314 TurkishW,
315 HebrewW,
316 ArabicW,
317 BalticW,
318 VietnameseW, /*08*/
319 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
320 ThaiW,
321 JapaneseW,
322 CHINESE_GB2312W,
323 HangulW,
324 CHINESE_BIG5W,
325 Hangul_Johab_W,
326 NULL, NULL, /*23*/
327 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
328 SymbolW /*31*/
331 typedef struct {
332 WCHAR *name;
333 INT charset;
334 } NameCs;
336 typedef struct tagFontSubst {
337 NameCs from;
338 NameCs to;
339 struct tagFontSubst *next;
340 } FontSubst;
342 static FontSubst *substlist = NULL;
343 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
345 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
348 /****************************************
349 * Notes on .fon files
351 * The fonts System, FixedSys and Terminal are special. There are typically multiple
352 * versions installed for different resolutions and codepages. Windows stores which one to use
353 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
354 * Key Meaning
355 * FIXEDFON.FON FixedSys
356 * FONTS.FON System
357 * OEMFONT.FON Terminal
358 * LogPixels Current dpi set by the display control panel applet
359 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
360 * also has a LogPixels value that appears to mirror this)
362 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
363 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
364 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
365 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
366 * so that makes sense.
368 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
369 * to be mapped into the registry on Windows 2000 at least).
370 * I have
371 * woafont=app850.fon
372 * ega80woa.fon=ega80850.fon
373 * ega40woa.fon=ega40850.fon
374 * cga80woa.fon=cga80850.fon
375 * cga40woa.fon=cga40850.fon
379 static inline BOOL is_win9x(void)
381 return GetVersion() & 0x80000000;
384 This function builds an FT_Fixed from a float. It puts the integer part
385 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
386 It fails if the integer part of the float number is greater than SHORT_MAX.
388 static inline FT_Fixed FT_FixedFromFloat(float f)
390 short value = f;
391 unsigned short fract = (f - value) * 0xFFFF;
392 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
396 This function builds an FT_Fixed from a FIXED. It simply put f.value
397 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
399 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
401 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
404 #define ADDFONT_EXTERNAL_FONT 0x01
405 #define ADDFONT_FORCE_BITMAP 0x02
406 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
408 FT_Face ft_face;
409 TT_OS2 *pOS2;
410 TT_Header *pHeader = NULL;
411 WCHAR *FamilyW, *StyleW;
412 DWORD len;
413 Family *family;
414 Face *face;
415 struct list *family_elem_ptr, *face_elem_ptr;
416 FT_Error err;
417 FT_Long face_index = 0, num_faces;
418 #ifdef HAVE_FREETYPE_FTWINFNT_H
419 FT_WinFNT_HeaderRec winfnt_header;
420 #endif
421 int i, bitmap_num;
423 do {
424 char *family_name = fake_family;
426 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
427 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
428 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
429 return FALSE;
432 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*/
433 pFT_Done_Face(ft_face);
434 return FALSE;
437 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
438 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
439 pFT_Done_Face(ft_face);
440 return FALSE;
443 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
444 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
445 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
446 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
447 "Skipping this font.\n", debugstr_a(file));
448 pFT_Done_Face(ft_face);
449 return FALSE;
452 if(!ft_face->family_name || !ft_face->style_name) {
453 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
454 pFT_Done_Face(ft_face);
455 return FALSE;
458 if(!family_name)
459 family_name = ft_face->family_name;
461 bitmap_num = 0;
462 do {
463 My_FT_Bitmap_Size *size = NULL;
465 if(!FT_IS_SCALABLE(ft_face))
466 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
468 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
469 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
470 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
472 family = NULL;
473 LIST_FOR_EACH(family_elem_ptr, &font_list) {
474 family = LIST_ENTRY(family_elem_ptr, Family, entry);
475 if(!strcmpW(family->FamilyName, FamilyW))
476 break;
477 family = NULL;
479 if(!family) {
480 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
481 family->FamilyName = FamilyW;
482 list_init(&family->faces);
483 list_add_tail(&font_list, &family->entry);
484 } else {
485 HeapFree(GetProcessHeap(), 0, FamilyW);
488 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
489 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
490 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
492 face_elem_ptr = list_head(&family->faces);
493 while(face_elem_ptr) {
494 face = LIST_ENTRY(face_elem_ptr, Face, entry);
495 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
496 if(!strcmpW(face->StyleName, StyleW) &&
497 (FT_IS_SCALABLE(ft_face) || (size->y_ppem == face->size.y_ppem))) {
498 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
499 debugstr_w(family->FamilyName), debugstr_w(StyleW),
500 face->font_version, pHeader ? pHeader->Font_Revision : 0);
502 if(fake_family) {
503 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
504 HeapFree(GetProcessHeap(), 0, StyleW);
505 pFT_Done_Face(ft_face);
506 return FALSE;
508 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
509 TRACE("Original font is newer so skipping this one\n");
510 HeapFree(GetProcessHeap(), 0, StyleW);
511 pFT_Done_Face(ft_face);
512 return FALSE;
513 } else {
514 TRACE("Replacing original with this one\n");
515 list_remove(&face->entry);
516 HeapFree(GetProcessHeap(), 0, face->file);
517 HeapFree(GetProcessHeap(), 0, face->StyleName);
518 HeapFree(GetProcessHeap(), 0, face);
519 break;
523 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
524 list_add_tail(&family->faces, &face->entry);
525 face->StyleName = StyleW;
526 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
527 strcpy(face->file, file);
528 face->face_index = face_index;
529 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
530 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
531 face->font_version = pHeader ? pHeader->Font_Revision : 0;
532 face->family = family;
533 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
535 if(FT_IS_SCALABLE(ft_face)) {
536 memset(&face->size, 0, sizeof(face->size));
537 face->scalable = TRUE;
538 } else {
539 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
540 size->height, size->width, size->size >> 6,
541 size->x_ppem >> 6, size->y_ppem >> 6);
542 face->size.height = size->height;
543 face->size.width = size->width;
544 face->size.size = size->size;
545 face->size.x_ppem = size->x_ppem;
546 face->size.y_ppem = size->y_ppem;
547 face->size.internal_leading = 0;
548 face->scalable = FALSE;
551 memset(&face->fs, 0, sizeof(face->fs));
553 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
554 if(pOS2) {
555 face->fs.fsCsb[0] = pOS2->ulCodePageRange1;
556 face->fs.fsCsb[1] = pOS2->ulCodePageRange2;
557 face->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
558 face->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
559 face->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
560 face->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
561 if(pOS2->version == 0) {
562 FT_UInt dummy;
564 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
565 face->fs.fsCsb[0] |= 1;
566 else
567 face->fs.fsCsb[0] |= 1L << 31;
570 #ifdef HAVE_FREETYPE_FTWINFNT_H
571 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
572 CHARSETINFO csi;
573 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
574 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
575 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
576 memcpy(&face->fs, &csi.fs, sizeof(csi.fs));
577 face->size.internal_leading = winfnt_header.internal_leading;
579 #endif
580 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
581 face->fs.fsCsb[0], face->fs.fsCsb[1],
582 face->fs.fsUsb[0], face->fs.fsUsb[1],
583 face->fs.fsUsb[2], face->fs.fsUsb[3]);
586 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
587 for(i = 0; i < ft_face->num_charmaps; i++) {
588 switch(ft_face->charmaps[i]->encoding) {
589 case FT_ENCODING_UNICODE:
590 case FT_ENCODING_APPLE_ROMAN:
591 face->fs.fsCsb[0] |= 1;
592 break;
593 case FT_ENCODING_MS_SYMBOL:
594 face->fs.fsCsb[0] |= 1L << 31;
595 break;
596 default:
597 break;
602 if(face->fs.fsCsb[0] & ~(1L << 31))
603 have_installed_roman_font = TRUE;
604 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
606 num_faces = ft_face->num_faces;
607 pFT_Done_Face(ft_face);
608 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
609 debugstr_w(StyleW));
610 } while(num_faces > ++face_index);
611 return TRUE;
614 static void DumpFontList(void)
616 Family *family;
617 Face *face;
618 struct list *family_elem_ptr, *face_elem_ptr;
620 LIST_FOR_EACH(family_elem_ptr, &font_list) {
621 family = LIST_ENTRY(family_elem_ptr, Family, entry);
622 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
623 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
624 face = LIST_ENTRY(face_elem_ptr, Face, entry);
625 TRACE("\t%s", debugstr_w(face->StyleName));
626 if(!face->scalable)
627 TRACE(" %ld", face->size.y_ppem >> 6);
628 TRACE("\n");
631 return;
634 static void DumpSubstList(void)
636 FontSubst *psub;
638 for(psub = substlist; psub; psub = psub->next)
639 if(psub->from.charset != -1 || psub->to.charset != -1)
640 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
641 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
642 else
643 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
644 debugstr_w(psub->to.name));
645 return;
648 static LPWSTR strdupW(LPWSTR p)
650 LPWSTR ret;
651 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
652 ret = HeapAlloc(GetProcessHeap(), 0, len);
653 memcpy(ret, p, len);
654 return ret;
657 static void split_subst_info(NameCs *nc, LPSTR str)
659 CHAR *p = strrchr(str, ',');
660 DWORD len;
662 nc->charset = -1;
663 if(p && *(p+1)) {
664 nc->charset = strtol(p+1, NULL, 10);
665 *p = '\0';
667 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
668 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
669 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
672 static void LoadSubstList(void)
674 FontSubst *psub, **ppsub;
675 HKEY hkey;
676 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
677 LPSTR value;
678 LPVOID data;
680 if(substlist) {
681 for(psub = substlist; psub;) {
682 FontSubst *ptmp;
683 HeapFree(GetProcessHeap(), 0, psub->to.name);
684 HeapFree(GetProcessHeap(), 0, psub->from.name);
685 ptmp = psub;
686 psub = psub->next;
687 HeapFree(GetProcessHeap(), 0, ptmp);
689 substlist = NULL;
692 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
693 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
694 &hkey) == ERROR_SUCCESS) {
696 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
697 &valuelen, &datalen, NULL, NULL);
699 valuelen++; /* returned value doesn't include room for '\0' */
700 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
701 data = HeapAlloc(GetProcessHeap(), 0, datalen);
703 dlen = datalen;
704 vlen = valuelen;
705 ppsub = &substlist;
706 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
707 &dlen) == ERROR_SUCCESS) {
708 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
710 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
711 (*ppsub)->next = NULL;
712 split_subst_info(&((*ppsub)->from), value);
713 split_subst_info(&((*ppsub)->to), data);
715 /* Win 2000 doesn't allow mapping between different charsets
716 or mapping of DEFAULT_CHARSET */
717 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
718 (*ppsub)->to.charset == DEFAULT_CHARSET) {
719 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
720 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
721 HeapFree(GetProcessHeap(), 0, *ppsub);
722 *ppsub = NULL;
723 } else {
724 ppsub = &((*ppsub)->next);
726 /* reset dlen and vlen */
727 dlen = datalen;
728 vlen = valuelen;
730 HeapFree(GetProcessHeap(), 0, data);
731 HeapFree(GetProcessHeap(), 0, value);
732 RegCloseKey(hkey);
736 /***********************************************************
737 * The replacement list is a way to map an entire font
738 * family onto another family. For example adding
740 * [HKLM\Software\Wine\Wine\FontReplacements]
741 * "Wingdings"="Winedings"
743 * would enumerate the Winedings font both as Winedings and
744 * Wingdings. However if a real Wingdings font is present the
745 * replacement does not take place.
748 static void LoadReplaceList(void)
750 HKEY hkey;
751 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
752 LPSTR value;
753 LPVOID data;
754 Family *family;
755 Face *face;
756 struct list *family_elem_ptr, *face_elem_ptr;
757 WCHAR old_nameW[200];
759 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
760 "Software\\Wine\\Wine\\FontReplacements",
761 &hkey) == ERROR_SUCCESS) {
763 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
764 &valuelen, &datalen, NULL, NULL);
766 valuelen++; /* returned value doesn't include room for '\0' */
767 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
768 data = HeapAlloc(GetProcessHeap(), 0, datalen);
770 dlen = datalen;
771 vlen = valuelen;
772 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
773 &dlen) == ERROR_SUCCESS) {
774 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
775 /* "NewName"="Oldname" */
776 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
777 break;
779 /* Find the old family and hence all of the font files
780 in that family */
781 LIST_FOR_EACH(family_elem_ptr, &font_list) {
782 family = LIST_ENTRY(family_elem_ptr, Family, entry);
783 if(!strcmpiW(family->FamilyName, old_nameW)) {
784 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
785 face = LIST_ENTRY(face_elem_ptr, Face, entry);
786 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
787 debugstr_w(face->StyleName), value);
788 /* Now add a new entry with the new family name */
789 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
791 break;
794 /* reset dlen and vlen */
795 dlen = datalen;
796 vlen = valuelen;
798 HeapFree(GetProcessHeap(), 0, data);
799 HeapFree(GetProcessHeap(), 0, value);
800 RegCloseKey(hkey);
805 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
807 DIR *dir;
808 struct dirent *dent;
809 char path[MAX_PATH];
811 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
813 dir = opendir(dirname);
814 if(!dir) {
815 ERR("Can't open directory %s\n", debugstr_a(dirname));
816 return FALSE;
818 while((dent = readdir(dir)) != NULL) {
819 struct stat statbuf;
821 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
822 continue;
824 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
826 sprintf(path, "%s/%s", dirname, dent->d_name);
828 if(stat(path, &statbuf) == -1)
830 WARN("Can't stat %s\n", debugstr_a(path));
831 continue;
833 if(S_ISDIR(statbuf.st_mode))
834 ReadFontDir(path, external_fonts);
835 else
836 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
838 closedir(dir);
839 return TRUE;
842 static void load_fontconfig_fonts(void)
844 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
845 void *fc_handle = NULL;
846 FcConfig *config;
847 FcPattern *pat;
848 FcObjectSet *os;
849 FcFontSet *fontset;
850 FcValue v;
851 int i, len;
852 const char *ext;
854 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
855 if(!fc_handle) {
856 TRACE("Wine cannot find the fontconfig library (%s).\n",
857 SONAME_LIBFONTCONFIG);
858 return;
860 #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;}
861 LOAD_FUNCPTR(FcConfigGetCurrent);
862 LOAD_FUNCPTR(FcFontList);
863 LOAD_FUNCPTR(FcFontSetDestroy);
864 LOAD_FUNCPTR(FcInit);
865 LOAD_FUNCPTR(FcObjectSetAdd);
866 LOAD_FUNCPTR(FcObjectSetCreate);
867 LOAD_FUNCPTR(FcObjectSetDestroy);
868 LOAD_FUNCPTR(FcPatternCreate);
869 LOAD_FUNCPTR(FcPatternDestroy);
870 LOAD_FUNCPTR(FcPatternGet);
871 #undef LOAD_FUNCPTR
873 if(!pFcInit()) return;
875 config = pFcConfigGetCurrent();
876 pat = pFcPatternCreate();
877 os = pFcObjectSetCreate();
878 pFcObjectSetAdd(os, FC_FILE);
879 fontset = pFcFontList(config, pat, os);
880 if(!fontset) return;
881 for(i = 0; i < fontset->nfont; i++) {
882 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
883 continue;
884 if(v.type != FcTypeString) continue;
885 TRACE("fontconfig: %s\n", v.u.s);
887 /* We're just interested in OT/TT fonts for now, so this hack just
888 picks up the standard extensions to save time loading every other
889 font */
890 len = strlen(v.u.s);
891 if(len < 4) continue;
892 ext = v.u.s + len - 3;
893 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
894 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
896 pFcFontSetDestroy(fontset);
897 pFcObjectSetDestroy(os);
898 pFcPatternDestroy(pat);
899 sym_not_found:
900 #endif
901 return;
905 static void load_system_fonts(void)
907 HKEY hkey;
908 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
909 const WCHAR **value;
910 DWORD dlen, type;
911 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
912 char *unixname;
914 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
915 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
916 strcatW(windowsdir, fontsW);
917 for(value = SystemFontValues; *value; value++) {
918 dlen = sizeof(data);
919 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
920 type == REG_SZ) {
921 sprintfW(pathW, fmtW, windowsdir, data);
922 if((unixname = wine_get_unix_file_name(pathW))) {
923 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
924 HeapFree(GetProcessHeap(), 0, unixname);
928 RegCloseKey(hkey);
932 /*************************************************************
934 * This adds registry entries for any externally loaded fonts
935 * (fonts from fontconfig or FontDirs). It also deletes entries
936 * of no longer existing fonts.
939 static void update_reg_entries(void)
941 HKEY winkey = 0, externalkey = 0;
942 LPWSTR valueW;
943 LPVOID data;
944 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
945 Family *family;
946 Face *face;
947 struct list *family_elem_ptr, *face_elem_ptr;
948 WCHAR *file;
949 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
950 static const WCHAR spaceW[] = {' ', '\0'};
951 char *path;
953 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
954 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
955 ERR("Can't create Windows font reg key\n");
956 goto end;
958 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
959 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
960 ERR("Can't create external font reg key\n");
961 goto end;
964 /* Delete all external fonts added last time */
966 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
967 &valuelen, &datalen, NULL, NULL);
968 valuelen++; /* returned value doesn't include room for '\0' */
969 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
970 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
972 dlen = datalen * sizeof(WCHAR);
973 vlen = valuelen;
974 i = 0;
975 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
976 &dlen) == ERROR_SUCCESS) {
978 RegDeleteValueW(winkey, valueW);
979 /* reset dlen and vlen */
980 dlen = datalen;
981 vlen = valuelen;
983 HeapFree(GetProcessHeap(), 0, data);
984 HeapFree(GetProcessHeap(), 0, valueW);
986 /* Delete the old external fonts key */
987 RegCloseKey(externalkey);
988 externalkey = 0;
989 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
991 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
992 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
993 ERR("Can't create external font reg key\n");
994 goto end;
997 /* enumerate the fonts and add external ones to the two keys */
999 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1000 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1001 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1002 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1003 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1004 if(!face->external) continue;
1005 len = len_fam;
1006 if(strcmpiW(face->StyleName, RegularW))
1007 len = len_fam + strlenW(face->StyleName) + 1;
1008 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1009 strcpyW(valueW, family->FamilyName);
1010 if(len != len_fam) {
1011 strcatW(valueW, spaceW);
1012 strcatW(valueW, face->StyleName);
1014 strcatW(valueW, TrueType);
1015 if((path = strrchr(face->file, '/')) == NULL)
1016 path = face->file;
1017 else
1018 path++;
1019 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1021 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1022 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1023 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1024 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1026 HeapFree(GetProcessHeap(), 0, file);
1027 HeapFree(GetProcessHeap(), 0, valueW);
1030 end:
1031 if(externalkey)
1032 RegCloseKey(externalkey);
1033 if(winkey)
1034 RegCloseKey(winkey);
1035 return;
1039 /*************************************************************
1040 * WineEngAddFontResourceEx
1043 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1045 if (ft_handle) /* do it only if we have freetype up and running */
1047 char *unixname;
1049 if(flags)
1050 FIXME("Ignoring flags %lx\n", flags);
1052 if((unixname = wine_get_unix_file_name(file)))
1054 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1055 HeapFree(GetProcessHeap(), 0, unixname);
1058 return 1;
1061 /*************************************************************
1062 * WineEngRemoveFontResourceEx
1065 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1067 FIXME(":stub\n");
1068 return TRUE;
1071 /*************************************************************
1072 * WineEngInit
1074 * Initialize FreeType library and create a list of available faces
1076 BOOL WineEngInit(void)
1078 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1079 HKEY hkey;
1080 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1081 LPVOID data;
1082 WCHAR windowsdir[MAX_PATH];
1083 char *unixname;
1084 HANDLE font_mutex;
1086 TRACE("\n");
1088 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1089 if(!ft_handle) {
1090 WINE_MESSAGE(
1091 "Wine cannot find the FreeType font library. To enable Wine to\n"
1092 "use TrueType fonts please install a version of FreeType greater than\n"
1093 "or equal to 2.0.5.\n"
1094 "http://www.freetype.org\n");
1095 return FALSE;
1098 #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;}
1100 LOAD_FUNCPTR(FT_Vector_Unit)
1101 LOAD_FUNCPTR(FT_Done_Face)
1102 LOAD_FUNCPTR(FT_Get_Char_Index)
1103 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1104 LOAD_FUNCPTR(FT_Init_FreeType)
1105 LOAD_FUNCPTR(FT_Load_Glyph)
1106 LOAD_FUNCPTR(FT_Matrix_Multiply)
1107 LOAD_FUNCPTR(FT_MulFix)
1108 LOAD_FUNCPTR(FT_New_Face)
1109 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1110 LOAD_FUNCPTR(FT_Outline_Transform)
1111 LOAD_FUNCPTR(FT_Outline_Translate)
1112 LOAD_FUNCPTR(FT_Select_Charmap)
1113 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1114 LOAD_FUNCPTR(FT_Vector_Transform)
1116 #undef LOAD_FUNCPTR
1117 /* Don't warn if this one is missing */
1118 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1119 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1120 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1121 #ifdef HAVE_FREETYPE_FTWINFNT_H
1122 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1123 #endif
1124 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1125 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1126 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1127 <= 2.0.3 has FT_Sqrt64 */
1128 goto sym_not_found;
1131 if(pFT_Init_FreeType(&library) != 0) {
1132 ERR("Can't init FreeType library\n");
1133 wine_dlclose(ft_handle, NULL, 0);
1134 ft_handle = NULL;
1135 return FALSE;
1137 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1138 if (pFT_Library_Version)
1140 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1142 if (FT_Version.major<=0)
1144 FT_Version.major=2;
1145 FT_Version.minor=0;
1146 FT_Version.patch=5;
1148 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1149 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1150 ((FT_Version.minor << 8) & 0x00ff00) |
1151 ((FT_Version.patch ) & 0x0000ff);
1153 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1154 ERR("Failed to create font mutex\n");
1155 return FALSE;
1157 WaitForSingleObject(font_mutex, INFINITE);
1159 /* load the system fonts */
1160 load_system_fonts();
1162 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1163 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1164 strcatW(windowsdir, fontsW);
1165 if((unixname = wine_get_unix_file_name(windowsdir)))
1167 ReadFontDir(unixname, FALSE);
1168 HeapFree(GetProcessHeap(), 0, unixname);
1171 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1172 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1173 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1174 will skip these. */
1175 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1176 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1177 &hkey) == ERROR_SUCCESS) {
1178 LPWSTR valueW;
1179 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1180 &valuelen, &datalen, NULL, NULL);
1182 valuelen++; /* returned value doesn't include room for '\0' */
1183 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1184 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1185 if (valueW && data)
1187 dlen = datalen * sizeof(WCHAR);
1188 vlen = valuelen;
1189 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1190 &dlen) == ERROR_SUCCESS) {
1191 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1193 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1195 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1196 HeapFree(GetProcessHeap(), 0, unixname);
1199 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1201 WCHAR pathW[MAX_PATH];
1202 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1203 sprintfW(pathW, fmtW, windowsdir, data);
1204 if((unixname = wine_get_unix_file_name(pathW)))
1206 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1207 HeapFree(GetProcessHeap(), 0, unixname);
1210 /* reset dlen and vlen */
1211 dlen = datalen;
1212 vlen = valuelen;
1215 HeapFree(GetProcessHeap(), 0, data);
1216 HeapFree(GetProcessHeap(), 0, valueW);
1217 RegCloseKey(hkey);
1220 load_fontconfig_fonts();
1222 /* then look in any directories that we've specified in the config file */
1223 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1224 "Software\\Wine\\Wine\\Config\\FontDirs",
1225 &hkey) == ERROR_SUCCESS) {
1226 LPSTR value;
1227 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1228 &valuelen, &datalen, NULL, NULL);
1230 valuelen++; /* returned value doesn't include room for '\0' */
1231 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1232 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1234 dlen = datalen;
1235 vlen = valuelen;
1236 i = 0;
1237 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1238 &dlen) == ERROR_SUCCESS) {
1239 TRACE("Got %s=%s\n", value, (LPSTR)data);
1240 ReadFontDir((LPSTR)data, TRUE);
1241 /* reset dlen and vlen */
1242 dlen = datalen;
1243 vlen = valuelen;
1245 HeapFree(GetProcessHeap(), 0, data);
1246 HeapFree(GetProcessHeap(), 0, value);
1247 RegCloseKey(hkey);
1250 DumpFontList();
1251 LoadSubstList();
1252 DumpSubstList();
1253 LoadReplaceList();
1254 update_reg_entries();
1256 ReleaseMutex(font_mutex);
1257 return TRUE;
1258 sym_not_found:
1259 WINE_MESSAGE(
1260 "Wine cannot find certain functions that it needs inside the FreeType\n"
1261 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1262 "FreeType to at least version 2.0.5.\n"
1263 "http://www.freetype.org\n");
1264 wine_dlclose(ft_handle, NULL, 0);
1265 ft_handle = NULL;
1266 return FALSE;
1270 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1272 TT_OS2 *pOS2;
1273 TT_HoriHeader *pHori;
1275 LONG ppem;
1277 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1278 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1280 if(height == 0) height = 16;
1282 /* Calc. height of EM square:
1284 * For +ve lfHeight we have
1285 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1286 * Re-arranging gives:
1287 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1289 * For -ve lfHeight we have
1290 * |lfHeight| = ppem
1291 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1292 * with il = winAscent + winDescent - units_per_em]
1296 if(height > 0) {
1297 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1298 ppem = ft_face->units_per_EM * height /
1299 (pHori->Ascender - pHori->Descender);
1300 else
1301 ppem = ft_face->units_per_EM * height /
1302 (pOS2->usWinAscent + pOS2->usWinDescent);
1304 else
1305 ppem = -height;
1307 return ppem;
1310 static LONG load_VDMX(GdiFont, LONG);
1312 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1314 FT_Error err;
1315 FT_Face ft_face;
1316 LONG ppem;
1318 err = pFT_New_Face(library, file, face_index, &ft_face);
1319 if(err) {
1320 ERR("FT_New_Face rets %d\n", err);
1321 return 0;
1324 /* set it here, as load_VDMX needs it */
1325 font->ft_face = ft_face;
1327 if(FT_IS_SCALABLE(ft_face)) {
1328 /* load the VDMX table if we have one */
1329 ppem = load_VDMX(font, height);
1330 if(ppem == 0)
1331 ppem = calc_ppem_for_height(ft_face, height);
1333 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1334 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1335 } else {
1336 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1337 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1339 return ft_face;
1343 static int get_nearest_charset(Face *face, int *cp)
1345 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1346 a single face with the requested charset. The idea is to check if
1347 the selected font supports the current ANSI codepage, if it does
1348 return the corresponding charset, else return the first charset */
1350 CHARSETINFO csi;
1351 int acp = GetACP(), i;
1352 DWORD fs0;
1354 *cp = acp;
1355 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1356 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1357 return csi.ciCharset;
1359 for(i = 0; i < 32; i++) {
1360 fs0 = 1L << i;
1361 if(face->fs.fsCsb[0] & fs0) {
1362 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1363 *cp = csi.ciACP;
1364 return csi.ciCharset;
1366 else
1367 FIXME("TCI failing on %lx\n", fs0);
1371 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1372 face->fs.fsCsb[0], face->file);
1373 *cp = acp;
1374 return DEFAULT_CHARSET;
1377 static GdiFont alloc_font(void)
1379 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1380 ret->gmsize = INIT_GM_SIZE;
1381 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1382 ret->gmsize * sizeof(*ret->gm));
1383 ret->potm = NULL;
1384 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1385 list_init(&ret->hfontlist);
1386 return ret;
1389 static void free_font(GdiFont font)
1391 if (font->ft_face) pFT_Done_Face(font->ft_face);
1392 HeapFree(GetProcessHeap(), 0, font->potm);
1393 HeapFree(GetProcessHeap(), 0, font->name);
1394 HeapFree(GetProcessHeap(), 0, font->gm);
1395 HeapFree(GetProcessHeap(), 0, font);
1399 /*************************************************************
1400 * load_VDMX
1402 * load the vdmx entry for the specified height
1405 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1406 ( ( (FT_ULong)_x4 << 24 ) | \
1407 ( (FT_ULong)_x3 << 16 ) | \
1408 ( (FT_ULong)_x2 << 8 ) | \
1409 (FT_ULong)_x1 )
1411 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1413 typedef struct {
1414 BYTE bCharSet;
1415 BYTE xRatio;
1416 BYTE yStartRatio;
1417 BYTE yEndRatio;
1418 } Ratios;
1421 static LONG load_VDMX(GdiFont font, LONG height)
1423 BYTE hdr[6], tmp[2], group[4];
1424 BYTE devXRatio, devYRatio;
1425 USHORT numRecs, numRatios;
1426 DWORD result, offset = -1;
1427 LONG ppem = 0;
1428 int i;
1430 /* For documentation on VDMX records, see
1431 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1434 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1436 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1437 return ppem;
1439 /* FIXME: need the real device aspect ratio */
1440 devXRatio = 1;
1441 devYRatio = 1;
1443 numRecs = GET_BE_WORD(&hdr[2]);
1444 numRatios = GET_BE_WORD(&hdr[4]);
1446 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1447 for(i = 0; i < numRatios; i++) {
1448 Ratios ratio;
1450 offset = (3 * 2) + (i * sizeof(Ratios));
1451 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1452 offset = -1;
1454 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1456 if((ratio.xRatio == 0 &&
1457 ratio.yStartRatio == 0 &&
1458 ratio.yEndRatio == 0) ||
1459 (devXRatio == ratio.xRatio &&
1460 devYRatio >= ratio.yStartRatio &&
1461 devYRatio <= ratio.yEndRatio))
1463 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1464 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1465 offset = GET_BE_WORD(tmp);
1466 break;
1470 if(offset == -1) {
1471 FIXME("No suitable ratio found\n");
1472 return ppem;
1475 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1476 USHORT recs;
1477 BYTE startsz, endsz;
1478 BYTE *vTable;
1480 recs = GET_BE_WORD(group);
1481 startsz = group[2];
1482 endsz = group[3];
1484 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1486 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1487 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1488 if(result == GDI_ERROR) {
1489 FIXME("Failed to retrieve vTable\n");
1490 goto end;
1493 if(height > 0) {
1494 for(i = 0; i < recs; i++) {
1495 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1496 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1497 ppem = GET_BE_WORD(&vTable[i * 6]);
1499 if(yMax + -yMin == height) {
1500 font->yMax = yMax;
1501 font->yMin = yMin;
1502 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1503 break;
1505 if(yMax + -yMin > height) {
1506 if(--i < 0) {
1507 ppem = 0;
1508 goto end; /* failed */
1510 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1511 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1512 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1513 break;
1516 if(!font->yMax) {
1517 ppem = 0;
1518 TRACE("ppem not found for height %ld\n", height);
1520 } else {
1521 ppem = -height;
1522 if(ppem < startsz || ppem > endsz)
1523 goto end;
1525 for(i = 0; i < recs; i++) {
1526 USHORT yPelHeight;
1527 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1529 if(yPelHeight > ppem)
1530 break; /* failed */
1532 if(yPelHeight == ppem) {
1533 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1534 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1535 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1536 break;
1540 end:
1541 HeapFree(GetProcessHeap(), 0, vTable);
1544 return ppem;
1547 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1549 if(font->font_desc.hash != fd->hash) return TRUE;
1550 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1551 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1552 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1555 static void calc_hash(FONT_DESC *pfd)
1557 DWORD hash = 0, *ptr, two_chars;
1558 WORD *pwc;
1559 unsigned int i;
1561 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1562 hash ^= *ptr;
1563 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1564 hash ^= *ptr;
1565 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1566 two_chars = *ptr;
1567 pwc = (WCHAR *)&two_chars;
1568 if(!*pwc) break;
1569 *pwc = toupperW(*pwc);
1570 pwc++;
1571 *pwc = toupperW(*pwc);
1572 hash ^= two_chars;
1573 if(!*pwc) break;
1575 pfd->hash = hash;
1576 return;
1579 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1581 GdiFont ret;
1582 FONT_DESC fd;
1583 HFONTLIST *hflist;
1584 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1586 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1587 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1588 calc_hash(&fd);
1590 /* try the in-use list */
1591 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1592 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1593 if(!fontcmp(ret, &fd)) {
1594 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1595 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1596 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1597 if(hflist->hfont == hfont)
1598 return ret;
1600 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1601 hflist->hfont = hfont;
1602 list_add_head(&ret->hfontlist, &hflist->entry);
1603 return ret;
1607 /* then the unused list */
1608 font_elem_ptr = list_head(&unused_gdi_font_list);
1609 while(font_elem_ptr) {
1610 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1611 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1612 if(!fontcmp(ret, &fd)) {
1613 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1614 assert(list_empty(&ret->hfontlist));
1615 TRACE("Found %p in unused list\n", ret);
1616 list_remove(&ret->entry);
1617 list_add_head(&gdi_font_list, &ret->entry);
1618 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1619 hflist->hfont = hfont;
1620 list_add_head(&ret->hfontlist, &hflist->entry);
1621 return ret;
1624 return NULL;
1627 /*************************************************************
1628 * WineEngCreateFontInstance
1631 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1633 GdiFont ret;
1634 Face *face, *best;
1635 Family *family;
1636 struct list *family_elem_ptr, *face_elem_ptr;
1637 INT height, width = 0;
1638 signed int diff = 0, newdiff;
1639 BOOL bd, it, can_use_bitmap;
1640 LOGFONTW lf;
1641 CHARSETINFO csi;
1642 HFONTLIST *hflist;
1644 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1645 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1647 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1648 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1649 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1650 lf.lfEscapement);
1652 /* check the cache first */
1653 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1654 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1655 return ret;
1658 TRACE("not in cache\n");
1659 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1661 TRACE("No fonts installed\n");
1662 return NULL;
1665 ret = alloc_font();
1667 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1668 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1669 calc_hash(&ret->font_desc);
1670 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1671 hflist->hfont = hfont;
1672 list_add_head(&ret->hfontlist, &hflist->entry);
1675 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1676 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1677 original value lfCharSet. Note this is a special case for
1678 Symbol and doesn't happen at least for "Wingdings*" */
1680 if(!strcmpiW(lf.lfFaceName, SymbolW))
1681 lf.lfCharSet = SYMBOL_CHARSET;
1683 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1684 switch(lf.lfCharSet) {
1685 case DEFAULT_CHARSET:
1686 csi.fs.fsCsb[0] = 0;
1687 break;
1688 default:
1689 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1690 csi.fs.fsCsb[0] = 0;
1691 break;
1695 family = NULL;
1696 if(lf.lfFaceName[0] != '\0') {
1697 FontSubst *psub;
1698 for(psub = substlist; psub; psub = psub->next)
1699 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1700 (psub->from.charset == -1 ||
1701 psub->from.charset == lf.lfCharSet))
1702 break;
1703 if(psub) {
1704 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1705 debugstr_w(psub->to.name));
1706 strcpyW(lf.lfFaceName, psub->to.name);
1709 /* We want a match on name and charset or just name if
1710 charset was DEFAULT_CHARSET. If the latter then
1711 we fixup the returned charset later in get_nearest_charset
1712 where we'll either use the charset of the current ansi codepage
1713 or if that's unavailable the first charset that the font supports.
1715 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1716 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1717 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1718 face_elem_ptr = list_head(&family->faces);
1719 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1720 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1721 if(face->scalable || can_use_bitmap)
1722 break;
1724 family = NULL;
1728 if(!family) {
1729 /* If requested charset was DEFAULT_CHARSET then try using charset
1730 corresponding to the current ansi codepage */
1731 if(!csi.fs.fsCsb[0]) {
1732 INT acp = GetACP();
1733 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1734 FIXME("TCI failed on codepage %d\n", acp);
1735 csi.fs.fsCsb[0] = 0;
1736 } else
1737 lf.lfCharSet = csi.ciCharset;
1740 /* Face families are in the top 4 bits of lfPitchAndFamily,
1741 so mask with 0xF0 before testing */
1743 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1744 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1745 strcpyW(lf.lfFaceName, defFixed);
1746 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1747 strcpyW(lf.lfFaceName, defSerif);
1748 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1749 strcpyW(lf.lfFaceName, defSans);
1750 else
1751 strcpyW(lf.lfFaceName, defSans);
1752 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1753 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1754 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1755 face_elem_ptr = list_head(&family->faces);
1756 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1757 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1758 if(face->scalable || can_use_bitmap)
1759 break;
1761 family = NULL;
1765 if(!family) {
1766 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1767 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1768 face_elem_ptr = list_head(&family->faces);
1769 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1770 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1771 if(face->scalable || can_use_bitmap)
1772 break;
1773 family = NULL;
1777 if(!family) {
1778 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1779 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1780 face_elem_ptr = list_head(&family->faces);
1781 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1782 if(face->scalable || can_use_bitmap) {
1783 csi.fs.fsCsb[0] = 0;
1784 FIXME("just using first face for now\n");
1785 break;
1787 family = NULL;
1789 if(!family) {
1790 FIXME("can't find a single appropriate font - bailing\n");
1791 free_font(ret);
1792 return NULL;
1796 it = lf.lfItalic ? 1 : 0;
1797 bd = lf.lfWeight > 550 ? 1 : 0;
1799 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1800 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1802 face = best = NULL;
1803 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1804 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1805 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1806 if(face->scalable)
1807 break;
1808 if(height > 0)
1809 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1810 else
1811 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1812 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1813 (diff < 0 && newdiff > diff)) {
1814 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1815 diff = newdiff;
1816 best = face;
1817 if(diff == 0)
1818 break;
1821 face = NULL;
1823 if(!face && best)
1824 face = best;
1825 else if(!face) {
1826 best = NULL;
1827 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1828 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1829 if(face->scalable)
1830 break;
1831 if(height > 0)
1832 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1833 else
1834 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1835 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1836 (diff < 0 && newdiff > diff)) {
1837 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1838 diff = newdiff;
1839 best = face;
1840 if(diff == 0)
1841 break;
1843 face = NULL;
1845 if(!face && best)
1846 face = best;
1847 if(it && !face->Italic) ret->fake_italic = TRUE;
1848 if(bd && !face->Bold) ret->fake_bold = TRUE;
1851 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1853 if(csi.fs.fsCsb[0]) {
1854 ret->charset = lf.lfCharSet;
1855 ret->codepage = csi.ciACP;
1857 else
1858 ret->charset = get_nearest_charset(face, &ret->codepage);
1860 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1861 debugstr_w(face->StyleName));
1863 if(!face->scalable) {
1864 width = face->size.x_ppem >> 6;
1865 height = face->size.y_ppem >> 6;
1867 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1869 if (!ret->ft_face)
1871 free_font( ret );
1872 return 0;
1875 if (ret->charset == SYMBOL_CHARSET &&
1876 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
1877 /* No ops */
1879 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
1880 /* No ops */
1882 else {
1883 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
1886 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1887 ret->name = strdupW(family->FamilyName);
1888 ret->underline = lf.lfUnderline ? 0xff : 0;
1889 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1891 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1893 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1894 list_add_head(&gdi_font_list, &ret->entry);
1895 return ret;
1898 static void dump_gdi_font_list(void)
1900 GdiFont gdiFont;
1901 struct list *elem_ptr;
1903 TRACE("---------- gdiFont Cache ----------\n");
1904 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1905 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1906 TRACE("gdiFont=%p %s %ld\n",
1907 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1910 TRACE("---------- Unused gdiFont Cache ----------\n");
1911 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1912 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1913 TRACE("gdiFont=%p %s %ld\n",
1914 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1918 /*************************************************************
1919 * WineEngDestroyFontInstance
1921 * free the gdiFont associated with this handle
1924 BOOL WineEngDestroyFontInstance(HFONT handle)
1926 GdiFont gdiFont;
1927 HFONTLIST *hflist;
1928 BOOL ret = FALSE;
1929 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1930 int i = 0;
1932 TRACE("destroying hfont=%p\n", handle);
1933 if(TRACE_ON(font))
1934 dump_gdi_font_list();
1936 font_elem_ptr = list_head(&gdi_font_list);
1937 while(font_elem_ptr) {
1938 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1939 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1941 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1942 while(hfontlist_elem_ptr) {
1943 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1944 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1945 if(hflist->hfont == handle) {
1946 list_remove(&hflist->entry);
1947 HeapFree(GetProcessHeap(), 0, hflist);
1948 ret = TRUE;
1951 if(list_empty(&gdiFont->hfontlist)) {
1952 TRACE("Moving to Unused list\n");
1953 list_remove(&gdiFont->entry);
1954 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1959 font_elem_ptr = list_head(&unused_gdi_font_list);
1960 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1961 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1962 while(font_elem_ptr) {
1963 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1964 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1965 TRACE("freeing %p\n", gdiFont);
1966 list_remove(&gdiFont->entry);
1967 free_font(gdiFont);
1969 return ret;
1972 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1973 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1975 OUTLINETEXTMETRICW *potm = NULL;
1976 UINT size;
1977 TEXTMETRICW tm, *ptm;
1978 GdiFont font = alloc_font();
1979 LONG width, height;
1981 if(face->scalable) {
1982 height = 100;
1983 width = 0;
1984 } else {
1985 height = face->size.y_ppem >> 6;
1986 width = face->size.x_ppem >> 6;
1989 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1991 free_font(font);
1992 return;
1995 font->name = strdupW(face->family->FamilyName);
1997 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1999 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2000 if(size) {
2001 potm = HeapAlloc(GetProcessHeap(), 0, size);
2002 WineEngGetOutlineTextMetrics(font, size, potm);
2003 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2004 } else {
2005 WineEngGetTextMetrics(font, &tm);
2006 ptm = &tm;
2009 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2010 pntm->ntmTm.tmAscent = ptm->tmAscent;
2011 pntm->ntmTm.tmDescent = ptm->tmDescent;
2012 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2013 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2014 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2015 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2016 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2017 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2018 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2019 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2020 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2021 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2022 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2023 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2024 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2025 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2026 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2027 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2028 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2029 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2030 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2031 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2032 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2034 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2035 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2036 *ptype |= RASTER_FONTTYPE;
2038 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2039 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2040 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2042 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2043 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2044 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2046 if(potm) {
2047 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2049 lstrcpynW(pelf->elfLogFont.lfFaceName,
2050 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2051 LF_FACESIZE);
2052 lstrcpynW(pelf->elfFullName,
2053 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2054 LF_FULLFACESIZE);
2055 lstrcpynW(pelf->elfStyle,
2056 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2057 LF_FACESIZE);
2059 HeapFree(GetProcessHeap(), 0, potm);
2060 } else {
2061 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2063 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2064 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2065 pelf->elfStyle[0] = '\0';
2068 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2070 free_font(font);
2073 /*************************************************************
2074 * WineEngEnumFonts
2077 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2079 Family *family;
2080 Face *face;
2081 struct list *family_elem_ptr, *face_elem_ptr;
2082 ENUMLOGFONTEXW elf;
2083 NEWTEXTMETRICEXW ntm;
2084 DWORD type, ret = 1;
2085 FONTSIGNATURE fs;
2086 CHARSETINFO csi;
2087 LOGFONTW lf;
2088 int i;
2090 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2092 if(plf->lfFaceName[0]) {
2093 FontSubst *psub;
2094 for(psub = substlist; psub; psub = psub->next)
2095 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2096 (psub->from.charset == -1 ||
2097 psub->from.charset == plf->lfCharSet))
2098 break;
2099 if(psub) {
2100 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2101 debugstr_w(psub->to.name));
2102 memcpy(&lf, plf, sizeof(lf));
2103 strcpyW(lf.lfFaceName, psub->to.name);
2104 plf = &lf;
2107 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2108 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2109 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2110 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2111 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2112 GetEnumStructs(face, &elf, &ntm, &type);
2113 for(i = 0; i < 32; i++) {
2114 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2115 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2116 strcpyW(elf.elfScript, OEM_DOSW);
2117 i = 32; /* break out of loop */
2118 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2119 continue;
2120 else {
2121 fs.fsCsb[0] = 1L << i;
2122 fs.fsCsb[1] = 0;
2123 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2124 TCI_SRCFONTSIG))
2125 csi.ciCharset = DEFAULT_CHARSET;
2126 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2127 if(csi.ciCharset != DEFAULT_CHARSET) {
2128 elf.elfLogFont.lfCharSet =
2129 ntm.ntmTm.tmCharSet = csi.ciCharset;
2130 if(ElfScriptsW[i])
2131 strcpyW(elf.elfScript, ElfScriptsW[i]);
2132 else
2133 FIXME("Unknown elfscript for bit %d\n", i);
2136 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2137 debugstr_w(elf.elfLogFont.lfFaceName),
2138 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2139 csi.ciCharset, type, debugstr_w(elf.elfScript),
2140 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2141 ntm.ntmTm.ntmFlags);
2142 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2143 if(!ret) goto end;
2148 } else {
2149 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2150 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2151 face_elem_ptr = list_head(&family->faces);
2152 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2153 GetEnumStructs(face, &elf, &ntm, &type);
2154 for(i = 0; i < 32; i++) {
2155 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2156 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2157 strcpyW(elf.elfScript, OEM_DOSW);
2158 i = 32; /* break out of loop */
2159 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2160 continue;
2161 else {
2162 fs.fsCsb[0] = 1L << i;
2163 fs.fsCsb[1] = 0;
2164 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2165 TCI_SRCFONTSIG))
2166 csi.ciCharset = DEFAULT_CHARSET;
2167 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2168 if(csi.ciCharset != DEFAULT_CHARSET) {
2169 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2170 csi.ciCharset;
2171 if(ElfScriptsW[i])
2172 strcpyW(elf.elfScript, ElfScriptsW[i]);
2173 else
2174 FIXME("Unknown elfscript for bit %d\n", i);
2177 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2178 debugstr_w(elf.elfLogFont.lfFaceName),
2179 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2180 csi.ciCharset, type, debugstr_w(elf.elfScript),
2181 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2182 ntm.ntmTm.ntmFlags);
2183 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2184 if(!ret) goto end;
2188 end:
2189 return ret;
2192 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2194 pt->x.value = vec->x >> 6;
2195 pt->x.fract = (vec->x & 0x3f) << 10;
2196 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2197 pt->y.value = vec->y >> 6;
2198 pt->y.fract = (vec->y & 0x3f) << 10;
2199 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2200 return;
2203 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2205 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2206 WCHAR wc = (WCHAR)glyph;
2207 unsigned char buf;
2208 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2209 return pFT_Get_Char_Index(font->ft_face, buf);
2212 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2213 glyph = glyph + 0xf000;
2214 return pFT_Get_Char_Index(font->ft_face, glyph);
2217 /*************************************************************
2218 * WineEngGetGlyphIndices
2220 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2222 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2223 LPWORD pgi, DWORD flags)
2225 INT i;
2227 for(i = 0; i < count; i++)
2228 pgi[i] = get_glyph_index(font, lpstr[i]);
2230 return count;
2233 /*************************************************************
2234 * WineEngGetGlyphOutline
2236 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2237 * except that the first parameter is the HWINEENGFONT of the font in
2238 * question rather than an HDC.
2241 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2242 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2243 const MAT2* lpmat)
2245 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2246 FT_Face ft_face = font->ft_face;
2247 FT_UInt glyph_index;
2248 DWORD width, height, pitch, needed = 0;
2249 FT_Bitmap ft_bitmap;
2250 FT_Error err;
2251 INT left, right, top = 0, bottom = 0;
2252 FT_Angle angle = 0;
2253 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2254 float widthRatio = 1.0;
2255 FT_Matrix transMat = identityMat;
2256 BOOL needsTransform = FALSE;
2259 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2260 buflen, buf, lpmat);
2262 if(format & GGO_GLYPH_INDEX) {
2263 glyph_index = glyph;
2264 format &= ~GGO_GLYPH_INDEX;
2265 } else
2266 glyph_index = get_glyph_index(font, glyph);
2268 if(glyph_index >= font->gmsize) {
2269 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2270 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2271 font->gmsize * sizeof(*font->gm));
2272 } else {
2273 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2274 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2275 return 1; /* FIXME */
2279 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2280 load_flags |= FT_LOAD_NO_BITMAP;
2282 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2284 if(err) {
2285 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2286 return GDI_ERROR;
2289 /* Scaling factor */
2290 if (font->aveWidth && font->potm) {
2291 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2294 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2295 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2297 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2298 font->gm[glyph_index].lsb = left >> 6;
2299 font->gm[glyph_index].bbx = (right - left) >> 6;
2301 /* Scaling transform */
2302 if(font->aveWidth) {
2303 FT_Matrix scaleMat;
2304 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2305 scaleMat.xy = 0;
2306 scaleMat.yx = 0;
2307 scaleMat.yy = (1 << 16);
2309 pFT_Matrix_Multiply(&scaleMat, &transMat);
2310 needsTransform = TRUE;
2313 /* Rotation transform */
2314 if(font->orientation) {
2315 FT_Matrix rotationMat;
2316 FT_Vector vecAngle;
2317 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2318 pFT_Vector_Unit(&vecAngle, angle);
2319 rotationMat.xx = vecAngle.x;
2320 rotationMat.xy = -vecAngle.y;
2321 rotationMat.yx = -rotationMat.xy;
2322 rotationMat.yy = rotationMat.xx;
2324 pFT_Matrix_Multiply(&rotationMat, &transMat);
2325 needsTransform = TRUE;
2328 /* Extra transformation specified by caller */
2329 if (lpmat) {
2330 FT_Matrix extraMat;
2331 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2332 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2333 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2334 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2335 pFT_Matrix_Multiply(&extraMat, &transMat);
2336 needsTransform = TRUE;
2339 if(!needsTransform) {
2340 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2341 bottom = (ft_face->glyph->metrics.horiBearingY -
2342 ft_face->glyph->metrics.height) & -64;
2343 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2344 lpgm->gmCellIncY = 0;
2345 } else {
2346 INT xc, yc;
2347 FT_Vector vec;
2348 for(xc = 0; xc < 2; xc++) {
2349 for(yc = 0; yc < 2; yc++) {
2350 vec.x = (ft_face->glyph->metrics.horiBearingX +
2351 xc * ft_face->glyph->metrics.width);
2352 vec.y = ft_face->glyph->metrics.horiBearingY -
2353 yc * ft_face->glyph->metrics.height;
2354 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2355 pFT_Vector_Transform(&vec, &transMat);
2356 if(xc == 0 && yc == 0) {
2357 left = right = vec.x;
2358 top = bottom = vec.y;
2359 } else {
2360 if(vec.x < left) left = vec.x;
2361 else if(vec.x > right) right = vec.x;
2362 if(vec.y < bottom) bottom = vec.y;
2363 else if(vec.y > top) top = vec.y;
2367 left = left & -64;
2368 right = (right + 63) & -64;
2369 bottom = bottom & -64;
2370 top = (top + 63) & -64;
2372 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2373 vec.x = ft_face->glyph->metrics.horiAdvance;
2374 vec.y = 0;
2375 pFT_Vector_Transform(&vec, &transMat);
2376 lpgm->gmCellIncX = (vec.x+63) >> 6;
2377 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2379 lpgm->gmBlackBoxX = (right - left) >> 6;
2380 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2381 lpgm->gmptGlyphOrigin.x = left >> 6;
2382 lpgm->gmptGlyphOrigin.y = top >> 6;
2384 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2385 font->gm[glyph_index].init = TRUE;
2387 if(format == GGO_METRICS)
2388 return 1; /* FIXME */
2390 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2391 TRACE("loaded a bitmap\n");
2392 return GDI_ERROR;
2395 switch(format) {
2396 case GGO_BITMAP:
2397 width = lpgm->gmBlackBoxX;
2398 height = lpgm->gmBlackBoxY;
2399 pitch = ((width + 31) >> 5) << 2;
2400 needed = pitch * height;
2402 if(!buf || !buflen) break;
2404 switch(ft_face->glyph->format) {
2405 case ft_glyph_format_bitmap:
2407 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2408 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2409 INT h = ft_face->glyph->bitmap.rows;
2410 while(h--) {
2411 memcpy(dst, src, w);
2412 src += ft_face->glyph->bitmap.pitch;
2413 dst += pitch;
2415 break;
2418 case ft_glyph_format_outline:
2419 ft_bitmap.width = width;
2420 ft_bitmap.rows = height;
2421 ft_bitmap.pitch = pitch;
2422 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2423 ft_bitmap.buffer = buf;
2425 if(needsTransform) {
2426 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2429 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2431 /* Note: FreeType will only set 'black' bits for us. */
2432 memset(buf, 0, needed);
2433 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2434 break;
2436 default:
2437 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2438 return GDI_ERROR;
2440 break;
2442 case GGO_GRAY2_BITMAP:
2443 case GGO_GRAY4_BITMAP:
2444 case GGO_GRAY8_BITMAP:
2445 case WINE_GGO_GRAY16_BITMAP:
2447 unsigned int mult, row, col;
2448 BYTE *start, *ptr;
2450 width = lpgm->gmBlackBoxX;
2451 height = lpgm->gmBlackBoxY;
2452 pitch = (width + 3) / 4 * 4;
2453 needed = pitch * height;
2455 if(!buf || !buflen) break;
2456 ft_bitmap.width = width;
2457 ft_bitmap.rows = height;
2458 ft_bitmap.pitch = pitch;
2459 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2460 ft_bitmap.buffer = buf;
2462 if(needsTransform) {
2463 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2466 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2468 memset(ft_bitmap.buffer, 0, buflen);
2470 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2472 if(format == GGO_GRAY2_BITMAP)
2473 mult = 4;
2474 else if(format == GGO_GRAY4_BITMAP)
2475 mult = 16;
2476 else if(format == GGO_GRAY8_BITMAP)
2477 mult = 64;
2478 else if(format == WINE_GGO_GRAY16_BITMAP)
2479 break;
2480 else {
2481 assert(0);
2482 break;
2485 start = buf;
2486 for(row = 0; row < height; row++) {
2487 ptr = start;
2488 for(col = 0; col < width; col++, ptr++) {
2489 *ptr = (((int)*ptr) * mult + 128) / 256;
2491 start += pitch;
2493 break;
2496 case GGO_NATIVE:
2498 int contour, point = 0, first_pt;
2499 FT_Outline *outline = &ft_face->glyph->outline;
2500 TTPOLYGONHEADER *pph;
2501 TTPOLYCURVE *ppc;
2502 DWORD pph_start, cpfx, type;
2504 if(buflen == 0) buf = NULL;
2506 if (needsTransform && buf) {
2507 pFT_Outline_Transform(outline, &transMat);
2510 for(contour = 0; contour < outline->n_contours; contour++) {
2511 pph_start = needed;
2512 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2513 first_pt = point;
2514 if(buf) {
2515 pph->dwType = TT_POLYGON_TYPE;
2516 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2518 needed += sizeof(*pph);
2519 point++;
2520 while(point <= outline->contours[contour]) {
2521 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2522 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2523 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2524 cpfx = 0;
2525 do {
2526 if(buf)
2527 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2528 cpfx++;
2529 point++;
2530 } while(point <= outline->contours[contour] &&
2531 (outline->tags[point] & FT_Curve_Tag_On) ==
2532 (outline->tags[point-1] & FT_Curve_Tag_On));
2533 /* At the end of a contour Windows adds the start point, but
2534 only for Beziers */
2535 if(point > outline->contours[contour] &&
2536 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2537 if(buf)
2538 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2539 cpfx++;
2540 } else if(point <= outline->contours[contour] &&
2541 outline->tags[point] & FT_Curve_Tag_On) {
2542 /* add closing pt for bezier */
2543 if(buf)
2544 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2545 cpfx++;
2546 point++;
2548 if(buf) {
2549 ppc->wType = type;
2550 ppc->cpfx = cpfx;
2552 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2554 if(buf)
2555 pph->cb = needed - pph_start;
2557 break;
2559 case GGO_BEZIER:
2561 /* Convert the quadratic Beziers to cubic Beziers.
2562 The parametric eqn for a cubic Bezier is, from PLRM:
2563 r(t) = at^3 + bt^2 + ct + r0
2564 with the control points:
2565 r1 = r0 + c/3
2566 r2 = r1 + (c + b)/3
2567 r3 = r0 + c + b + a
2569 A quadratic Beizer has the form:
2570 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2572 So equating powers of t leads to:
2573 r1 = 2/3 p1 + 1/3 p0
2574 r2 = 2/3 p1 + 1/3 p2
2575 and of course r0 = p0, r3 = p2
2578 int contour, point = 0, first_pt;
2579 FT_Outline *outline = &ft_face->glyph->outline;
2580 TTPOLYGONHEADER *pph;
2581 TTPOLYCURVE *ppc;
2582 DWORD pph_start, cpfx, type;
2583 FT_Vector cubic_control[4];
2584 if(buflen == 0) buf = NULL;
2586 if (needsTransform && buf) {
2587 pFT_Outline_Transform(outline, &transMat);
2590 for(contour = 0; contour < outline->n_contours; contour++) {
2591 pph_start = needed;
2592 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2593 first_pt = point;
2594 if(buf) {
2595 pph->dwType = TT_POLYGON_TYPE;
2596 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2598 needed += sizeof(*pph);
2599 point++;
2600 while(point <= outline->contours[contour]) {
2601 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2602 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2603 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2604 cpfx = 0;
2605 do {
2606 if(type == TT_PRIM_LINE) {
2607 if(buf)
2608 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2609 cpfx++;
2610 point++;
2611 } else {
2612 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2613 so cpfx = 3n */
2615 /* FIXME: Possible optimization in endpoint calculation
2616 if there are two consecutive curves */
2617 cubic_control[0] = outline->points[point-1];
2618 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2619 cubic_control[0].x += outline->points[point].x + 1;
2620 cubic_control[0].y += outline->points[point].y + 1;
2621 cubic_control[0].x >>= 1;
2622 cubic_control[0].y >>= 1;
2624 if(point+1 > outline->contours[contour])
2625 cubic_control[3] = outline->points[first_pt];
2626 else {
2627 cubic_control[3] = outline->points[point+1];
2628 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2629 cubic_control[3].x += outline->points[point].x + 1;
2630 cubic_control[3].y += outline->points[point].y + 1;
2631 cubic_control[3].x >>= 1;
2632 cubic_control[3].y >>= 1;
2635 /* r1 = 1/3 p0 + 2/3 p1
2636 r2 = 1/3 p2 + 2/3 p1 */
2637 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2638 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2639 cubic_control[2] = cubic_control[1];
2640 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2641 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2642 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2643 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2644 if(buf) {
2645 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2646 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2647 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2649 cpfx += 3;
2650 point++;
2652 } while(point <= outline->contours[contour] &&
2653 (outline->tags[point] & FT_Curve_Tag_On) ==
2654 (outline->tags[point-1] & FT_Curve_Tag_On));
2655 /* At the end of a contour Windows adds the start point,
2656 but only for Beziers and we've already done that.
2658 if(point <= outline->contours[contour] &&
2659 outline->tags[point] & FT_Curve_Tag_On) {
2660 /* This is the closing pt of a bezier, but we've already
2661 added it, so just inc point and carry on */
2662 point++;
2664 if(buf) {
2665 ppc->wType = type;
2666 ppc->cpfx = cpfx;
2668 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2670 if(buf)
2671 pph->cb = needed - pph_start;
2673 break;
2676 default:
2677 FIXME("Unsupported format %d\n", format);
2678 return GDI_ERROR;
2680 return needed;
2683 static BOOL get_bitmap_text_metrics(GdiFont font)
2685 FT_Face ft_face = font->ft_face;
2686 #ifdef HAVE_FREETYPE_FTWINFNT_H
2687 FT_WinFNT_HeaderRec winfnt_header;
2688 #endif
2689 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2690 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2691 font->potm->otmSize = size;
2693 #define TM font->potm->otmTextMetrics
2694 #ifdef HAVE_FREETYPE_FTWINFNT_H
2695 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2697 TM.tmHeight = winfnt_header.pixel_height;
2698 TM.tmAscent = winfnt_header.ascent;
2699 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2700 TM.tmInternalLeading = winfnt_header.internal_leading;
2701 TM.tmExternalLeading = winfnt_header.external_leading;
2702 TM.tmAveCharWidth = winfnt_header.avg_width;
2703 TM.tmMaxCharWidth = winfnt_header.max_width;
2704 TM.tmWeight = winfnt_header.weight;
2705 TM.tmOverhang = 0;
2706 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2707 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2708 TM.tmFirstChar = winfnt_header.first_char;
2709 TM.tmLastChar = winfnt_header.last_char;
2710 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2711 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2712 TM.tmItalic = winfnt_header.italic;
2713 TM.tmUnderlined = font->underline;
2714 TM.tmStruckOut = font->strikeout;
2715 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2716 TM.tmCharSet = winfnt_header.charset;
2718 else
2719 #endif
2721 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2722 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2723 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2724 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2725 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2726 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2727 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2728 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2729 TM.tmOverhang = 0;
2730 TM.tmDigitizedAspectX = 96; /* FIXME */
2731 TM.tmDigitizedAspectY = 96; /* FIXME */
2732 TM.tmFirstChar = 1;
2733 TM.tmLastChar = 255;
2734 TM.tmDefaultChar = 32;
2735 TM.tmBreakChar = 32;
2736 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2737 TM.tmUnderlined = font->underline;
2738 TM.tmStruckOut = font->strikeout;
2739 /* NB inverted meaning of TMPF_FIXED_PITCH */
2740 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2741 TM.tmCharSet = font->charset;
2743 #undef TM
2745 return TRUE;
2748 /*************************************************************
2749 * WineEngGetTextMetrics
2752 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2754 if(!font->potm) {
2755 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2756 if(!get_bitmap_text_metrics(font))
2757 return FALSE;
2759 if(!font->potm) return FALSE;
2760 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2762 if (font->aveWidth) {
2763 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2765 return TRUE;
2769 /*************************************************************
2770 * WineEngGetOutlineTextMetrics
2773 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2774 OUTLINETEXTMETRICW *potm)
2776 FT_Face ft_face = font->ft_face;
2777 UINT needed, lenfam, lensty, ret;
2778 TT_OS2 *pOS2;
2779 TT_HoriHeader *pHori;
2780 TT_Postscript *pPost;
2781 FT_Fixed x_scale, y_scale;
2782 WCHAR *family_nameW, *style_nameW;
2783 static const WCHAR spaceW[] = {' ', '\0'};
2784 char *cp;
2785 INT ascent, descent;
2787 TRACE("font=%p\n", font);
2789 if(!FT_IS_SCALABLE(ft_face))
2790 return 0;
2792 if(font->potm) {
2793 if(cbSize >= font->potm->otmSize)
2794 memcpy(potm, font->potm, font->potm->otmSize);
2795 return font->potm->otmSize;
2799 needed = sizeof(*potm);
2801 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2802 family_nameW = strdupW(font->name);
2804 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2805 * sizeof(WCHAR);
2806 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2807 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2808 style_nameW, lensty);
2810 /* These names should be read from the TT name table */
2812 /* length of otmpFamilyName */
2813 needed += lenfam;
2815 /* length of otmpFaceName */
2816 if(!strcasecmp(ft_face->style_name, "regular")) {
2817 needed += lenfam; /* just the family name */
2818 } else {
2819 needed += lenfam + lensty; /* family + " " + style */
2822 /* length of otmpStyleName */
2823 needed += lensty;
2825 /* length of otmpFullName */
2826 needed += lenfam + lensty;
2829 x_scale = ft_face->size->metrics.x_scale;
2830 y_scale = ft_face->size->metrics.y_scale;
2832 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2833 if(!pOS2) {
2834 FIXME("Can't find OS/2 table - not TT font?\n");
2835 ret = 0;
2836 goto end;
2839 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2840 if(!pHori) {
2841 FIXME("Can't find HHEA table - not TT font?\n");
2842 ret = 0;
2843 goto end;
2846 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2848 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",
2849 pOS2->usWinAscent, pOS2->usWinDescent,
2850 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2851 ft_face->ascender, ft_face->descender, ft_face->height,
2852 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2853 ft_face->bbox.yMax, ft_face->bbox.yMin);
2855 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2856 font->potm->otmSize = needed;
2858 #define TM font->potm->otmTextMetrics
2860 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2861 ascent = pHori->Ascender;
2862 descent = -pHori->Descender;
2863 } else {
2864 ascent = pOS2->usWinAscent;
2865 descent = pOS2->usWinDescent;
2868 if(font->yMax) {
2869 TM.tmAscent = font->yMax;
2870 TM.tmDescent = -font->yMin;
2871 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2872 } else {
2873 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2874 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2875 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2876 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2879 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2881 /* MSDN says:
2882 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2884 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2885 ((ascent + descent) -
2886 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2888 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2889 if (TM.tmAveCharWidth == 0) {
2890 TM.tmAveCharWidth = 1;
2892 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2893 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2894 TM.tmOverhang = 0;
2895 TM.tmDigitizedAspectX = 300;
2896 TM.tmDigitizedAspectY = 300;
2897 TM.tmFirstChar = pOS2->usFirstCharIndex;
2898 TM.tmLastChar = pOS2->usLastCharIndex;
2899 TM.tmDefaultChar = pOS2->usDefaultChar;
2900 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2901 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2902 TM.tmUnderlined = font->underline;
2903 TM.tmStruckOut = font->strikeout;
2905 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2906 if(!FT_IS_FIXED_WIDTH(ft_face) &&
2907 (pOS2->version == 0xFFFFU ||
2908 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
2909 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2910 else
2911 TM.tmPitchAndFamily = 0;
2913 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2914 case PAN_FAMILY_SCRIPT:
2915 TM.tmPitchAndFamily |= FF_SCRIPT;
2916 break;
2917 case PAN_FAMILY_DECORATIVE:
2918 case PAN_FAMILY_PICTORIAL:
2919 TM.tmPitchAndFamily |= FF_DECORATIVE;
2920 break;
2921 case PAN_FAMILY_TEXT_DISPLAY:
2922 if(TM.tmPitchAndFamily == 0) /* fixed */
2923 TM.tmPitchAndFamily = FF_MODERN;
2924 else {
2925 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2926 case PAN_SERIF_NORMAL_SANS:
2927 case PAN_SERIF_OBTUSE_SANS:
2928 case PAN_SERIF_PERP_SANS:
2929 TM.tmPitchAndFamily |= FF_SWISS;
2930 break;
2931 default:
2932 TM.tmPitchAndFamily |= FF_ROMAN;
2935 break;
2936 default:
2937 TM.tmPitchAndFamily |= FF_DONTCARE;
2940 if(FT_IS_SCALABLE(ft_face))
2941 TM.tmPitchAndFamily |= TMPF_VECTOR;
2942 if(FT_IS_SFNT(ft_face))
2943 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2945 TM.tmCharSet = font->charset;
2946 #undef TM
2948 font->potm->otmFiller = 0;
2949 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2950 font->potm->otmfsSelection = pOS2->fsSelection;
2951 font->potm->otmfsType = pOS2->fsType;
2952 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2953 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2954 font->potm->otmItalicAngle = 0; /* POST table */
2955 font->potm->otmEMSquare = ft_face->units_per_EM;
2956 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2957 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2958 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2959 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2960 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2961 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2962 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2963 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2964 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2965 font->potm->otmMacAscent = 0; /* where do these come from ? */
2966 font->potm->otmMacDescent = 0;
2967 font->potm->otmMacLineGap = 0;
2968 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2969 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2970 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2971 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2972 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2973 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2974 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2975 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2976 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2977 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2978 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2979 if(!pPost) {
2980 font->potm->otmsUnderscoreSize = 0;
2981 font->potm->otmsUnderscorePosition = 0;
2982 } else {
2983 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2984 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2987 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2988 cp = (char*)font->potm + sizeof(*font->potm);
2989 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2990 strcpyW((WCHAR*)cp, family_nameW);
2991 cp += lenfam;
2992 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2993 strcpyW((WCHAR*)cp, style_nameW);
2994 cp += lensty;
2995 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2996 strcpyW((WCHAR*)cp, family_nameW);
2997 if(strcasecmp(ft_face->style_name, "regular")) {
2998 strcatW((WCHAR*)cp, spaceW);
2999 strcatW((WCHAR*)cp, style_nameW);
3000 cp += lenfam + lensty;
3001 } else
3002 cp += lenfam;
3003 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3004 strcpyW((WCHAR*)cp, family_nameW);
3005 strcatW((WCHAR*)cp, spaceW);
3006 strcatW((WCHAR*)cp, style_nameW);
3007 ret = needed;
3009 if(potm && needed <= cbSize)
3010 memcpy(potm, font->potm, font->potm->otmSize);
3012 end:
3013 HeapFree(GetProcessHeap(), 0, style_nameW);
3014 HeapFree(GetProcessHeap(), 0, family_nameW);
3016 return ret;
3020 /*************************************************************
3021 * WineEngGetCharWidth
3024 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3025 LPINT buffer)
3027 UINT c;
3028 GLYPHMETRICS gm;
3029 FT_UInt glyph_index;
3031 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3033 for(c = firstChar; c <= lastChar; c++) {
3034 glyph_index = get_glyph_index(font, c);
3035 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3036 &gm, 0, NULL, NULL);
3037 buffer[c - firstChar] = font->gm[glyph_index].adv;
3039 return TRUE;
3042 /*************************************************************
3043 * WineEngGetCharABCWidths
3046 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3047 LPABC buffer)
3049 UINT c;
3050 GLYPHMETRICS gm;
3051 FT_UInt glyph_index;
3053 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3055 if(!FT_IS_SCALABLE(font->ft_face))
3056 return FALSE;
3058 for(c = firstChar; c <= lastChar; c++) {
3059 glyph_index = get_glyph_index(font, c);
3060 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3061 &gm, 0, NULL, NULL);
3062 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3063 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3064 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3065 font->gm[glyph_index].bbx;
3067 return TRUE;
3070 /*************************************************************
3071 * WineEngGetTextExtentPoint
3074 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3075 LPSIZE size)
3077 INT idx;
3078 GLYPHMETRICS gm;
3079 TEXTMETRICW tm;
3080 FT_UInt glyph_index;
3082 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3083 size);
3085 size->cx = 0;
3086 WineEngGetTextMetrics(font, &tm);
3087 size->cy = tm.tmHeight;
3089 for(idx = 0; idx < count; idx++) {
3090 glyph_index = get_glyph_index(font, wstr[idx]);
3091 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3092 &gm, 0, NULL, NULL);
3093 size->cx += font->gm[glyph_index].adv;
3095 TRACE("return %ld,%ld\n", size->cx, size->cy);
3096 return TRUE;
3099 /*************************************************************
3100 * WineEngGetTextExtentPointI
3103 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3104 LPSIZE size)
3106 INT idx;
3107 GLYPHMETRICS gm;
3108 TEXTMETRICW tm;
3110 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3112 size->cx = 0;
3113 WineEngGetTextMetrics(font, &tm);
3114 size->cy = tm.tmHeight;
3116 for(idx = 0; idx < count; idx++) {
3117 WineEngGetGlyphOutline(font, indices[idx],
3118 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3119 NULL);
3120 size->cx += font->gm[indices[idx]].adv;
3122 TRACE("return %ld,%ld\n", size->cx, size->cy);
3123 return TRUE;
3126 /*************************************************************
3127 * WineEngGetFontData
3130 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3131 DWORD cbData)
3133 FT_Face ft_face = font->ft_face;
3134 DWORD len;
3135 FT_Error err;
3137 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3138 font, table, offset, buf, cbData);
3140 if(!FT_IS_SFNT(ft_face))
3141 return GDI_ERROR;
3143 if(!buf || !cbData)
3144 len = 0;
3145 else
3146 len = cbData;
3148 if(table) { /* MS tags differ in endidness from FT ones */
3149 table = table >> 24 | table << 24 |
3150 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3153 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3154 if(pFT_Load_Sfnt_Table)
3155 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3156 else { /* Do it the hard way */
3157 TT_Face tt_face = (TT_Face) ft_face;
3158 SFNT_Interface *sfnt;
3159 if (FT_Version.major==2 && FT_Version.minor==0)
3161 /* 2.0.x */
3162 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3164 else
3166 /* A field was added in the middle of the structure in 2.1.x */
3167 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3169 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3171 if(err) {
3172 TRACE("Can't find table %08lx.\n", table);
3173 return GDI_ERROR;
3175 return len;
3178 /*************************************************************
3179 * WineEngGetTextFace
3182 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3184 if(str) {
3185 lstrcpynW(str, font->name, count);
3186 return strlenW(font->name);
3187 } else
3188 return strlenW(font->name) + 1;
3191 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3193 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3194 return font->charset;
3197 #else /* HAVE_FREETYPE */
3199 BOOL WineEngInit(void)
3201 return FALSE;
3203 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3205 return NULL;
3207 BOOL WineEngDestroyFontInstance(HFONT hfont)
3209 return FALSE;
3212 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3214 return 1;
3217 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3218 LPWORD pgi, DWORD flags)
3220 return GDI_ERROR;
3223 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3224 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3225 const MAT2* lpmat)
3227 ERR("called but we don't have FreeType\n");
3228 return GDI_ERROR;
3231 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3233 ERR("called but we don't have FreeType\n");
3234 return FALSE;
3237 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3238 OUTLINETEXTMETRICW *potm)
3240 ERR("called but we don't have FreeType\n");
3241 return 0;
3244 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3245 LPINT buffer)
3247 ERR("called but we don't have FreeType\n");
3248 return FALSE;
3251 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3252 LPABC buffer)
3254 ERR("called but we don't have FreeType\n");
3255 return FALSE;
3258 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3259 LPSIZE size)
3261 ERR("called but we don't have FreeType\n");
3262 return FALSE;
3265 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3266 LPSIZE size)
3268 ERR("called but we don't have FreeType\n");
3269 return FALSE;
3272 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3273 DWORD cbData)
3275 ERR("called but we don't have FreeType\n");
3276 return GDI_ERROR;
3279 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3281 ERR("called but we don't have FreeType\n");
3282 return 0;
3285 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3287 FIXME(":stub\n");
3288 return 1;
3291 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3293 FIXME(":stub\n");
3294 return TRUE;
3297 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3299 FIXME(":stub\n");
3300 return DEFAULT_CHARSET;
3303 #endif /* HAVE_FREETYPE */