It's important to keep the original dib colour table and not just the
[wine/multimedia.git] / dlls / gdi / freetype.c
blob3eaff3f876a6eea4a6811ecf5162f393ae4832e1
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 #include <sys/stat.h>
29 #include <string.h>
30 #include <dirent.h>
31 #include <stdio.h>
32 #include <assert.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wingdi.h"
39 #include "gdi.h"
40 #include "gdi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 #include "wine/list.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(font);
47 #ifdef HAVE_FREETYPE
49 #ifdef HAVE_FT2BUILD_H
50 #include <ft2build.h>
51 #endif
52 #ifdef HAVE_FREETYPE_FREETYPE_H
53 #include <freetype/freetype.h>
54 #endif
55 #ifdef HAVE_FREETYPE_FTGLYPH_H
56 #include <freetype/ftglyph.h>
57 #endif
58 #ifdef HAVE_FREETYPE_TTTABLES_H
59 #include <freetype/tttables.h>
60 #endif
61 #ifdef HAVE_FREETYPE_FTSNAMES_H
62 #include <freetype/ftsnames.h>
63 #else
64 # ifdef HAVE_FREETYPE_FTNAMES_H
65 # include <freetype/ftnames.h>
66 # endif
67 #endif
68 #ifdef HAVE_FREETYPE_TTNAMEID_H
69 #include <freetype/ttnameid.h>
70 #endif
71 #ifdef HAVE_FREETYPE_FTOUTLN_H
72 #include <freetype/ftoutln.h>
73 #endif
74 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
75 #include <freetype/internal/sfnt.h>
76 #endif
77 #ifdef HAVE_FREETYPE_FTTRIGON_H
78 #include <freetype/fttrigon.h>
79 #endif
80 #ifdef HAVE_FREETYPE_FTWINFNT_H
81 #include <freetype/ftwinfnt.h>
82 #endif
84 #ifndef SONAME_LIBFREETYPE
85 #define SONAME_LIBFREETYPE "libfreetype.so"
86 #endif
88 static FT_Library library = 0;
89 typedef struct
91 FT_Int major;
92 FT_Int minor;
93 FT_Int patch;
94 } FT_Version_t;
95 static FT_Version_t FT_Version;
96 static DWORD FT_SimpleVersion;
98 static void *ft_handle = NULL;
100 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
101 MAKE_FUNCPTR(FT_Vector_Unit);
102 MAKE_FUNCPTR(FT_Done_Face);
103 MAKE_FUNCPTR(FT_Get_Char_Index);
104 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
105 MAKE_FUNCPTR(FT_Init_FreeType);
106 MAKE_FUNCPTR(FT_Load_Glyph);
107 MAKE_FUNCPTR(FT_Matrix_Multiply);
108 MAKE_FUNCPTR(FT_MulFix);
109 MAKE_FUNCPTR(FT_New_Face);
110 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
111 MAKE_FUNCPTR(FT_Outline_Transform);
112 MAKE_FUNCPTR(FT_Outline_Translate);
113 MAKE_FUNCPTR(FT_Select_Charmap);
114 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
115 MAKE_FUNCPTR(FT_Vector_Transform);
116 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
117 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
118 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
119 #ifdef HAVE_FREETYPE_FTWINFNT_H
120 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
121 #endif
123 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
124 #include <fontconfig/fontconfig.h>
125 MAKE_FUNCPTR(FcConfigGetCurrent);
126 MAKE_FUNCPTR(FcFontList);
127 MAKE_FUNCPTR(FcFontSetDestroy);
128 MAKE_FUNCPTR(FcInit);
129 MAKE_FUNCPTR(FcObjectSetAdd);
130 MAKE_FUNCPTR(FcObjectSetCreate);
131 MAKE_FUNCPTR(FcObjectSetDestroy);
132 MAKE_FUNCPTR(FcPatternCreate);
133 MAKE_FUNCPTR(FcPatternDestroy);
134 MAKE_FUNCPTR(FcPatternGet);
135 #ifndef SONAME_LIBFONTCONFIG
136 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
137 #endif
138 #endif
140 #undef MAKE_FUNCPTR
142 #ifndef FT_ENCODING_NONE
143 #define FT_ENCODING_NONE ft_encoding_none
144 #endif
145 #ifndef FT_ENCODING_MS_SYMBOL
146 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
147 #endif
148 #ifndef FT_ENCODING_UNICODE
149 #define FT_ENCODING_UNICODE ft_encoding_unicode
150 #endif
151 #ifndef FT_ENCODING_APPLE_ROMAN
152 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
153 #endif
155 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
157 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
158 typedef struct {
159 FT_Short height;
160 FT_Short width;
161 FT_Pos size;
162 FT_Pos x_ppem;
163 FT_Pos y_ppem;
164 FT_Short internal_leading;
165 } Bitmap_Size;
167 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
168 So to let this compile on older versions of FreeType we'll define the
169 new structure here. */
170 typedef struct {
171 FT_Short height, width;
172 FT_Pos size, x_ppem, y_ppem;
173 } My_FT_Bitmap_Size;
175 typedef struct tagFace {
176 struct list entry;
177 WCHAR *StyleName;
178 char *file;
179 FT_Long face_index;
180 BOOL Italic;
181 BOOL Bold;
182 FONTSIGNATURE fs;
183 FT_Fixed font_version;
184 BOOL scalable;
185 Bitmap_Size size; /* set if face is a bitmap */
186 BOOL external; /* TRUE if we should manually add this font to the registry */
187 struct tagFamily *family;
188 } Face;
190 typedef struct tagFamily {
191 struct list entry;
192 WCHAR *FamilyName;
193 struct list faces;
194 } Family;
196 typedef struct {
197 GLYPHMETRICS gm;
198 INT adv; /* These three hold to widths of the unrotated chars */
199 INT lsb;
200 INT bbx;
201 BOOL init;
202 } GM;
204 typedef struct {
205 FLOAT eM11, eM12;
206 FLOAT eM21, eM22;
207 } FMAT2;
209 typedef struct {
210 DWORD hash;
211 LOGFONTW lf;
212 FMAT2 matrix;
213 } FONT_DESC;
215 typedef struct tagHFONTLIST {
216 struct list entry;
217 HFONT hfont;
218 } HFONTLIST;
220 struct tagGdiFont {
221 struct list entry;
222 FT_Face ft_face;
223 LPWSTR name;
224 int charset;
225 int codepage;
226 BOOL fake_italic;
227 BOOL fake_bold;
228 BYTE underline;
229 BYTE strikeout;
230 INT orientation;
231 GM *gm;
232 DWORD gmsize;
233 struct list hfontlist;
234 FONT_DESC font_desc;
235 LONG aveWidth;
236 SHORT yMax;
237 SHORT yMin;
238 OUTLINETEXTMETRICW *potm;
239 FONTSIGNATURE fs;
242 #define INIT_GM_SIZE 128
244 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
245 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
246 #define UNUSED_CACHE_SIZE 10
248 static struct list font_list = LIST_INIT(font_list);
250 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
251 'R','o','m','a','n','\0'};
252 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
253 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
255 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
256 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
257 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
258 'S','e','r','i','f','\0'};
259 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
260 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
262 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
263 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
264 'W','i','n','d','o','w','s','\\',
265 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
266 'F','o','n','t','s','\0'};
268 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
269 'W','i','n','d','o','w','s',' ','N','T','\\',
270 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
271 'F','o','n','t','s','\0'};
273 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
274 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
275 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
276 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
278 static const WCHAR *SystemFontValues[4] = {
279 System_Value,
280 OEMFont_Value,
281 FixedSys_Value,
282 NULL
285 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
286 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
288 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
289 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
290 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
291 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
292 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
293 'E','u','r','o','p','e','a','n','\0'};
294 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
295 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
296 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
297 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
298 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
299 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
300 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
301 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
302 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
303 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
304 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
305 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
307 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
308 WesternW, /*00*/
309 Central_EuropeanW,
310 CyrillicW,
311 GreekW,
312 TurkishW,
313 HebrewW,
314 ArabicW,
315 BalticW,
316 VietnameseW, /*08*/
317 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
318 ThaiW,
319 JapaneseW,
320 CHINESE_GB2312W,
321 HangulW,
322 CHINESE_BIG5W,
323 Hangul_Johab_W,
324 NULL, NULL, /*23*/
325 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
326 SymbolW /*31*/
329 typedef struct {
330 WCHAR *name;
331 INT charset;
332 } NameCs;
334 typedef struct tagFontSubst {
335 NameCs from;
336 NameCs to;
337 struct tagFontSubst *next;
338 } FontSubst;
340 static FontSubst *substlist = NULL;
341 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
343 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
346 /****************************************
347 * Notes on .fon files
349 * The fonts System, FixedSys and Terminal are special. There are typically multiple
350 * versions installed for different resolutions and codepages. Windows stores which one to use
351 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
352 * Key Meaning
353 * FIXEDFON.FON FixedSys
354 * FONTS.FON System
355 * OEMFONT.FON Termial
356 * LogPixels Current dpi set by the display control panel applet
357 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
358 * also has a LogPixels value that appears to mirror this)
360 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
361 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
362 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
363 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
364 * so that makes sense.
366 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
367 * to be mapped into the registry on Windows 2000 at least).
368 * I have
369 * woafont=app850.fon
370 * ega80woa.fon=ega80850.fon
371 * ega40woa.fon=ega40850.fon
372 * cga80woa.fon=cga80850.fon
373 * cga40woa.fon=cga40850.fon
377 static inline BOOL is_win9x(void)
379 return GetVersion() & 0x80000000;
382 This function builds an FT_Fixed from a float. It puts the integer part
383 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
384 It fails if the integer part of the float number is greater than SHORT_MAX.
386 static inline FT_Fixed FT_FixedFromFloat(float f)
388 short value = f;
389 unsigned short fract = (f - value) * 0xFFFF;
390 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
394 This function builds an FT_Fixed from a FIXED. It simply put f.value
395 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
397 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
399 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
402 #define ADDFONT_EXTERNAL_FONT 0x01
403 #define ADDFONT_FORCE_BITMAP 0x02
404 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
406 FT_Face ft_face;
407 TT_OS2 *pOS2;
408 TT_Header *pHeader = NULL;
409 WCHAR *FamilyW, *StyleW;
410 DWORD len;
411 Family *family;
412 Face *face;
413 struct list *family_elem_ptr, *face_elem_ptr;
414 FT_Error err;
415 FT_Long face_index = 0, num_faces;
416 #ifdef HAVE_FREETYPE_FTWINFNT_H
417 FT_WinFNT_HeaderRec winfnt_header;
418 #endif
419 int i, bitmap_num;
421 do {
422 char *family_name = fake_family;
424 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
425 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
426 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
427 return FALSE;
430 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*/
431 pFT_Done_Face(ft_face);
432 return FALSE;
435 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
436 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
437 pFT_Done_Face(ft_face);
438 return FALSE;
441 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
442 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
443 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
444 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
445 "Skipping this font.\n", debugstr_a(file));
446 pFT_Done_Face(ft_face);
447 return FALSE;
450 if(!ft_face->family_name || !ft_face->style_name) {
451 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
452 pFT_Done_Face(ft_face);
453 return FALSE;
456 if(!family_name)
457 family_name = ft_face->family_name;
459 bitmap_num = 0;
460 do {
461 My_FT_Bitmap_Size *size = NULL;
463 if(!FT_IS_SCALABLE(ft_face))
464 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
466 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
467 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
468 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
470 family = NULL;
471 LIST_FOR_EACH(family_elem_ptr, &font_list) {
472 family = LIST_ENTRY(family_elem_ptr, Family, entry);
473 if(!strcmpW(family->FamilyName, FamilyW))
474 break;
475 family = NULL;
477 if(!family) {
478 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
479 family->FamilyName = FamilyW;
480 list_init(&family->faces);
481 list_add_tail(&font_list, &family->entry);
482 } else {
483 HeapFree(GetProcessHeap(), 0, FamilyW);
486 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
487 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
488 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
490 face_elem_ptr = list_head(&family->faces);
491 while(face_elem_ptr) {
492 face = LIST_ENTRY(face_elem_ptr, Face, entry);
493 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
494 if(!strcmpW(face->StyleName, StyleW) &&
495 (FT_IS_SCALABLE(ft_face) || (size->y_ppem == face->size.y_ppem))) {
496 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
497 debugstr_w(family->FamilyName), debugstr_w(StyleW),
498 face->font_version, pHeader ? pHeader->Font_Revision : 0);
500 if(fake_family) {
501 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
502 HeapFree(GetProcessHeap(), 0, StyleW);
503 pFT_Done_Face(ft_face);
504 return FALSE;
506 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
507 TRACE("Original font is newer so skipping this one\n");
508 HeapFree(GetProcessHeap(), 0, StyleW);
509 pFT_Done_Face(ft_face);
510 return FALSE;
511 } else {
512 TRACE("Replacing original with this one\n");
513 list_remove(&face->entry);
514 HeapFree(GetProcessHeap(), 0, face->file);
515 HeapFree(GetProcessHeap(), 0, face->StyleName);
516 HeapFree(GetProcessHeap(), 0, face);
517 break;
521 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
522 list_add_tail(&family->faces, &face->entry);
523 face->StyleName = StyleW;
524 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
525 strcpy(face->file, file);
526 face->face_index = face_index;
527 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
528 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
529 face->font_version = pHeader ? pHeader->Font_Revision : 0;
530 face->family = family;
531 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
533 if(FT_IS_SCALABLE(ft_face)) {
534 memset(&face->size, 0, sizeof(face->size));
535 face->scalable = TRUE;
536 } else {
537 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
538 size->height, size->width, size->size >> 6,
539 size->x_ppem >> 6, size->y_ppem >> 6);
540 face->size.height = size->height;
541 face->size.width = size->width;
542 face->size.size = size->size;
543 face->size.x_ppem = size->x_ppem;
544 face->size.y_ppem = size->y_ppem;
545 face->size.internal_leading = 0;
546 face->scalable = FALSE;
549 memset(&face->fs, 0, sizeof(face->fs));
551 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
552 if(pOS2) {
553 face->fs.fsCsb[0] = pOS2->ulCodePageRange1;
554 face->fs.fsCsb[1] = pOS2->ulCodePageRange2;
555 face->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
556 face->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
557 face->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
558 face->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
559 if(pOS2->version == 0) {
560 FT_UInt dummy;
562 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
563 face->fs.fsCsb[0] |= 1;
564 else
565 face->fs.fsCsb[0] |= 1L << 31;
568 #ifdef HAVE_FREETYPE_FTWINFNT_H
569 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
570 CHARSETINFO csi;
571 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
572 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
573 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
574 memcpy(&face->fs, &csi.fs, sizeof(csi.fs));
575 face->size.internal_leading = winfnt_header.internal_leading;
577 #endif
578 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
579 face->fs.fsCsb[0], face->fs.fsCsb[1],
580 face->fs.fsUsb[0], face->fs.fsUsb[1],
581 face->fs.fsUsb[2], face->fs.fsUsb[3]);
584 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
585 for(i = 0; i < ft_face->num_charmaps; i++) {
586 switch(ft_face->charmaps[i]->encoding) {
587 case FT_ENCODING_UNICODE:
588 case FT_ENCODING_APPLE_ROMAN:
589 face->fs.fsCsb[0] |= 1;
590 break;
591 case FT_ENCODING_MS_SYMBOL:
592 face->fs.fsCsb[0] |= 1L << 31;
593 break;
594 default:
595 break;
600 if(face->fs.fsCsb[0] & ~(1L << 31))
601 have_installed_roman_font = TRUE;
602 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
604 num_faces = ft_face->num_faces;
605 pFT_Done_Face(ft_face);
606 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
607 debugstr_w(StyleW));
608 } while(num_faces > ++face_index);
609 return TRUE;
612 static void DumpFontList(void)
614 Family *family;
615 Face *face;
616 struct list *family_elem_ptr, *face_elem_ptr;
618 LIST_FOR_EACH(family_elem_ptr, &font_list) {
619 family = LIST_ENTRY(family_elem_ptr, Family, entry);
620 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
621 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
622 face = LIST_ENTRY(face_elem_ptr, Face, entry);
623 TRACE("\t%s", debugstr_w(face->StyleName));
624 if(!face->scalable)
625 TRACE(" %ld", face->size.y_ppem >> 6);
626 TRACE("\n");
629 return;
632 static void DumpSubstList(void)
634 FontSubst *psub;
636 for(psub = substlist; psub; psub = psub->next)
637 if(psub->from.charset != -1 || psub->to.charset != -1)
638 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
639 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
640 else
641 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
642 debugstr_w(psub->to.name));
643 return;
646 static LPWSTR strdupW(LPWSTR p)
648 LPWSTR ret;
649 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
650 ret = HeapAlloc(GetProcessHeap(), 0, len);
651 memcpy(ret, p, len);
652 return ret;
655 static void split_subst_info(NameCs *nc, LPSTR str)
657 CHAR *p = strrchr(str, ',');
658 DWORD len;
660 nc->charset = -1;
661 if(p && *(p+1)) {
662 nc->charset = strtol(p+1, NULL, 10);
663 *p = '\0';
665 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
666 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
667 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
670 static void LoadSubstList(void)
672 FontSubst *psub, **ppsub;
673 HKEY hkey;
674 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
675 LPSTR value;
676 LPVOID data;
678 if(substlist) {
679 for(psub = substlist; psub;) {
680 FontSubst *ptmp;
681 HeapFree(GetProcessHeap(), 0, psub->to.name);
682 HeapFree(GetProcessHeap(), 0, psub->from.name);
683 ptmp = psub;
684 psub = psub->next;
685 HeapFree(GetProcessHeap(), 0, ptmp);
687 substlist = NULL;
690 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
691 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
692 &hkey) == ERROR_SUCCESS) {
694 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
695 &valuelen, &datalen, NULL, NULL);
697 valuelen++; /* returned value doesn't include room for '\0' */
698 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
699 data = HeapAlloc(GetProcessHeap(), 0, datalen);
701 dlen = datalen;
702 vlen = valuelen;
703 ppsub = &substlist;
704 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
705 &dlen) == ERROR_SUCCESS) {
706 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
708 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
709 (*ppsub)->next = NULL;
710 split_subst_info(&((*ppsub)->from), value);
711 split_subst_info(&((*ppsub)->to), data);
713 /* Win 2000 doesn't allow mapping between different charsets
714 or mapping of DEFAULT_CHARSET */
715 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
716 (*ppsub)->to.charset == DEFAULT_CHARSET) {
717 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
718 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
719 HeapFree(GetProcessHeap(), 0, *ppsub);
720 *ppsub = NULL;
721 } else {
722 ppsub = &((*ppsub)->next);
724 /* reset dlen and vlen */
725 dlen = datalen;
726 vlen = valuelen;
728 HeapFree(GetProcessHeap(), 0, data);
729 HeapFree(GetProcessHeap(), 0, value);
730 RegCloseKey(hkey);
734 /***********************************************************
735 * The replacement list is a way to map an entire font
736 * family onto another family. For example adding
738 * [HKLM\Software\Wine\Wine\FontReplacements]
739 * "Wingdings"="Winedings"
741 * would enumerate the Winedings font both as Winedings and
742 * Wingdings. However if a real Wingdings font is present the
743 * replacement does not take place.
746 static void LoadReplaceList(void)
748 HKEY hkey;
749 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
750 LPSTR value;
751 LPVOID data;
752 Family *family;
753 Face *face;
754 struct list *family_elem_ptr, *face_elem_ptr;
755 WCHAR old_nameW[200];
757 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
758 "Software\\Wine\\Wine\\FontReplacements",
759 &hkey) == ERROR_SUCCESS) {
761 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
762 &valuelen, &datalen, NULL, NULL);
764 valuelen++; /* returned value doesn't include room for '\0' */
765 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
766 data = HeapAlloc(GetProcessHeap(), 0, datalen);
768 dlen = datalen;
769 vlen = valuelen;
770 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
771 &dlen) == ERROR_SUCCESS) {
772 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
773 /* "NewName"="Oldname" */
774 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
775 break;
777 /* Find the old family and hence all of the font files
778 in that family */
779 LIST_FOR_EACH(family_elem_ptr, &font_list) {
780 family = LIST_ENTRY(family_elem_ptr, Family, entry);
781 if(!strcmpiW(family->FamilyName, old_nameW)) {
782 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
783 face = LIST_ENTRY(face_elem_ptr, Face, entry);
784 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
785 debugstr_w(face->StyleName), value);
786 /* Now add a new entry with the new family name */
787 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
789 break;
792 /* reset dlen and vlen */
793 dlen = datalen;
794 vlen = valuelen;
796 HeapFree(GetProcessHeap(), 0, data);
797 HeapFree(GetProcessHeap(), 0, value);
798 RegCloseKey(hkey);
803 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
805 DIR *dir;
806 struct dirent *dent;
807 char path[MAX_PATH];
809 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
811 dir = opendir(dirname);
812 if(!dir) {
813 ERR("Can't open directory %s\n", debugstr_a(dirname));
814 return FALSE;
816 while((dent = readdir(dir)) != NULL) {
817 struct stat statbuf;
819 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
820 continue;
822 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
824 sprintf(path, "%s/%s", dirname, dent->d_name);
826 if(stat(path, &statbuf) == -1)
828 WARN("Can't stat %s\n", debugstr_a(path));
829 continue;
831 if(S_ISDIR(statbuf.st_mode))
832 ReadFontDir(path, external_fonts);
833 else
834 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
836 closedir(dir);
837 return TRUE;
840 static void load_fontconfig_fonts(void)
842 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
843 void *fc_handle = NULL;
844 FcConfig *config;
845 FcPattern *pat;
846 FcObjectSet *os;
847 FcFontSet *fontset;
848 FcValue v;
849 int i, len;
850 const char *ext;
852 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
853 if(!fc_handle) {
854 TRACE("Wine cannot find the fontconfig library (%s).\n",
855 SONAME_LIBFONTCONFIG);
856 return;
858 #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;}
859 LOAD_FUNCPTR(FcConfigGetCurrent);
860 LOAD_FUNCPTR(FcFontList);
861 LOAD_FUNCPTR(FcFontSetDestroy);
862 LOAD_FUNCPTR(FcInit);
863 LOAD_FUNCPTR(FcObjectSetAdd);
864 LOAD_FUNCPTR(FcObjectSetCreate);
865 LOAD_FUNCPTR(FcObjectSetDestroy);
866 LOAD_FUNCPTR(FcPatternCreate);
867 LOAD_FUNCPTR(FcPatternDestroy);
868 LOAD_FUNCPTR(FcPatternGet);
869 #undef LOAD_FUNCPTR
871 if(!pFcInit()) return;
873 config = pFcConfigGetCurrent();
874 pat = pFcPatternCreate();
875 os = pFcObjectSetCreate();
876 pFcObjectSetAdd(os, FC_FILE);
877 fontset = pFcFontList(config, pat, os);
878 if(!fontset) return;
879 for(i = 0; i < fontset->nfont; i++) {
880 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
881 continue;
882 if(v.type != FcTypeString) continue;
883 TRACE("fontconfig: %s\n", v.u.s);
885 /* We're just interested in OT/TT fonts for now, so this hack just
886 picks up the standard extensions to save time loading every other
887 font */
888 len = strlen(v.u.s);
889 if(len < 4) continue;
890 ext = v.u.s + len - 3;
891 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
892 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
894 pFcFontSetDestroy(fontset);
895 pFcObjectSetDestroy(os);
896 pFcPatternDestroy(pat);
897 sym_not_found:
898 #endif
899 return;
903 void load_system_fonts(void)
905 HKEY hkey;
906 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
907 const WCHAR **value;
908 DWORD dlen, type;
909 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
910 char *unixname;
912 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
913 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
914 strcatW(windowsdir, fontsW);
915 for(value = SystemFontValues; *value; value++) {
916 dlen = sizeof(data);
917 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
918 type == REG_SZ) {
919 sprintfW(pathW, fmtW, windowsdir, data);
920 if((unixname = wine_get_unix_file_name(pathW))) {
921 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
922 HeapFree(GetProcessHeap(), 0, unixname);
926 RegCloseKey(hkey);
930 /*************************************************************
932 * This adds registry entries for any externally loaded fonts
933 * (fonts from fontconfig or FontDirs). It also deletes entries
934 * of no longer existing fonts.
937 void update_reg_entries(void)
939 HKEY winkey = 0, externalkey = 0;
940 LPWSTR valueW;
941 LPVOID data;
942 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
943 Family *family;
944 Face *face;
945 struct list *family_elem_ptr, *face_elem_ptr;
946 WCHAR *file;
947 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
948 static const WCHAR spaceW[] = {' ', '\0'};
949 char *path;
951 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
952 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
953 ERR("Can't create Windows font reg key\n");
954 goto end;
956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
957 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
958 ERR("Can't create external font reg key\n");
959 goto end;
962 /* Delete all external fonts added last time */
964 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
965 &valuelen, &datalen, NULL, NULL);
966 valuelen++; /* returned value doesn't include room for '\0' */
967 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
968 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
970 dlen = datalen * sizeof(WCHAR);
971 vlen = valuelen;
972 i = 0;
973 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
974 &dlen) == ERROR_SUCCESS) {
976 RegDeleteValueW(winkey, valueW);
977 /* reset dlen and vlen */
978 dlen = datalen;
979 vlen = valuelen;
981 HeapFree(GetProcessHeap(), 0, data);
982 HeapFree(GetProcessHeap(), 0, valueW);
984 /* Delete the old external fonts key */
985 RegCloseKey(externalkey);
986 externalkey = 0;
987 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
989 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
990 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
991 ERR("Can't create external font reg key\n");
992 goto end;
995 /* enumerate the fonts and add external ones to the two keys */
997 LIST_FOR_EACH(family_elem_ptr, &font_list) {
998 family = LIST_ENTRY(family_elem_ptr, Family, entry);
999 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1000 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1001 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1002 if(!face->external) continue;
1003 len = len_fam;
1004 if(strcmpiW(face->StyleName, RegularW))
1005 len = len_fam + strlenW(face->StyleName) + 1;
1006 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1007 strcpyW(valueW, family->FamilyName);
1008 if(len != len_fam) {
1009 strcatW(valueW, spaceW);
1010 strcatW(valueW, face->StyleName);
1012 strcatW(valueW, TrueType);
1013 if((path = strrchr(face->file, '/')) == NULL)
1014 path = face->file;
1015 else
1016 path++;
1017 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1019 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1020 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1021 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1022 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1024 HeapFree(GetProcessHeap(), 0, file);
1025 HeapFree(GetProcessHeap(), 0, valueW);
1028 end:
1029 if(externalkey)
1030 RegCloseKey(externalkey);
1031 if(winkey)
1032 RegCloseKey(winkey);
1033 return;
1037 /*************************************************************
1038 * WineEngAddFontResourceEx
1041 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1043 if (ft_handle) /* do it only if we have freetype up and running */
1045 char *unixname;
1047 if(flags)
1048 FIXME("Ignoring flags %lx\n", flags);
1050 if((unixname = wine_get_unix_file_name(file)))
1052 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1053 HeapFree(GetProcessHeap(), 0, unixname);
1056 return 1;
1059 /*************************************************************
1060 * WineEngRemoveFontResourceEx
1063 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1065 FIXME(":stub\n");
1066 return TRUE;
1069 /*************************************************************
1070 * WineEngInit
1072 * Initialize FreeType library and create a list of available faces
1074 BOOL WineEngInit(void)
1076 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1077 HKEY hkey;
1078 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1079 LPVOID data;
1080 WCHAR windowsdir[MAX_PATH];
1081 char *unixname;
1082 HANDLE font_mutex;
1084 TRACE("\n");
1086 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1087 if(!ft_handle) {
1088 WINE_MESSAGE(
1089 "Wine cannot find the FreeType font library. To enable Wine to\n"
1090 "use TrueType fonts please install a version of FreeType greater than\n"
1091 "or equal to 2.0.5.\n"
1092 "http://www.freetype.org\n");
1093 return FALSE;
1096 #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;}
1098 LOAD_FUNCPTR(FT_Vector_Unit)
1099 LOAD_FUNCPTR(FT_Done_Face)
1100 LOAD_FUNCPTR(FT_Get_Char_Index)
1101 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1102 LOAD_FUNCPTR(FT_Init_FreeType)
1103 LOAD_FUNCPTR(FT_Load_Glyph)
1104 LOAD_FUNCPTR(FT_Matrix_Multiply)
1105 LOAD_FUNCPTR(FT_MulFix)
1106 LOAD_FUNCPTR(FT_New_Face)
1107 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1108 LOAD_FUNCPTR(FT_Outline_Transform)
1109 LOAD_FUNCPTR(FT_Outline_Translate)
1110 LOAD_FUNCPTR(FT_Select_Charmap)
1111 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1112 LOAD_FUNCPTR(FT_Vector_Transform)
1114 #undef LOAD_FUNCPTR
1115 /* Don't warn if this one is missing */
1116 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1117 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1118 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1119 #ifdef HAVE_FREETYPE_FTWINFNT_H
1120 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1121 #endif
1122 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1123 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1124 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1125 <= 2.0.3 has FT_Sqrt64 */
1126 goto sym_not_found;
1129 if(pFT_Init_FreeType(&library) != 0) {
1130 ERR("Can't init FreeType library\n");
1131 wine_dlclose(ft_handle, NULL, 0);
1132 ft_handle = NULL;
1133 return FALSE;
1135 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1136 if (pFT_Library_Version)
1138 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1140 if (FT_Version.major<=0)
1142 FT_Version.major=2;
1143 FT_Version.minor=0;
1144 FT_Version.patch=5;
1146 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1147 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1148 ((FT_Version.minor << 8) & 0x00ff00) |
1149 ((FT_Version.patch ) & 0x0000ff);
1151 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1152 ERR("Failed to create font mutex\n");
1153 return FALSE;
1155 WaitForSingleObject(font_mutex, INFINITE);
1157 /* load the system fonts */
1158 load_system_fonts();
1160 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1161 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1162 strcatW(windowsdir, fontsW);
1163 if((unixname = wine_get_unix_file_name(windowsdir)))
1165 ReadFontDir(unixname, FALSE);
1166 HeapFree(GetProcessHeap(), 0, unixname);
1169 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1170 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1171 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1172 will skip these. */
1173 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1174 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1175 &hkey) == ERROR_SUCCESS) {
1176 LPWSTR valueW;
1177 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1178 &valuelen, &datalen, NULL, NULL);
1180 valuelen++; /* returned value doesn't include room for '\0' */
1181 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1182 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1183 if (valueW && data)
1185 dlen = datalen * sizeof(WCHAR);
1186 vlen = valuelen;
1187 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1188 &dlen) == ERROR_SUCCESS) {
1189 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1191 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1193 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1194 HeapFree(GetProcessHeap(), 0, unixname);
1197 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1199 WCHAR pathW[MAX_PATH];
1200 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1201 sprintfW(pathW, fmtW, windowsdir, data);
1202 if((unixname = wine_get_unix_file_name(pathW)))
1204 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1205 HeapFree(GetProcessHeap(), 0, unixname);
1208 /* reset dlen and vlen */
1209 dlen = datalen;
1210 vlen = valuelen;
1213 if (data) HeapFree(GetProcessHeap(), 0, data);
1214 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1215 RegCloseKey(hkey);
1218 load_fontconfig_fonts();
1220 /* then look in any directories that we've specified in the config file */
1221 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1222 "Software\\Wine\\Wine\\Config\\FontDirs",
1223 &hkey) == ERROR_SUCCESS) {
1224 LPSTR value;
1225 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1226 &valuelen, &datalen, NULL, NULL);
1228 valuelen++; /* returned value doesn't include room for '\0' */
1229 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1230 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1232 dlen = datalen;
1233 vlen = valuelen;
1234 i = 0;
1235 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1236 &dlen) == ERROR_SUCCESS) {
1237 TRACE("Got %s=%s\n", value, (LPSTR)data);
1238 ReadFontDir((LPSTR)data, TRUE);
1239 /* reset dlen and vlen */
1240 dlen = datalen;
1241 vlen = valuelen;
1243 HeapFree(GetProcessHeap(), 0, data);
1244 HeapFree(GetProcessHeap(), 0, value);
1245 RegCloseKey(hkey);
1248 DumpFontList();
1249 LoadSubstList();
1250 DumpSubstList();
1251 LoadReplaceList();
1252 update_reg_entries();
1254 ReleaseMutex(font_mutex);
1255 return TRUE;
1256 sym_not_found:
1257 WINE_MESSAGE(
1258 "Wine cannot find certain functions that it needs inside the FreeType\n"
1259 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1260 "FreeType to at least version 2.0.5.\n"
1261 "http://www.freetype.org\n");
1262 wine_dlclose(ft_handle, NULL, 0);
1263 ft_handle = NULL;
1264 return FALSE;
1268 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1270 TT_OS2 *pOS2;
1271 TT_HoriHeader *pHori;
1273 LONG ppem;
1275 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1276 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1278 if(height == 0) height = 16;
1280 /* Calc. height of EM square:
1282 * For +ve lfHeight we have
1283 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1284 * Re-arranging gives:
1285 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1287 * For -ve lfHeight we have
1288 * |lfHeight| = ppem
1289 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1290 * with il = winAscent + winDescent - units_per_em]
1294 if(height > 0) {
1295 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1296 ppem = ft_face->units_per_EM * height /
1297 (pHori->Ascender - pHori->Descender);
1298 else
1299 ppem = ft_face->units_per_EM * height /
1300 (pOS2->usWinAscent + pOS2->usWinDescent);
1302 else
1303 ppem = -height;
1305 return ppem;
1308 static LONG load_VDMX(GdiFont, LONG);
1310 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1312 FT_Error err;
1313 FT_Face ft_face;
1314 LONG ppem;
1316 err = pFT_New_Face(library, file, face_index, &ft_face);
1317 if(err) {
1318 ERR("FT_New_Face rets %d\n", err);
1319 return 0;
1322 /* set it here, as load_VDMX needs it */
1323 font->ft_face = ft_face;
1325 if(FT_IS_SCALABLE(ft_face)) {
1326 /* load the VDMX table if we have one */
1327 ppem = load_VDMX(font, height);
1328 if(ppem == 0)
1329 ppem = calc_ppem_for_height(ft_face, height);
1331 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1332 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1333 } else {
1334 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1335 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1337 return ft_face;
1341 static int get_nearest_charset(Face *face, int *cp)
1343 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1344 a single face with the requested charset. The idea is to check if
1345 the selected font supports the current ANSI codepage, if it does
1346 return the corresponding charset, else return the first charset */
1348 CHARSETINFO csi;
1349 int acp = GetACP(), i;
1350 DWORD fs0;
1352 *cp = acp;
1353 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1354 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1355 return csi.ciCharset;
1357 for(i = 0; i < 32; i++) {
1358 fs0 = 1L << i;
1359 if(face->fs.fsCsb[0] & fs0) {
1360 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1361 *cp = csi.ciACP;
1362 return csi.ciCharset;
1364 else
1365 FIXME("TCI failing on %lx\n", fs0);
1369 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1370 face->fs.fsCsb[0], face->file);
1371 *cp = acp;
1372 return DEFAULT_CHARSET;
1375 static GdiFont alloc_font(void)
1377 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1378 ret->gmsize = INIT_GM_SIZE;
1379 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1380 ret->gmsize * sizeof(*ret->gm));
1381 ret->potm = NULL;
1382 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1383 list_init(&ret->hfontlist);
1384 return ret;
1387 static void free_font(GdiFont font)
1389 if (font->ft_face) pFT_Done_Face(font->ft_face);
1390 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1391 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1392 HeapFree(GetProcessHeap(), 0, font->gm);
1393 HeapFree(GetProcessHeap(), 0, font);
1397 /*************************************************************
1398 * load_VDMX
1400 * load the vdmx entry for the specified height
1403 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1404 ( ( (FT_ULong)_x4 << 24 ) | \
1405 ( (FT_ULong)_x3 << 16 ) | \
1406 ( (FT_ULong)_x2 << 8 ) | \
1407 (FT_ULong)_x1 )
1409 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1411 typedef struct {
1412 BYTE bCharSet;
1413 BYTE xRatio;
1414 BYTE yStartRatio;
1415 BYTE yEndRatio;
1416 } Ratios;
1419 static LONG load_VDMX(GdiFont font, LONG height)
1421 BYTE hdr[6], tmp[2], group[4];
1422 BYTE devXRatio, devYRatio;
1423 USHORT numRecs, numRatios;
1424 DWORD result, offset = -1;
1425 LONG ppem = 0;
1426 int i;
1428 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1430 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1431 return ppem;
1433 /* FIXME: need the real device aspect ratio */
1434 devXRatio = 1;
1435 devYRatio = 1;
1437 numRecs = GET_BE_WORD(&hdr[2]);
1438 numRatios = GET_BE_WORD(&hdr[4]);
1440 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1441 for(i = 0; i < numRatios; i++) {
1442 Ratios ratio;
1444 offset = (3 * 2) + (i * sizeof(Ratios));
1445 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1446 offset = -1;
1448 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1450 if(ratio.bCharSet != 1)
1451 continue;
1453 if((ratio.xRatio == 0 &&
1454 ratio.yStartRatio == 0 &&
1455 ratio.yEndRatio == 0) ||
1456 (devXRatio == ratio.xRatio &&
1457 devYRatio >= ratio.yStartRatio &&
1458 devYRatio <= ratio.yEndRatio))
1460 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1461 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1462 offset = GET_BE_WORD(tmp);
1463 break;
1467 if(offset < 0) {
1468 FIXME("No suitable ratio found\n");
1469 return ppem;
1472 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1473 USHORT recs;
1474 BYTE startsz, endsz;
1475 BYTE *vTable;
1477 recs = GET_BE_WORD(group);
1478 startsz = group[2];
1479 endsz = group[3];
1481 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1483 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1484 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1485 if(result == GDI_ERROR) {
1486 FIXME("Failed to retrieve vTable\n");
1487 goto end;
1490 if(height > 0) {
1491 for(i = 0; i < recs; i++) {
1492 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1493 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1494 ppem = GET_BE_WORD(&vTable[i * 6]);
1496 if(yMax + -yMin == height) {
1497 font->yMax = yMax;
1498 font->yMin = yMin;
1499 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1500 break;
1502 if(yMax + -yMin > height) {
1503 if(--i < 0) {
1504 ppem = 0;
1505 goto end; /* failed */
1507 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1508 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1509 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1510 break;
1513 if(!font->yMax) {
1514 ppem = 0;
1515 TRACE("ppem not found for height %ld\n", height);
1517 } else {
1518 ppem = -height;
1519 if(ppem < startsz || ppem > endsz)
1520 goto end;
1522 for(i = 0; i < recs; i++) {
1523 USHORT yPelHeight;
1524 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1526 if(yPelHeight > ppem)
1527 break; /* failed */
1529 if(yPelHeight == ppem) {
1530 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1531 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1532 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1533 break;
1537 end:
1538 HeapFree(GetProcessHeap(), 0, vTable);
1541 return ppem;
1544 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1546 if(font->font_desc.hash != fd->hash) return TRUE;
1547 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1548 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1549 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1552 static void calc_hash(FONT_DESC *pfd)
1554 DWORD hash = 0, *ptr, two_chars;
1555 WORD *pwc;
1556 unsigned int i;
1558 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1559 hash ^= *ptr;
1560 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1561 hash ^= *ptr;
1562 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1563 two_chars = *ptr;
1564 pwc = (WCHAR *)&two_chars;
1565 if(!*pwc) break;
1566 *pwc = toupperW(*pwc);
1567 pwc++;
1568 *pwc = toupperW(*pwc);
1569 hash ^= two_chars;
1570 if(!*pwc) break;
1572 pfd->hash = hash;
1573 return;
1576 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1578 GdiFont ret;
1579 FONT_DESC fd;
1580 HFONTLIST *hflist;
1581 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1583 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1584 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1585 calc_hash(&fd);
1587 /* try the in-use list */
1588 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1589 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1590 if(!fontcmp(ret, &fd)) {
1591 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1592 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1593 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1594 if(hflist->hfont == hfont)
1595 return ret;
1597 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1598 hflist->hfont = hfont;
1599 list_add_head(&ret->hfontlist, &hflist->entry);
1600 return ret;
1604 /* then the unused list */
1605 font_elem_ptr = list_head(&unused_gdi_font_list);
1606 while(font_elem_ptr) {
1607 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1608 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1609 if(!fontcmp(ret, &fd)) {
1610 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1611 assert(list_empty(&ret->hfontlist));
1612 TRACE("Found %p in unused list\n", ret);
1613 list_remove(&ret->entry);
1614 list_add_head(&gdi_font_list, &ret->entry);
1615 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1616 hflist->hfont = hfont;
1617 list_add_head(&ret->hfontlist, &hflist->entry);
1618 return ret;
1621 return NULL;
1624 /*************************************************************
1625 * WineEngCreateFontInstance
1628 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1630 GdiFont ret;
1631 Face *face, *best;
1632 Family *family;
1633 struct list *family_elem_ptr, *face_elem_ptr;
1634 INT height, width = 0;
1635 signed int diff = 0, newdiff;
1636 BOOL bd, it, can_use_bitmap;
1637 LOGFONTW lf;
1638 CHARSETINFO csi;
1639 HFONTLIST *hflist;
1641 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1642 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1644 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1645 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1646 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1647 lf.lfEscapement);
1649 /* check the cache first */
1650 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1651 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1652 return ret;
1655 TRACE("not in cache\n");
1656 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1658 TRACE("No fonts installed\n");
1659 return NULL;
1662 ret = alloc_font();
1664 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1665 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1666 calc_hash(&ret->font_desc);
1667 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1668 hflist->hfont = hfont;
1669 list_add_head(&ret->hfontlist, &hflist->entry);
1672 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1673 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1674 original value lfCharSet. Note this is a special case for
1675 Symbol and doesn't happen at least for "Wingdings*" */
1677 if(!strcmpiW(lf.lfFaceName, SymbolW))
1678 lf.lfCharSet = SYMBOL_CHARSET;
1680 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1681 switch(lf.lfCharSet) {
1682 case DEFAULT_CHARSET:
1683 csi.fs.fsCsb[0] = 0;
1684 break;
1685 default:
1686 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1687 csi.fs.fsCsb[0] = 0;
1688 break;
1692 family = NULL;
1693 if(lf.lfFaceName[0] != '\0') {
1694 FontSubst *psub;
1695 for(psub = substlist; psub; psub = psub->next)
1696 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1697 (psub->from.charset == -1 ||
1698 psub->from.charset == lf.lfCharSet))
1699 break;
1700 if(psub) {
1701 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1702 debugstr_w(psub->to.name));
1703 strcpyW(lf.lfFaceName, psub->to.name);
1706 /* We want a match on name and charset or just name if
1707 charset was DEFAULT_CHARSET. If the latter then
1708 we fixup the returned charset later in get_nearest_charset
1709 where we'll either use the charset of the current ansi codepage
1710 or if that's unavailable the first charset that the font supports.
1712 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1713 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1714 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1715 face_elem_ptr = list_head(&family->faces);
1716 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1717 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1718 if(face->scalable || can_use_bitmap)
1719 break;
1721 family = NULL;
1725 if(!family) {
1726 /* If requested charset was DEFAULT_CHARSET then try using charset
1727 corresponding to the current ansi codepage */
1728 if(!csi.fs.fsCsb[0]) {
1729 INT acp = GetACP();
1730 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1731 FIXME("TCI failed on codepage %d\n", acp);
1732 csi.fs.fsCsb[0] = 0;
1733 } else
1734 lf.lfCharSet = csi.ciCharset;
1737 /* Face families are in the top 4 bits of lfPitchAndFamily,
1738 so mask with 0xF0 before testing */
1740 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1741 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1742 strcpyW(lf.lfFaceName, defFixed);
1743 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1744 strcpyW(lf.lfFaceName, defSerif);
1745 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1746 strcpyW(lf.lfFaceName, defSans);
1747 else
1748 strcpyW(lf.lfFaceName, defSans);
1749 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1750 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1751 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1752 face_elem_ptr = list_head(&family->faces);
1753 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1754 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1755 if(face->scalable || can_use_bitmap)
1756 break;
1758 family = NULL;
1762 if(!family) {
1763 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1764 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1765 face_elem_ptr = list_head(&family->faces);
1766 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1767 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1768 if(face->scalable || can_use_bitmap)
1769 break;
1770 family = NULL;
1774 if(!family) {
1775 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1776 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1777 face_elem_ptr = list_head(&family->faces);
1778 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1779 if(face->scalable || can_use_bitmap) {
1780 csi.fs.fsCsb[0] = 0;
1781 FIXME("just using first face for now\n");
1782 break;
1784 family = NULL;
1786 if(!family) {
1787 FIXME("can't find a single appropriate font - bailing\n");
1788 free_font(ret);
1789 return NULL;
1793 it = lf.lfItalic ? 1 : 0;
1794 bd = lf.lfWeight > 550 ? 1 : 0;
1796 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1797 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1799 face = best = NULL;
1800 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1801 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1802 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1803 if(face->scalable)
1804 break;
1805 if(height > 0)
1806 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1807 else
1808 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1809 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1810 (diff < 0 && newdiff > diff)) {
1811 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1812 diff = newdiff;
1813 best = face;
1814 if(diff == 0)
1815 break;
1818 face = NULL;
1820 if(!face && best)
1821 face = best;
1822 else if(!face) {
1823 best = NULL;
1824 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1825 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1826 if(face->scalable)
1827 break;
1828 if(height > 0)
1829 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1830 else
1831 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1832 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1833 (diff < 0 && newdiff > diff)) {
1834 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1835 diff = newdiff;
1836 best = face;
1837 if(diff == 0)
1838 break;
1840 face = NULL;
1842 if(!face && best)
1843 face = best;
1844 if(it && !face->Italic) ret->fake_italic = TRUE;
1845 if(bd && !face->Bold) ret->fake_bold = TRUE;
1848 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1850 if(csi.fs.fsCsb[0]) {
1851 ret->charset = lf.lfCharSet;
1852 ret->codepage = csi.ciACP;
1854 else
1855 ret->charset = get_nearest_charset(face, &ret->codepage);
1857 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1858 debugstr_w(face->StyleName));
1860 if(!face->scalable) {
1861 width = face->size.x_ppem >> 6;
1862 height = face->size.y_ppem >> 6;
1864 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1866 if (!ret->ft_face)
1868 free_font( ret );
1869 return 0;
1872 if (ret->charset == SYMBOL_CHARSET &&
1873 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
1874 /* No ops */
1876 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
1877 /* No ops */
1879 else {
1880 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
1883 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1884 ret->name = strdupW(family->FamilyName);
1885 ret->underline = lf.lfUnderline ? 0xff : 0;
1886 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1888 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1890 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1891 list_add_head(&gdi_font_list, &ret->entry);
1892 return ret;
1895 static void dump_gdi_font_list(void)
1897 GdiFont gdiFont;
1898 struct list *elem_ptr;
1900 TRACE("---------- gdiFont Cache ----------\n");
1901 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1902 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1903 TRACE("gdiFont=%p %s %ld\n",
1904 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1907 TRACE("---------- Unused gdiFont Cache ----------\n");
1908 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1909 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1910 TRACE("gdiFont=%p %s %ld\n",
1911 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1915 /*************************************************************
1916 * WineEngDestroyFontInstance
1918 * free the gdiFont associated with this handle
1921 BOOL WineEngDestroyFontInstance(HFONT handle)
1923 GdiFont gdiFont;
1924 HFONTLIST *hflist;
1925 BOOL ret = FALSE;
1926 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1927 int i = 0;
1929 TRACE("destroying hfont=%p\n", handle);
1930 if(TRACE_ON(font))
1931 dump_gdi_font_list();
1933 font_elem_ptr = list_head(&gdi_font_list);
1934 while(font_elem_ptr) {
1935 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1936 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1938 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1939 while(hfontlist_elem_ptr) {
1940 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1941 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1942 if(hflist->hfont == handle) {
1943 list_remove(&hflist->entry);
1944 HeapFree(GetProcessHeap(), 0, hflist);
1945 ret = TRUE;
1948 if(list_empty(&gdiFont->hfontlist)) {
1949 TRACE("Moving to Unused list\n");
1950 list_remove(&gdiFont->entry);
1951 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1956 font_elem_ptr = list_head(&unused_gdi_font_list);
1957 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1958 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1959 while(font_elem_ptr) {
1960 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1961 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1962 TRACE("freeing %p\n", gdiFont);
1963 list_remove(&gdiFont->entry);
1964 free_font(gdiFont);
1966 return ret;
1969 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1970 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1972 OUTLINETEXTMETRICW *potm = NULL;
1973 UINT size;
1974 TEXTMETRICW tm, *ptm;
1975 GdiFont font = alloc_font();
1976 LONG width, height;
1978 if(face->scalable) {
1979 height = 100;
1980 width = 0;
1981 } else {
1982 height = face->size.y_ppem >> 6;
1983 width = face->size.x_ppem >> 6;
1986 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1988 free_font(font);
1989 return;
1992 font->name = strdupW(face->family->FamilyName);
1994 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1996 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1997 if(size) {
1998 potm = HeapAlloc(GetProcessHeap(), 0, size);
1999 WineEngGetOutlineTextMetrics(font, size, potm);
2000 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2001 } else {
2002 WineEngGetTextMetrics(font, &tm);
2003 ptm = &tm;
2006 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2007 pntm->ntmTm.tmAscent = ptm->tmAscent;
2008 pntm->ntmTm.tmDescent = ptm->tmDescent;
2009 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2010 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2011 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2012 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2013 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2014 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2015 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2016 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2017 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2018 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2019 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2020 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2021 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2022 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2023 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2024 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2025 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2026 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2027 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2028 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2029 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2031 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2032 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2033 *ptype |= RASTER_FONTTYPE;
2035 if(potm) {
2036 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2037 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2038 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2040 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2041 pntm->ntmTm.ntmCellHeight = 0;
2042 pntm->ntmTm.ntmAvgWidth = 0;
2044 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2046 strncpyW(pelf->elfLogFont.lfFaceName,
2047 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2048 LF_FACESIZE);
2049 strncpyW(pelf->elfFullName,
2050 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2051 LF_FULLFACESIZE);
2052 strncpyW(pelf->elfStyle,
2053 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2054 LF_FACESIZE);
2056 } else {
2057 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2058 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2059 pelf->elfStyle[0] = '\0';
2062 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2064 HeapFree(GetProcessHeap(), 0, potm);
2065 free_font(font);
2066 return;
2069 /*************************************************************
2070 * WineEngEnumFonts
2073 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2075 Family *family;
2076 Face *face;
2077 struct list *family_elem_ptr, *face_elem_ptr;
2078 ENUMLOGFONTEXW elf;
2079 NEWTEXTMETRICEXW ntm;
2080 DWORD type, ret = 1;
2081 FONTSIGNATURE fs;
2082 CHARSETINFO csi;
2083 LOGFONTW lf;
2084 int i;
2086 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2088 if(plf->lfFaceName[0]) {
2089 FontSubst *psub;
2090 for(psub = substlist; psub; psub = psub->next)
2091 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2092 (psub->from.charset == -1 ||
2093 psub->from.charset == plf->lfCharSet))
2094 break;
2095 if(psub) {
2096 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2097 debugstr_w(psub->to.name));
2098 memcpy(&lf, plf, sizeof(lf));
2099 strcpyW(lf.lfFaceName, psub->to.name);
2100 plf = &lf;
2103 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2104 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2105 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2106 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2107 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2108 GetEnumStructs(face, &elf, &ntm, &type);
2109 for(i = 0; i < 32; i++) {
2110 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2111 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2112 strcpyW(elf.elfScript, OEM_DOSW);
2113 i = 32; /* break out of loop */
2114 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2115 continue;
2116 else {
2117 fs.fsCsb[0] = 1L << i;
2118 fs.fsCsb[1] = 0;
2119 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2120 TCI_SRCFONTSIG))
2121 csi.ciCharset = DEFAULT_CHARSET;
2122 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2123 if(csi.ciCharset != DEFAULT_CHARSET) {
2124 elf.elfLogFont.lfCharSet =
2125 ntm.ntmTm.tmCharSet = csi.ciCharset;
2126 if(ElfScriptsW[i])
2127 strcpyW(elf.elfScript, ElfScriptsW[i]);
2128 else
2129 FIXME("Unknown elfscript for bit %d\n", i);
2132 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2133 debugstr_w(elf.elfLogFont.lfFaceName),
2134 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2135 csi.ciCharset, type, debugstr_w(elf.elfScript),
2136 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2137 ntm.ntmTm.ntmFlags);
2138 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2139 if(!ret) goto end;
2144 } else {
2145 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2146 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2147 face_elem_ptr = list_head(&family->faces);
2148 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2149 GetEnumStructs(face, &elf, &ntm, &type);
2150 for(i = 0; i < 32; i++) {
2151 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2152 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2153 strcpyW(elf.elfScript, OEM_DOSW);
2154 i = 32; /* break out of loop */
2155 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2156 continue;
2157 else {
2158 fs.fsCsb[0] = 1L << i;
2159 fs.fsCsb[1] = 0;
2160 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2161 TCI_SRCFONTSIG))
2162 csi.ciCharset = DEFAULT_CHARSET;
2163 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2164 if(csi.ciCharset != DEFAULT_CHARSET) {
2165 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2166 csi.ciCharset;
2167 if(ElfScriptsW[i])
2168 strcpyW(elf.elfScript, ElfScriptsW[i]);
2169 else
2170 FIXME("Unknown elfscript for bit %d\n", i);
2173 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2174 debugstr_w(elf.elfLogFont.lfFaceName),
2175 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2176 csi.ciCharset, type, debugstr_w(elf.elfScript),
2177 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2178 ntm.ntmTm.ntmFlags);
2179 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2180 if(!ret) goto end;
2184 end:
2185 return ret;
2188 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2190 pt->x.value = vec->x >> 6;
2191 pt->x.fract = (vec->x & 0x3f) << 10;
2192 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2193 pt->y.value = vec->y >> 6;
2194 pt->y.fract = (vec->y & 0x3f) << 10;
2195 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2196 return;
2199 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2201 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2202 WCHAR wc = (WCHAR)glyph;
2203 unsigned char buf;
2204 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2205 return pFT_Get_Char_Index(font->ft_face, buf);
2208 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2209 glyph = glyph + 0xf000;
2210 return pFT_Get_Char_Index(font->ft_face, glyph);
2213 /*************************************************************
2214 * WineEngGetGlyphIndices
2216 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2218 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2219 LPWORD pgi, DWORD flags)
2221 INT i;
2223 for(i = 0; i < count; i++)
2224 pgi[i] = get_glyph_index(font, lpstr[i]);
2226 return count;
2229 /*************************************************************
2230 * WineEngGetGlyphOutline
2232 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2233 * except that the first parameter is the HWINEENGFONT of the font in
2234 * question rather than an HDC.
2237 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2238 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2239 const MAT2* lpmat)
2241 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2242 FT_Face ft_face = font->ft_face;
2243 FT_UInt glyph_index;
2244 DWORD width, height, pitch, needed = 0;
2245 FT_Bitmap ft_bitmap;
2246 FT_Error err;
2247 INT left, right, top = 0, bottom = 0;
2248 FT_Angle angle = 0;
2249 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2250 float widthRatio = 1.0;
2251 FT_Matrix transMat = identityMat;
2252 BOOL needsTransform = FALSE;
2255 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2256 buflen, buf, lpmat);
2258 if(format & GGO_GLYPH_INDEX) {
2259 glyph_index = glyph;
2260 format &= ~GGO_GLYPH_INDEX;
2261 } else
2262 glyph_index = get_glyph_index(font, glyph);
2264 if(glyph_index >= font->gmsize) {
2265 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2266 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2267 font->gmsize * sizeof(*font->gm));
2268 } else {
2269 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2270 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2271 return 1; /* FIXME */
2275 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2276 load_flags |= FT_LOAD_NO_BITMAP;
2278 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2280 if(err) {
2281 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2282 return GDI_ERROR;
2285 /* Scaling factor */
2286 if (font->aveWidth && font->potm) {
2287 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2290 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2291 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2293 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2294 font->gm[glyph_index].lsb = left >> 6;
2295 font->gm[glyph_index].bbx = (right - left) >> 6;
2297 /* Scaling transform */
2298 if(font->aveWidth) {
2299 FT_Matrix scaleMat;
2300 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2301 scaleMat.xy = 0;
2302 scaleMat.yx = 0;
2303 scaleMat.yy = (1 << 16);
2305 pFT_Matrix_Multiply(&scaleMat, &transMat);
2306 needsTransform = TRUE;
2309 /* Rotation transform */
2310 if(font->orientation) {
2311 FT_Matrix rotationMat;
2312 FT_Vector vecAngle;
2313 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2314 pFT_Vector_Unit(&vecAngle, angle);
2315 rotationMat.xx = vecAngle.x;
2316 rotationMat.xy = -vecAngle.y;
2317 rotationMat.yx = -rotationMat.xy;
2318 rotationMat.yy = rotationMat.xx;
2320 pFT_Matrix_Multiply(&rotationMat, &transMat);
2321 needsTransform = TRUE;
2324 /* Extra transformation specified by caller */
2325 if (lpmat) {
2326 FT_Matrix extraMat;
2327 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2328 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2329 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2330 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2331 pFT_Matrix_Multiply(&extraMat, &transMat);
2332 needsTransform = TRUE;
2335 if(!needsTransform) {
2336 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2337 bottom = (ft_face->glyph->metrics.horiBearingY -
2338 ft_face->glyph->metrics.height) & -64;
2339 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2340 lpgm->gmCellIncY = 0;
2341 } else {
2342 INT xc, yc;
2343 FT_Vector vec;
2344 for(xc = 0; xc < 2; xc++) {
2345 for(yc = 0; yc < 2; yc++) {
2346 vec.x = (ft_face->glyph->metrics.horiBearingX +
2347 xc * ft_face->glyph->metrics.width);
2348 vec.y = ft_face->glyph->metrics.horiBearingY -
2349 yc * ft_face->glyph->metrics.height;
2350 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2351 pFT_Vector_Transform(&vec, &transMat);
2352 if(xc == 0 && yc == 0) {
2353 left = right = vec.x;
2354 top = bottom = vec.y;
2355 } else {
2356 if(vec.x < left) left = vec.x;
2357 else if(vec.x > right) right = vec.x;
2358 if(vec.y < bottom) bottom = vec.y;
2359 else if(vec.y > top) top = vec.y;
2363 left = left & -64;
2364 right = (right + 63) & -64;
2365 bottom = bottom & -64;
2366 top = (top + 63) & -64;
2368 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2369 vec.x = ft_face->glyph->metrics.horiAdvance;
2370 vec.y = 0;
2371 pFT_Vector_Transform(&vec, &transMat);
2372 lpgm->gmCellIncX = (vec.x+63) >> 6;
2373 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2375 lpgm->gmBlackBoxX = (right - left) >> 6;
2376 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2377 lpgm->gmptGlyphOrigin.x = left >> 6;
2378 lpgm->gmptGlyphOrigin.y = top >> 6;
2380 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2381 font->gm[glyph_index].init = TRUE;
2383 if(format == GGO_METRICS)
2384 return 1; /* FIXME */
2386 if (buf && !buflen){
2387 return GDI_ERROR;
2390 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2391 TRACE("loaded a bitmap\n");
2392 return GDI_ERROR;
2395 switch(format) {
2396 case GGO_BITMAP:
2397 width = lpgm->gmBlackBoxX;
2398 height = lpgm->gmBlackBoxY;
2399 pitch = ((width + 31) >> 5) << 2;
2400 needed = pitch * height;
2402 if(!buf || !buflen) break;
2404 switch(ft_face->glyph->format) {
2405 case ft_glyph_format_bitmap:
2407 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2408 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2409 INT h = ft_face->glyph->bitmap.rows;
2410 while(h--) {
2411 memcpy(dst, src, w);
2412 src += ft_face->glyph->bitmap.pitch;
2413 dst += pitch;
2415 break;
2418 case ft_glyph_format_outline:
2419 ft_bitmap.width = width;
2420 ft_bitmap.rows = height;
2421 ft_bitmap.pitch = pitch;
2422 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2423 ft_bitmap.buffer = buf;
2425 if(needsTransform) {
2426 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2429 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2431 /* Note: FreeType will only set 'black' bits for us. */
2432 memset(buf, 0, needed);
2433 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2434 break;
2436 default:
2437 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2438 return GDI_ERROR;
2440 break;
2442 case GGO_GRAY2_BITMAP:
2443 case GGO_GRAY4_BITMAP:
2444 case GGO_GRAY8_BITMAP:
2445 case WINE_GGO_GRAY16_BITMAP:
2447 unsigned int mult, row, col;
2448 BYTE *start, *ptr;
2450 width = lpgm->gmBlackBoxX;
2451 height = lpgm->gmBlackBoxY;
2452 pitch = (width + 3) / 4 * 4;
2453 needed = pitch * height;
2455 if(!buf || !buflen) break;
2456 ft_bitmap.width = width;
2457 ft_bitmap.rows = height;
2458 ft_bitmap.pitch = pitch;
2459 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2460 ft_bitmap.buffer = buf;
2462 if(needsTransform) {
2463 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2466 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2468 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2470 if(format == GGO_GRAY2_BITMAP)
2471 mult = 5;
2472 else if(format == GGO_GRAY4_BITMAP)
2473 mult = 17;
2474 else if(format == GGO_GRAY8_BITMAP)
2475 mult = 65;
2476 else if(format == WINE_GGO_GRAY16_BITMAP)
2477 break;
2478 else {
2479 assert(0);
2480 break;
2483 start = buf;
2484 for(row = 0; row < height; row++) {
2485 ptr = start;
2486 for(col = 0; col < width; col++, ptr++) {
2487 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2489 start += pitch;
2491 break;
2494 case GGO_NATIVE:
2496 int contour, point = 0, first_pt;
2497 FT_Outline *outline = &ft_face->glyph->outline;
2498 TTPOLYGONHEADER *pph;
2499 TTPOLYCURVE *ppc;
2500 DWORD pph_start, cpfx, type;
2502 if(buflen == 0) buf = NULL;
2504 if (needsTransform && buf) {
2505 pFT_Outline_Transform(outline, &transMat);
2508 for(contour = 0; contour < outline->n_contours; contour++) {
2509 pph_start = needed;
2510 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2511 first_pt = point;
2512 if(buf) {
2513 pph->dwType = TT_POLYGON_TYPE;
2514 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2516 needed += sizeof(*pph);
2517 point++;
2518 while(point <= outline->contours[contour]) {
2519 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2520 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2521 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2522 cpfx = 0;
2523 do {
2524 if(buf)
2525 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2526 cpfx++;
2527 point++;
2528 } while(point <= outline->contours[contour] &&
2529 (outline->tags[point] & FT_Curve_Tag_On) ==
2530 (outline->tags[point-1] & FT_Curve_Tag_On));
2531 /* At the end of a contour Windows adds the start point, but
2532 only for Beziers */
2533 if(point > outline->contours[contour] &&
2534 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2535 if(buf)
2536 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2537 cpfx++;
2538 } else if(point <= outline->contours[contour] &&
2539 outline->tags[point] & FT_Curve_Tag_On) {
2540 /* add closing pt for bezier */
2541 if(buf)
2542 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2543 cpfx++;
2544 point++;
2546 if(buf) {
2547 ppc->wType = type;
2548 ppc->cpfx = cpfx;
2550 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2552 if(buf)
2553 pph->cb = needed - pph_start;
2555 break;
2557 case GGO_BEZIER:
2559 /* Convert the quadratic Beziers to cubic Beziers.
2560 The parametric eqn for a cubic Bezier is, from PLRM:
2561 r(t) = at^3 + bt^2 + ct + r0
2562 with the control points:
2563 r1 = r0 + c/3
2564 r2 = r1 + (c + b)/3
2565 r3 = r0 + c + b + a
2567 A quadratic Beizer has the form:
2568 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2570 So equating powers of t leads to:
2571 r1 = 2/3 p1 + 1/3 p0
2572 r2 = 2/3 p1 + 1/3 p2
2573 and of course r0 = p0, r3 = p2
2576 int contour, point = 0, first_pt;
2577 FT_Outline *outline = &ft_face->glyph->outline;
2578 TTPOLYGONHEADER *pph;
2579 TTPOLYCURVE *ppc;
2580 DWORD pph_start, cpfx, type;
2581 FT_Vector cubic_control[4];
2582 if(buflen == 0) buf = NULL;
2584 if (needsTransform && buf) {
2585 pFT_Outline_Transform(outline, &transMat);
2588 for(contour = 0; contour < outline->n_contours; contour++) {
2589 pph_start = needed;
2590 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2591 first_pt = point;
2592 if(buf) {
2593 pph->dwType = TT_POLYGON_TYPE;
2594 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2596 needed += sizeof(*pph);
2597 point++;
2598 while(point <= outline->contours[contour]) {
2599 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2600 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2601 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2602 cpfx = 0;
2603 do {
2604 if(type == TT_PRIM_LINE) {
2605 if(buf)
2606 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2607 cpfx++;
2608 point++;
2609 } else {
2610 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2611 so cpfx = 3n */
2613 /* FIXME: Possible optimization in endpoint calculation
2614 if there are two consecutive curves */
2615 cubic_control[0] = outline->points[point-1];
2616 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2617 cubic_control[0].x += outline->points[point].x + 1;
2618 cubic_control[0].y += outline->points[point].y + 1;
2619 cubic_control[0].x >>= 1;
2620 cubic_control[0].y >>= 1;
2622 if(point+1 > outline->contours[contour])
2623 cubic_control[3] = outline->points[first_pt];
2624 else {
2625 cubic_control[3] = outline->points[point+1];
2626 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2627 cubic_control[3].x += outline->points[point].x + 1;
2628 cubic_control[3].y += outline->points[point].y + 1;
2629 cubic_control[3].x >>= 1;
2630 cubic_control[3].y >>= 1;
2633 /* r1 = 1/3 p0 + 2/3 p1
2634 r2 = 1/3 p2 + 2/3 p1 */
2635 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2636 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2637 cubic_control[2] = cubic_control[1];
2638 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2639 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2640 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2641 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2642 if(buf) {
2643 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2644 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2645 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2647 cpfx += 3;
2648 point++;
2650 } while(point <= outline->contours[contour] &&
2651 (outline->tags[point] & FT_Curve_Tag_On) ==
2652 (outline->tags[point-1] & FT_Curve_Tag_On));
2653 /* At the end of a contour Windows adds the start point,
2654 but only for Beziers and we've already done that.
2656 if(point <= outline->contours[contour] &&
2657 outline->tags[point] & FT_Curve_Tag_On) {
2658 /* This is the closing pt of a bezier, but we've already
2659 added it, so just inc point and carry on */
2660 point++;
2662 if(buf) {
2663 ppc->wType = type;
2664 ppc->cpfx = cpfx;
2666 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2668 if(buf)
2669 pph->cb = needed - pph_start;
2671 break;
2674 default:
2675 FIXME("Unsupported format %d\n", format);
2676 return GDI_ERROR;
2678 return needed;
2681 static BOOL get_bitmap_text_metrics(GdiFont font)
2683 FT_Face ft_face = font->ft_face;
2684 #ifdef HAVE_FREETYPE_FTWINFNT_H
2685 FT_WinFNT_HeaderRec winfnt_header;
2686 #endif
2687 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2688 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2689 font->potm->otmSize = size;
2691 #define TM font->potm->otmTextMetrics
2692 #ifdef HAVE_FREETYPE_FTWINFNT_H
2693 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2695 TM.tmHeight = winfnt_header.pixel_height;
2696 TM.tmAscent = winfnt_header.ascent;
2697 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2698 TM.tmInternalLeading = winfnt_header.internal_leading;
2699 TM.tmExternalLeading = winfnt_header.external_leading;
2700 TM.tmAveCharWidth = winfnt_header.avg_width;
2701 TM.tmMaxCharWidth = winfnt_header.max_width;
2702 TM.tmWeight = winfnt_header.weight;
2703 TM.tmOverhang = 0;
2704 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2705 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2706 TM.tmFirstChar = winfnt_header.first_char;
2707 TM.tmLastChar = winfnt_header.last_char;
2708 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2709 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2710 TM.tmItalic = winfnt_header.italic;
2711 TM.tmUnderlined = font->underline;
2712 TM.tmStruckOut = font->strikeout;
2713 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2714 TM.tmCharSet = winfnt_header.charset;
2716 else
2717 #endif
2719 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2720 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2721 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2722 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2723 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2724 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2725 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2726 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2727 TM.tmOverhang = 0;
2728 TM.tmDigitizedAspectX = 96; /* FIXME */
2729 TM.tmDigitizedAspectY = 96; /* FIXME */
2730 TM.tmFirstChar = 1;
2731 TM.tmLastChar = 255;
2732 TM.tmDefaultChar = 32;
2733 TM.tmBreakChar = 32;
2734 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2735 TM.tmUnderlined = font->underline;
2736 TM.tmStruckOut = font->strikeout;
2737 /* NB inverted meaning of TMPF_FIXED_PITCH */
2738 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2739 TM.tmCharSet = font->charset;
2741 #undef TM
2743 return TRUE;
2746 /*************************************************************
2747 * WineEngGetTextMetrics
2750 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2752 if(!font->potm) {
2753 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2754 if(!get_bitmap_text_metrics(font))
2755 return FALSE;
2757 if(!font->potm) return FALSE;
2758 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2760 if (font->aveWidth) {
2761 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2763 return TRUE;
2767 /*************************************************************
2768 * WineEngGetOutlineTextMetrics
2771 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2772 OUTLINETEXTMETRICW *potm)
2774 FT_Face ft_face = font->ft_face;
2775 UINT needed, lenfam, lensty, ret;
2776 TT_OS2 *pOS2;
2777 TT_HoriHeader *pHori;
2778 TT_Postscript *pPost;
2779 FT_Fixed x_scale, y_scale;
2780 WCHAR *family_nameW, *style_nameW;
2781 static const WCHAR spaceW[] = {' ', '\0'};
2782 char *cp;
2783 INT ascent, descent;
2785 TRACE("font=%p\n", font);
2787 if(!FT_IS_SCALABLE(ft_face))
2788 return 0;
2790 if(font->potm) {
2791 if(cbSize >= font->potm->otmSize)
2792 memcpy(potm, font->potm, font->potm->otmSize);
2793 return font->potm->otmSize;
2797 needed = sizeof(*potm);
2799 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2800 family_nameW = strdupW(font->name);
2802 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2803 * sizeof(WCHAR);
2804 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2805 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2806 style_nameW, lensty);
2808 /* These names should be read from the TT name table */
2810 /* length of otmpFamilyName */
2811 needed += lenfam;
2813 /* length of otmpFaceName */
2814 if(!strcasecmp(ft_face->style_name, "regular")) {
2815 needed += lenfam; /* just the family name */
2816 } else {
2817 needed += lenfam + lensty; /* family + " " + style */
2820 /* length of otmpStyleName */
2821 needed += lensty;
2823 /* length of otmpFullName */
2824 needed += lenfam + lensty;
2827 x_scale = ft_face->size->metrics.x_scale;
2828 y_scale = ft_face->size->metrics.y_scale;
2830 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2831 if(!pOS2) {
2832 FIXME("Can't find OS/2 table - not TT font?\n");
2833 ret = 0;
2834 goto end;
2837 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2838 if(!pHori) {
2839 FIXME("Can't find HHEA table - not TT font?\n");
2840 ret = 0;
2841 goto end;
2844 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2846 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",
2847 pOS2->usWinAscent, pOS2->usWinDescent,
2848 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2849 ft_face->ascender, ft_face->descender, ft_face->height,
2850 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2851 ft_face->bbox.yMax, ft_face->bbox.yMin);
2853 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2854 font->potm->otmSize = needed;
2856 #define TM font->potm->otmTextMetrics
2858 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2859 ascent = pHori->Ascender;
2860 descent = -pHori->Descender;
2861 } else {
2862 ascent = pOS2->usWinAscent;
2863 descent = pOS2->usWinDescent;
2866 if(font->yMax) {
2867 TM.tmAscent = font->yMax;
2868 TM.tmDescent = -font->yMin;
2869 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2870 } else {
2871 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2872 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2873 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2874 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2877 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2879 /* MSDN says:
2880 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2882 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2883 ((ascent + descent) -
2884 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2886 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2887 if (TM.tmAveCharWidth == 0) {
2888 TM.tmAveCharWidth = 1;
2890 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2891 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2892 TM.tmOverhang = 0;
2893 TM.tmDigitizedAspectX = 300;
2894 TM.tmDigitizedAspectY = 300;
2895 TM.tmFirstChar = pOS2->usFirstCharIndex;
2896 TM.tmLastChar = pOS2->usLastCharIndex;
2897 TM.tmDefaultChar = pOS2->usDefaultChar;
2898 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2899 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2900 TM.tmUnderlined = font->underline;
2901 TM.tmStruckOut = font->strikeout;
2903 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2904 if(!FT_IS_FIXED_WIDTH(ft_face))
2905 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2906 else
2907 TM.tmPitchAndFamily = 0;
2909 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2910 case PAN_FAMILY_SCRIPT:
2911 TM.tmPitchAndFamily |= FF_SCRIPT;
2912 break;
2913 case PAN_FAMILY_DECORATIVE:
2914 case PAN_FAMILY_PICTORIAL:
2915 TM.tmPitchAndFamily |= FF_DECORATIVE;
2916 break;
2917 case PAN_FAMILY_TEXT_DISPLAY:
2918 if(TM.tmPitchAndFamily == 0) /* fixed */
2919 TM.tmPitchAndFamily = FF_MODERN;
2920 else {
2921 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2922 case PAN_SERIF_NORMAL_SANS:
2923 case PAN_SERIF_OBTUSE_SANS:
2924 case PAN_SERIF_PERP_SANS:
2925 TM.tmPitchAndFamily |= FF_SWISS;
2926 break;
2927 default:
2928 TM.tmPitchAndFamily |= FF_ROMAN;
2931 break;
2932 default:
2933 TM.tmPitchAndFamily |= FF_DONTCARE;
2936 if(FT_IS_SCALABLE(ft_face))
2937 TM.tmPitchAndFamily |= TMPF_VECTOR;
2938 if(FT_IS_SFNT(ft_face))
2939 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2941 TM.tmCharSet = font->charset;
2942 #undef TM
2944 font->potm->otmFiller = 0;
2945 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2946 font->potm->otmfsSelection = pOS2->fsSelection;
2947 font->potm->otmfsType = pOS2->fsType;
2948 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2949 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2950 font->potm->otmItalicAngle = 0; /* POST table */
2951 font->potm->otmEMSquare = ft_face->units_per_EM;
2952 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2953 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2954 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2955 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2956 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2957 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2958 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2959 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2960 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2961 font->potm->otmMacAscent = 0; /* where do these come from ? */
2962 font->potm->otmMacDescent = 0;
2963 font->potm->otmMacLineGap = 0;
2964 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2965 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2966 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2967 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2968 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2969 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2970 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2971 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2972 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2973 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2974 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2975 if(!pPost) {
2976 font->potm->otmsUnderscoreSize = 0;
2977 font->potm->otmsUnderscorePosition = 0;
2978 } else {
2979 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2980 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2983 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2984 cp = (char*)font->potm + sizeof(*font->potm);
2985 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2986 strcpyW((WCHAR*)cp, family_nameW);
2987 cp += lenfam;
2988 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2989 strcpyW((WCHAR*)cp, style_nameW);
2990 cp += lensty;
2991 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2992 strcpyW((WCHAR*)cp, family_nameW);
2993 if(strcasecmp(ft_face->style_name, "regular")) {
2994 strcatW((WCHAR*)cp, spaceW);
2995 strcatW((WCHAR*)cp, style_nameW);
2996 cp += lenfam + lensty;
2997 } else
2998 cp += lenfam;
2999 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3000 strcpyW((WCHAR*)cp, family_nameW);
3001 strcatW((WCHAR*)cp, spaceW);
3002 strcatW((WCHAR*)cp, style_nameW);
3003 ret = needed;
3005 if(potm && needed <= cbSize)
3006 memcpy(potm, font->potm, font->potm->otmSize);
3008 end:
3009 HeapFree(GetProcessHeap(), 0, style_nameW);
3010 HeapFree(GetProcessHeap(), 0, family_nameW);
3012 return ret;
3016 /*************************************************************
3017 * WineEngGetCharWidth
3020 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3021 LPINT buffer)
3023 UINT c;
3024 GLYPHMETRICS gm;
3025 FT_UInt glyph_index;
3027 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3029 for(c = firstChar; c <= lastChar; c++) {
3030 glyph_index = get_glyph_index(font, c);
3031 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3032 &gm, 0, NULL, NULL);
3033 buffer[c - firstChar] = font->gm[glyph_index].adv;
3035 return TRUE;
3038 /*************************************************************
3039 * WineEngGetCharABCWidths
3042 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3043 LPABC buffer)
3045 UINT c;
3046 GLYPHMETRICS gm;
3047 FT_UInt glyph_index;
3049 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3051 if(!FT_IS_SCALABLE(font->ft_face))
3052 return FALSE;
3054 for(c = firstChar; c <= lastChar; c++) {
3055 glyph_index = get_glyph_index(font, c);
3056 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3057 &gm, 0, NULL, NULL);
3058 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3059 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3060 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3061 font->gm[glyph_index].bbx;
3063 return TRUE;
3066 /*************************************************************
3067 * WineEngGetTextExtentPoint
3070 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3071 LPSIZE size)
3073 INT idx;
3074 GLYPHMETRICS gm;
3075 TEXTMETRICW tm;
3076 FT_UInt glyph_index;
3078 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3079 size);
3081 size->cx = 0;
3082 WineEngGetTextMetrics(font, &tm);
3083 size->cy = tm.tmHeight;
3085 for(idx = 0; idx < count; idx++) {
3086 glyph_index = get_glyph_index(font, wstr[idx]);
3087 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3088 &gm, 0, NULL, NULL);
3089 size->cx += font->gm[glyph_index].adv;
3091 TRACE("return %ld,%ld\n", size->cx, size->cy);
3092 return TRUE;
3095 /*************************************************************
3096 * WineEngGetTextExtentPointI
3099 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3100 LPSIZE size)
3102 INT idx;
3103 GLYPHMETRICS gm;
3104 TEXTMETRICW tm;
3106 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3108 size->cx = 0;
3109 WineEngGetTextMetrics(font, &tm);
3110 size->cy = tm.tmHeight;
3112 for(idx = 0; idx < count; idx++) {
3113 WineEngGetGlyphOutline(font, indices[idx],
3114 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3115 NULL);
3116 size->cx += font->gm[indices[idx]].adv;
3118 TRACE("return %ld,%ld\n", size->cx, size->cy);
3119 return TRUE;
3122 /*************************************************************
3123 * WineEngGetFontData
3126 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3127 DWORD cbData)
3129 FT_Face ft_face = font->ft_face;
3130 DWORD len;
3131 FT_Error err;
3133 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3134 font, table, offset, buf, cbData);
3136 if(!FT_IS_SFNT(ft_face))
3137 return GDI_ERROR;
3139 if(!buf || !cbData)
3140 len = 0;
3141 else
3142 len = cbData;
3144 if(table) { /* MS tags differ in endidness from FT ones */
3145 table = table >> 24 | table << 24 |
3146 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3149 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3150 if(pFT_Load_Sfnt_Table)
3151 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3152 else { /* Do it the hard way */
3153 TT_Face tt_face = (TT_Face) ft_face;
3154 SFNT_Interface *sfnt;
3155 if (FT_Version.major==2 && FT_Version.minor==0)
3157 /* 2.0.x */
3158 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3160 else
3162 /* A field was added in the middle of the structure in 2.1.x */
3163 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3165 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3167 if(err) {
3168 TRACE("Can't find table %08lx.\n", table);
3169 return GDI_ERROR;
3171 return len;
3174 /*************************************************************
3175 * WineEngGetTextFace
3178 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3180 if(str) {
3181 lstrcpynW(str, font->name, count);
3182 return strlenW(font->name);
3183 } else
3184 return strlenW(font->name) + 1;
3187 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3189 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3190 return font->charset;
3193 #else /* HAVE_FREETYPE */
3195 BOOL WineEngInit(void)
3197 return FALSE;
3199 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3201 return NULL;
3203 BOOL WineEngDestroyFontInstance(HFONT hfont)
3205 return FALSE;
3208 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3210 return 1;
3213 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3214 LPWORD pgi, DWORD flags)
3216 return GDI_ERROR;
3219 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3220 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3221 const MAT2* lpmat)
3223 ERR("called but we don't have FreeType\n");
3224 return GDI_ERROR;
3227 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3229 ERR("called but we don't have FreeType\n");
3230 return FALSE;
3233 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3234 OUTLINETEXTMETRICW *potm)
3236 ERR("called but we don't have FreeType\n");
3237 return 0;
3240 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3241 LPINT buffer)
3243 ERR("called but we don't have FreeType\n");
3244 return FALSE;
3247 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3248 LPABC buffer)
3250 ERR("called but we don't have FreeType\n");
3251 return FALSE;
3254 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3255 LPSIZE size)
3257 ERR("called but we don't have FreeType\n");
3258 return FALSE;
3261 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3262 LPSIZE size)
3264 ERR("called but we don't have FreeType\n");
3265 return FALSE;
3268 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3269 DWORD cbData)
3271 ERR("called but we don't have FreeType\n");
3272 return GDI_ERROR;
3275 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3277 ERR("called but we don't have FreeType\n");
3278 return 0;
3281 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3283 FIXME(":stub\n");
3284 return 1;
3287 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3289 FIXME(":stub\n");
3290 return TRUE;
3293 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3295 FIXME(":stub\n");
3296 return DEFAULT_CHARSET;
3299 #endif /* HAVE_FREETYPE */