Break and default char are both relative to first char in the winfnt
[wine.git] / dlls / gdi / freetype.c
blobefbd9fff119a3bc36d7701cabe1dd7700b170b11
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
143 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
145 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
146 typedef struct {
147 FT_Short height;
148 FT_Short width;
149 FT_Pos size;
150 FT_Pos x_ppem;
151 FT_Pos y_ppem;
152 FT_Short internal_leading;
153 } Bitmap_Size;
155 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
156 So to let this compile on older versions of FreeType we'll define the
157 new structure here. */
158 typedef struct {
159 FT_Short height, width;
160 FT_Pos size, x_ppem, y_ppem;
161 } My_FT_Bitmap_Size;
163 typedef struct tagFace {
164 WCHAR *StyleName;
165 char *file;
166 FT_Long face_index;
167 BOOL Italic;
168 BOOL Bold;
169 FONTSIGNATURE fs;
170 FT_Fixed font_version;
171 BOOL scalable;
172 Bitmap_Size size; /* set if face is a bitmap */
173 BOOL external; /* TRUE if we should manually add this font to the registry */
174 struct tagFace *next;
175 struct tagFamily *family;
176 } Face;
178 typedef struct tagFamily {
179 WCHAR *FamilyName;
180 Face *FirstFace;
181 struct tagFamily *next;
182 } Family;
184 typedef struct {
185 GLYPHMETRICS gm;
186 INT adv; /* These three hold to widths of the unrotated chars */
187 INT lsb;
188 INT bbx;
189 BOOL init;
190 } GM;
192 typedef struct {
193 FLOAT eM11, eM12;
194 FLOAT eM21, eM22;
195 } FMAT2;
197 typedef struct {
198 DWORD hash;
199 LOGFONTW lf;
200 FMAT2 matrix;
201 } FONT_DESC;
203 typedef struct tagHFONTLIST {
204 struct list entry;
205 HFONT hfont;
206 } HFONTLIST;
208 struct tagGdiFont {
209 struct list entry;
210 FT_Face ft_face;
211 LPWSTR name;
212 int charset;
213 BOOL fake_italic;
214 BOOL fake_bold;
215 BYTE underline;
216 BYTE strikeout;
217 INT orientation;
218 GM *gm;
219 DWORD gmsize;
220 struct list hfontlist;
221 FONT_DESC font_desc;
222 LONG aveWidth;
223 SHORT yMax;
224 SHORT yMin;
225 OUTLINETEXTMETRICW *potm;
226 FONTSIGNATURE fs;
229 #define INIT_GM_SIZE 128
231 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
232 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
233 #define UNUSED_CACHE_SIZE 10
235 static Family *FontList = NULL;
237 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
238 'R','o','m','a','n','\0'};
239 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
240 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
242 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
243 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
244 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
245 'S','e','r','i','f','\0'};
246 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
247 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
249 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
250 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
251 'W','i','n','d','o','w','s','\\',
252 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
253 'F','o','n','t','s','\0'};
255 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
256 'W','i','n','d','o','w','s',' ','N','T','\\',
257 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
258 'F','o','n','t','s','\0'};
260 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
261 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
262 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
263 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
265 static const WCHAR *SystemFontValues[4] = {
266 System_Value,
267 OEMFont_Value,
268 FixedSys_Value,
269 NULL
272 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
273 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
275 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
276 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
277 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
278 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
279 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
280 'E','u','r','o','p','e','a','n','\0'};
281 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
282 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
283 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
284 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
285 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
286 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
287 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
288 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
289 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
290 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
291 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
292 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
294 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
295 WesternW, /*00*/
296 Central_EuropeanW,
297 CyrillicW,
298 GreekW,
299 TurkishW,
300 HebrewW,
301 ArabicW,
302 BalticW,
303 VietnameseW, /*08*/
304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
305 ThaiW,
306 JapaneseW,
307 CHINESE_GB2312W,
308 HangulW,
309 CHINESE_BIG5W,
310 Hangul_Johab_W,
311 NULL, NULL, /*23*/
312 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
313 SymbolW /*31*/
316 typedef struct {
317 WCHAR *name;
318 INT charset;
319 } NameCs;
321 typedef struct tagFontSubst {
322 NameCs from;
323 NameCs to;
324 struct tagFontSubst *next;
325 } FontSubst;
327 static FontSubst *substlist = NULL;
328 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
330 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
333 /****************************************
334 * Notes on .fon files
336 * The fonts System, FixedSys and Terminal are special. There are typically multiple
337 * versions installed for different resolutions and codepages. Windows stores which one to use
338 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
339 * Key Meaning
340 * FIXEDFON.FON FixedSys
341 * FONTS.FON System
342 * OEMFONT.FON Termial
343 * LogPixels Current dpi set by the display control panel applet
344 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
345 * also has a LogPixels value that appears to mirror this)
347 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
348 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
349 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
350 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
351 * so that makes sense.
353 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
354 * to be mapped into the registry on Windows 2000 at least).
355 * I have
356 * woafont=app850.fon
357 * ega80woa.fon=ega80850.fon
358 * ega40woa.fon=ega40850.fon
359 * cga80woa.fon=cga80850.fon
360 * cga40woa.fon=cga40850.fon
364 static inline BOOL is_win9x(void)
366 return GetVersion() & 0x80000000;
369 This function builds an FT_Fixed from a float. It puts the integer part
370 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
371 It fails if the integer part of the float number is greater than SHORT_MAX.
373 static inline FT_Fixed FT_FixedFromFloat(float f)
375 short value = f;
376 unsigned short fract = (f - value) * 0xFFFF;
377 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
381 This function builds an FT_Fixed from a FIXED. It simply put f.value
382 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
384 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
386 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
389 #define ADDFONT_EXTERNAL_FONT 0x01
390 #define ADDFONT_FORCE_BITMAP 0x02
391 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
393 FT_Face ft_face;
394 TT_OS2 *pOS2;
395 TT_Header *pHeader = NULL;
396 WCHAR *FamilyW, *StyleW;
397 DWORD len;
398 Family **pfamily;
399 Face **insertface, *next;
400 FT_Error err;
401 FT_Long face_index = 0, num_faces;
402 #ifdef HAVE_FREETYPE_FTWINFNT_H
403 FT_WinFNT_HeaderRec winfnt_header;
404 #endif
405 int i, bitmap_num;
407 do {
408 char *family_name = fake_family;
410 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
411 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
412 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
413 return FALSE;
416 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*/
417 pFT_Done_Face(ft_face);
418 return FALSE;
421 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
422 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
423 pFT_Done_Face(ft_face);
424 return FALSE;
427 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
428 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
429 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
430 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
431 "Skipping this font.\n", debugstr_a(file));
432 pFT_Done_Face(ft_face);
433 return FALSE;
436 if(!ft_face->family_name || !ft_face->style_name) {
437 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
438 pFT_Done_Face(ft_face);
439 return FALSE;
442 if(!family_name)
443 family_name = ft_face->family_name;
445 bitmap_num = 0;
446 do {
447 My_FT_Bitmap_Size *size = NULL;
449 if(!FT_IS_SCALABLE(ft_face))
450 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
452 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
453 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
454 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
456 pfamily = &FontList;
457 while(*pfamily) {
458 if(!strcmpW((*pfamily)->FamilyName, FamilyW))
459 break;
460 pfamily = &(*pfamily)->next;
462 if(!*pfamily) {
463 *pfamily = HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily));
464 (*pfamily)->FamilyName = FamilyW;
465 (*pfamily)->FirstFace = NULL;
466 (*pfamily)->next = NULL;
467 } else {
468 HeapFree(GetProcessHeap(), 0, FamilyW);
471 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
472 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
473 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
475 next = NULL;
476 for(insertface = &(*pfamily)->FirstFace; *insertface;
477 insertface = &(*insertface)->next) {
478 if(!strcmpW((*insertface)->StyleName, StyleW) && (FT_IS_SCALABLE(ft_face) || (size->y_ppem == (*insertface)->size.y_ppem))) {
479 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
480 debugstr_w((*pfamily)->FamilyName), debugstr_w(StyleW),
481 (*insertface)->font_version, pHeader ? pHeader->Font_Revision : 0);
483 if(fake_family) {
484 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
485 HeapFree(GetProcessHeap(), 0, StyleW);
486 pFT_Done_Face(ft_face);
487 return FALSE;
489 if(!pHeader || pHeader->Font_Revision <= (*insertface)->font_version) {
490 TRACE("Original font is newer so skipping this one\n");
491 HeapFree(GetProcessHeap(), 0, StyleW);
492 pFT_Done_Face(ft_face);
493 return FALSE;
494 } else {
495 TRACE("Replacing original with this one\n");
496 next = (*insertface)->next;
497 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
498 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
499 HeapFree(GetProcessHeap(), 0, *insertface);
500 break;
504 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
505 (*insertface)->StyleName = StyleW;
506 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
507 strcpy((*insertface)->file, file);
508 (*insertface)->face_index = face_index;
509 (*insertface)->next = next;
510 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
511 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
512 (*insertface)->font_version = pHeader ? pHeader->Font_Revision : 0;
513 (*insertface)->family = *pfamily;
514 (*insertface)->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
516 if(FT_IS_SCALABLE(ft_face)) {
517 memset(&(*insertface)->size, 0, sizeof((*insertface)->size));
518 (*insertface)->scalable = TRUE;
519 } else {
520 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
521 size->height, size->width, size->size >> 6,
522 size->x_ppem >> 6, size->y_ppem >> 6);
523 (*insertface)->size.height = size->height;
524 (*insertface)->size.width = size->width;
525 (*insertface)->size.size = size->size;
526 (*insertface)->size.x_ppem = size->x_ppem;
527 (*insertface)->size.y_ppem = size->y_ppem;
528 (*insertface)->size.internal_leading = 0;
529 (*insertface)->scalable = FALSE;
532 memset(&(*insertface)->fs, 0, sizeof((*insertface)->fs));
534 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
535 if(pOS2) {
536 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
537 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
538 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
539 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
540 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
541 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
542 if(pOS2->version == 0) {
543 FT_UInt dummy;
545 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
546 (*insertface)->fs.fsCsb[0] |= 1;
547 else
548 (*insertface)->fs.fsCsb[0] |= 1L << 31;
551 #ifdef HAVE_FREETYPE_FTWINFNT_H
552 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
553 CHARSETINFO csi;
554 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
555 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
556 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
557 memcpy(&(*insertface)->fs, &csi.fs, sizeof(csi.fs));
558 (*insertface)->size.internal_leading = winfnt_header.internal_leading;
560 #endif
561 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
562 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
563 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
564 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
567 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
568 for(i = 0; i < ft_face->num_charmaps; i++) {
569 switch(ft_face->charmaps[i]->encoding) {
570 case ft_encoding_unicode:
571 case ft_encoding_apple_roman:
572 (*insertface)->fs.fsCsb[0] |= 1;
573 break;
574 case ft_encoding_symbol:
575 (*insertface)->fs.fsCsb[0] |= 1L << 31;
576 break;
577 default:
578 break;
583 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
584 have_installed_roman_font = TRUE;
585 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
587 num_faces = ft_face->num_faces;
588 pFT_Done_Face(ft_face);
589 TRACE("Added font %s %s\n", debugstr_w((*pfamily)->FamilyName),
590 debugstr_w(StyleW));
591 } while(num_faces > ++face_index);
592 return TRUE;
595 static void DumpFontList(void)
597 Family *family;
598 Face *face;
600 for(family = FontList; family; family = family->next) {
601 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
602 for(face = family->FirstFace; face; face = face->next) {
603 TRACE("\t%s", debugstr_w(face->StyleName));
604 if(!face->scalable)
605 TRACE(" %ld", face->size.y_ppem >> 6);
606 TRACE("\n");
609 return;
612 static void DumpSubstList(void)
614 FontSubst *psub;
616 for(psub = substlist; psub; psub = psub->next)
617 if(psub->from.charset != -1 || psub->to.charset != -1)
618 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
619 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
620 else
621 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
622 debugstr_w(psub->to.name));
623 return;
626 static LPWSTR strdupW(LPWSTR p)
628 LPWSTR ret;
629 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
630 ret = HeapAlloc(GetProcessHeap(), 0, len);
631 memcpy(ret, p, len);
632 return ret;
635 static void split_subst_info(NameCs *nc, LPSTR str)
637 CHAR *p = strrchr(str, ',');
638 DWORD len;
640 nc->charset = -1;
641 if(p && *(p+1)) {
642 nc->charset = strtol(p+1, NULL, 10);
643 *p = '\0';
645 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
646 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
647 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
650 static void LoadSubstList(void)
652 FontSubst *psub, **ppsub;
653 HKEY hkey;
654 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
655 LPSTR value;
656 LPVOID data;
658 if(substlist) {
659 for(psub = substlist; psub;) {
660 FontSubst *ptmp;
661 HeapFree(GetProcessHeap(), 0, psub->to.name);
662 HeapFree(GetProcessHeap(), 0, psub->from.name);
663 ptmp = psub;
664 psub = psub->next;
665 HeapFree(GetProcessHeap(), 0, ptmp);
667 substlist = NULL;
670 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
671 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
672 &hkey) == ERROR_SUCCESS) {
674 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
675 &valuelen, &datalen, NULL, NULL);
677 valuelen++; /* returned value doesn't include room for '\0' */
678 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
679 data = HeapAlloc(GetProcessHeap(), 0, datalen);
681 dlen = datalen;
682 vlen = valuelen;
683 ppsub = &substlist;
684 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
685 &dlen) == ERROR_SUCCESS) {
686 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
688 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
689 (*ppsub)->next = NULL;
690 split_subst_info(&((*ppsub)->from), value);
691 split_subst_info(&((*ppsub)->to), data);
693 /* Win 2000 doesn't allow mapping between different charsets
694 or mapping of DEFAULT_CHARSET */
695 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
696 (*ppsub)->to.charset == DEFAULT_CHARSET) {
697 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
698 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
699 HeapFree(GetProcessHeap(), 0, *ppsub);
700 *ppsub = NULL;
701 } else {
702 ppsub = &((*ppsub)->next);
704 /* reset dlen and vlen */
705 dlen = datalen;
706 vlen = valuelen;
708 HeapFree(GetProcessHeap(), 0, data);
709 HeapFree(GetProcessHeap(), 0, value);
710 RegCloseKey(hkey);
714 /***********************************************************
715 * The replacement list is a way to map an entire font
716 * family onto another family. For example adding
718 * [HKLM\Software\Wine\Wine\FontReplacements]
719 * "Wingdings"="Winedings"
721 * would enumerate the Winedings font both as Winedings and
722 * Wingdings. However if a real Wingdings font is present the
723 * replacement does not take place.
726 static void LoadReplaceList(void)
728 HKEY hkey;
729 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
730 LPSTR value;
731 LPVOID data;
732 Family *family;
733 Face *face;
734 WCHAR old_nameW[200];
736 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
737 "Software\\Wine\\Wine\\FontReplacements",
738 &hkey) == ERROR_SUCCESS) {
740 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
741 &valuelen, &datalen, NULL, NULL);
743 valuelen++; /* returned value doesn't include room for '\0' */
744 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
745 data = HeapAlloc(GetProcessHeap(), 0, datalen);
747 dlen = datalen;
748 vlen = valuelen;
749 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
750 &dlen) == ERROR_SUCCESS) {
751 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
752 /* "NewName"="Oldname" */
753 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
754 break;
756 /* Find the old family and hence all of the font files
757 in that family */
758 for(family = FontList; family; family = family->next) {
759 if(!strcmpiW(family->FamilyName, old_nameW)) {
760 for(face = family->FirstFace; face; face = face->next) {
761 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
762 debugstr_w(face->StyleName), value);
763 /* Now add a new entry with the new family name */
764 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
766 break;
769 /* reset dlen and vlen */
770 dlen = datalen;
771 vlen = valuelen;
773 HeapFree(GetProcessHeap(), 0, data);
774 HeapFree(GetProcessHeap(), 0, value);
775 RegCloseKey(hkey);
780 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
782 DIR *dir;
783 struct dirent *dent;
784 char path[MAX_PATH];
786 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
788 dir = opendir(dirname);
789 if(!dir) {
790 ERR("Can't open directory %s\n", debugstr_a(dirname));
791 return FALSE;
793 while((dent = readdir(dir)) != NULL) {
794 struct stat statbuf;
796 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
797 continue;
799 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
801 sprintf(path, "%s/%s", dirname, dent->d_name);
803 if(stat(path, &statbuf) == -1)
805 WARN("Can't stat %s\n", debugstr_a(path));
806 continue;
808 if(S_ISDIR(statbuf.st_mode))
809 ReadFontDir(path, external_fonts);
810 else
811 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
813 closedir(dir);
814 return TRUE;
817 static void load_fontconfig_fonts(void)
819 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
820 void *fc_handle = NULL;
821 FcConfig *config;
822 FcPattern *pat;
823 FcObjectSet *os;
824 FcFontSet *fontset;
825 FcValue v;
826 int i, len;
827 const char *ext;
829 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
830 if(!fc_handle) {
831 TRACE("Wine cannot find the fontconfig library (%s).\n",
832 SONAME_LIBFONTCONFIG);
833 return;
835 #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;}
836 LOAD_FUNCPTR(FcConfigGetCurrent);
837 LOAD_FUNCPTR(FcFontList);
838 LOAD_FUNCPTR(FcFontSetDestroy);
839 LOAD_FUNCPTR(FcInit);
840 LOAD_FUNCPTR(FcObjectSetAdd);
841 LOAD_FUNCPTR(FcObjectSetCreate);
842 LOAD_FUNCPTR(FcObjectSetDestroy);
843 LOAD_FUNCPTR(FcPatternCreate);
844 LOAD_FUNCPTR(FcPatternDestroy);
845 LOAD_FUNCPTR(FcPatternGet);
846 #undef LOAD_FUNCPTR
848 if(!pFcInit()) return;
850 config = pFcConfigGetCurrent();
851 pat = pFcPatternCreate();
852 os = pFcObjectSetCreate();
853 pFcObjectSetAdd(os, FC_FILE);
854 fontset = pFcFontList(config, pat, os);
855 if(!fontset) return;
856 for(i = 0; i < fontset->nfont; i++) {
857 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
858 continue;
859 if(v.type != FcTypeString) continue;
860 TRACE("fontconfig: %s\n", v.u.s);
862 /* We're just interested in OT/TT fonts for now, so this hack just
863 picks up the standard extensions to save time loading every other
864 font */
865 len = strlen(v.u.s);
866 if(len < 4) continue;
867 ext = v.u.s + len - 3;
868 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
869 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
871 pFcFontSetDestroy(fontset);
872 pFcObjectSetDestroy(os);
873 pFcPatternDestroy(pat);
874 sym_not_found:
875 #endif
876 return;
880 void load_system_fonts(void)
882 HKEY hkey;
883 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
884 const WCHAR **value;
885 DWORD dlen, type;
886 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
887 char *unixname;
889 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
890 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
891 strcatW(windowsdir, fontsW);
892 for(value = SystemFontValues; *value; value++) {
893 dlen = sizeof(data);
894 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
895 type == REG_SZ) {
896 sprintfW(pathW, fmtW, windowsdir, data);
897 if((unixname = wine_get_unix_file_name(pathW))) {
898 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
899 HeapFree(GetProcessHeap(), 0, unixname);
903 RegCloseKey(hkey);
907 /*************************************************************
909 * This adds registry entries for any externally loaded fonts
910 * (fonts from fontconfig or FontDirs). It also deletes entries
911 * of no longer existing fonts.
914 void update_reg_entries(void)
916 HKEY winkey = 0, externalkey = 0;
917 LPWSTR valueW;
918 LPVOID data;
919 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
920 Family *family;
921 Face *face;
922 WCHAR *file;
923 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
924 static const WCHAR spaceW[] = {' ', '\0'};
925 char *path;
927 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
928 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
929 ERR("Can't create Windows font reg key\n");
930 goto end;
932 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
933 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
934 ERR("Can't create external font reg key\n");
935 goto end;
938 /* Delete all external fonts added last time */
940 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
941 &valuelen, &datalen, NULL, NULL);
942 valuelen++; /* returned value doesn't include room for '\0' */
943 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
944 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
946 dlen = datalen * sizeof(WCHAR);
947 vlen = valuelen;
948 i = 0;
949 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
950 &dlen) == ERROR_SUCCESS) {
952 RegDeleteValueW(winkey, valueW);
953 /* reset dlen and vlen */
954 dlen = datalen;
955 vlen = valuelen;
957 HeapFree(GetProcessHeap(), 0, data);
958 HeapFree(GetProcessHeap(), 0, valueW);
960 /* Delete the old external fonts key */
961 RegCloseKey(externalkey);
962 externalkey = 0;
963 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
965 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
966 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
967 ERR("Can't create external font reg key\n");
968 goto end;
971 /* enumerate the fonts and add external ones to the two keys */
973 for(family = FontList; family; family = family->next) {
974 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
975 for(face = family->FirstFace; face; face = face->next) {
976 if(!face->external) continue;
977 len = len_fam;
978 if(strcmpiW(face->StyleName, RegularW))
979 len = len_fam + strlenW(face->StyleName) + 1;
980 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
981 strcpyW(valueW, family->FamilyName);
982 if(len != len_fam) {
983 strcatW(valueW, spaceW);
984 strcatW(valueW, face->StyleName);
986 strcatW(valueW, TrueType);
987 if((path = strrchr(face->file, '/')) == NULL)
988 path = face->file;
989 else
990 path++;
991 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
993 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
994 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
995 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
996 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
998 HeapFree(GetProcessHeap(), 0, file);
999 HeapFree(GetProcessHeap(), 0, valueW);
1002 end:
1003 if(externalkey)
1004 RegCloseKey(externalkey);
1005 if(winkey)
1006 RegCloseKey(winkey);
1007 return;
1011 /*************************************************************
1012 * WineEngAddFontResourceEx
1015 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1017 if (ft_handle) /* do it only if we have freetype up and running */
1019 char *unixname;
1021 if(flags)
1022 FIXME("Ignoring flags %lx\n", flags);
1024 if((unixname = wine_get_unix_file_name(file)))
1026 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1027 HeapFree(GetProcessHeap(), 0, unixname);
1030 return 1;
1033 /*************************************************************
1034 * WineEngRemoveFontResourceEx
1037 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1039 FIXME(":stub\n");
1040 return TRUE;
1043 /*************************************************************
1044 * WineEngInit
1046 * Initialize FreeType library and create a list of available faces
1048 BOOL WineEngInit(void)
1050 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1051 HKEY hkey;
1052 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1053 LPVOID data;
1054 WCHAR windowsdir[MAX_PATH];
1055 char *unixname;
1056 HANDLE font_mutex;
1058 TRACE("\n");
1060 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1061 if(!ft_handle) {
1062 WINE_MESSAGE(
1063 "Wine cannot find the FreeType font library. To enable Wine to\n"
1064 "use TrueType fonts please install a version of FreeType greater than\n"
1065 "or equal to 2.0.5.\n"
1066 "http://www.freetype.org\n");
1067 return FALSE;
1070 #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;}
1072 LOAD_FUNCPTR(FT_Vector_Unit)
1073 LOAD_FUNCPTR(FT_Done_Face)
1074 LOAD_FUNCPTR(FT_Get_Char_Index)
1075 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1076 LOAD_FUNCPTR(FT_Init_FreeType)
1077 LOAD_FUNCPTR(FT_Load_Glyph)
1078 LOAD_FUNCPTR(FT_Matrix_Multiply)
1079 LOAD_FUNCPTR(FT_MulFix)
1080 LOAD_FUNCPTR(FT_New_Face)
1081 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1082 LOAD_FUNCPTR(FT_Outline_Transform)
1083 LOAD_FUNCPTR(FT_Outline_Translate)
1084 LOAD_FUNCPTR(FT_Select_Charmap)
1085 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1086 LOAD_FUNCPTR(FT_Vector_Transform)
1088 #undef LOAD_FUNCPTR
1089 /* Don't warn if this one is missing */
1090 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1091 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1092 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1093 #ifdef HAVE_FREETYPE_FTWINFNT_H
1094 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1095 #endif
1096 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1097 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1098 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1099 <= 2.0.3 has FT_Sqrt64 */
1100 goto sym_not_found;
1103 if(pFT_Init_FreeType(&library) != 0) {
1104 ERR("Can't init FreeType library\n");
1105 wine_dlclose(ft_handle, NULL, 0);
1106 ft_handle = NULL;
1107 return FALSE;
1109 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1110 if (pFT_Library_Version)
1112 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1114 if (FT_Version.major<=0)
1116 FT_Version.major=2;
1117 FT_Version.minor=0;
1118 FT_Version.patch=5;
1120 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1121 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1122 ((FT_Version.minor << 8) & 0x00ff00) |
1123 ((FT_Version.patch ) & 0x0000ff);
1125 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1126 ERR("Failed to create font mutex\n");
1127 return FALSE;
1129 WaitForSingleObject(font_mutex, INFINITE);
1131 /* load the system fonts */
1132 load_system_fonts();
1134 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1135 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1136 strcatW(windowsdir, fontsW);
1137 if((unixname = wine_get_unix_file_name(windowsdir)))
1139 ReadFontDir(unixname, FALSE);
1140 HeapFree(GetProcessHeap(), 0, unixname);
1143 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1144 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1145 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1146 will skip these. */
1147 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1148 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1149 &hkey) == ERROR_SUCCESS) {
1150 LPWSTR valueW;
1151 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1152 &valuelen, &datalen, NULL, NULL);
1154 valuelen++; /* returned value doesn't include room for '\0' */
1155 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1156 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1157 if (valueW && data)
1159 dlen = datalen * sizeof(WCHAR);
1160 vlen = valuelen;
1161 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1162 &dlen) == ERROR_SUCCESS) {
1163 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1165 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1167 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1168 HeapFree(GetProcessHeap(), 0, unixname);
1171 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1173 WCHAR pathW[MAX_PATH];
1174 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1175 sprintfW(pathW, fmtW, windowsdir, data);
1176 if((unixname = wine_get_unix_file_name(pathW)))
1178 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1179 HeapFree(GetProcessHeap(), 0, unixname);
1182 /* reset dlen and vlen */
1183 dlen = datalen;
1184 vlen = valuelen;
1187 if (data) HeapFree(GetProcessHeap(), 0, data);
1188 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1189 RegCloseKey(hkey);
1192 load_fontconfig_fonts();
1194 /* then look in any directories that we've specified in the config file */
1195 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1196 "Software\\Wine\\Wine\\Config\\FontDirs",
1197 &hkey) == ERROR_SUCCESS) {
1198 LPSTR value;
1199 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1200 &valuelen, &datalen, NULL, NULL);
1202 valuelen++; /* returned value doesn't include room for '\0' */
1203 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1204 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1206 dlen = datalen;
1207 vlen = valuelen;
1208 i = 0;
1209 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1210 &dlen) == ERROR_SUCCESS) {
1211 TRACE("Got %s=%s\n", value, (LPSTR)data);
1212 ReadFontDir((LPSTR)data, TRUE);
1213 /* reset dlen and vlen */
1214 dlen = datalen;
1215 vlen = valuelen;
1217 HeapFree(GetProcessHeap(), 0, data);
1218 HeapFree(GetProcessHeap(), 0, value);
1219 RegCloseKey(hkey);
1222 DumpFontList();
1223 LoadSubstList();
1224 DumpSubstList();
1225 LoadReplaceList();
1226 update_reg_entries();
1228 ReleaseMutex(font_mutex);
1229 return TRUE;
1230 sym_not_found:
1231 WINE_MESSAGE(
1232 "Wine cannot find certain functions that it needs inside the FreeType\n"
1233 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1234 "FreeType to at least version 2.0.5.\n"
1235 "http://www.freetype.org\n");
1236 wine_dlclose(ft_handle, NULL, 0);
1237 ft_handle = NULL;
1238 return FALSE;
1242 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1244 TT_OS2 *pOS2;
1245 TT_HoriHeader *pHori;
1247 LONG ppem;
1249 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1250 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1252 if(height == 0) height = 16;
1254 /* Calc. height of EM square:
1256 * For +ve lfHeight we have
1257 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1258 * Re-arranging gives:
1259 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1261 * For -ve lfHeight we have
1262 * |lfHeight| = ppem
1263 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1264 * with il = winAscent + winDescent - units_per_em]
1268 if(height > 0) {
1269 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1270 ppem = ft_face->units_per_EM * height /
1271 (pHori->Ascender - pHori->Descender);
1272 else
1273 ppem = ft_face->units_per_EM * height /
1274 (pOS2->usWinAscent + pOS2->usWinDescent);
1276 else
1277 ppem = -height;
1279 return ppem;
1282 static LONG load_VDMX(GdiFont, LONG);
1284 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1286 FT_Error err;
1287 FT_Face ft_face;
1288 LONG ppem;
1290 err = pFT_New_Face(library, file, face_index, &ft_face);
1291 if(err) {
1292 ERR("FT_New_Face rets %d\n", err);
1293 return 0;
1296 /* set it here, as load_VDMX needs it */
1297 font->ft_face = ft_face;
1299 if(FT_IS_SCALABLE(ft_face)) {
1300 /* load the VDMX table if we have one */
1301 ppem = load_VDMX(font, height);
1302 if(ppem == 0)
1303 ppem = calc_ppem_for_height(ft_face, height);
1305 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1306 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1307 } else {
1308 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1309 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1311 return ft_face;
1315 static int get_nearest_charset(Face *face)
1317 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1318 a single face with the requested charset. The idea is to check if
1319 the selected font supports the current ANSI codepage, if it does
1320 return the corresponding charset, else return the first charset */
1322 CHARSETINFO csi;
1323 int acp = GetACP(), i;
1324 DWORD fs0;
1326 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1327 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1328 return csi.ciCharset;
1330 for(i = 0; i < 32; i++) {
1331 fs0 = 1L << i;
1332 if(face->fs.fsCsb[0] & fs0) {
1333 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1334 return csi.ciCharset;
1335 else
1336 FIXME("TCI failing on %lx\n", fs0);
1340 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1341 face->fs.fsCsb[0], face->file);
1342 return DEFAULT_CHARSET;
1345 static GdiFont alloc_font(void)
1347 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1348 ret->gmsize = INIT_GM_SIZE;
1349 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1350 ret->gmsize * sizeof(*ret->gm));
1351 ret->potm = NULL;
1352 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1353 list_init(&ret->hfontlist);
1354 return ret;
1357 static void free_font(GdiFont font)
1359 if (font->ft_face) pFT_Done_Face(font->ft_face);
1360 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1361 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1362 HeapFree(GetProcessHeap(), 0, font->gm);
1363 HeapFree(GetProcessHeap(), 0, font);
1367 /*************************************************************
1368 * load_VDMX
1370 * load the vdmx entry for the specified height
1373 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1374 ( ( (FT_ULong)_x4 << 24 ) | \
1375 ( (FT_ULong)_x3 << 16 ) | \
1376 ( (FT_ULong)_x2 << 8 ) | \
1377 (FT_ULong)_x1 )
1379 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1381 typedef struct {
1382 BYTE bCharSet;
1383 BYTE xRatio;
1384 BYTE yStartRatio;
1385 BYTE yEndRatio;
1386 } Ratios;
1389 static LONG load_VDMX(GdiFont font, LONG height)
1391 BYTE hdr[6], tmp[2], group[4];
1392 BYTE devXRatio, devYRatio;
1393 USHORT numRecs, numRatios;
1394 DWORD offset = -1;
1395 LONG ppem = 0;
1396 int i, result;
1398 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1400 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1401 return ppem;
1403 /* FIXME: need the real device aspect ratio */
1404 devXRatio = 1;
1405 devYRatio = 1;
1407 numRecs = GET_BE_WORD(&hdr[2]);
1408 numRatios = GET_BE_WORD(&hdr[4]);
1410 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1411 for(i = 0; i < numRatios; i++) {
1412 Ratios ratio;
1414 offset = (3 * 2) + (i * sizeof(Ratios));
1415 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1416 offset = -1;
1418 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1420 if(ratio.bCharSet != 1)
1421 continue;
1423 if((ratio.xRatio == 0 &&
1424 ratio.yStartRatio == 0 &&
1425 ratio.yEndRatio == 0) ||
1426 (devXRatio == ratio.xRatio &&
1427 devYRatio >= ratio.yStartRatio &&
1428 devYRatio <= ratio.yEndRatio))
1430 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1431 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1432 offset = GET_BE_WORD(tmp);
1433 break;
1437 if(offset < 0) {
1438 FIXME("No suitable ratio found\n");
1439 return ppem;
1442 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1443 USHORT recs;
1444 BYTE startsz, endsz;
1445 BYTE *vTable;
1447 recs = GET_BE_WORD(group);
1448 startsz = group[2];
1449 endsz = group[3];
1451 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1453 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1454 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1455 if(result == GDI_ERROR) {
1456 FIXME("Failed to retrieve vTable\n");
1457 goto end;
1460 if(height > 0) {
1461 for(i = 0; i < recs; i++) {
1462 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1463 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1464 ppem = GET_BE_WORD(&vTable[i * 6]);
1466 if(yMax + -yMin == height) {
1467 font->yMax = yMax;
1468 font->yMin = yMin;
1469 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1470 break;
1472 if(yMax + -yMin > height) {
1473 if(--i < 0) {
1474 ppem = 0;
1475 goto end; /* failed */
1477 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1478 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1479 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1480 break;
1483 if(!font->yMax) {
1484 ppem = 0;
1485 TRACE("ppem not found for height %ld\n", height);
1487 } else {
1488 ppem = -height;
1489 if(ppem < startsz || ppem > endsz)
1490 goto end;
1492 for(i = 0; i < recs; i++) {
1493 USHORT yPelHeight;
1494 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1496 if(yPelHeight > ppem)
1497 break; /* failed */
1499 if(yPelHeight == ppem) {
1500 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1501 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1502 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1503 break;
1507 end:
1508 HeapFree(GetProcessHeap(), 0, vTable);
1511 return ppem;
1514 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1516 if(font->font_desc.hash != fd->hash) return TRUE;
1517 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1518 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1519 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1522 static void calc_hash(FONT_DESC *pfd)
1524 DWORD hash = 0, *ptr, two_chars;
1525 WORD *pwc;
1526 int i;
1528 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1529 hash ^= *ptr;
1530 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1531 hash ^= *ptr;
1532 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1533 two_chars = *ptr;
1534 pwc = (WCHAR *)&two_chars;
1535 if(!*pwc) break;
1536 *pwc = toupperW(*pwc);
1537 pwc++;
1538 *pwc = toupperW(*pwc);
1539 hash ^= two_chars;
1540 if(!*pwc) break;
1542 pfd->hash = hash;
1543 return;
1546 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1548 GdiFont ret;
1549 FONT_DESC fd;
1550 HFONTLIST *hflist;
1551 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1553 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1554 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1555 calc_hash(&fd);
1557 /* try the in-use list */
1558 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1559 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1560 if(!fontcmp(ret, &fd)) {
1561 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1562 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1563 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1564 if(hflist->hfont == hfont)
1565 return ret;
1567 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1568 hflist->hfont = hfont;
1569 list_add_head(&ret->hfontlist, &hflist->entry);
1570 return ret;
1574 /* then the unused list */
1575 font_elem_ptr = list_head(&unused_gdi_font_list);
1576 while(font_elem_ptr) {
1577 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1578 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1579 if(!fontcmp(ret, &fd)) {
1580 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1581 assert(list_empty(&ret->hfontlist));
1582 TRACE("Found %p in unused list\n", ret);
1583 list_remove(&ret->entry);
1584 list_add_head(&gdi_font_list, &ret->entry);
1585 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1586 hflist->hfont = hfont;
1587 list_add_head(&ret->hfontlist, &hflist->entry);
1588 return ret;
1591 return NULL;
1594 /*************************************************************
1595 * WineEngCreateFontInstance
1598 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1600 GdiFont ret;
1601 Face *face, *best;
1602 Family *family = NULL;
1603 INT height, width = 0;
1604 signed int diff = 0, newdiff;
1605 BOOL bd, it, can_use_bitmap;
1606 LOGFONTW lf;
1607 CHARSETINFO csi;
1608 HFONTLIST *hflist;
1610 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1611 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1613 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1614 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1615 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1616 lf.lfEscapement);
1618 /* check the cache first */
1619 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1620 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1621 return ret;
1624 TRACE("not in cache\n");
1625 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1627 TRACE("No fonts installed\n");
1628 return NULL;
1631 ret = alloc_font();
1633 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1634 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1635 calc_hash(&ret->font_desc);
1636 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1637 hflist->hfont = hfont;
1638 list_add_head(&ret->hfontlist, &hflist->entry);
1641 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1642 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1643 original value lfCharSet. Note this is a special case for
1644 Symbol and doesn't happen at least for "Wingdings*" */
1646 if(!strcmpiW(lf.lfFaceName, SymbolW))
1647 lf.lfCharSet = SYMBOL_CHARSET;
1649 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1650 switch(lf.lfCharSet) {
1651 case DEFAULT_CHARSET:
1652 csi.fs.fsCsb[0] = 0;
1653 break;
1654 default:
1655 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1656 csi.fs.fsCsb[0] = 0;
1657 break;
1661 if(lf.lfFaceName[0] != '\0') {
1662 FontSubst *psub;
1663 for(psub = substlist; psub; psub = psub->next)
1664 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1665 (psub->from.charset == -1 ||
1666 psub->from.charset == lf.lfCharSet))
1667 break;
1668 if(psub) {
1669 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1670 debugstr_w(psub->to.name));
1671 strcpyW(lf.lfFaceName, psub->to.name);
1674 /* We want a match on name and charset or just name if
1675 charset was DEFAULT_CHARSET. If the latter then
1676 we fixup the returned charset later in get_nearest_charset
1677 where we'll either use the charset of the current ansi codepage
1678 or if that's unavailable the first charset that the font supports.
1680 for(family = FontList; family; family = family->next) {
1681 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1682 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1683 if(family->FirstFace->scalable || can_use_bitmap)
1684 break;
1688 if(!family) {
1689 /* If requested charset was DEFAULT_CHARSET then try using charset
1690 corresponding to the current ansi codepage */
1691 if(!csi.fs.fsCsb[0]) {
1692 INT acp = GetACP();
1693 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1694 FIXME("TCI failed on codepage %d\n", acp);
1695 csi.fs.fsCsb[0] = 0;
1696 } else
1697 lf.lfCharSet = csi.ciCharset;
1700 /* Face families are in the top 4 bits of lfPitchAndFamily,
1701 so mask with 0xF0 before testing */
1703 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1704 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1705 strcpyW(lf.lfFaceName, defFixed);
1706 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1707 strcpyW(lf.lfFaceName, defSerif);
1708 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1709 strcpyW(lf.lfFaceName, defSans);
1710 else
1711 strcpyW(lf.lfFaceName, defSans);
1712 for(family = FontList; family; family = family->next) {
1713 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1714 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1715 if(family->FirstFace->scalable || can_use_bitmap)
1716 break;
1720 if(!family) {
1721 for(family = FontList; family; family = family->next) {
1722 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1723 if(family->FirstFace->scalable || can_use_bitmap)
1724 break;
1728 if(!family) {
1729 family = FontList;
1730 csi.fs.fsCsb[0] = 0;
1731 FIXME("just using first face for now\n");
1734 it = lf.lfItalic ? 1 : 0;
1735 bd = lf.lfWeight > 550 ? 1 : 0;
1737 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1738 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1740 best = NULL;
1741 for(face = family->FirstFace; face; face = face->next) {
1742 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1743 if(face->scalable)
1744 break;
1745 if(height > 0)
1746 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1747 else
1748 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1749 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1750 (diff < 0 && newdiff > diff)) {
1751 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1752 diff = newdiff;
1753 best = face;
1754 if(diff == 0)
1755 break;
1759 if(!face && best)
1760 face = best;
1761 else if(!face) {
1762 face = family->FirstFace;
1763 if(it && !face->Italic) ret->fake_italic = TRUE;
1764 if(bd && !face->Bold) ret->fake_bold = TRUE;
1767 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1769 if(csi.fs.fsCsb[0])
1770 ret->charset = lf.lfCharSet;
1771 else
1772 ret->charset = get_nearest_charset(face);
1774 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1775 debugstr_w(face->StyleName));
1777 if(!face->scalable) {
1778 width = face->size.x_ppem >> 6;
1779 height = face->size.y_ppem >> 6;
1781 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1783 if (!ret->ft_face)
1785 free_font( ret );
1786 return 0;
1789 if (ret->charset == SYMBOL_CHARSET &&
1790 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1791 /* No ops */
1793 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1794 /* No ops */
1796 else {
1797 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1800 ret->orientation = lf.lfOrientation;
1801 ret->name = strdupW(family->FamilyName);
1802 ret->underline = lf.lfUnderline ? 0xff : 0;
1803 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1805 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1806 ret->aveWidth= lf.lfWidth;
1807 list_add_head(&gdi_font_list, &ret->entry);
1808 return ret;
1811 static void dump_gdi_font_list(void)
1813 GdiFont gdiFont;
1814 struct list *elem_ptr;
1816 TRACE("---------- gdiFont Cache ----------\n");
1817 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1818 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1819 TRACE("gdiFont=%p %s %ld\n",
1820 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1823 TRACE("---------- Unused gdiFont Cache ----------\n");
1824 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1825 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1826 TRACE("gdiFont=%p %s %ld\n",
1827 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1831 /*************************************************************
1832 * WineEngDestroyFontInstance
1834 * free the gdiFont associated with this handle
1837 BOOL WineEngDestroyFontInstance(HFONT handle)
1839 GdiFont gdiFont;
1840 HFONTLIST *hflist;
1841 BOOL ret = FALSE;
1842 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1843 int i = 0;
1845 TRACE("destroying hfont=%p\n", handle);
1846 if(TRACE_ON(font))
1847 dump_gdi_font_list();
1849 font_elem_ptr = list_head(&gdi_font_list);
1850 while(font_elem_ptr) {
1851 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1852 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1854 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1855 while(hfontlist_elem_ptr) {
1856 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1857 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1858 if(hflist->hfont == handle) {
1859 list_remove(&hflist->entry);
1860 HeapFree(GetProcessHeap(), 0, hflist);
1861 ret = TRUE;
1864 if(list_empty(&gdiFont->hfontlist)) {
1865 TRACE("Moving to Unused list\n");
1866 list_remove(&gdiFont->entry);
1867 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1872 font_elem_ptr = list_head(&unused_gdi_font_list);
1873 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1874 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1875 while(font_elem_ptr) {
1876 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1877 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1878 TRACE("freeing %p\n", gdiFont);
1879 list_remove(&gdiFont->entry);
1880 free_font(gdiFont);
1882 return ret;
1885 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1886 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1888 OUTLINETEXTMETRICW *potm = NULL;
1889 UINT size;
1890 TEXTMETRICW tm, *ptm;
1891 GdiFont font = alloc_font();
1892 LONG width, height;
1894 if(face->scalable) {
1895 height = 100;
1896 width = 0;
1897 } else {
1898 height = face->size.y_ppem >> 6;
1899 width = face->size.x_ppem >> 6;
1902 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1904 free_font(font);
1905 return;
1908 font->name = strdupW(face->family->FamilyName);
1910 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1912 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1913 if(size) {
1914 potm = HeapAlloc(GetProcessHeap(), 0, size);
1915 WineEngGetOutlineTextMetrics(font, size, potm);
1916 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1917 } else {
1918 WineEngGetTextMetrics(font, &tm);
1919 ptm = &tm;
1922 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1923 pntm->ntmTm.tmAscent = ptm->tmAscent;
1924 pntm->ntmTm.tmDescent = ptm->tmDescent;
1925 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1926 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1927 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1928 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1929 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1930 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1931 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1932 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1933 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1934 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
1935 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
1936 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
1937 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
1938 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
1939 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
1940 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
1941 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
1942 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
1943 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1944 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1945 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1947 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1948 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
1949 *ptype |= RASTER_FONTTYPE;
1951 if(potm) {
1952 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
1953 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1954 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1956 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1957 pntm->ntmTm.ntmCellHeight = 0;
1958 pntm->ntmTm.ntmAvgWidth = 0;
1960 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1962 strncpyW(pelf->elfLogFont.lfFaceName,
1963 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1964 LF_FACESIZE);
1965 strncpyW(pelf->elfFullName,
1966 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1967 LF_FULLFACESIZE);
1968 strncpyW(pelf->elfStyle,
1969 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1970 LF_FACESIZE);
1972 } else {
1973 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
1974 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
1975 pelf->elfStyle[0] = '\0';
1978 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1980 HeapFree(GetProcessHeap(), 0, potm);
1981 free_font(font);
1982 return;
1985 /*************************************************************
1986 * WineEngEnumFonts
1989 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1991 Family *family;
1992 Face *face;
1993 ENUMLOGFONTEXW elf;
1994 NEWTEXTMETRICEXW ntm;
1995 DWORD type, ret = 1;
1996 FONTSIGNATURE fs;
1997 CHARSETINFO csi;
1998 LOGFONTW lf;
1999 int i;
2001 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2003 if(plf->lfFaceName[0]) {
2004 FontSubst *psub;
2005 for(psub = substlist; psub; psub = psub->next)
2006 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2007 (psub->from.charset == -1 ||
2008 psub->from.charset == plf->lfCharSet))
2009 break;
2010 if(psub) {
2011 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2012 debugstr_w(psub->to.name));
2013 memcpy(&lf, plf, sizeof(lf));
2014 strcpyW(lf.lfFaceName, psub->to.name);
2015 plf = &lf;
2017 for(family = FontList; family; family = family->next) {
2018 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2019 for(face = family->FirstFace; face; face = face->next) {
2020 GetEnumStructs(face, &elf, &ntm, &type);
2021 for(i = 0; i < 32; i++) {
2022 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2023 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2024 strcpyW(elf.elfScript, OEM_DOSW);
2025 i = 32; /* break out of loop */
2026 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2027 continue;
2028 else {
2029 fs.fsCsb[0] = 1L << i;
2030 fs.fsCsb[1] = 0;
2031 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2032 TCI_SRCFONTSIG))
2033 csi.ciCharset = DEFAULT_CHARSET;
2034 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2035 if(csi.ciCharset != DEFAULT_CHARSET) {
2036 elf.elfLogFont.lfCharSet =
2037 ntm.ntmTm.tmCharSet = csi.ciCharset;
2038 if(ElfScriptsW[i])
2039 strcpyW(elf.elfScript, ElfScriptsW[i]);
2040 else
2041 FIXME("Unknown elfscript for bit %d\n", i);
2044 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2045 debugstr_w(elf.elfLogFont.lfFaceName),
2046 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2047 csi.ciCharset, type, debugstr_w(elf.elfScript),
2048 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2049 ntm.ntmTm.ntmFlags);
2050 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2051 if(!ret) goto end;
2056 } else {
2057 for(family = FontList; family; family = family->next) {
2058 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
2059 for(i = 0; i < 32; i++) {
2060 if(!family->FirstFace->scalable && family->FirstFace->fs.fsCsb[0] == 0) { /* OEM bitmap */
2061 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2062 strcpyW(elf.elfScript, OEM_DOSW);
2063 i = 32; /* break out of loop */
2064 } else if(!(family->FirstFace->fs.fsCsb[0] & (1L << i)))
2065 continue;
2066 else {
2067 fs.fsCsb[0] = 1L << i;
2068 fs.fsCsb[1] = 0;
2069 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2070 TCI_SRCFONTSIG))
2071 csi.ciCharset = DEFAULT_CHARSET;
2072 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2073 if(csi.ciCharset != DEFAULT_CHARSET) {
2074 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2075 csi.ciCharset;
2076 if(ElfScriptsW[i])
2077 strcpyW(elf.elfScript, ElfScriptsW[i]);
2078 else
2079 FIXME("Unknown elfscript for bit %d\n", i);
2082 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2083 debugstr_w(elf.elfLogFont.lfFaceName),
2084 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2085 csi.ciCharset, type, debugstr_w(elf.elfScript),
2086 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2087 ntm.ntmTm.ntmFlags);
2088 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2089 if(!ret) goto end;
2093 end:
2094 return ret;
2097 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2099 pt->x.value = vec->x >> 6;
2100 pt->x.fract = (vec->x & 0x3f) << 10;
2101 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2102 pt->y.value = vec->y >> 6;
2103 pt->y.fract = (vec->y & 0x3f) << 10;
2104 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2105 return;
2108 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2110 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2111 glyph = glyph + 0xf000;
2112 return pFT_Get_Char_Index(font->ft_face, glyph);
2115 /*************************************************************
2116 * WineEngGetGlyphIndices
2118 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2120 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2121 LPWORD pgi, DWORD flags)
2123 INT i;
2125 for(i = 0; i < count; i++)
2126 pgi[i] = get_glyph_index(font, lpstr[i]);
2128 return count;
2131 /*************************************************************
2132 * WineEngGetGlyphOutline
2134 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2135 * except that the first parameter is the HWINEENGFONT of the font in
2136 * question rather than an HDC.
2139 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2140 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2141 const MAT2* lpmat)
2143 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2144 FT_Face ft_face = font->ft_face;
2145 FT_UInt glyph_index;
2146 DWORD width, height, pitch, needed = 0;
2147 FT_Bitmap ft_bitmap;
2148 FT_Error err;
2149 INT left, right, top = 0, bottom = 0;
2150 FT_Angle angle = 0;
2151 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2152 float widthRatio = 1.0;
2153 FT_Matrix transMat = identityMat;
2154 BOOL needsTransform = FALSE;
2157 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2158 buflen, buf, lpmat);
2160 if(format & GGO_GLYPH_INDEX) {
2161 glyph_index = glyph;
2162 format &= ~GGO_GLYPH_INDEX;
2163 } else
2164 glyph_index = get_glyph_index(font, glyph);
2166 if(glyph_index >= font->gmsize) {
2167 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2168 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2169 font->gmsize * sizeof(*font->gm));
2170 } else {
2171 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2172 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2173 return 1; /* FIXME */
2177 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2178 load_flags |= FT_LOAD_NO_BITMAP;
2180 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2182 if(err) {
2183 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2184 return GDI_ERROR;
2187 /* Scaling factor */
2188 if (font->aveWidth && font->potm) {
2189 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2192 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2193 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2195 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2196 font->gm[glyph_index].lsb = left >> 6;
2197 font->gm[glyph_index].bbx = (right - left) >> 6;
2199 /* Scaling transform */
2200 if(font->aveWidth) {
2201 FT_Matrix scaleMat;
2202 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2203 scaleMat.xy = 0;
2204 scaleMat.yx = 0;
2205 scaleMat.yy = (1 << 16);
2207 pFT_Matrix_Multiply(&scaleMat, &transMat);
2208 needsTransform = TRUE;
2211 /* Rotation transform */
2212 if(font->orientation) {
2213 FT_Matrix rotationMat;
2214 FT_Vector vecAngle;
2215 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2216 pFT_Vector_Unit(&vecAngle, angle);
2217 rotationMat.xx = vecAngle.x;
2218 rotationMat.xy = -vecAngle.y;
2219 rotationMat.yx = -rotationMat.xy;
2220 rotationMat.yy = rotationMat.xx;
2222 pFT_Matrix_Multiply(&rotationMat, &transMat);
2223 needsTransform = TRUE;
2226 /* Extra transformation specified by caller */
2227 if (lpmat) {
2228 FT_Matrix extraMat;
2229 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2230 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2231 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2232 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2233 pFT_Matrix_Multiply(&extraMat, &transMat);
2234 needsTransform = TRUE;
2237 if(!needsTransform) {
2238 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2239 bottom = (ft_face->glyph->metrics.horiBearingY -
2240 ft_face->glyph->metrics.height) & -64;
2241 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2242 lpgm->gmCellIncY = 0;
2243 } else {
2244 INT xc, yc;
2245 FT_Vector vec;
2246 for(xc = 0; xc < 2; xc++) {
2247 for(yc = 0; yc < 2; yc++) {
2248 vec.x = (ft_face->glyph->metrics.horiBearingX +
2249 xc * ft_face->glyph->metrics.width);
2250 vec.y = ft_face->glyph->metrics.horiBearingY -
2251 yc * ft_face->glyph->metrics.height;
2252 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2253 pFT_Vector_Transform(&vec, &transMat);
2254 if(xc == 0 && yc == 0) {
2255 left = right = vec.x;
2256 top = bottom = vec.y;
2257 } else {
2258 if(vec.x < left) left = vec.x;
2259 else if(vec.x > right) right = vec.x;
2260 if(vec.y < bottom) bottom = vec.y;
2261 else if(vec.y > top) top = vec.y;
2265 left = left & -64;
2266 right = (right + 63) & -64;
2267 bottom = bottom & -64;
2268 top = (top + 63) & -64;
2270 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2271 vec.x = ft_face->glyph->metrics.horiAdvance;
2272 vec.y = 0;
2273 pFT_Vector_Transform(&vec, &transMat);
2274 lpgm->gmCellIncX = (vec.x+63) >> 6;
2275 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2277 lpgm->gmBlackBoxX = (right - left) >> 6;
2278 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2279 lpgm->gmptGlyphOrigin.x = left >> 6;
2280 lpgm->gmptGlyphOrigin.y = top >> 6;
2282 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2283 font->gm[glyph_index].init = TRUE;
2285 if(format == GGO_METRICS)
2286 return 1; /* FIXME */
2288 if (buf && !buflen){
2289 return GDI_ERROR;
2292 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2293 TRACE("loaded a bitmap\n");
2294 return GDI_ERROR;
2297 switch(format) {
2298 case GGO_BITMAP:
2299 width = lpgm->gmBlackBoxX;
2300 height = lpgm->gmBlackBoxY;
2301 pitch = ((width + 31) >> 5) << 2;
2302 needed = pitch * height;
2304 if(!buf || !buflen) break;
2306 switch(ft_face->glyph->format) {
2307 case ft_glyph_format_bitmap:
2309 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2310 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2311 INT h = ft_face->glyph->bitmap.rows;
2312 while(h--) {
2313 memcpy(dst, src, w);
2314 src += ft_face->glyph->bitmap.pitch;
2315 dst += pitch;
2317 break;
2320 case ft_glyph_format_outline:
2321 ft_bitmap.width = width;
2322 ft_bitmap.rows = height;
2323 ft_bitmap.pitch = pitch;
2324 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2325 ft_bitmap.buffer = buf;
2327 if(needsTransform) {
2328 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2331 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2333 /* Note: FreeType will only set 'black' bits for us. */
2334 memset(buf, 0, needed);
2335 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2336 break;
2338 default:
2339 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2340 return GDI_ERROR;
2342 break;
2344 case GGO_GRAY2_BITMAP:
2345 case GGO_GRAY4_BITMAP:
2346 case GGO_GRAY8_BITMAP:
2347 case WINE_GGO_GRAY16_BITMAP:
2349 int mult, row, col;
2350 BYTE *start, *ptr;
2352 width = lpgm->gmBlackBoxX;
2353 height = lpgm->gmBlackBoxY;
2354 pitch = (width + 3) / 4 * 4;
2355 needed = pitch * height;
2357 if(!buf || !buflen) break;
2358 ft_bitmap.width = width;
2359 ft_bitmap.rows = height;
2360 ft_bitmap.pitch = pitch;
2361 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2362 ft_bitmap.buffer = buf;
2364 if(needsTransform) {
2365 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2368 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2370 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2372 if(format == GGO_GRAY2_BITMAP)
2373 mult = 5;
2374 else if(format == GGO_GRAY4_BITMAP)
2375 mult = 17;
2376 else if(format == GGO_GRAY8_BITMAP)
2377 mult = 65;
2378 else if(format == WINE_GGO_GRAY16_BITMAP)
2379 break;
2380 else {
2381 assert(0);
2382 break;
2385 start = buf;
2386 for(row = 0; row < height; row++) {
2387 ptr = start;
2388 for(col = 0; col < width; col++, ptr++) {
2389 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2391 start += pitch;
2393 break;
2396 case GGO_NATIVE:
2398 int contour, point = 0, first_pt;
2399 FT_Outline *outline = &ft_face->glyph->outline;
2400 TTPOLYGONHEADER *pph;
2401 TTPOLYCURVE *ppc;
2402 DWORD pph_start, cpfx, type;
2404 if(buflen == 0) buf = NULL;
2406 if (needsTransform && buf) {
2407 pFT_Outline_Transform(outline, &transMat);
2410 for(contour = 0; contour < outline->n_contours; contour++) {
2411 pph_start = needed;
2412 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2413 first_pt = point;
2414 if(buf) {
2415 pph->dwType = TT_POLYGON_TYPE;
2416 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2418 needed += sizeof(*pph);
2419 point++;
2420 while(point <= outline->contours[contour]) {
2421 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2422 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2423 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2424 cpfx = 0;
2425 do {
2426 if(buf)
2427 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2428 cpfx++;
2429 point++;
2430 } while(point <= outline->contours[contour] &&
2431 (outline->tags[point] & FT_Curve_Tag_On) ==
2432 (outline->tags[point-1] & FT_Curve_Tag_On));
2433 /* At the end of a contour Windows adds the start point, but
2434 only for Beziers */
2435 if(point > outline->contours[contour] &&
2436 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2437 if(buf)
2438 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2439 cpfx++;
2440 } else if(point <= outline->contours[contour] &&
2441 outline->tags[point] & FT_Curve_Tag_On) {
2442 /* add closing pt for bezier */
2443 if(buf)
2444 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2445 cpfx++;
2446 point++;
2448 if(buf) {
2449 ppc->wType = type;
2450 ppc->cpfx = cpfx;
2452 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2454 if(buf)
2455 pph->cb = needed - pph_start;
2457 break;
2459 case GGO_BEZIER:
2461 /* Convert the quadratic Beziers to cubic Beziers.
2462 The parametric eqn for a cubic Bezier is, from PLRM:
2463 r(t) = at^3 + bt^2 + ct + r0
2464 with the control points:
2465 r1 = r0 + c/3
2466 r2 = r1 + (c + b)/3
2467 r3 = r0 + c + b + a
2469 A quadratic Beizer has the form:
2470 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2472 So equating powers of t leads to:
2473 r1 = 2/3 p1 + 1/3 p0
2474 r2 = 2/3 p1 + 1/3 p2
2475 and of course r0 = p0, r3 = p2
2478 int contour, point = 0, first_pt;
2479 FT_Outline *outline = &ft_face->glyph->outline;
2480 TTPOLYGONHEADER *pph;
2481 TTPOLYCURVE *ppc;
2482 DWORD pph_start, cpfx, type;
2483 FT_Vector cubic_control[4];
2484 if(buflen == 0) buf = NULL;
2486 if (needsTransform && buf) {
2487 pFT_Outline_Transform(outline, &transMat);
2490 for(contour = 0; contour < outline->n_contours; contour++) {
2491 pph_start = needed;
2492 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2493 first_pt = point;
2494 if(buf) {
2495 pph->dwType = TT_POLYGON_TYPE;
2496 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2498 needed += sizeof(*pph);
2499 point++;
2500 while(point <= outline->contours[contour]) {
2501 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2502 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2503 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2504 cpfx = 0;
2505 do {
2506 if(type == TT_PRIM_LINE) {
2507 if(buf)
2508 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2509 cpfx++;
2510 point++;
2511 } else {
2512 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2513 so cpfx = 3n */
2515 /* FIXME: Possible optimization in endpoint calculation
2516 if there are two consecutive curves */
2517 cubic_control[0] = outline->points[point-1];
2518 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2519 cubic_control[0].x += outline->points[point].x + 1;
2520 cubic_control[0].y += outline->points[point].y + 1;
2521 cubic_control[0].x >>= 1;
2522 cubic_control[0].y >>= 1;
2524 if(point+1 > outline->contours[contour])
2525 cubic_control[3] = outline->points[first_pt];
2526 else {
2527 cubic_control[3] = outline->points[point+1];
2528 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2529 cubic_control[3].x += outline->points[point].x + 1;
2530 cubic_control[3].y += outline->points[point].y + 1;
2531 cubic_control[3].x >>= 1;
2532 cubic_control[3].y >>= 1;
2535 /* r1 = 1/3 p0 + 2/3 p1
2536 r2 = 1/3 p2 + 2/3 p1 */
2537 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2538 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2539 cubic_control[2] = cubic_control[1];
2540 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2541 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2542 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2543 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2544 if(buf) {
2545 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2546 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2547 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2549 cpfx += 3;
2550 point++;
2552 } while(point <= outline->contours[contour] &&
2553 (outline->tags[point] & FT_Curve_Tag_On) ==
2554 (outline->tags[point-1] & FT_Curve_Tag_On));
2555 /* At the end of a contour Windows adds the start point,
2556 but only for Beziers and we've already done that.
2558 if(point <= outline->contours[contour] &&
2559 outline->tags[point] & FT_Curve_Tag_On) {
2560 /* This is the closing pt of a bezier, but we've already
2561 added it, so just inc point and carry on */
2562 point++;
2564 if(buf) {
2565 ppc->wType = type;
2566 ppc->cpfx = cpfx;
2568 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2570 if(buf)
2571 pph->cb = needed - pph_start;
2573 break;
2576 default:
2577 FIXME("Unsupported format %d\n", format);
2578 return GDI_ERROR;
2580 return needed;
2583 static BOOL get_bitmap_text_metrics(GdiFont font)
2585 FT_Face ft_face = font->ft_face;
2586 #ifdef HAVE_FREETYPE_FTWINFNT_H
2587 FT_WinFNT_HeaderRec winfnt_header;
2588 #endif
2589 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2590 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2591 font->potm->otmSize = size;
2593 #define TM font->potm->otmTextMetrics
2594 #ifdef HAVE_FREETYPE_FTWINFNT_H
2595 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2597 TM.tmHeight = winfnt_header.pixel_height;
2598 TM.tmAscent = winfnt_header.ascent;
2599 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2600 TM.tmInternalLeading = winfnt_header.internal_leading;
2601 TM.tmExternalLeading = winfnt_header.external_leading;
2602 TM.tmAveCharWidth = winfnt_header.avg_width;
2603 TM.tmMaxCharWidth = winfnt_header.max_width;
2604 TM.tmWeight = winfnt_header.weight;
2605 TM.tmOverhang = 0;
2606 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2607 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2608 TM.tmFirstChar = winfnt_header.first_char;
2609 TM.tmLastChar = winfnt_header.last_char;
2610 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2611 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2612 TM.tmItalic = winfnt_header.italic;
2613 TM.tmUnderlined = font->underline;
2614 TM.tmStruckOut = font->strikeout;
2615 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2616 TM.tmCharSet = winfnt_header.charset;
2618 else
2619 #endif
2621 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2622 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2623 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2624 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2625 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2626 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2627 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2628 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2629 TM.tmOverhang = 0;
2630 TM.tmDigitizedAspectX = 96; /* FIXME */
2631 TM.tmDigitizedAspectY = 96; /* FIXME */
2632 TM.tmFirstChar = 1;
2633 TM.tmLastChar = 255;
2634 TM.tmDefaultChar = 32;
2635 TM.tmBreakChar = 32;
2636 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2637 TM.tmUnderlined = font->underline;
2638 TM.tmStruckOut = font->strikeout;
2639 /* NB inverted meaning of TMPF_FIXED_PITCH */
2640 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2641 TM.tmCharSet = font->charset;
2643 #undef TM
2645 return TRUE;
2648 /*************************************************************
2649 * WineEngGetTextMetrics
2652 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2654 if(!font->potm) {
2655 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2656 if(!get_bitmap_text_metrics(font))
2657 return FALSE;
2659 if(!font->potm) return FALSE;
2660 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2662 if (font->aveWidth) {
2663 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2665 return TRUE;
2669 /*************************************************************
2670 * WineEngGetOutlineTextMetrics
2673 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2674 OUTLINETEXTMETRICW *potm)
2676 FT_Face ft_face = font->ft_face;
2677 UINT needed, lenfam, lensty, ret;
2678 TT_OS2 *pOS2;
2679 TT_HoriHeader *pHori;
2680 TT_Postscript *pPost;
2681 FT_Fixed x_scale, y_scale;
2682 WCHAR *family_nameW, *style_nameW;
2683 static const WCHAR spaceW[] = {' ', '\0'};
2684 char *cp;
2685 INT ascent, descent;
2687 TRACE("font=%p\n", font);
2689 if(!FT_IS_SCALABLE(ft_face))
2690 return 0;
2692 if(font->potm) {
2693 if(cbSize >= font->potm->otmSize)
2694 memcpy(potm, font->potm, font->potm->otmSize);
2695 return font->potm->otmSize;
2699 needed = sizeof(*potm);
2701 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2702 family_nameW = strdupW(font->name);
2704 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2705 * sizeof(WCHAR);
2706 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2707 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2708 style_nameW, lensty);
2710 /* These names should be read from the TT name table */
2712 /* length of otmpFamilyName */
2713 needed += lenfam;
2715 /* length of otmpFaceName */
2716 if(!strcasecmp(ft_face->style_name, "regular")) {
2717 needed += lenfam; /* just the family name */
2718 } else {
2719 needed += lenfam + lensty; /* family + " " + style */
2722 /* length of otmpStyleName */
2723 needed += lensty;
2725 /* length of otmpFullName */
2726 needed += lenfam + lensty;
2729 x_scale = ft_face->size->metrics.x_scale;
2730 y_scale = ft_face->size->metrics.y_scale;
2732 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2733 if(!pOS2) {
2734 FIXME("Can't find OS/2 table - not TT font?\n");
2735 ret = 0;
2736 goto end;
2739 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2740 if(!pHori) {
2741 FIXME("Can't find HHEA table - not TT font?\n");
2742 ret = 0;
2743 goto end;
2746 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2748 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",
2749 pOS2->usWinAscent, pOS2->usWinDescent,
2750 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2751 ft_face->ascender, ft_face->descender, ft_face->height,
2752 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2753 ft_face->bbox.yMax, ft_face->bbox.yMin);
2755 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2756 font->potm->otmSize = needed;
2758 #define TM font->potm->otmTextMetrics
2760 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2761 ascent = pHori->Ascender;
2762 descent = -pHori->Descender;
2763 } else {
2764 ascent = pOS2->usWinAscent;
2765 descent = pOS2->usWinDescent;
2768 if(font->yMax) {
2769 TM.tmAscent = font->yMax;
2770 TM.tmDescent = -font->yMin;
2771 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2772 } else {
2773 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2774 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2775 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2776 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2779 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2781 /* MSDN says:
2782 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2784 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2785 ((ascent + descent) -
2786 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2788 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2789 if (TM.tmAveCharWidth == 0) {
2790 TM.tmAveCharWidth = 1;
2792 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2793 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2794 TM.tmOverhang = 0;
2795 TM.tmDigitizedAspectX = 300;
2796 TM.tmDigitizedAspectY = 300;
2797 TM.tmFirstChar = pOS2->usFirstCharIndex;
2798 TM.tmLastChar = pOS2->usLastCharIndex;
2799 TM.tmDefaultChar = pOS2->usDefaultChar;
2800 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2801 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2802 TM.tmUnderlined = font->underline;
2803 TM.tmStruckOut = font->strikeout;
2805 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2806 if(!FT_IS_FIXED_WIDTH(ft_face))
2807 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2808 else
2809 TM.tmPitchAndFamily = 0;
2811 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2812 case PAN_FAMILY_SCRIPT:
2813 TM.tmPitchAndFamily |= FF_SCRIPT;
2814 break;
2815 case PAN_FAMILY_DECORATIVE:
2816 case PAN_FAMILY_PICTORIAL:
2817 TM.tmPitchAndFamily |= FF_DECORATIVE;
2818 break;
2819 case PAN_FAMILY_TEXT_DISPLAY:
2820 if(TM.tmPitchAndFamily == 0) /* fixed */
2821 TM.tmPitchAndFamily = FF_MODERN;
2822 else {
2823 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2824 case PAN_SERIF_NORMAL_SANS:
2825 case PAN_SERIF_OBTUSE_SANS:
2826 case PAN_SERIF_PERP_SANS:
2827 TM.tmPitchAndFamily |= FF_SWISS;
2828 break;
2829 default:
2830 TM.tmPitchAndFamily |= FF_ROMAN;
2833 break;
2834 default:
2835 TM.tmPitchAndFamily |= FF_DONTCARE;
2838 if(FT_IS_SCALABLE(ft_face))
2839 TM.tmPitchAndFamily |= TMPF_VECTOR;
2840 if(FT_IS_SFNT(ft_face))
2841 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2843 TM.tmCharSet = font->charset;
2844 #undef TM
2846 font->potm->otmFiller = 0;
2847 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2848 font->potm->otmfsSelection = pOS2->fsSelection;
2849 font->potm->otmfsType = pOS2->fsType;
2850 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2851 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2852 font->potm->otmItalicAngle = 0; /* POST table */
2853 font->potm->otmEMSquare = ft_face->units_per_EM;
2854 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2855 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2856 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2857 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2858 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2859 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2860 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2861 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2862 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2863 font->potm->otmMacAscent = 0; /* where do these come from ? */
2864 font->potm->otmMacDescent = 0;
2865 font->potm->otmMacLineGap = 0;
2866 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2867 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2868 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2869 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2870 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2871 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2872 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2873 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2874 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2875 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2876 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2877 if(!pPost) {
2878 font->potm->otmsUnderscoreSize = 0;
2879 font->potm->otmsUnderscorePosition = 0;
2880 } else {
2881 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2882 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2885 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2886 cp = (char*)font->potm + sizeof(*font->potm);
2887 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2888 strcpyW((WCHAR*)cp, family_nameW);
2889 cp += lenfam;
2890 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2891 strcpyW((WCHAR*)cp, style_nameW);
2892 cp += lensty;
2893 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2894 strcpyW((WCHAR*)cp, family_nameW);
2895 if(strcasecmp(ft_face->style_name, "regular")) {
2896 strcatW((WCHAR*)cp, spaceW);
2897 strcatW((WCHAR*)cp, style_nameW);
2898 cp += lenfam + lensty;
2899 } else
2900 cp += lenfam;
2901 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2902 strcpyW((WCHAR*)cp, family_nameW);
2903 strcatW((WCHAR*)cp, spaceW);
2904 strcatW((WCHAR*)cp, style_nameW);
2905 ret = needed;
2907 if(potm && needed <= cbSize)
2908 memcpy(potm, font->potm, font->potm->otmSize);
2910 end:
2911 HeapFree(GetProcessHeap(), 0, style_nameW);
2912 HeapFree(GetProcessHeap(), 0, family_nameW);
2914 return ret;
2918 /*************************************************************
2919 * WineEngGetCharWidth
2922 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2923 LPINT buffer)
2925 UINT c;
2926 GLYPHMETRICS gm;
2927 FT_UInt glyph_index;
2929 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2931 for(c = firstChar; c <= lastChar; c++) {
2932 glyph_index = get_glyph_index(font, c);
2933 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2934 &gm, 0, NULL, NULL);
2935 buffer[c - firstChar] = font->gm[glyph_index].adv;
2937 return TRUE;
2940 /*************************************************************
2941 * WineEngGetCharABCWidths
2944 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2945 LPABC buffer)
2947 UINT c;
2948 GLYPHMETRICS gm;
2949 FT_UInt glyph_index;
2951 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2953 for(c = firstChar; c <= lastChar; c++) {
2954 glyph_index = get_glyph_index(font, c);
2955 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2956 &gm, 0, NULL, NULL);
2957 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2958 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2959 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2960 font->gm[glyph_index].bbx;
2962 return TRUE;
2965 /*************************************************************
2966 * WineEngGetTextExtentPoint
2969 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2970 LPSIZE size)
2972 INT idx;
2973 GLYPHMETRICS gm;
2974 TEXTMETRICW tm;
2975 FT_UInt glyph_index;
2977 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2978 size);
2980 size->cx = 0;
2981 WineEngGetTextMetrics(font, &tm);
2982 size->cy = tm.tmHeight;
2984 for(idx = 0; idx < count; idx++) {
2985 glyph_index = get_glyph_index(font, wstr[idx]);
2986 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2987 &gm, 0, NULL, NULL);
2988 size->cx += font->gm[glyph_index].adv;
2990 TRACE("return %ld,%ld\n", size->cx, size->cy);
2991 return TRUE;
2994 /*************************************************************
2995 * WineEngGetTextExtentPointI
2998 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2999 LPSIZE size)
3001 INT idx;
3002 GLYPHMETRICS gm;
3003 TEXTMETRICW tm;
3005 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3007 size->cx = 0;
3008 WineEngGetTextMetrics(font, &tm);
3009 size->cy = tm.tmHeight;
3011 for(idx = 0; idx < count; idx++) {
3012 WineEngGetGlyphOutline(font, indices[idx],
3013 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3014 NULL);
3015 size->cx += font->gm[indices[idx]].adv;
3017 TRACE("return %ld,%ld\n", size->cx, size->cy);
3018 return TRUE;
3021 /*************************************************************
3022 * WineEngGetFontData
3025 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3026 DWORD cbData)
3028 FT_Face ft_face = font->ft_face;
3029 DWORD len;
3030 FT_Error err;
3032 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3033 font, table, offset, buf, cbData);
3035 if(!FT_IS_SFNT(ft_face))
3036 return GDI_ERROR;
3038 if(!buf || !cbData)
3039 len = 0;
3040 else
3041 len = cbData;
3043 if(table) { /* MS tags differ in endidness from FT ones */
3044 table = table >> 24 | table << 24 |
3045 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3048 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3049 if(pFT_Load_Sfnt_Table)
3050 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3051 else { /* Do it the hard way */
3052 TT_Face tt_face = (TT_Face) ft_face;
3053 SFNT_Interface *sfnt;
3054 if (FT_Version.major==2 && FT_Version.minor==0)
3056 /* 2.0.x */
3057 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3059 else
3061 /* A field was added in the middle of the structure in 2.1.x */
3062 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3064 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3066 if(err) {
3067 TRACE("Can't find table %08lx.\n", table);
3068 return GDI_ERROR;
3070 return len;
3073 /*************************************************************
3074 * WineEngGetTextFace
3077 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3079 if(str) {
3080 lstrcpynW(str, font->name, count);
3081 return strlenW(font->name);
3082 } else
3083 return strlenW(font->name) + 1;
3086 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3088 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3089 return font->charset;
3092 #else /* HAVE_FREETYPE */
3094 BOOL WineEngInit(void)
3096 return FALSE;
3098 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3100 return NULL;
3102 BOOL WineEngDestroyFontInstance(HFONT hfont)
3104 return FALSE;
3107 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3109 return 1;
3112 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3113 LPWORD pgi, DWORD flags)
3115 return GDI_ERROR;
3118 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3119 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3120 const MAT2* lpmat)
3122 ERR("called but we don't have FreeType\n");
3123 return GDI_ERROR;
3126 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3128 ERR("called but we don't have FreeType\n");
3129 return FALSE;
3132 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3133 OUTLINETEXTMETRICW *potm)
3135 ERR("called but we don't have FreeType\n");
3136 return 0;
3139 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3140 LPINT buffer)
3142 ERR("called but we don't have FreeType\n");
3143 return FALSE;
3146 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3147 LPABC buffer)
3149 ERR("called but we don't have FreeType\n");
3150 return FALSE;
3153 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3154 LPSIZE size)
3156 ERR("called but we don't have FreeType\n");
3157 return FALSE;
3160 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3161 LPSIZE size)
3163 ERR("called but we don't have FreeType\n");
3164 return FALSE;
3167 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3168 DWORD cbData)
3170 ERR("called but we don't have FreeType\n");
3171 return GDI_ERROR;
3174 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3176 ERR("called but we don't have FreeType\n");
3177 return 0;
3180 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3182 FIXME(":stub\n");
3183 return 1;
3186 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3188 FIXME(":stub\n");
3189 return TRUE;
3192 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3194 FIXME(":stub\n");
3195 return DEFAULT_CHARSET;
3198 #endif /* HAVE_FREETYPE */