-Wpointer-sign fixes for gcc 4.0.
[wine/multimedia.git] / dlls / gdi / freetype.c
blob04a2de2329543d2e7606138351135a009d97b706
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','\\',
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 * [HKCU\Software\Wine\Fonts\Replacements]
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 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
760 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
762 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
763 &valuelen, &datalen, NULL, NULL);
765 valuelen++; /* returned value doesn't include room for '\0' */
766 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
767 data = HeapAlloc(GetProcessHeap(), 0, datalen);
769 dlen = datalen;
770 vlen = valuelen;
771 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
772 &dlen) == ERROR_SUCCESS) {
773 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
774 /* "NewName"="Oldname" */
775 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
776 break;
778 /* Find the old family and hence all of the font files
779 in that family */
780 LIST_FOR_EACH(family_elem_ptr, &font_list) {
781 family = LIST_ENTRY(family_elem_ptr, Family, entry);
782 if(!strcmpiW(family->FamilyName, old_nameW)) {
783 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
784 face = LIST_ENTRY(face_elem_ptr, Face, entry);
785 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
786 debugstr_w(face->StyleName), value);
787 /* Now add a new entry with the new family name */
788 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
790 break;
793 /* reset dlen and vlen */
794 dlen = datalen;
795 vlen = valuelen;
797 HeapFree(GetProcessHeap(), 0, data);
798 HeapFree(GetProcessHeap(), 0, value);
799 RegCloseKey(hkey);
804 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
806 DIR *dir;
807 struct dirent *dent;
808 char path[MAX_PATH];
810 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
812 dir = opendir(dirname);
813 if(!dir) {
814 ERR("Can't open directory %s\n", debugstr_a(dirname));
815 return FALSE;
817 while((dent = readdir(dir)) != NULL) {
818 struct stat statbuf;
820 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
821 continue;
823 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
825 sprintf(path, "%s/%s", dirname, dent->d_name);
827 if(stat(path, &statbuf) == -1)
829 WARN("Can't stat %s\n", debugstr_a(path));
830 continue;
832 if(S_ISDIR(statbuf.st_mode))
833 ReadFontDir(path, external_fonts);
834 else
835 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
837 closedir(dir);
838 return TRUE;
841 static void load_fontconfig_fonts(void)
843 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
844 void *fc_handle = NULL;
845 FcConfig *config;
846 FcPattern *pat;
847 FcObjectSet *os;
848 FcFontSet *fontset;
849 FcValue v;
850 int i, len;
851 const char *ext;
853 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
854 if(!fc_handle) {
855 TRACE("Wine cannot find the fontconfig library (%s).\n",
856 SONAME_LIBFONTCONFIG);
857 return;
859 #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;}
860 LOAD_FUNCPTR(FcConfigGetCurrent);
861 LOAD_FUNCPTR(FcFontList);
862 LOAD_FUNCPTR(FcFontSetDestroy);
863 LOAD_FUNCPTR(FcInit);
864 LOAD_FUNCPTR(FcObjectSetAdd);
865 LOAD_FUNCPTR(FcObjectSetCreate);
866 LOAD_FUNCPTR(FcObjectSetDestroy);
867 LOAD_FUNCPTR(FcPatternCreate);
868 LOAD_FUNCPTR(FcPatternDestroy);
869 LOAD_FUNCPTR(FcPatternGet);
870 #undef LOAD_FUNCPTR
872 if(!pFcInit()) return;
874 config = pFcConfigGetCurrent();
875 pat = pFcPatternCreate();
876 os = pFcObjectSetCreate();
877 pFcObjectSetAdd(os, FC_FILE);
878 fontset = pFcFontList(config, pat, os);
879 if(!fontset) return;
880 for(i = 0; i < fontset->nfont; i++) {
881 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
882 continue;
883 if(v.type != FcTypeString) continue;
884 TRACE("fontconfig: %s\n", v.u.s);
886 /* We're just interested in OT/TT fonts for now, so this hack just
887 picks up the standard extensions to save time loading every other
888 font */
889 len = strlen(v.u.s);
890 if(len < 4) continue;
891 ext = v.u.s + len - 3;
892 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
893 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
895 pFcFontSetDestroy(fontset);
896 pFcObjectSetDestroy(os);
897 pFcPatternDestroy(pat);
898 sym_not_found:
899 #endif
900 return;
904 static void load_system_fonts(void)
906 HKEY hkey;
907 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
908 const WCHAR **value;
909 DWORD dlen, type;
910 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
911 char *unixname;
913 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
914 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
915 strcatW(windowsdir, fontsW);
916 for(value = SystemFontValues; *value; value++) {
917 dlen = sizeof(data);
918 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
919 type == REG_SZ) {
920 sprintfW(pathW, fmtW, windowsdir, data);
921 if((unixname = wine_get_unix_file_name(pathW))) {
922 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
923 HeapFree(GetProcessHeap(), 0, unixname);
927 RegCloseKey(hkey);
931 /*************************************************************
933 * This adds registry entries for any externally loaded fonts
934 * (fonts from fontconfig or FontDirs). It also deletes entries
935 * of no longer existing fonts.
938 static void update_reg_entries(void)
940 HKEY winkey = 0, externalkey = 0;
941 LPWSTR valueW;
942 LPVOID data;
943 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
944 Family *family;
945 Face *face;
946 struct list *family_elem_ptr, *face_elem_ptr;
947 WCHAR *file;
948 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
949 static const WCHAR spaceW[] = {' ', '\0'};
950 char *path;
952 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
953 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
954 ERR("Can't create Windows font reg key\n");
955 goto end;
957 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
958 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
959 ERR("Can't create external font reg key\n");
960 goto end;
963 /* Delete all external fonts added last time */
965 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
966 &valuelen, &datalen, NULL, NULL);
967 valuelen++; /* returned value doesn't include room for '\0' */
968 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
969 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
971 dlen = datalen * sizeof(WCHAR);
972 vlen = valuelen;
973 i = 0;
974 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
975 &dlen) == ERROR_SUCCESS) {
977 RegDeleteValueW(winkey, valueW);
978 /* reset dlen and vlen */
979 dlen = datalen;
980 vlen = valuelen;
982 HeapFree(GetProcessHeap(), 0, data);
983 HeapFree(GetProcessHeap(), 0, valueW);
985 /* Delete the old external fonts key */
986 RegCloseKey(externalkey);
987 externalkey = 0;
988 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
990 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
991 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
992 ERR("Can't create external font reg key\n");
993 goto end;
996 /* enumerate the fonts and add external ones to the two keys */
998 LIST_FOR_EACH(family_elem_ptr, &font_list) {
999 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1000 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1001 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1002 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1003 if(!face->external) continue;
1004 len = len_fam;
1005 if(strcmpiW(face->StyleName, RegularW))
1006 len = len_fam + strlenW(face->StyleName) + 1;
1007 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1008 strcpyW(valueW, family->FamilyName);
1009 if(len != len_fam) {
1010 strcatW(valueW, spaceW);
1011 strcatW(valueW, face->StyleName);
1013 strcatW(valueW, TrueType);
1014 if((path = strrchr(face->file, '/')) == NULL)
1015 path = face->file;
1016 else
1017 path++;
1018 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1020 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1021 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1022 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1023 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1025 HeapFree(GetProcessHeap(), 0, file);
1026 HeapFree(GetProcessHeap(), 0, valueW);
1029 end:
1030 if(externalkey)
1031 RegCloseKey(externalkey);
1032 if(winkey)
1033 RegCloseKey(winkey);
1034 return;
1038 /*************************************************************
1039 * WineEngAddFontResourceEx
1042 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1044 if (ft_handle) /* do it only if we have freetype up and running */
1046 char *unixname;
1048 if(flags)
1049 FIXME("Ignoring flags %lx\n", flags);
1051 if((unixname = wine_get_unix_file_name(file)))
1053 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1054 HeapFree(GetProcessHeap(), 0, unixname);
1057 return 1;
1060 /*************************************************************
1061 * WineEngRemoveFontResourceEx
1064 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1066 FIXME(":stub\n");
1067 return TRUE;
1070 /*************************************************************
1071 * WineEngInit
1073 * Initialize FreeType library and create a list of available faces
1075 BOOL WineEngInit(void)
1077 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1078 static const WCHAR pathW[] = {'P','a','t','h',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 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1224 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1226 DWORD len;
1227 LPWSTR valueW;
1228 LPSTR valueA, ptr;
1230 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1232 len += sizeof(WCHAR);
1233 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1234 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1236 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1237 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1238 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1239 TRACE( "got font path %s\n", debugstr_a(valueA) );
1240 ptr = valueA;
1241 while (ptr)
1243 LPSTR next = strchr( ptr, ':' );
1244 if (next) *next++ = 0;
1245 ReadFontDir( ptr, TRUE );
1246 ptr = next;
1248 HeapFree( GetProcessHeap(), 0, valueA );
1250 HeapFree( GetProcessHeap(), 0, valueW );
1252 RegCloseKey(hkey);
1255 DumpFontList();
1256 LoadSubstList();
1257 DumpSubstList();
1258 LoadReplaceList();
1259 update_reg_entries();
1261 ReleaseMutex(font_mutex);
1262 return TRUE;
1263 sym_not_found:
1264 WINE_MESSAGE(
1265 "Wine cannot find certain functions that it needs inside the FreeType\n"
1266 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1267 "FreeType to at least version 2.0.5.\n"
1268 "http://www.freetype.org\n");
1269 wine_dlclose(ft_handle, NULL, 0);
1270 ft_handle = NULL;
1271 return FALSE;
1275 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1277 TT_OS2 *pOS2;
1278 TT_HoriHeader *pHori;
1280 LONG ppem;
1282 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1283 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1285 if(height == 0) height = 16;
1287 /* Calc. height of EM square:
1289 * For +ve lfHeight we have
1290 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1291 * Re-arranging gives:
1292 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1294 * For -ve lfHeight we have
1295 * |lfHeight| = ppem
1296 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1297 * with il = winAscent + winDescent - units_per_em]
1301 if(height > 0) {
1302 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1303 ppem = ft_face->units_per_EM * height /
1304 (pHori->Ascender - pHori->Descender);
1305 else
1306 ppem = ft_face->units_per_EM * height /
1307 (pOS2->usWinAscent + pOS2->usWinDescent);
1309 else
1310 ppem = -height;
1312 return ppem;
1315 static LONG load_VDMX(GdiFont, LONG);
1317 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1319 FT_Error err;
1320 FT_Face ft_face;
1321 LONG ppem;
1323 err = pFT_New_Face(library, file, face_index, &ft_face);
1324 if(err) {
1325 ERR("FT_New_Face rets %d\n", err);
1326 return 0;
1329 /* set it here, as load_VDMX needs it */
1330 font->ft_face = ft_face;
1332 if(FT_IS_SCALABLE(ft_face)) {
1333 /* load the VDMX table if we have one */
1334 ppem = load_VDMX(font, height);
1335 if(ppem == 0)
1336 ppem = calc_ppem_for_height(ft_face, height);
1338 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1339 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1340 } else {
1341 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1342 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1344 return ft_face;
1348 static int get_nearest_charset(Face *face, int *cp)
1350 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1351 a single face with the requested charset. The idea is to check if
1352 the selected font supports the current ANSI codepage, if it does
1353 return the corresponding charset, else return the first charset */
1355 CHARSETINFO csi;
1356 int acp = GetACP(), i;
1357 DWORD fs0;
1359 *cp = acp;
1360 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1361 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1362 return csi.ciCharset;
1364 for(i = 0; i < 32; i++) {
1365 fs0 = 1L << i;
1366 if(face->fs.fsCsb[0] & fs0) {
1367 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1368 *cp = csi.ciACP;
1369 return csi.ciCharset;
1371 else
1372 FIXME("TCI failing on %lx\n", fs0);
1376 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1377 face->fs.fsCsb[0], face->file);
1378 *cp = acp;
1379 return DEFAULT_CHARSET;
1382 static GdiFont alloc_font(void)
1384 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1385 ret->gmsize = INIT_GM_SIZE;
1386 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1387 ret->gmsize * sizeof(*ret->gm));
1388 ret->potm = NULL;
1389 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1390 list_init(&ret->hfontlist);
1391 return ret;
1394 static void free_font(GdiFont font)
1396 if (font->ft_face) pFT_Done_Face(font->ft_face);
1397 HeapFree(GetProcessHeap(), 0, font->potm);
1398 HeapFree(GetProcessHeap(), 0, font->name);
1399 HeapFree(GetProcessHeap(), 0, font->gm);
1400 HeapFree(GetProcessHeap(), 0, font);
1404 /*************************************************************
1405 * load_VDMX
1407 * load the vdmx entry for the specified height
1410 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1411 ( ( (FT_ULong)_x4 << 24 ) | \
1412 ( (FT_ULong)_x3 << 16 ) | \
1413 ( (FT_ULong)_x2 << 8 ) | \
1414 (FT_ULong)_x1 )
1416 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1418 typedef struct {
1419 BYTE bCharSet;
1420 BYTE xRatio;
1421 BYTE yStartRatio;
1422 BYTE yEndRatio;
1423 } Ratios;
1426 static LONG load_VDMX(GdiFont font, LONG height)
1428 BYTE hdr[6], tmp[2], group[4];
1429 BYTE devXRatio, devYRatio;
1430 USHORT numRecs, numRatios;
1431 DWORD result, offset = -1;
1432 LONG ppem = 0;
1433 int i;
1435 /* For documentation on VDMX records, see
1436 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1439 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1441 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1442 return ppem;
1444 /* FIXME: need the real device aspect ratio */
1445 devXRatio = 1;
1446 devYRatio = 1;
1448 numRecs = GET_BE_WORD(&hdr[2]);
1449 numRatios = GET_BE_WORD(&hdr[4]);
1451 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1452 for(i = 0; i < numRatios; i++) {
1453 Ratios ratio;
1455 offset = (3 * 2) + (i * sizeof(Ratios));
1456 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1457 offset = -1;
1459 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1461 if((ratio.xRatio == 0 &&
1462 ratio.yStartRatio == 0 &&
1463 ratio.yEndRatio == 0) ||
1464 (devXRatio == ratio.xRatio &&
1465 devYRatio >= ratio.yStartRatio &&
1466 devYRatio <= ratio.yEndRatio))
1468 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1469 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1470 offset = GET_BE_WORD(tmp);
1471 break;
1475 if(offset == -1) {
1476 FIXME("No suitable ratio found\n");
1477 return ppem;
1480 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1481 USHORT recs;
1482 BYTE startsz, endsz;
1483 BYTE *vTable;
1485 recs = GET_BE_WORD(group);
1486 startsz = group[2];
1487 endsz = group[3];
1489 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1491 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1492 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1493 if(result == GDI_ERROR) {
1494 FIXME("Failed to retrieve vTable\n");
1495 goto end;
1498 if(height > 0) {
1499 for(i = 0; i < recs; i++) {
1500 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1501 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1502 ppem = GET_BE_WORD(&vTable[i * 6]);
1504 if(yMax + -yMin == height) {
1505 font->yMax = yMax;
1506 font->yMin = yMin;
1507 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1508 break;
1510 if(yMax + -yMin > height) {
1511 if(--i < 0) {
1512 ppem = 0;
1513 goto end; /* failed */
1515 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1516 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1517 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1518 break;
1521 if(!font->yMax) {
1522 ppem = 0;
1523 TRACE("ppem not found for height %ld\n", height);
1525 } else {
1526 ppem = -height;
1527 if(ppem < startsz || ppem > endsz)
1528 goto end;
1530 for(i = 0; i < recs; i++) {
1531 USHORT yPelHeight;
1532 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1534 if(yPelHeight > ppem)
1535 break; /* failed */
1537 if(yPelHeight == ppem) {
1538 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1539 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1540 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1541 break;
1545 end:
1546 HeapFree(GetProcessHeap(), 0, vTable);
1549 return ppem;
1552 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1554 if(font->font_desc.hash != fd->hash) return TRUE;
1555 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1556 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1557 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1560 static void calc_hash(FONT_DESC *pfd)
1562 DWORD hash = 0, *ptr, two_chars;
1563 WORD *pwc;
1564 unsigned int i;
1566 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1567 hash ^= *ptr;
1568 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1569 hash ^= *ptr;
1570 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1571 two_chars = *ptr;
1572 pwc = (WCHAR *)&two_chars;
1573 if(!*pwc) break;
1574 *pwc = toupperW(*pwc);
1575 pwc++;
1576 *pwc = toupperW(*pwc);
1577 hash ^= two_chars;
1578 if(!*pwc) break;
1580 pfd->hash = hash;
1581 return;
1584 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1586 GdiFont ret;
1587 FONT_DESC fd;
1588 HFONTLIST *hflist;
1589 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1591 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1592 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1593 calc_hash(&fd);
1595 /* try the in-use list */
1596 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1597 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1598 if(!fontcmp(ret, &fd)) {
1599 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1600 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1601 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1602 if(hflist->hfont == hfont)
1603 return ret;
1605 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1606 hflist->hfont = hfont;
1607 list_add_head(&ret->hfontlist, &hflist->entry);
1608 return ret;
1612 /* then the unused list */
1613 font_elem_ptr = list_head(&unused_gdi_font_list);
1614 while(font_elem_ptr) {
1615 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1616 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1617 if(!fontcmp(ret, &fd)) {
1618 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1619 assert(list_empty(&ret->hfontlist));
1620 TRACE("Found %p in unused list\n", ret);
1621 list_remove(&ret->entry);
1622 list_add_head(&gdi_font_list, &ret->entry);
1623 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1624 hflist->hfont = hfont;
1625 list_add_head(&ret->hfontlist, &hflist->entry);
1626 return ret;
1629 return NULL;
1632 /*************************************************************
1633 * WineEngCreateFontInstance
1636 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1638 GdiFont ret;
1639 Face *face, *best;
1640 Family *family;
1641 struct list *family_elem_ptr, *face_elem_ptr;
1642 INT height, width = 0;
1643 signed int diff = 0, newdiff;
1644 BOOL bd, it, can_use_bitmap;
1645 LOGFONTW lf;
1646 CHARSETINFO csi;
1647 HFONTLIST *hflist;
1649 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1650 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1652 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1653 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1654 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1655 lf.lfEscapement);
1657 /* check the cache first */
1658 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1659 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1660 return ret;
1663 TRACE("not in cache\n");
1664 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1666 TRACE("No fonts installed\n");
1667 return NULL;
1670 ret = alloc_font();
1672 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1673 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1674 calc_hash(&ret->font_desc);
1675 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1676 hflist->hfont = hfont;
1677 list_add_head(&ret->hfontlist, &hflist->entry);
1680 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1681 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1682 original value lfCharSet. Note this is a special case for
1683 Symbol and doesn't happen at least for "Wingdings*" */
1685 if(!strcmpiW(lf.lfFaceName, SymbolW))
1686 lf.lfCharSet = SYMBOL_CHARSET;
1688 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1689 switch(lf.lfCharSet) {
1690 case DEFAULT_CHARSET:
1691 csi.fs.fsCsb[0] = 0;
1692 break;
1693 default:
1694 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1695 csi.fs.fsCsb[0] = 0;
1696 break;
1700 family = NULL;
1701 if(lf.lfFaceName[0] != '\0') {
1702 FontSubst *psub;
1703 for(psub = substlist; psub; psub = psub->next)
1704 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1705 (psub->from.charset == -1 ||
1706 psub->from.charset == lf.lfCharSet))
1707 break;
1708 if(psub) {
1709 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1710 debugstr_w(psub->to.name));
1711 strcpyW(lf.lfFaceName, psub->to.name);
1714 /* We want a match on name and charset or just name if
1715 charset was DEFAULT_CHARSET. If the latter then
1716 we fixup the returned charset later in get_nearest_charset
1717 where we'll either use the charset of the current ansi codepage
1718 or if that's unavailable the first charset that the font supports.
1720 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1721 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1722 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1723 face_elem_ptr = list_head(&family->faces);
1724 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1725 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1726 if(face->scalable || can_use_bitmap)
1727 break;
1729 family = NULL;
1733 if(!family) {
1734 /* If requested charset was DEFAULT_CHARSET then try using charset
1735 corresponding to the current ansi codepage */
1736 if(!csi.fs.fsCsb[0]) {
1737 INT acp = GetACP();
1738 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1739 FIXME("TCI failed on codepage %d\n", acp);
1740 csi.fs.fsCsb[0] = 0;
1741 } else
1742 lf.lfCharSet = csi.ciCharset;
1745 /* Face families are in the top 4 bits of lfPitchAndFamily,
1746 so mask with 0xF0 before testing */
1748 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1749 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1750 strcpyW(lf.lfFaceName, defFixed);
1751 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1752 strcpyW(lf.lfFaceName, defSerif);
1753 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1754 strcpyW(lf.lfFaceName, defSans);
1755 else
1756 strcpyW(lf.lfFaceName, defSans);
1757 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1758 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1759 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1760 face_elem_ptr = list_head(&family->faces);
1761 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1762 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1763 if(face->scalable || can_use_bitmap)
1764 break;
1766 family = NULL;
1770 if(!family) {
1771 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1772 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1773 face_elem_ptr = list_head(&family->faces);
1774 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1775 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1776 if(face->scalable || can_use_bitmap)
1777 break;
1778 family = NULL;
1782 if(!family) {
1783 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1784 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1785 face_elem_ptr = list_head(&family->faces);
1786 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1787 if(face->scalable || can_use_bitmap) {
1788 csi.fs.fsCsb[0] = 0;
1789 FIXME("just using first face for now\n");
1790 break;
1792 family = NULL;
1794 if(!family) {
1795 FIXME("can't find a single appropriate font - bailing\n");
1796 free_font(ret);
1797 return NULL;
1801 it = lf.lfItalic ? 1 : 0;
1802 bd = lf.lfWeight > 550 ? 1 : 0;
1804 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1805 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1807 face = best = NULL;
1808 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1809 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1810 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1811 if(face->scalable)
1812 break;
1813 if(height > 0)
1814 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1815 else
1816 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1817 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1818 (diff < 0 && newdiff > diff)) {
1819 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1820 diff = newdiff;
1821 best = face;
1822 if(diff == 0)
1823 break;
1826 face = NULL;
1828 if(!face && best)
1829 face = best;
1830 else if(!face) {
1831 best = NULL;
1832 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1833 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1834 if(face->scalable)
1835 break;
1836 if(height > 0)
1837 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1838 else
1839 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1840 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1841 (diff < 0 && newdiff > diff)) {
1842 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1843 diff = newdiff;
1844 best = face;
1845 if(diff == 0)
1846 break;
1848 face = NULL;
1850 if(!face && best)
1851 face = best;
1852 if(it && !face->Italic) ret->fake_italic = TRUE;
1853 if(bd && !face->Bold) ret->fake_bold = TRUE;
1856 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1858 if(csi.fs.fsCsb[0]) {
1859 ret->charset = lf.lfCharSet;
1860 ret->codepage = csi.ciACP;
1862 else
1863 ret->charset = get_nearest_charset(face, &ret->codepage);
1865 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1866 debugstr_w(face->StyleName));
1868 if(!face->scalable) {
1869 width = face->size.x_ppem >> 6;
1870 height = face->size.y_ppem >> 6;
1872 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1874 if (!ret->ft_face)
1876 free_font( ret );
1877 return 0;
1880 if (ret->charset == SYMBOL_CHARSET &&
1881 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
1882 /* No ops */
1884 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
1885 /* No ops */
1887 else {
1888 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
1891 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1892 ret->name = strdupW(family->FamilyName);
1893 ret->underline = lf.lfUnderline ? 0xff : 0;
1894 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1896 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1898 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1899 list_add_head(&gdi_font_list, &ret->entry);
1900 return ret;
1903 static void dump_gdi_font_list(void)
1905 GdiFont gdiFont;
1906 struct list *elem_ptr;
1908 TRACE("---------- gdiFont Cache ----------\n");
1909 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1910 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1911 TRACE("gdiFont=%p %s %ld\n",
1912 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1915 TRACE("---------- Unused gdiFont Cache ----------\n");
1916 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1917 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1918 TRACE("gdiFont=%p %s %ld\n",
1919 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1923 /*************************************************************
1924 * WineEngDestroyFontInstance
1926 * free the gdiFont associated with this handle
1929 BOOL WineEngDestroyFontInstance(HFONT handle)
1931 GdiFont gdiFont;
1932 HFONTLIST *hflist;
1933 BOOL ret = FALSE;
1934 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1935 int i = 0;
1937 TRACE("destroying hfont=%p\n", handle);
1938 if(TRACE_ON(font))
1939 dump_gdi_font_list();
1941 font_elem_ptr = list_head(&gdi_font_list);
1942 while(font_elem_ptr) {
1943 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1944 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1946 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1947 while(hfontlist_elem_ptr) {
1948 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1949 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1950 if(hflist->hfont == handle) {
1951 list_remove(&hflist->entry);
1952 HeapFree(GetProcessHeap(), 0, hflist);
1953 ret = TRUE;
1956 if(list_empty(&gdiFont->hfontlist)) {
1957 TRACE("Moving to Unused list\n");
1958 list_remove(&gdiFont->entry);
1959 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1964 font_elem_ptr = list_head(&unused_gdi_font_list);
1965 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1966 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1967 while(font_elem_ptr) {
1968 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1969 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1970 TRACE("freeing %p\n", gdiFont);
1971 list_remove(&gdiFont->entry);
1972 free_font(gdiFont);
1974 return ret;
1977 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1978 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1980 OUTLINETEXTMETRICW *potm = NULL;
1981 UINT size;
1982 TEXTMETRICW tm, *ptm;
1983 GdiFont font = alloc_font();
1984 LONG width, height;
1986 if(face->scalable) {
1987 height = 100;
1988 width = 0;
1989 } else {
1990 height = face->size.y_ppem >> 6;
1991 width = face->size.x_ppem >> 6;
1994 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1996 free_font(font);
1997 return;
2000 font->name = strdupW(face->family->FamilyName);
2002 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2004 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2005 if(size) {
2006 potm = HeapAlloc(GetProcessHeap(), 0, size);
2007 WineEngGetOutlineTextMetrics(font, size, potm);
2008 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2009 } else {
2010 WineEngGetTextMetrics(font, &tm);
2011 ptm = &tm;
2014 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2015 pntm->ntmTm.tmAscent = ptm->tmAscent;
2016 pntm->ntmTm.tmDescent = ptm->tmDescent;
2017 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2018 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2019 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2020 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2021 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2022 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2023 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2024 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2025 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2026 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2027 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2028 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2029 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2030 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2031 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2032 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2033 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2034 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2035 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2036 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2037 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2039 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2040 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2041 *ptype |= RASTER_FONTTYPE;
2043 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2044 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2045 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2047 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2048 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2049 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2051 if(potm) {
2052 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2054 lstrcpynW(pelf->elfLogFont.lfFaceName,
2055 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2056 LF_FACESIZE);
2057 lstrcpynW(pelf->elfFullName,
2058 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2059 LF_FULLFACESIZE);
2060 lstrcpynW(pelf->elfStyle,
2061 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2062 LF_FACESIZE);
2064 HeapFree(GetProcessHeap(), 0, potm);
2065 } else {
2066 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2068 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2069 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2070 pelf->elfStyle[0] = '\0';
2073 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2075 free_font(font);
2078 /*************************************************************
2079 * WineEngEnumFonts
2082 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2084 Family *family;
2085 Face *face;
2086 struct list *family_elem_ptr, *face_elem_ptr;
2087 ENUMLOGFONTEXW elf;
2088 NEWTEXTMETRICEXW ntm;
2089 DWORD type, ret = 1;
2090 FONTSIGNATURE fs;
2091 CHARSETINFO csi;
2092 LOGFONTW lf;
2093 int i;
2095 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2097 if(plf->lfFaceName[0]) {
2098 FontSubst *psub;
2099 for(psub = substlist; psub; psub = psub->next)
2100 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2101 (psub->from.charset == -1 ||
2102 psub->from.charset == plf->lfCharSet))
2103 break;
2104 if(psub) {
2105 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2106 debugstr_w(psub->to.name));
2107 memcpy(&lf, plf, sizeof(lf));
2108 strcpyW(lf.lfFaceName, psub->to.name);
2109 plf = &lf;
2112 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2113 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2114 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2115 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2116 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2117 GetEnumStructs(face, &elf, &ntm, &type);
2118 for(i = 0; i < 32; i++) {
2119 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2120 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2121 strcpyW(elf.elfScript, OEM_DOSW);
2122 i = 32; /* break out of loop */
2123 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2124 continue;
2125 else {
2126 fs.fsCsb[0] = 1L << i;
2127 fs.fsCsb[1] = 0;
2128 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2129 TCI_SRCFONTSIG))
2130 csi.ciCharset = DEFAULT_CHARSET;
2131 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2132 if(csi.ciCharset != DEFAULT_CHARSET) {
2133 elf.elfLogFont.lfCharSet =
2134 ntm.ntmTm.tmCharSet = csi.ciCharset;
2135 if(ElfScriptsW[i])
2136 strcpyW(elf.elfScript, ElfScriptsW[i]);
2137 else
2138 FIXME("Unknown elfscript for bit %d\n", i);
2141 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2142 debugstr_w(elf.elfLogFont.lfFaceName),
2143 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2144 csi.ciCharset, type, debugstr_w(elf.elfScript),
2145 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2146 ntm.ntmTm.ntmFlags);
2147 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2148 if(!ret) goto end;
2153 } else {
2154 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2155 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2156 face_elem_ptr = list_head(&family->faces);
2157 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2158 GetEnumStructs(face, &elf, &ntm, &type);
2159 for(i = 0; i < 32; i++) {
2160 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2161 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2162 strcpyW(elf.elfScript, OEM_DOSW);
2163 i = 32; /* break out of loop */
2164 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2165 continue;
2166 else {
2167 fs.fsCsb[0] = 1L << i;
2168 fs.fsCsb[1] = 0;
2169 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2170 TCI_SRCFONTSIG))
2171 csi.ciCharset = DEFAULT_CHARSET;
2172 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2173 if(csi.ciCharset != DEFAULT_CHARSET) {
2174 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2175 csi.ciCharset;
2176 if(ElfScriptsW[i])
2177 strcpyW(elf.elfScript, ElfScriptsW[i]);
2178 else
2179 FIXME("Unknown elfscript for bit %d\n", i);
2182 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2183 debugstr_w(elf.elfLogFont.lfFaceName),
2184 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2185 csi.ciCharset, type, debugstr_w(elf.elfScript),
2186 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2187 ntm.ntmTm.ntmFlags);
2188 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2189 if(!ret) goto end;
2193 end:
2194 return ret;
2197 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2199 pt->x.value = vec->x >> 6;
2200 pt->x.fract = (vec->x & 0x3f) << 10;
2201 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2202 pt->y.value = vec->y >> 6;
2203 pt->y.fract = (vec->y & 0x3f) << 10;
2204 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2205 return;
2208 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2210 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2211 WCHAR wc = (WCHAR)glyph;
2212 char buf;
2213 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2214 return pFT_Get_Char_Index(font->ft_face, buf);
2217 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2218 glyph = glyph + 0xf000;
2219 return pFT_Get_Char_Index(font->ft_face, glyph);
2222 /*************************************************************
2223 * WineEngGetGlyphIndices
2225 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2227 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2228 LPWORD pgi, DWORD flags)
2230 INT i;
2232 for(i = 0; i < count; i++)
2233 pgi[i] = get_glyph_index(font, lpstr[i]);
2235 return count;
2238 /*************************************************************
2239 * WineEngGetGlyphOutline
2241 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2242 * except that the first parameter is the HWINEENGFONT of the font in
2243 * question rather than an HDC.
2246 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2247 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2248 const MAT2* lpmat)
2250 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2251 FT_Face ft_face = font->ft_face;
2252 FT_UInt glyph_index;
2253 DWORD width, height, pitch, needed = 0;
2254 FT_Bitmap ft_bitmap;
2255 FT_Error err;
2256 INT left, right, top = 0, bottom = 0;
2257 FT_Angle angle = 0;
2258 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2259 float widthRatio = 1.0;
2260 FT_Matrix transMat = identityMat;
2261 BOOL needsTransform = FALSE;
2264 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2265 buflen, buf, lpmat);
2267 if(format & GGO_GLYPH_INDEX) {
2268 glyph_index = glyph;
2269 format &= ~GGO_GLYPH_INDEX;
2270 } else
2271 glyph_index = get_glyph_index(font, glyph);
2273 if(glyph_index >= font->gmsize) {
2274 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2275 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2276 font->gmsize * sizeof(*font->gm));
2277 } else {
2278 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2279 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2280 return 1; /* FIXME */
2284 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2285 load_flags |= FT_LOAD_NO_BITMAP;
2287 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2289 if(err) {
2290 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2291 return GDI_ERROR;
2294 /* Scaling factor */
2295 if (font->aveWidth && font->potm) {
2296 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2299 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2300 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2302 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2303 font->gm[glyph_index].lsb = left >> 6;
2304 font->gm[glyph_index].bbx = (right - left) >> 6;
2306 /* Scaling transform */
2307 if(font->aveWidth) {
2308 FT_Matrix scaleMat;
2309 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2310 scaleMat.xy = 0;
2311 scaleMat.yx = 0;
2312 scaleMat.yy = (1 << 16);
2314 pFT_Matrix_Multiply(&scaleMat, &transMat);
2315 needsTransform = TRUE;
2318 /* Rotation transform */
2319 if(font->orientation) {
2320 FT_Matrix rotationMat;
2321 FT_Vector vecAngle;
2322 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2323 pFT_Vector_Unit(&vecAngle, angle);
2324 rotationMat.xx = vecAngle.x;
2325 rotationMat.xy = -vecAngle.y;
2326 rotationMat.yx = -rotationMat.xy;
2327 rotationMat.yy = rotationMat.xx;
2329 pFT_Matrix_Multiply(&rotationMat, &transMat);
2330 needsTransform = TRUE;
2333 /* Extra transformation specified by caller */
2334 if (lpmat) {
2335 FT_Matrix extraMat;
2336 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2337 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2338 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2339 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2340 pFT_Matrix_Multiply(&extraMat, &transMat);
2341 needsTransform = TRUE;
2344 if(!needsTransform) {
2345 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2346 bottom = (ft_face->glyph->metrics.horiBearingY -
2347 ft_face->glyph->metrics.height) & -64;
2348 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2349 lpgm->gmCellIncY = 0;
2350 } else {
2351 INT xc, yc;
2352 FT_Vector vec;
2353 for(xc = 0; xc < 2; xc++) {
2354 for(yc = 0; yc < 2; yc++) {
2355 vec.x = (ft_face->glyph->metrics.horiBearingX +
2356 xc * ft_face->glyph->metrics.width);
2357 vec.y = ft_face->glyph->metrics.horiBearingY -
2358 yc * ft_face->glyph->metrics.height;
2359 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2360 pFT_Vector_Transform(&vec, &transMat);
2361 if(xc == 0 && yc == 0) {
2362 left = right = vec.x;
2363 top = bottom = vec.y;
2364 } else {
2365 if(vec.x < left) left = vec.x;
2366 else if(vec.x > right) right = vec.x;
2367 if(vec.y < bottom) bottom = vec.y;
2368 else if(vec.y > top) top = vec.y;
2372 left = left & -64;
2373 right = (right + 63) & -64;
2374 bottom = bottom & -64;
2375 top = (top + 63) & -64;
2377 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2378 vec.x = ft_face->glyph->metrics.horiAdvance;
2379 vec.y = 0;
2380 pFT_Vector_Transform(&vec, &transMat);
2381 lpgm->gmCellIncX = (vec.x+63) >> 6;
2382 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2384 lpgm->gmBlackBoxX = (right - left) >> 6;
2385 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2386 lpgm->gmptGlyphOrigin.x = left >> 6;
2387 lpgm->gmptGlyphOrigin.y = top >> 6;
2389 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2390 font->gm[glyph_index].init = TRUE;
2392 if(format == GGO_METRICS)
2393 return 1; /* FIXME */
2395 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2396 TRACE("loaded a bitmap\n");
2397 return GDI_ERROR;
2400 switch(format) {
2401 case GGO_BITMAP:
2402 width = lpgm->gmBlackBoxX;
2403 height = lpgm->gmBlackBoxY;
2404 pitch = ((width + 31) >> 5) << 2;
2405 needed = pitch * height;
2407 if(!buf || !buflen) break;
2409 switch(ft_face->glyph->format) {
2410 case ft_glyph_format_bitmap:
2412 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2413 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2414 INT h = ft_face->glyph->bitmap.rows;
2415 while(h--) {
2416 memcpy(dst, src, w);
2417 src += ft_face->glyph->bitmap.pitch;
2418 dst += pitch;
2420 break;
2423 case ft_glyph_format_outline:
2424 ft_bitmap.width = width;
2425 ft_bitmap.rows = height;
2426 ft_bitmap.pitch = pitch;
2427 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2428 ft_bitmap.buffer = buf;
2430 if(needsTransform) {
2431 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2434 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2436 /* Note: FreeType will only set 'black' bits for us. */
2437 memset(buf, 0, needed);
2438 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2439 break;
2441 default:
2442 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2443 return GDI_ERROR;
2445 break;
2447 case GGO_GRAY2_BITMAP:
2448 case GGO_GRAY4_BITMAP:
2449 case GGO_GRAY8_BITMAP:
2450 case WINE_GGO_GRAY16_BITMAP:
2452 unsigned int mult, row, col;
2453 BYTE *start, *ptr;
2455 width = lpgm->gmBlackBoxX;
2456 height = lpgm->gmBlackBoxY;
2457 pitch = (width + 3) / 4 * 4;
2458 needed = pitch * height;
2460 if(!buf || !buflen) break;
2461 ft_bitmap.width = width;
2462 ft_bitmap.rows = height;
2463 ft_bitmap.pitch = pitch;
2464 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2465 ft_bitmap.buffer = buf;
2467 if(needsTransform) {
2468 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2471 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2473 memset(ft_bitmap.buffer, 0, buflen);
2475 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2477 if(format == GGO_GRAY2_BITMAP)
2478 mult = 4;
2479 else if(format == GGO_GRAY4_BITMAP)
2480 mult = 16;
2481 else if(format == GGO_GRAY8_BITMAP)
2482 mult = 64;
2483 else if(format == WINE_GGO_GRAY16_BITMAP)
2484 break;
2485 else {
2486 assert(0);
2487 break;
2490 start = buf;
2491 for(row = 0; row < height; row++) {
2492 ptr = start;
2493 for(col = 0; col < width; col++, ptr++) {
2494 *ptr = (((int)*ptr) * mult + 128) / 256;
2496 start += pitch;
2498 break;
2501 case GGO_NATIVE:
2503 int contour, point = 0, first_pt;
2504 FT_Outline *outline = &ft_face->glyph->outline;
2505 TTPOLYGONHEADER *pph;
2506 TTPOLYCURVE *ppc;
2507 DWORD pph_start, cpfx, type;
2509 if(buflen == 0) buf = NULL;
2511 if (needsTransform && buf) {
2512 pFT_Outline_Transform(outline, &transMat);
2515 for(contour = 0; contour < outline->n_contours; contour++) {
2516 pph_start = needed;
2517 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2518 first_pt = point;
2519 if(buf) {
2520 pph->dwType = TT_POLYGON_TYPE;
2521 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2523 needed += sizeof(*pph);
2524 point++;
2525 while(point <= outline->contours[contour]) {
2526 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2527 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2528 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2529 cpfx = 0;
2530 do {
2531 if(buf)
2532 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2533 cpfx++;
2534 point++;
2535 } while(point <= outline->contours[contour] &&
2536 (outline->tags[point] & FT_Curve_Tag_On) ==
2537 (outline->tags[point-1] & FT_Curve_Tag_On));
2538 /* At the end of a contour Windows adds the start point, but
2539 only for Beziers */
2540 if(point > outline->contours[contour] &&
2541 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2542 if(buf)
2543 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2544 cpfx++;
2545 } else if(point <= outline->contours[contour] &&
2546 outline->tags[point] & FT_Curve_Tag_On) {
2547 /* add closing pt for bezier */
2548 if(buf)
2549 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2550 cpfx++;
2551 point++;
2553 if(buf) {
2554 ppc->wType = type;
2555 ppc->cpfx = cpfx;
2557 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2559 if(buf)
2560 pph->cb = needed - pph_start;
2562 break;
2564 case GGO_BEZIER:
2566 /* Convert the quadratic Beziers to cubic Beziers.
2567 The parametric eqn for a cubic Bezier is, from PLRM:
2568 r(t) = at^3 + bt^2 + ct + r0
2569 with the control points:
2570 r1 = r0 + c/3
2571 r2 = r1 + (c + b)/3
2572 r3 = r0 + c + b + a
2574 A quadratic Beizer has the form:
2575 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2577 So equating powers of t leads to:
2578 r1 = 2/3 p1 + 1/3 p0
2579 r2 = 2/3 p1 + 1/3 p2
2580 and of course r0 = p0, r3 = p2
2583 int contour, point = 0, first_pt;
2584 FT_Outline *outline = &ft_face->glyph->outline;
2585 TTPOLYGONHEADER *pph;
2586 TTPOLYCURVE *ppc;
2587 DWORD pph_start, cpfx, type;
2588 FT_Vector cubic_control[4];
2589 if(buflen == 0) buf = NULL;
2591 if (needsTransform && buf) {
2592 pFT_Outline_Transform(outline, &transMat);
2595 for(contour = 0; contour < outline->n_contours; contour++) {
2596 pph_start = needed;
2597 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2598 first_pt = point;
2599 if(buf) {
2600 pph->dwType = TT_POLYGON_TYPE;
2601 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2603 needed += sizeof(*pph);
2604 point++;
2605 while(point <= outline->contours[contour]) {
2606 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2607 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2608 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2609 cpfx = 0;
2610 do {
2611 if(type == TT_PRIM_LINE) {
2612 if(buf)
2613 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2614 cpfx++;
2615 point++;
2616 } else {
2617 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2618 so cpfx = 3n */
2620 /* FIXME: Possible optimization in endpoint calculation
2621 if there are two consecutive curves */
2622 cubic_control[0] = outline->points[point-1];
2623 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2624 cubic_control[0].x += outline->points[point].x + 1;
2625 cubic_control[0].y += outline->points[point].y + 1;
2626 cubic_control[0].x >>= 1;
2627 cubic_control[0].y >>= 1;
2629 if(point+1 > outline->contours[contour])
2630 cubic_control[3] = outline->points[first_pt];
2631 else {
2632 cubic_control[3] = outline->points[point+1];
2633 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2634 cubic_control[3].x += outline->points[point].x + 1;
2635 cubic_control[3].y += outline->points[point].y + 1;
2636 cubic_control[3].x >>= 1;
2637 cubic_control[3].y >>= 1;
2640 /* r1 = 1/3 p0 + 2/3 p1
2641 r2 = 1/3 p2 + 2/3 p1 */
2642 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2643 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2644 cubic_control[2] = cubic_control[1];
2645 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2646 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2647 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2648 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2649 if(buf) {
2650 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2651 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2652 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2654 cpfx += 3;
2655 point++;
2657 } while(point <= outline->contours[contour] &&
2658 (outline->tags[point] & FT_Curve_Tag_On) ==
2659 (outline->tags[point-1] & FT_Curve_Tag_On));
2660 /* At the end of a contour Windows adds the start point,
2661 but only for Beziers and we've already done that.
2663 if(point <= outline->contours[contour] &&
2664 outline->tags[point] & FT_Curve_Tag_On) {
2665 /* This is the closing pt of a bezier, but we've already
2666 added it, so just inc point and carry on */
2667 point++;
2669 if(buf) {
2670 ppc->wType = type;
2671 ppc->cpfx = cpfx;
2673 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2675 if(buf)
2676 pph->cb = needed - pph_start;
2678 break;
2681 default:
2682 FIXME("Unsupported format %d\n", format);
2683 return GDI_ERROR;
2685 return needed;
2688 static BOOL get_bitmap_text_metrics(GdiFont font)
2690 FT_Face ft_face = font->ft_face;
2691 #ifdef HAVE_FREETYPE_FTWINFNT_H
2692 FT_WinFNT_HeaderRec winfnt_header;
2693 #endif
2694 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2695 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2696 font->potm->otmSize = size;
2698 #define TM font->potm->otmTextMetrics
2699 #ifdef HAVE_FREETYPE_FTWINFNT_H
2700 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2702 TM.tmHeight = winfnt_header.pixel_height;
2703 TM.tmAscent = winfnt_header.ascent;
2704 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2705 TM.tmInternalLeading = winfnt_header.internal_leading;
2706 TM.tmExternalLeading = winfnt_header.external_leading;
2707 TM.tmAveCharWidth = winfnt_header.avg_width;
2708 TM.tmMaxCharWidth = winfnt_header.max_width;
2709 TM.tmWeight = winfnt_header.weight;
2710 TM.tmOverhang = 0;
2711 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2712 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2713 TM.tmFirstChar = winfnt_header.first_char;
2714 TM.tmLastChar = winfnt_header.last_char;
2715 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2716 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2717 TM.tmItalic = winfnt_header.italic;
2718 TM.tmUnderlined = font->underline;
2719 TM.tmStruckOut = font->strikeout;
2720 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2721 TM.tmCharSet = winfnt_header.charset;
2723 else
2724 #endif
2726 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2727 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2728 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2729 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2730 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2731 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2732 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2733 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2734 TM.tmOverhang = 0;
2735 TM.tmDigitizedAspectX = 96; /* FIXME */
2736 TM.tmDigitizedAspectY = 96; /* FIXME */
2737 TM.tmFirstChar = 1;
2738 TM.tmLastChar = 255;
2739 TM.tmDefaultChar = 32;
2740 TM.tmBreakChar = 32;
2741 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2742 TM.tmUnderlined = font->underline;
2743 TM.tmStruckOut = font->strikeout;
2744 /* NB inverted meaning of TMPF_FIXED_PITCH */
2745 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2746 TM.tmCharSet = font->charset;
2748 #undef TM
2750 return TRUE;
2753 /*************************************************************
2754 * WineEngGetTextMetrics
2757 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2759 if(!font->potm) {
2760 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2761 if(!get_bitmap_text_metrics(font))
2762 return FALSE;
2764 if(!font->potm) return FALSE;
2765 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2767 if (font->aveWidth) {
2768 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2770 return TRUE;
2774 /*************************************************************
2775 * WineEngGetOutlineTextMetrics
2778 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2779 OUTLINETEXTMETRICW *potm)
2781 FT_Face ft_face = font->ft_face;
2782 UINT needed, lenfam, lensty, ret;
2783 TT_OS2 *pOS2;
2784 TT_HoriHeader *pHori;
2785 TT_Postscript *pPost;
2786 FT_Fixed x_scale, y_scale;
2787 WCHAR *family_nameW, *style_nameW;
2788 static const WCHAR spaceW[] = {' ', '\0'};
2789 char *cp;
2790 INT ascent, descent;
2792 TRACE("font=%p\n", font);
2794 if(!FT_IS_SCALABLE(ft_face))
2795 return 0;
2797 if(font->potm) {
2798 if(cbSize >= font->potm->otmSize)
2799 memcpy(potm, font->potm, font->potm->otmSize);
2800 return font->potm->otmSize;
2804 needed = sizeof(*potm);
2806 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2807 family_nameW = strdupW(font->name);
2809 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2810 * sizeof(WCHAR);
2811 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2812 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2813 style_nameW, lensty);
2815 /* These names should be read from the TT name table */
2817 /* length of otmpFamilyName */
2818 needed += lenfam;
2820 /* length of otmpFaceName */
2821 if(!strcasecmp(ft_face->style_name, "regular")) {
2822 needed += lenfam; /* just the family name */
2823 } else {
2824 needed += lenfam + lensty; /* family + " " + style */
2827 /* length of otmpStyleName */
2828 needed += lensty;
2830 /* length of otmpFullName */
2831 needed += lenfam + lensty;
2834 x_scale = ft_face->size->metrics.x_scale;
2835 y_scale = ft_face->size->metrics.y_scale;
2837 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2838 if(!pOS2) {
2839 FIXME("Can't find OS/2 table - not TT font?\n");
2840 ret = 0;
2841 goto end;
2844 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2845 if(!pHori) {
2846 FIXME("Can't find HHEA table - not TT font?\n");
2847 ret = 0;
2848 goto end;
2851 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2853 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",
2854 pOS2->usWinAscent, pOS2->usWinDescent,
2855 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2856 ft_face->ascender, ft_face->descender, ft_face->height,
2857 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2858 ft_face->bbox.yMax, ft_face->bbox.yMin);
2860 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2861 font->potm->otmSize = needed;
2863 #define TM font->potm->otmTextMetrics
2865 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2866 ascent = pHori->Ascender;
2867 descent = -pHori->Descender;
2868 } else {
2869 ascent = pOS2->usWinAscent;
2870 descent = pOS2->usWinDescent;
2873 if(font->yMax) {
2874 TM.tmAscent = font->yMax;
2875 TM.tmDescent = -font->yMin;
2876 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2877 } else {
2878 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2879 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2880 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2881 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2884 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2886 /* MSDN says:
2887 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2889 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2890 ((ascent + descent) -
2891 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2893 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2894 if (TM.tmAveCharWidth == 0) {
2895 TM.tmAveCharWidth = 1;
2897 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2898 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2899 TM.tmOverhang = 0;
2900 TM.tmDigitizedAspectX = 300;
2901 TM.tmDigitizedAspectY = 300;
2902 TM.tmFirstChar = pOS2->usFirstCharIndex;
2903 TM.tmLastChar = pOS2->usLastCharIndex;
2904 TM.tmDefaultChar = pOS2->usDefaultChar;
2905 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2906 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2907 TM.tmUnderlined = font->underline;
2908 TM.tmStruckOut = font->strikeout;
2910 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2911 if(!FT_IS_FIXED_WIDTH(ft_face) &&
2912 (pOS2->version == 0xFFFFU ||
2913 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
2914 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2915 else
2916 TM.tmPitchAndFamily = 0;
2918 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2919 case PAN_FAMILY_SCRIPT:
2920 TM.tmPitchAndFamily |= FF_SCRIPT;
2921 break;
2922 case PAN_FAMILY_DECORATIVE:
2923 case PAN_FAMILY_PICTORIAL:
2924 TM.tmPitchAndFamily |= FF_DECORATIVE;
2925 break;
2926 case PAN_FAMILY_TEXT_DISPLAY:
2927 if(TM.tmPitchAndFamily == 0) /* fixed */
2928 TM.tmPitchAndFamily = FF_MODERN;
2929 else {
2930 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2931 case PAN_SERIF_NORMAL_SANS:
2932 case PAN_SERIF_OBTUSE_SANS:
2933 case PAN_SERIF_PERP_SANS:
2934 TM.tmPitchAndFamily |= FF_SWISS;
2935 break;
2936 default:
2937 TM.tmPitchAndFamily |= FF_ROMAN;
2940 break;
2941 default:
2942 TM.tmPitchAndFamily |= FF_DONTCARE;
2945 if(FT_IS_SCALABLE(ft_face))
2946 TM.tmPitchAndFamily |= TMPF_VECTOR;
2947 if(FT_IS_SFNT(ft_face))
2948 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2950 TM.tmCharSet = font->charset;
2951 #undef TM
2953 font->potm->otmFiller = 0;
2954 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2955 font->potm->otmfsSelection = pOS2->fsSelection;
2956 font->potm->otmfsType = pOS2->fsType;
2957 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2958 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2959 font->potm->otmItalicAngle = 0; /* POST table */
2960 font->potm->otmEMSquare = ft_face->units_per_EM;
2961 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2962 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2963 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2964 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2965 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2966 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2967 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2968 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2969 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2970 font->potm->otmMacAscent = 0; /* where do these come from ? */
2971 font->potm->otmMacDescent = 0;
2972 font->potm->otmMacLineGap = 0;
2973 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2974 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2975 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2976 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2977 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2978 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2979 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2980 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2981 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2982 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2983 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2984 if(!pPost) {
2985 font->potm->otmsUnderscoreSize = 0;
2986 font->potm->otmsUnderscorePosition = 0;
2987 } else {
2988 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2989 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2992 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2993 cp = (char*)font->potm + sizeof(*font->potm);
2994 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2995 strcpyW((WCHAR*)cp, family_nameW);
2996 cp += lenfam;
2997 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2998 strcpyW((WCHAR*)cp, style_nameW);
2999 cp += lensty;
3000 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3001 strcpyW((WCHAR*)cp, family_nameW);
3002 if(strcasecmp(ft_face->style_name, "regular")) {
3003 strcatW((WCHAR*)cp, spaceW);
3004 strcatW((WCHAR*)cp, style_nameW);
3005 cp += lenfam + lensty;
3006 } else
3007 cp += lenfam;
3008 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3009 strcpyW((WCHAR*)cp, family_nameW);
3010 strcatW((WCHAR*)cp, spaceW);
3011 strcatW((WCHAR*)cp, style_nameW);
3012 ret = needed;
3014 if(potm && needed <= cbSize)
3015 memcpy(potm, font->potm, font->potm->otmSize);
3017 end:
3018 HeapFree(GetProcessHeap(), 0, style_nameW);
3019 HeapFree(GetProcessHeap(), 0, family_nameW);
3021 return ret;
3025 /*************************************************************
3026 * WineEngGetCharWidth
3029 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3030 LPINT buffer)
3032 UINT c;
3033 GLYPHMETRICS gm;
3034 FT_UInt glyph_index;
3036 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3038 for(c = firstChar; c <= lastChar; c++) {
3039 glyph_index = get_glyph_index(font, c);
3040 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3041 &gm, 0, NULL, NULL);
3042 buffer[c - firstChar] = font->gm[glyph_index].adv;
3044 return TRUE;
3047 /*************************************************************
3048 * WineEngGetCharABCWidths
3051 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3052 LPABC buffer)
3054 UINT c;
3055 GLYPHMETRICS gm;
3056 FT_UInt glyph_index;
3058 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3060 if(!FT_IS_SCALABLE(font->ft_face))
3061 return FALSE;
3063 for(c = firstChar; c <= lastChar; c++) {
3064 glyph_index = get_glyph_index(font, c);
3065 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3066 &gm, 0, NULL, NULL);
3067 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3068 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3069 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3070 font->gm[glyph_index].bbx;
3072 return TRUE;
3075 /*************************************************************
3076 * WineEngGetTextExtentPoint
3079 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3080 LPSIZE size)
3082 INT idx;
3083 GLYPHMETRICS gm;
3084 TEXTMETRICW tm;
3085 FT_UInt glyph_index;
3087 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3088 size);
3090 size->cx = 0;
3091 WineEngGetTextMetrics(font, &tm);
3092 size->cy = tm.tmHeight;
3094 for(idx = 0; idx < count; idx++) {
3095 glyph_index = get_glyph_index(font, wstr[idx]);
3096 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3097 &gm, 0, NULL, NULL);
3098 size->cx += font->gm[glyph_index].adv;
3100 TRACE("return %ld,%ld\n", size->cx, size->cy);
3101 return TRUE;
3104 /*************************************************************
3105 * WineEngGetTextExtentPointI
3108 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3109 LPSIZE size)
3111 INT idx;
3112 GLYPHMETRICS gm;
3113 TEXTMETRICW tm;
3115 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3117 size->cx = 0;
3118 WineEngGetTextMetrics(font, &tm);
3119 size->cy = tm.tmHeight;
3121 for(idx = 0; idx < count; idx++) {
3122 WineEngGetGlyphOutline(font, indices[idx],
3123 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3124 NULL);
3125 size->cx += font->gm[indices[idx]].adv;
3127 TRACE("return %ld,%ld\n", size->cx, size->cy);
3128 return TRUE;
3131 /*************************************************************
3132 * WineEngGetFontData
3135 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3136 DWORD cbData)
3138 FT_Face ft_face = font->ft_face;
3139 DWORD len;
3140 FT_Error err;
3142 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3143 font, table, offset, buf, cbData);
3145 if(!FT_IS_SFNT(ft_face))
3146 return GDI_ERROR;
3148 if(!buf || !cbData)
3149 len = 0;
3150 else
3151 len = cbData;
3153 if(table) { /* MS tags differ in endidness from FT ones */
3154 table = table >> 24 | table << 24 |
3155 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3158 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3159 if(pFT_Load_Sfnt_Table)
3160 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3161 else { /* Do it the hard way */
3162 TT_Face tt_face = (TT_Face) ft_face;
3163 SFNT_Interface *sfnt;
3164 if (FT_Version.major==2 && FT_Version.minor==0)
3166 /* 2.0.x */
3167 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3169 else
3171 /* A field was added in the middle of the structure in 2.1.x */
3172 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3174 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3176 if(err) {
3177 TRACE("Can't find table %08lx.\n", table);
3178 return GDI_ERROR;
3180 return len;
3183 /*************************************************************
3184 * WineEngGetTextFace
3187 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3189 if(str) {
3190 lstrcpynW(str, font->name, count);
3191 return strlenW(font->name);
3192 } else
3193 return strlenW(font->name) + 1;
3196 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3198 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3199 return font->charset;
3202 #else /* HAVE_FREETYPE */
3204 BOOL WineEngInit(void)
3206 return FALSE;
3208 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3210 return NULL;
3212 BOOL WineEngDestroyFontInstance(HFONT hfont)
3214 return FALSE;
3217 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3219 return 1;
3222 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3223 LPWORD pgi, DWORD flags)
3225 return GDI_ERROR;
3228 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3229 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3230 const MAT2* lpmat)
3232 ERR("called but we don't have FreeType\n");
3233 return GDI_ERROR;
3236 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3238 ERR("called but we don't have FreeType\n");
3239 return FALSE;
3242 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3243 OUTLINETEXTMETRICW *potm)
3245 ERR("called but we don't have FreeType\n");
3246 return 0;
3249 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3250 LPINT buffer)
3252 ERR("called but we don't have FreeType\n");
3253 return FALSE;
3256 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3257 LPABC buffer)
3259 ERR("called but we don't have FreeType\n");
3260 return FALSE;
3263 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3264 LPSIZE size)
3266 ERR("called but we don't have FreeType\n");
3267 return FALSE;
3270 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3271 LPSIZE size)
3273 ERR("called but we don't have FreeType\n");
3274 return FALSE;
3277 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3278 DWORD cbData)
3280 ERR("called but we don't have FreeType\n");
3281 return GDI_ERROR;
3284 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3286 ERR("called but we don't have FreeType\n");
3287 return 0;
3290 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3292 FIXME(":stub\n");
3293 return 1;
3296 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3298 FIXME(":stub\n");
3299 return TRUE;
3302 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3304 FIXME(":stub\n");
3305 return DEFAULT_CHARSET;
3308 #endif /* HAVE_FREETYPE */