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
24 #include "wine/port.h"
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
42 #include "gdi_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(font);
51 #ifdef HAVE_FT2BUILD_H
54 #ifdef HAVE_FREETYPE_FREETYPE_H
55 #include <freetype/freetype.h>
57 #ifdef HAVE_FREETYPE_FTGLYPH_H
58 #include <freetype/ftglyph.h>
60 #ifdef HAVE_FREETYPE_TTTABLES_H
61 #include <freetype/tttables.h>
63 #ifdef HAVE_FREETYPE_FTSNAMES_H
64 #include <freetype/ftsnames.h>
66 # ifdef HAVE_FREETYPE_FTNAMES_H
67 # include <freetype/ftnames.h>
70 #ifdef HAVE_FREETYPE_TTNAMEID_H
71 #include <freetype/ttnameid.h>
73 #ifdef HAVE_FREETYPE_FTOUTLN_H
74 #include <freetype/ftoutln.h>
76 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
77 #include <freetype/internal/sfnt.h>
79 #ifdef HAVE_FREETYPE_FTTRIGON_H
80 #include <freetype/fttrigon.h>
82 #ifdef HAVE_FREETYPE_FTWINFNT_H
83 #include <freetype/ftwinfnt.h>
86 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
90 static FT_Library library = 0;
97 static FT_Version_t FT_Version;
98 static DWORD FT_SimpleVersion;
100 static void *ft_handle = NULL;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
103 MAKE_FUNCPTR(FT_Vector_Unit);
104 MAKE_FUNCPTR(FT_Done_Face);
105 MAKE_FUNCPTR(FT_Get_Char_Index);
106 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
107 MAKE_FUNCPTR(FT_Init_FreeType);
108 MAKE_FUNCPTR(FT_Load_Glyph);
109 MAKE_FUNCPTR(FT_Matrix_Multiply);
110 MAKE_FUNCPTR(FT_MulFix);
111 MAKE_FUNCPTR(FT_New_Face);
112 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
113 MAKE_FUNCPTR(FT_Outline_Transform);
114 MAKE_FUNCPTR(FT_Outline_Translate);
115 MAKE_FUNCPTR(FT_Select_Charmap);
116 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
117 MAKE_FUNCPTR(FT_Vector_Transform);
118 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
119 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
120 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
121 #ifdef HAVE_FREETYPE_FTWINFNT_H
122 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
125 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
126 #include <fontconfig/fontconfig.h>
127 MAKE_FUNCPTR(FcConfigGetCurrent);
128 MAKE_FUNCPTR(FcFontList);
129 MAKE_FUNCPTR(FcFontSetDestroy);
130 MAKE_FUNCPTR(FcInit);
131 MAKE_FUNCPTR(FcObjectSetAdd);
132 MAKE_FUNCPTR(FcObjectSetCreate);
133 MAKE_FUNCPTR(FcObjectSetDestroy);
134 MAKE_FUNCPTR(FcPatternCreate);
135 MAKE_FUNCPTR(FcPatternDestroy);
136 MAKE_FUNCPTR(FcPatternGet);
137 #ifndef SONAME_LIBFONTCONFIG
138 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
144 #ifndef ft_encoding_none
145 #define FT_ENCODING_NONE ft_encoding_none
147 #ifndef ft_encoding_ms_symbol
148 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
150 #ifndef ft_encoding_unicode
151 #define FT_ENCODING_UNICODE ft_encoding_unicode
153 #ifndef ft_encoding_apple_roman
154 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
157 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
159 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
166 FT_Short internal_leading;
169 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
170 So to let this compile on older versions of FreeType we'll define the
171 new structure here. */
173 FT_Short height, width;
174 FT_Pos size, x_ppem, y_ppem;
177 typedef struct tagFace {
185 FT_Fixed font_version;
187 Bitmap_Size size; /* set if face is a bitmap */
188 BOOL external; /* TRUE if we should manually add this font to the registry */
189 struct tagFamily *family;
192 typedef struct tagFamily {
200 INT adv; /* These three hold to widths of the unrotated chars */
217 typedef struct tagHFONTLIST {
235 struct list hfontlist;
240 OUTLINETEXTMETRICW *potm;
244 #define INIT_GM_SIZE 128
246 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
247 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
248 #define UNUSED_CACHE_SIZE 10
250 static struct list font_list = LIST_INIT(font_list);
252 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
253 'R','o','m','a','n','\0'};
254 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
255 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
257 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
258 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
259 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
260 'S','e','r','i','f','\0'};
261 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
262 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
264 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
265 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
266 'W','i','n','d','o','w','s','\\',
267 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
268 'F','o','n','t','s','\0'};
270 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
271 'W','i','n','d','o','w','s',' ','N','T','\\',
272 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
273 'F','o','n','t','s','\0'};
275 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
276 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
277 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
278 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
280 static const WCHAR *SystemFontValues[4] = {
287 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
288 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
290 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
291 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
292 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
293 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
294 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
295 'E','u','r','o','p','e','a','n','\0'};
296 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
297 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
298 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
299 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
300 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
301 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
302 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
303 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
304 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
305 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
306 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
307 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
309 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
319 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
327 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
336 typedef struct tagFontSubst {
339 struct tagFontSubst *next;
342 static FontSubst *substlist = NULL;
343 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
345 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
348 /****************************************
349 * Notes on .fon files
351 * The fonts System, FixedSys and Terminal are special. There are typically multiple
352 * versions installed for different resolutions and codepages. Windows stores which one to use
353 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
355 * FIXEDFON.FON FixedSys
357 * OEMFONT.FON Terminal
358 * LogPixels Current dpi set by the display control panel applet
359 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
360 * also has a LogPixels value that appears to mirror this)
362 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
363 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
364 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
365 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
366 * so that makes sense.
368 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
369 * to be mapped into the registry on Windows 2000 at least).
372 * ega80woa.fon=ega80850.fon
373 * ega40woa.fon=ega40850.fon
374 * cga80woa.fon=cga80850.fon
375 * cga40woa.fon=cga40850.fon
379 static inline BOOL is_win9x(void)
381 return GetVersion() & 0x80000000;
384 This function builds an FT_Fixed from a float. It puts the integer part
385 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
386 It fails if the integer part of the float number is greater than SHORT_MAX.
388 static inline FT_Fixed FT_FixedFromFloat(float f)
391 unsigned short fract = (f - value) * 0xFFFF;
392 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
396 This function builds an FT_Fixed from a FIXED. It simply put f.value
397 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
399 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
401 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
404 #define ADDFONT_EXTERNAL_FONT 0x01
405 #define ADDFONT_FORCE_BITMAP 0x02
406 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
410 TT_Header *pHeader = NULL;
411 WCHAR *FamilyW, *StyleW;
415 struct list *family_elem_ptr, *face_elem_ptr;
417 FT_Long face_index = 0, num_faces;
418 #ifdef HAVE_FREETYPE_FTWINFNT_H
419 FT_WinFNT_HeaderRec winfnt_header;
421 int i, bitmap_num, internal_leading;
425 char *family_name = fake_family;
427 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
428 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
429 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
433 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*/
434 pFT_Done_Face(ft_face);
438 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
439 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
440 pFT_Done_Face(ft_face);
444 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
445 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
446 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
447 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
448 "Skipping this font.\n", debugstr_a(file));
449 pFT_Done_Face(ft_face);
453 if(!ft_face->family_name || !ft_face->style_name) {
454 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
455 pFT_Done_Face(ft_face);
460 family_name = ft_face->family_name;
464 My_FT_Bitmap_Size *size = NULL;
466 if(!FT_IS_SCALABLE(ft_face))
467 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
469 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
470 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
471 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
474 LIST_FOR_EACH(family_elem_ptr, &font_list) {
475 family = LIST_ENTRY(family_elem_ptr, Family, entry);
476 if(!strcmpW(family->FamilyName, FamilyW))
481 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
482 family->FamilyName = FamilyW;
483 list_init(&family->faces);
484 list_add_tail(&font_list, &family->entry);
486 HeapFree(GetProcessHeap(), 0, FamilyW);
489 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
490 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
491 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
493 internal_leading = 0;
494 memset(&fs, 0, sizeof(fs));
496 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
498 fs.fsCsb[0] = pOS2->ulCodePageRange1;
499 fs.fsCsb[1] = pOS2->ulCodePageRange2;
500 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
501 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
502 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
503 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
504 if(pOS2->version == 0) {
507 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
510 fs.fsCsb[0] |= 1L << 31;
513 #ifdef HAVE_FREETYPE_FTWINFNT_H
514 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
516 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
517 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
518 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
519 memcpy(&fs, &csi.fs, sizeof(csi.fs));
520 internal_leading = winfnt_header.internal_leading;
524 face_elem_ptr = list_head(&family->faces);
525 while(face_elem_ptr) {
526 face = LIST_ENTRY(face_elem_ptr, Face, entry);
527 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
528 if(!strcmpW(face->StyleName, StyleW) &&
529 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
530 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
531 debugstr_w(family->FamilyName), debugstr_w(StyleW),
532 face->font_version, pHeader ? pHeader->Font_Revision : 0);
535 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
536 HeapFree(GetProcessHeap(), 0, StyleW);
537 pFT_Done_Face(ft_face);
540 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
541 TRACE("Original font is newer so skipping this one\n");
542 HeapFree(GetProcessHeap(), 0, StyleW);
543 pFT_Done_Face(ft_face);
546 TRACE("Replacing original with this one\n");
547 list_remove(&face->entry);
548 HeapFree(GetProcessHeap(), 0, face->file);
549 HeapFree(GetProcessHeap(), 0, face->StyleName);
550 HeapFree(GetProcessHeap(), 0, face);
555 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
556 list_add_tail(&family->faces, &face->entry);
557 face->StyleName = StyleW;
558 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
559 strcpy(face->file, file);
560 face->face_index = face_index;
561 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
562 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
563 face->font_version = pHeader ? pHeader->Font_Revision : 0;
564 face->family = family;
565 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
566 memcpy(&face->fs, &fs, sizeof(face->fs));
568 if(FT_IS_SCALABLE(ft_face)) {
569 memset(&face->size, 0, sizeof(face->size));
570 face->scalable = TRUE;
572 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
573 size->height, size->width, size->size >> 6,
574 size->x_ppem >> 6, size->y_ppem >> 6);
575 face->size.height = size->height;
576 face->size.width = size->width;
577 face->size.size = size->size;
578 face->size.x_ppem = size->x_ppem;
579 face->size.y_ppem = size->y_ppem;
580 face->size.internal_leading = internal_leading;
581 face->scalable = FALSE;
584 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
585 face->fs.fsCsb[0], face->fs.fsCsb[1],
586 face->fs.fsUsb[0], face->fs.fsUsb[1],
587 face->fs.fsUsb[2], face->fs.fsUsb[3]);
590 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
591 for(i = 0; i < ft_face->num_charmaps; i++) {
592 switch(ft_face->charmaps[i]->encoding) {
593 case FT_ENCODING_UNICODE:
594 case FT_ENCODING_APPLE_ROMAN:
595 face->fs.fsCsb[0] |= 1;
597 case FT_ENCODING_MS_SYMBOL:
598 face->fs.fsCsb[0] |= 1L << 31;
606 if(face->fs.fsCsb[0] & ~(1L << 31))
607 have_installed_roman_font = TRUE;
608 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
610 num_faces = ft_face->num_faces;
611 pFT_Done_Face(ft_face);
612 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
614 } while(num_faces > ++face_index);
618 static void DumpFontList(void)
622 struct list *family_elem_ptr, *face_elem_ptr;
624 LIST_FOR_EACH(family_elem_ptr, &font_list) {
625 family = LIST_ENTRY(family_elem_ptr, Family, entry);
626 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
627 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
628 face = LIST_ENTRY(face_elem_ptr, Face, entry);
629 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
631 TRACE(" %ld", face->size.y_ppem >> 6);
638 static void DumpSubstList(void)
642 for(psub = substlist; psub; psub = psub->next)
643 if(psub->from.charset != -1 || psub->to.charset != -1)
644 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
645 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
647 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
648 debugstr_w(psub->to.name));
652 static LPWSTR strdupW(LPWSTR p)
655 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
656 ret = HeapAlloc(GetProcessHeap(), 0, len);
661 static void split_subst_info(NameCs *nc, LPSTR str)
663 CHAR *p = strrchr(str, ',');
668 nc->charset = strtol(p+1, NULL, 10);
671 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
672 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
673 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
676 static void LoadSubstList(void)
678 FontSubst *psub, **ppsub;
680 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
685 for(psub = substlist; psub;) {
687 HeapFree(GetProcessHeap(), 0, psub->to.name);
688 HeapFree(GetProcessHeap(), 0, psub->from.name);
691 HeapFree(GetProcessHeap(), 0, ptmp);
696 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
697 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
698 &hkey) == ERROR_SUCCESS) {
700 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
701 &valuelen, &datalen, NULL, NULL);
703 valuelen++; /* returned value doesn't include room for '\0' */
704 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
705 data = HeapAlloc(GetProcessHeap(), 0, datalen);
710 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
711 &dlen) == ERROR_SUCCESS) {
712 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
714 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
715 (*ppsub)->next = NULL;
716 split_subst_info(&((*ppsub)->from), value);
717 split_subst_info(&((*ppsub)->to), data);
719 /* Win 2000 doesn't allow mapping between different charsets
720 or mapping of DEFAULT_CHARSET */
721 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
722 (*ppsub)->to.charset == DEFAULT_CHARSET) {
723 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
724 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
725 HeapFree(GetProcessHeap(), 0, *ppsub);
728 ppsub = &((*ppsub)->next);
730 /* reset dlen and vlen */
734 HeapFree(GetProcessHeap(), 0, data);
735 HeapFree(GetProcessHeap(), 0, value);
740 /***********************************************************
741 * The replacement list is a way to map an entire font
742 * family onto another family. For example adding
744 * [HKCU\Software\Wine\Fonts\Replacements]
745 * "Wingdings"="Winedings"
747 * would enumerate the Winedings font both as Winedings and
748 * Wingdings. However if a real Wingdings font is present the
749 * replacement does not take place.
752 static void LoadReplaceList(void)
755 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
760 struct list *family_elem_ptr, *face_elem_ptr;
761 WCHAR old_nameW[200];
763 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
764 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
766 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
767 &valuelen, &datalen, NULL, NULL);
769 valuelen++; /* returned value doesn't include room for '\0' */
770 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
771 data = HeapAlloc(GetProcessHeap(), 0, datalen);
775 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
776 &dlen) == ERROR_SUCCESS) {
777 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
778 /* "NewName"="Oldname" */
779 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
782 /* Find the old family and hence all of the font files
784 LIST_FOR_EACH(family_elem_ptr, &font_list) {
785 family = LIST_ENTRY(family_elem_ptr, Family, entry);
786 if(!strcmpiW(family->FamilyName, old_nameW)) {
787 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
788 face = LIST_ENTRY(face_elem_ptr, Face, entry);
789 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
790 debugstr_w(face->StyleName), value);
791 /* Now add a new entry with the new family name */
792 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
797 /* reset dlen and vlen */
801 HeapFree(GetProcessHeap(), 0, data);
802 HeapFree(GetProcessHeap(), 0, value);
808 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
814 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
816 dir = opendir(dirname);
818 ERR("Can't open directory %s\n", debugstr_a(dirname));
821 while((dent = readdir(dir)) != NULL) {
824 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
827 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
829 sprintf(path, "%s/%s", dirname, dent->d_name);
831 if(stat(path, &statbuf) == -1)
833 WARN("Can't stat %s\n", debugstr_a(path));
836 if(S_ISDIR(statbuf.st_mode))
837 ReadFontDir(path, external_fonts);
839 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
845 static void load_fontconfig_fonts(void)
847 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
848 void *fc_handle = NULL;
855 const char *file, *ext;
857 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
859 TRACE("Wine cannot find the fontconfig library (%s).\n",
860 SONAME_LIBFONTCONFIG);
863 #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;}
864 LOAD_FUNCPTR(FcConfigGetCurrent);
865 LOAD_FUNCPTR(FcFontList);
866 LOAD_FUNCPTR(FcFontSetDestroy);
867 LOAD_FUNCPTR(FcInit);
868 LOAD_FUNCPTR(FcObjectSetAdd);
869 LOAD_FUNCPTR(FcObjectSetCreate);
870 LOAD_FUNCPTR(FcObjectSetDestroy);
871 LOAD_FUNCPTR(FcPatternCreate);
872 LOAD_FUNCPTR(FcPatternDestroy);
873 LOAD_FUNCPTR(FcPatternGet);
876 if(!pFcInit()) return;
878 config = pFcConfigGetCurrent();
879 pat = pFcPatternCreate();
880 os = pFcObjectSetCreate();
881 pFcObjectSetAdd(os, FC_FILE);
882 fontset = pFcFontList(config, pat, os);
884 for(i = 0; i < fontset->nfont; i++) {
885 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
887 if(v.type != FcTypeString) continue;
888 file = (LPCSTR) v.u.s;
889 TRACE("fontconfig: %s\n", file);
891 /* We're just interested in OT/TT fonts for now, so this hack just
892 picks up the standard extensions to save time loading every other
894 len = strlen( file );
895 if(len < 4) continue;
896 ext = &file[ len - 3 ];
897 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
898 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
900 pFcFontSetDestroy(fontset);
901 pFcObjectSetDestroy(os);
902 pFcPatternDestroy(pat);
909 static void load_system_fonts(void)
912 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
915 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
918 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
919 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
920 strcatW(windowsdir, fontsW);
921 for(value = SystemFontValues; *value; value++) {
923 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
925 sprintfW(pathW, fmtW, windowsdir, data);
926 if((unixname = wine_get_unix_file_name(pathW))) {
927 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
928 HeapFree(GetProcessHeap(), 0, unixname);
936 /*************************************************************
938 * This adds registry entries for any externally loaded fonts
939 * (fonts from fontconfig or FontDirs). It also deletes entries
940 * of no longer existing fonts.
943 static void update_reg_entries(void)
945 HKEY winkey = 0, externalkey = 0;
948 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
951 struct list *family_elem_ptr, *face_elem_ptr;
953 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
954 static const WCHAR spaceW[] = {' ', '\0'};
957 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
958 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
959 ERR("Can't create Windows font reg key\n");
962 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
963 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
964 ERR("Can't create external font reg key\n");
968 /* Delete all external fonts added last time */
970 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
971 &valuelen, &datalen, NULL, NULL);
972 valuelen++; /* returned value doesn't include room for '\0' */
973 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
974 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
976 dlen = datalen * sizeof(WCHAR);
979 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
980 &dlen) == ERROR_SUCCESS) {
982 RegDeleteValueW(winkey, valueW);
983 /* reset dlen and vlen */
987 HeapFree(GetProcessHeap(), 0, data);
988 HeapFree(GetProcessHeap(), 0, valueW);
990 /* Delete the old external fonts key */
991 RegCloseKey(externalkey);
993 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
995 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
996 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
997 ERR("Can't create external font reg key\n");
1001 /* enumerate the fonts and add external ones to the two keys */
1003 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1004 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1005 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1006 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1007 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1008 if(!face->external) continue;
1010 if(strcmpiW(face->StyleName, RegularW))
1011 len = len_fam + strlenW(face->StyleName) + 1;
1012 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1013 strcpyW(valueW, family->FamilyName);
1014 if(len != len_fam) {
1015 strcatW(valueW, spaceW);
1016 strcatW(valueW, face->StyleName);
1018 strcatW(valueW, TrueType);
1019 if((path = strrchr(face->file, '/')) == NULL)
1023 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1025 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1026 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1027 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1028 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1030 HeapFree(GetProcessHeap(), 0, file);
1031 HeapFree(GetProcessHeap(), 0, valueW);
1036 RegCloseKey(externalkey);
1038 RegCloseKey(winkey);
1043 /*************************************************************
1044 * WineEngAddFontResourceEx
1047 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1049 if (ft_handle) /* do it only if we have freetype up and running */
1054 FIXME("Ignoring flags %lx\n", flags);
1056 if((unixname = wine_get_unix_file_name(file)))
1058 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1059 HeapFree(GetProcessHeap(), 0, unixname);
1065 /*************************************************************
1066 * WineEngRemoveFontResourceEx
1069 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1075 /*************************************************************
1078 * Initialize FreeType library and create a list of available faces
1080 BOOL WineEngInit(void)
1082 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1083 static const WCHAR pathW[] = {'P','a','t','h',0};
1085 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1087 WCHAR windowsdir[MAX_PATH];
1093 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1096 "Wine cannot find the FreeType font library. To enable Wine to\n"
1097 "use TrueType fonts please install a version of FreeType greater than\n"
1098 "or equal to 2.0.5.\n"
1099 "http://www.freetype.org\n");
1103 #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;}
1105 LOAD_FUNCPTR(FT_Vector_Unit)
1106 LOAD_FUNCPTR(FT_Done_Face)
1107 LOAD_FUNCPTR(FT_Get_Char_Index)
1108 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1109 LOAD_FUNCPTR(FT_Init_FreeType)
1110 LOAD_FUNCPTR(FT_Load_Glyph)
1111 LOAD_FUNCPTR(FT_Matrix_Multiply)
1112 LOAD_FUNCPTR(FT_MulFix)
1113 LOAD_FUNCPTR(FT_New_Face)
1114 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1115 LOAD_FUNCPTR(FT_Outline_Transform)
1116 LOAD_FUNCPTR(FT_Outline_Translate)
1117 LOAD_FUNCPTR(FT_Select_Charmap)
1118 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1119 LOAD_FUNCPTR(FT_Vector_Transform)
1122 /* Don't warn if this one is missing */
1123 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1124 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1125 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1126 #ifdef HAVE_FREETYPE_FTWINFNT_H
1127 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1129 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1130 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1131 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1132 <= 2.0.3 has FT_Sqrt64 */
1136 if(pFT_Init_FreeType(&library) != 0) {
1137 ERR("Can't init FreeType library\n");
1138 wine_dlclose(ft_handle, NULL, 0);
1142 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1143 if (pFT_Library_Version)
1145 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1147 if (FT_Version.major<=0)
1153 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1154 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1155 ((FT_Version.minor << 8) & 0x00ff00) |
1156 ((FT_Version.patch ) & 0x0000ff);
1158 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1159 ERR("Failed to create font mutex\n");
1162 WaitForSingleObject(font_mutex, INFINITE);
1164 /* load the system fonts */
1165 load_system_fonts();
1167 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1168 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1169 strcatW(windowsdir, fontsW);
1170 if((unixname = wine_get_unix_file_name(windowsdir)))
1172 ReadFontDir(unixname, FALSE);
1173 HeapFree(GetProcessHeap(), 0, unixname);
1176 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1177 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1178 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1180 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1181 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1182 &hkey) == ERROR_SUCCESS) {
1184 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1185 &valuelen, &datalen, NULL, NULL);
1187 valuelen++; /* returned value doesn't include room for '\0' */
1188 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1189 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1192 dlen = datalen * sizeof(WCHAR);
1194 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1195 &dlen) == ERROR_SUCCESS) {
1196 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1198 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1200 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1201 HeapFree(GetProcessHeap(), 0, unixname);
1204 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1206 WCHAR pathW[MAX_PATH];
1207 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1208 sprintfW(pathW, fmtW, windowsdir, data);
1209 if((unixname = wine_get_unix_file_name(pathW)))
1211 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1212 HeapFree(GetProcessHeap(), 0, unixname);
1215 /* reset dlen and vlen */
1220 HeapFree(GetProcessHeap(), 0, data);
1221 HeapFree(GetProcessHeap(), 0, valueW);
1225 load_fontconfig_fonts();
1227 /* then look in any directories that we've specified in the config file */
1228 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1229 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1235 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1237 len += sizeof(WCHAR);
1238 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1239 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1241 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1242 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1243 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1244 TRACE( "got font path %s\n", debugstr_a(valueA) );
1248 LPSTR next = strchr( ptr, ':' );
1249 if (next) *next++ = 0;
1250 ReadFontDir( ptr, TRUE );
1253 HeapFree( GetProcessHeap(), 0, valueA );
1255 HeapFree( GetProcessHeap(), 0, valueW );
1264 update_reg_entries();
1266 ReleaseMutex(font_mutex);
1270 "Wine cannot find certain functions that it needs inside the FreeType\n"
1271 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1272 "FreeType to at least version 2.0.5.\n"
1273 "http://www.freetype.org\n");
1274 wine_dlclose(ft_handle, NULL, 0);
1280 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1283 TT_HoriHeader *pHori;
1287 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1288 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1290 if(height == 0) height = 16;
1292 /* Calc. height of EM square:
1294 * For +ve lfHeight we have
1295 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1296 * Re-arranging gives:
1297 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1299 * For -ve lfHeight we have
1301 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1302 * with il = winAscent + winDescent - units_per_em]
1307 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1308 ppem = ft_face->units_per_EM * height /
1309 (pHori->Ascender - pHori->Descender);
1311 ppem = ft_face->units_per_EM * height /
1312 (pOS2->usWinAscent + pOS2->usWinDescent);
1320 static LONG load_VDMX(GdiFont, LONG);
1322 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1328 err = pFT_New_Face(library, file, face_index, &ft_face);
1330 ERR("FT_New_Face rets %d\n", err);
1334 /* set it here, as load_VDMX needs it */
1335 font->ft_face = ft_face;
1337 if(FT_IS_SCALABLE(ft_face)) {
1338 /* load the VDMX table if we have one */
1339 ppem = load_VDMX(font, height);
1341 ppem = calc_ppem_for_height(ft_face, height);
1343 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1344 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1346 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1347 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1353 static int get_nearest_charset(Face *face, int *cp)
1355 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1356 a single face with the requested charset. The idea is to check if
1357 the selected font supports the current ANSI codepage, if it does
1358 return the corresponding charset, else return the first charset */
1361 int acp = GetACP(), i;
1365 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1366 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1367 return csi.ciCharset;
1369 for(i = 0; i < 32; i++) {
1371 if(face->fs.fsCsb[0] & fs0) {
1372 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1374 return csi.ciCharset;
1377 FIXME("TCI failing on %lx\n", fs0);
1381 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1382 face->fs.fsCsb[0], face->file);
1384 return DEFAULT_CHARSET;
1387 static GdiFont alloc_font(void)
1389 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1390 ret->gmsize = INIT_GM_SIZE;
1391 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1392 ret->gmsize * sizeof(*ret->gm));
1394 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1395 list_init(&ret->hfontlist);
1399 static void free_font(GdiFont font)
1401 if (font->ft_face) pFT_Done_Face(font->ft_face);
1402 HeapFree(GetProcessHeap(), 0, font->potm);
1403 HeapFree(GetProcessHeap(), 0, font->name);
1404 HeapFree(GetProcessHeap(), 0, font->gm);
1405 HeapFree(GetProcessHeap(), 0, font);
1409 /*************************************************************
1412 * load the vdmx entry for the specified height
1415 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1416 ( ( (FT_ULong)_x4 << 24 ) | \
1417 ( (FT_ULong)_x3 << 16 ) | \
1418 ( (FT_ULong)_x2 << 8 ) | \
1421 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1431 static LONG load_VDMX(GdiFont font, LONG height)
1433 BYTE hdr[6], tmp[2], group[4];
1434 BYTE devXRatio, devYRatio;
1435 USHORT numRecs, numRatios;
1436 DWORD result, offset = -1;
1440 /* For documentation on VDMX records, see
1441 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1444 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1446 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1449 /* FIXME: need the real device aspect ratio */
1453 numRecs = GET_BE_WORD(&hdr[2]);
1454 numRatios = GET_BE_WORD(&hdr[4]);
1456 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1457 for(i = 0; i < numRatios; i++) {
1460 offset = (3 * 2) + (i * sizeof(Ratios));
1461 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1464 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1466 if((ratio.xRatio == 0 &&
1467 ratio.yStartRatio == 0 &&
1468 ratio.yEndRatio == 0) ||
1469 (devXRatio == ratio.xRatio &&
1470 devYRatio >= ratio.yStartRatio &&
1471 devYRatio <= ratio.yEndRatio))
1473 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1474 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1475 offset = GET_BE_WORD(tmp);
1481 FIXME("No suitable ratio found\n");
1485 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1487 BYTE startsz, endsz;
1490 recs = GET_BE_WORD(group);
1494 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1496 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1497 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1498 if(result == GDI_ERROR) {
1499 FIXME("Failed to retrieve vTable\n");
1504 for(i = 0; i < recs; i++) {
1505 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1506 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1507 ppem = GET_BE_WORD(&vTable[i * 6]);
1509 if(yMax + -yMin == height) {
1512 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1515 if(yMax + -yMin > height) {
1518 goto end; /* failed */
1520 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1521 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1522 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1528 TRACE("ppem not found for height %ld\n", height);
1532 if(ppem < startsz || ppem > endsz)
1535 for(i = 0; i < recs; i++) {
1537 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1539 if(yPelHeight > ppem)
1542 if(yPelHeight == ppem) {
1543 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1544 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1545 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1551 HeapFree(GetProcessHeap(), 0, vTable);
1557 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1559 if(font->font_desc.hash != fd->hash) return TRUE;
1560 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1561 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1562 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1565 static void calc_hash(FONT_DESC *pfd)
1567 DWORD hash = 0, *ptr, two_chars;
1571 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1573 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1575 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1577 pwc = (WCHAR *)&two_chars;
1579 *pwc = toupperW(*pwc);
1581 *pwc = toupperW(*pwc);
1589 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1594 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1596 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1597 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1600 /* try the in-use list */
1601 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1602 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1603 if(!fontcmp(ret, &fd)) {
1604 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1605 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1606 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1607 if(hflist->hfont == hfont)
1610 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1611 hflist->hfont = hfont;
1612 list_add_head(&ret->hfontlist, &hflist->entry);
1617 /* then the unused list */
1618 font_elem_ptr = list_head(&unused_gdi_font_list);
1619 while(font_elem_ptr) {
1620 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1621 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1622 if(!fontcmp(ret, &fd)) {
1623 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1624 assert(list_empty(&ret->hfontlist));
1625 TRACE("Found %p in unused list\n", ret);
1626 list_remove(&ret->entry);
1627 list_add_head(&gdi_font_list, &ret->entry);
1628 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1629 hflist->hfont = hfont;
1630 list_add_head(&ret->hfontlist, &hflist->entry);
1637 /*************************************************************
1638 * WineEngCreateFontInstance
1641 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1646 struct list *family_elem_ptr, *face_elem_ptr;
1647 INT height, width = 0;
1648 signed int diff = 0, newdiff;
1649 BOOL bd, it, can_use_bitmap;
1654 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1655 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1657 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1658 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1659 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1662 /* check the cache first */
1663 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1664 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1668 TRACE("not in cache\n");
1669 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1671 TRACE("No fonts installed\n");
1677 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1678 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1679 calc_hash(&ret->font_desc);
1680 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1681 hflist->hfont = hfont;
1682 list_add_head(&ret->hfontlist, &hflist->entry);
1685 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1686 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1687 original value lfCharSet. Note this is a special case for
1688 Symbol and doesn't happen at least for "Wingdings*" */
1690 if(!strcmpiW(lf.lfFaceName, SymbolW))
1691 lf.lfCharSet = SYMBOL_CHARSET;
1693 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1694 switch(lf.lfCharSet) {
1695 case DEFAULT_CHARSET:
1696 csi.fs.fsCsb[0] = 0;
1699 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1700 csi.fs.fsCsb[0] = 0;
1706 if(lf.lfFaceName[0] != '\0') {
1708 for(psub = substlist; psub; psub = psub->next)
1709 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1710 (psub->from.charset == -1 ||
1711 psub->from.charset == lf.lfCharSet))
1714 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1715 debugstr_w(psub->to.name));
1716 strcpyW(lf.lfFaceName, psub->to.name);
1719 /* We want a match on name and charset or just name if
1720 charset was DEFAULT_CHARSET. If the latter then
1721 we fixup the returned charset later in get_nearest_charset
1722 where we'll either use the charset of the current ansi codepage
1723 or if that's unavailable the first charset that the font supports.
1725 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1726 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1727 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1728 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1729 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1730 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1731 if(face->scalable || can_use_bitmap)
1738 /* If requested charset was DEFAULT_CHARSET then try using charset
1739 corresponding to the current ansi codepage */
1740 if(!csi.fs.fsCsb[0]) {
1742 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1743 FIXME("TCI failed on codepage %d\n", acp);
1744 csi.fs.fsCsb[0] = 0;
1746 lf.lfCharSet = csi.ciCharset;
1749 /* Face families are in the top 4 bits of lfPitchAndFamily,
1750 so mask with 0xF0 before testing */
1752 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1753 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1754 strcpyW(lf.lfFaceName, defFixed);
1755 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1756 strcpyW(lf.lfFaceName, defSerif);
1757 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1758 strcpyW(lf.lfFaceName, defSans);
1760 strcpyW(lf.lfFaceName, defSans);
1761 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1762 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1763 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1764 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1765 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1766 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1767 if(face->scalable || can_use_bitmap)
1773 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1774 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1775 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1776 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1777 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1778 if(face->scalable || can_use_bitmap)
1784 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1785 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1786 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1787 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1788 if(face->scalable || can_use_bitmap) {
1789 csi.fs.fsCsb[0] = 0;
1790 FIXME("just using first face for now\n");
1795 FIXME("can't find a single appropriate font - bailing\n");
1800 it = lf.lfItalic ? 1 : 0;
1801 bd = lf.lfWeight > 550 ? 1 : 0;
1803 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1804 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1807 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1808 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1809 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
1810 ((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])) {
1814 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1816 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1817 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1818 (diff < 0 && newdiff > diff)) {
1819 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1832 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1833 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1834 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0]) {
1838 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1840 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1841 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1842 (diff < 0 && newdiff > diff)) {
1843 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1854 if(it && !face->Italic) ret->fake_italic = TRUE;
1855 if(bd && !face->Bold) ret->fake_bold = TRUE;
1858 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1860 if(csi.fs.fsCsb[0]) {
1861 ret->charset = lf.lfCharSet;
1862 ret->codepage = csi.ciACP;
1865 ret->charset = get_nearest_charset(face, &ret->codepage);
1867 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
1868 debugstr_w(face->StyleName), face->file, face->face_index);
1870 if(!face->scalable) {
1871 width = face->size.x_ppem >> 6;
1872 height = face->size.y_ppem >> 6;
1874 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1882 if (ret->charset == SYMBOL_CHARSET &&
1883 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
1886 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
1890 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
1893 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1894 ret->name = strdupW(family->FamilyName);
1895 ret->underline = lf.lfUnderline ? 0xff : 0;
1896 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1898 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1900 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1901 list_add_head(&gdi_font_list, &ret->entry);
1905 static void dump_gdi_font_list(void)
1908 struct list *elem_ptr;
1910 TRACE("---------- gdiFont Cache ----------\n");
1911 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1912 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1913 TRACE("gdiFont=%p %s %ld\n",
1914 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1917 TRACE("---------- Unused gdiFont Cache ----------\n");
1918 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1919 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1920 TRACE("gdiFont=%p %s %ld\n",
1921 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1925 /*************************************************************
1926 * WineEngDestroyFontInstance
1928 * free the gdiFont associated with this handle
1931 BOOL WineEngDestroyFontInstance(HFONT handle)
1936 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1939 TRACE("destroying hfont=%p\n", handle);
1941 dump_gdi_font_list();
1943 font_elem_ptr = list_head(&gdi_font_list);
1944 while(font_elem_ptr) {
1945 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1946 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1948 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1949 while(hfontlist_elem_ptr) {
1950 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1951 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1952 if(hflist->hfont == handle) {
1953 list_remove(&hflist->entry);
1954 HeapFree(GetProcessHeap(), 0, hflist);
1958 if(list_empty(&gdiFont->hfontlist)) {
1959 TRACE("Moving to Unused list\n");
1960 list_remove(&gdiFont->entry);
1961 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1966 font_elem_ptr = list_head(&unused_gdi_font_list);
1967 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1968 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1969 while(font_elem_ptr) {
1970 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1971 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1972 TRACE("freeing %p\n", gdiFont);
1973 list_remove(&gdiFont->entry);
1979 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1980 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1982 OUTLINETEXTMETRICW *potm = NULL;
1984 TEXTMETRICW tm, *ptm;
1985 GdiFont font = alloc_font();
1988 if(face->scalable) {
1992 height = face->size.y_ppem >> 6;
1993 width = face->size.x_ppem >> 6;
1996 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2002 font->name = strdupW(face->family->FamilyName);
2004 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2006 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2008 potm = HeapAlloc(GetProcessHeap(), 0, size);
2009 WineEngGetOutlineTextMetrics(font, size, potm);
2010 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2012 WineEngGetTextMetrics(font, &tm);
2016 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2017 pntm->ntmTm.tmAscent = ptm->tmAscent;
2018 pntm->ntmTm.tmDescent = ptm->tmDescent;
2019 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2020 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2021 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2022 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2023 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2024 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2025 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2026 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2027 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2028 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2029 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2030 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2031 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2032 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2033 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2034 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2035 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2036 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2037 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2038 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2039 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2041 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2042 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2043 *ptype |= RASTER_FONTTYPE;
2045 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2046 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2047 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2049 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2050 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2051 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2054 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2056 lstrcpynW(pelf->elfLogFont.lfFaceName,
2057 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2059 lstrcpynW(pelf->elfFullName,
2060 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2062 lstrcpynW(pelf->elfStyle,
2063 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2066 HeapFree(GetProcessHeap(), 0, potm);
2068 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2070 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2071 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2072 pelf->elfStyle[0] = '\0';
2075 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2080 /*************************************************************
2084 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2088 struct list *family_elem_ptr, *face_elem_ptr;
2090 NEWTEXTMETRICEXW ntm;
2091 DWORD type, ret = 1;
2097 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2099 if(plf->lfFaceName[0]) {
2101 for(psub = substlist; psub; psub = psub->next)
2102 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2103 (psub->from.charset == -1 ||
2104 psub->from.charset == plf->lfCharSet))
2107 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2108 debugstr_w(psub->to.name));
2109 memcpy(&lf, plf, sizeof(lf));
2110 strcpyW(lf.lfFaceName, psub->to.name);
2114 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2115 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2116 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2117 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2118 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2119 GetEnumStructs(face, &elf, &ntm, &type);
2120 for(i = 0; i < 32; i++) {
2121 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2122 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2123 strcpyW(elf.elfScript, OEM_DOSW);
2124 i = 32; /* break out of loop */
2125 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2128 fs.fsCsb[0] = 1L << i;
2130 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2132 csi.ciCharset = DEFAULT_CHARSET;
2133 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2134 if(csi.ciCharset != DEFAULT_CHARSET) {
2135 elf.elfLogFont.lfCharSet =
2136 ntm.ntmTm.tmCharSet = csi.ciCharset;
2138 strcpyW(elf.elfScript, ElfScriptsW[i]);
2140 FIXME("Unknown elfscript for bit %d\n", i);
2143 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2144 debugstr_w(elf.elfLogFont.lfFaceName),
2145 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2146 csi.ciCharset, type, debugstr_w(elf.elfScript),
2147 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2148 ntm.ntmTm.ntmFlags);
2149 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2156 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2157 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2158 face_elem_ptr = list_head(&family->faces);
2159 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2160 GetEnumStructs(face, &elf, &ntm, &type);
2161 for(i = 0; i < 32; i++) {
2162 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2163 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2164 strcpyW(elf.elfScript, OEM_DOSW);
2165 i = 32; /* break out of loop */
2166 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2169 fs.fsCsb[0] = 1L << i;
2171 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2173 csi.ciCharset = DEFAULT_CHARSET;
2174 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2175 if(csi.ciCharset != DEFAULT_CHARSET) {
2176 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2179 strcpyW(elf.elfScript, ElfScriptsW[i]);
2181 FIXME("Unknown elfscript for bit %d\n", i);
2184 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2185 debugstr_w(elf.elfLogFont.lfFaceName),
2186 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2187 csi.ciCharset, type, debugstr_w(elf.elfScript),
2188 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2189 ntm.ntmTm.ntmFlags);
2190 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2199 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2201 pt->x.value = vec->x >> 6;
2202 pt->x.fract = (vec->x & 0x3f) << 10;
2203 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2204 pt->y.value = vec->y >> 6;
2205 pt->y.fract = (vec->y & 0x3f) << 10;
2206 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2210 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2212 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2213 WCHAR wc = (WCHAR)glyph;
2215 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2216 return pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2219 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2220 glyph = glyph + 0xf000;
2221 return pFT_Get_Char_Index(font->ft_face, glyph);
2224 /*************************************************************
2225 * WineEngGetGlyphIndices
2227 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2229 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2230 LPWORD pgi, DWORD flags)
2234 for(i = 0; i < count; i++)
2235 pgi[i] = get_glyph_index(font, lpstr[i]);
2240 /*************************************************************
2241 * WineEngGetGlyphOutline
2243 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2244 * except that the first parameter is the HWINEENGFONT of the font in
2245 * question rather than an HDC.
2248 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2249 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2252 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2253 FT_Face ft_face = font->ft_face;
2254 FT_UInt glyph_index;
2255 DWORD width, height, pitch, needed = 0;
2256 FT_Bitmap ft_bitmap;
2258 INT left, right, top = 0, bottom = 0;
2260 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2261 float widthRatio = 1.0;
2262 FT_Matrix transMat = identityMat;
2263 BOOL needsTransform = FALSE;
2266 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2267 buflen, buf, lpmat);
2269 if(format & GGO_GLYPH_INDEX) {
2270 glyph_index = glyph;
2271 format &= ~GGO_GLYPH_INDEX;
2273 glyph_index = get_glyph_index(font, glyph);
2275 if(glyph_index >= font->gmsize) {
2276 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2277 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2278 font->gmsize * sizeof(*font->gm));
2280 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2281 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2282 return 1; /* FIXME */
2286 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2287 load_flags |= FT_LOAD_NO_BITMAP;
2289 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2292 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2296 /* Scaling factor */
2297 if (font->aveWidth && font->potm) {
2298 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2301 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2302 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2304 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2305 font->gm[glyph_index].lsb = left >> 6;
2306 font->gm[glyph_index].bbx = (right - left) >> 6;
2308 /* Scaling transform */
2309 if(font->aveWidth) {
2311 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2314 scaleMat.yy = (1 << 16);
2316 pFT_Matrix_Multiply(&scaleMat, &transMat);
2317 needsTransform = TRUE;
2320 /* Rotation transform */
2321 if(font->orientation) {
2322 FT_Matrix rotationMat;
2324 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2325 pFT_Vector_Unit(&vecAngle, angle);
2326 rotationMat.xx = vecAngle.x;
2327 rotationMat.xy = -vecAngle.y;
2328 rotationMat.yx = -rotationMat.xy;
2329 rotationMat.yy = rotationMat.xx;
2331 pFT_Matrix_Multiply(&rotationMat, &transMat);
2332 needsTransform = TRUE;
2335 /* Extra transformation specified by caller */
2338 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2339 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2340 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2341 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2342 pFT_Matrix_Multiply(&extraMat, &transMat);
2343 needsTransform = TRUE;
2346 if(!needsTransform) {
2347 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2348 bottom = (ft_face->glyph->metrics.horiBearingY -
2349 ft_face->glyph->metrics.height) & -64;
2350 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2351 lpgm->gmCellIncY = 0;
2355 for(xc = 0; xc < 2; xc++) {
2356 for(yc = 0; yc < 2; yc++) {
2357 vec.x = (ft_face->glyph->metrics.horiBearingX +
2358 xc * ft_face->glyph->metrics.width);
2359 vec.y = ft_face->glyph->metrics.horiBearingY -
2360 yc * ft_face->glyph->metrics.height;
2361 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2362 pFT_Vector_Transform(&vec, &transMat);
2363 if(xc == 0 && yc == 0) {
2364 left = right = vec.x;
2365 top = bottom = vec.y;
2367 if(vec.x < left) left = vec.x;
2368 else if(vec.x > right) right = vec.x;
2369 if(vec.y < bottom) bottom = vec.y;
2370 else if(vec.y > top) top = vec.y;
2375 right = (right + 63) & -64;
2376 bottom = bottom & -64;
2377 top = (top + 63) & -64;
2379 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2380 vec.x = ft_face->glyph->metrics.horiAdvance;
2382 pFT_Vector_Transform(&vec, &transMat);
2383 lpgm->gmCellIncX = (vec.x+63) >> 6;
2384 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2386 lpgm->gmBlackBoxX = (right - left) >> 6;
2387 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2388 lpgm->gmptGlyphOrigin.x = left >> 6;
2389 lpgm->gmptGlyphOrigin.y = top >> 6;
2391 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2392 font->gm[glyph_index].init = TRUE;
2394 if(format == GGO_METRICS)
2395 return 1; /* FIXME */
2397 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2398 TRACE("loaded a bitmap\n");
2404 width = lpgm->gmBlackBoxX;
2405 height = lpgm->gmBlackBoxY;
2406 pitch = ((width + 31) >> 5) << 2;
2407 needed = pitch * height;
2409 if(!buf || !buflen) break;
2411 switch(ft_face->glyph->format) {
2412 case ft_glyph_format_bitmap:
2414 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2415 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2416 INT h = ft_face->glyph->bitmap.rows;
2418 memcpy(dst, src, w);
2419 src += ft_face->glyph->bitmap.pitch;
2425 case ft_glyph_format_outline:
2426 ft_bitmap.width = width;
2427 ft_bitmap.rows = height;
2428 ft_bitmap.pitch = pitch;
2429 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2430 ft_bitmap.buffer = buf;
2432 if(needsTransform) {
2433 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2436 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2438 /* Note: FreeType will only set 'black' bits for us. */
2439 memset(buf, 0, needed);
2440 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2444 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2449 case GGO_GRAY2_BITMAP:
2450 case GGO_GRAY4_BITMAP:
2451 case GGO_GRAY8_BITMAP:
2452 case WINE_GGO_GRAY16_BITMAP:
2454 unsigned int mult, row, col;
2457 width = lpgm->gmBlackBoxX;
2458 height = lpgm->gmBlackBoxY;
2459 pitch = (width + 3) / 4 * 4;
2460 needed = pitch * height;
2462 if(!buf || !buflen) break;
2463 ft_bitmap.width = width;
2464 ft_bitmap.rows = height;
2465 ft_bitmap.pitch = pitch;
2466 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2467 ft_bitmap.buffer = buf;
2469 if(needsTransform) {
2470 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2473 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2475 memset(ft_bitmap.buffer, 0, buflen);
2477 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2479 if(format == GGO_GRAY2_BITMAP)
2481 else if(format == GGO_GRAY4_BITMAP)
2483 else if(format == GGO_GRAY8_BITMAP)
2485 else if(format == WINE_GGO_GRAY16_BITMAP)
2493 for(row = 0; row < height; row++) {
2495 for(col = 0; col < width; col++, ptr++) {
2496 *ptr = (((int)*ptr) * mult + 128) / 256;
2505 int contour, point = 0, first_pt;
2506 FT_Outline *outline = &ft_face->glyph->outline;
2507 TTPOLYGONHEADER *pph;
2509 DWORD pph_start, cpfx, type;
2511 if(buflen == 0) buf = NULL;
2513 if (needsTransform && buf) {
2514 pFT_Outline_Transform(outline, &transMat);
2517 for(contour = 0; contour < outline->n_contours; contour++) {
2519 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2522 pph->dwType = TT_POLYGON_TYPE;
2523 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2525 needed += sizeof(*pph);
2527 while(point <= outline->contours[contour]) {
2528 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2529 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2530 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2534 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2537 } while(point <= outline->contours[contour] &&
2538 (outline->tags[point] & FT_Curve_Tag_On) ==
2539 (outline->tags[point-1] & FT_Curve_Tag_On));
2540 /* At the end of a contour Windows adds the start point, but
2542 if(point > outline->contours[contour] &&
2543 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2545 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2547 } else if(point <= outline->contours[contour] &&
2548 outline->tags[point] & FT_Curve_Tag_On) {
2549 /* add closing pt for bezier */
2551 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2559 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2562 pph->cb = needed - pph_start;
2568 /* Convert the quadratic Beziers to cubic Beziers.
2569 The parametric eqn for a cubic Bezier is, from PLRM:
2570 r(t) = at^3 + bt^2 + ct + r0
2571 with the control points:
2576 A quadratic Beizer has the form:
2577 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2579 So equating powers of t leads to:
2580 r1 = 2/3 p1 + 1/3 p0
2581 r2 = 2/3 p1 + 1/3 p2
2582 and of course r0 = p0, r3 = p2
2585 int contour, point = 0, first_pt;
2586 FT_Outline *outline = &ft_face->glyph->outline;
2587 TTPOLYGONHEADER *pph;
2589 DWORD pph_start, cpfx, type;
2590 FT_Vector cubic_control[4];
2591 if(buflen == 0) buf = NULL;
2593 if (needsTransform && buf) {
2594 pFT_Outline_Transform(outline, &transMat);
2597 for(contour = 0; contour < outline->n_contours; contour++) {
2599 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2602 pph->dwType = TT_POLYGON_TYPE;
2603 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2605 needed += sizeof(*pph);
2607 while(point <= outline->contours[contour]) {
2608 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2609 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2610 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2613 if(type == TT_PRIM_LINE) {
2615 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2619 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2622 /* FIXME: Possible optimization in endpoint calculation
2623 if there are two consecutive curves */
2624 cubic_control[0] = outline->points[point-1];
2625 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2626 cubic_control[0].x += outline->points[point].x + 1;
2627 cubic_control[0].y += outline->points[point].y + 1;
2628 cubic_control[0].x >>= 1;
2629 cubic_control[0].y >>= 1;
2631 if(point+1 > outline->contours[contour])
2632 cubic_control[3] = outline->points[first_pt];
2634 cubic_control[3] = outline->points[point+1];
2635 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2636 cubic_control[3].x += outline->points[point].x + 1;
2637 cubic_control[3].y += outline->points[point].y + 1;
2638 cubic_control[3].x >>= 1;
2639 cubic_control[3].y >>= 1;
2642 /* r1 = 1/3 p0 + 2/3 p1
2643 r2 = 1/3 p2 + 2/3 p1 */
2644 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2645 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2646 cubic_control[2] = cubic_control[1];
2647 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2648 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2649 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2650 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2652 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2653 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2654 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2659 } while(point <= outline->contours[contour] &&
2660 (outline->tags[point] & FT_Curve_Tag_On) ==
2661 (outline->tags[point-1] & FT_Curve_Tag_On));
2662 /* At the end of a contour Windows adds the start point,
2663 but only for Beziers and we've already done that.
2665 if(point <= outline->contours[contour] &&
2666 outline->tags[point] & FT_Curve_Tag_On) {
2667 /* This is the closing pt of a bezier, but we've already
2668 added it, so just inc point and carry on */
2675 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2678 pph->cb = needed - pph_start;
2684 FIXME("Unsupported format %d\n", format);
2690 static BOOL get_bitmap_text_metrics(GdiFont font)
2692 FT_Face ft_face = font->ft_face;
2693 #ifdef HAVE_FREETYPE_FTWINFNT_H
2694 FT_WinFNT_HeaderRec winfnt_header;
2696 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2697 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2698 font->potm->otmSize = size;
2700 #define TM font->potm->otmTextMetrics
2701 #ifdef HAVE_FREETYPE_FTWINFNT_H
2702 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2704 TM.tmHeight = winfnt_header.pixel_height;
2705 TM.tmAscent = winfnt_header.ascent;
2706 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2707 TM.tmInternalLeading = winfnt_header.internal_leading;
2708 TM.tmExternalLeading = winfnt_header.external_leading;
2709 TM.tmAveCharWidth = winfnt_header.avg_width;
2710 TM.tmMaxCharWidth = winfnt_header.max_width;
2711 TM.tmWeight = winfnt_header.weight;
2713 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2714 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2715 TM.tmFirstChar = winfnt_header.first_char;
2716 TM.tmLastChar = winfnt_header.last_char;
2717 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2718 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2719 TM.tmItalic = winfnt_header.italic;
2720 TM.tmUnderlined = font->underline;
2721 TM.tmStruckOut = font->strikeout;
2722 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2723 TM.tmCharSet = winfnt_header.charset;
2728 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2729 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2730 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2731 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2732 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2733 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2734 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2735 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2737 TM.tmDigitizedAspectX = 96; /* FIXME */
2738 TM.tmDigitizedAspectY = 96; /* FIXME */
2740 TM.tmLastChar = 255;
2741 TM.tmDefaultChar = 32;
2742 TM.tmBreakChar = 32;
2743 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2744 TM.tmUnderlined = font->underline;
2745 TM.tmStruckOut = font->strikeout;
2746 /* NB inverted meaning of TMPF_FIXED_PITCH */
2747 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2748 TM.tmCharSet = font->charset;
2755 /*************************************************************
2756 * WineEngGetTextMetrics
2759 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2762 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2763 if(!get_bitmap_text_metrics(font))
2766 if(!font->potm) return FALSE;
2767 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2769 if (font->aveWidth) {
2770 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2776 /*************************************************************
2777 * WineEngGetOutlineTextMetrics
2780 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2781 OUTLINETEXTMETRICW *potm)
2783 FT_Face ft_face = font->ft_face;
2784 UINT needed, lenfam, lensty, ret;
2786 TT_HoriHeader *pHori;
2787 TT_Postscript *pPost;
2788 FT_Fixed x_scale, y_scale;
2789 WCHAR *family_nameW, *style_nameW;
2790 static const WCHAR spaceW[] = {' ', '\0'};
2792 INT ascent, descent;
2794 TRACE("font=%p\n", font);
2796 if(!FT_IS_SCALABLE(ft_face))
2800 if(cbSize >= font->potm->otmSize)
2801 memcpy(potm, font->potm, font->potm->otmSize);
2802 return font->potm->otmSize;
2806 needed = sizeof(*potm);
2808 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2809 family_nameW = strdupW(font->name);
2811 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2813 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2814 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2815 style_nameW, lensty);
2817 /* These names should be read from the TT name table */
2819 /* length of otmpFamilyName */
2822 /* length of otmpFaceName */
2823 if(!strcasecmp(ft_face->style_name, "regular")) {
2824 needed += lenfam; /* just the family name */
2826 needed += lenfam + lensty; /* family + " " + style */
2829 /* length of otmpStyleName */
2832 /* length of otmpFullName */
2833 needed += lenfam + lensty;
2836 x_scale = ft_face->size->metrics.x_scale;
2837 y_scale = ft_face->size->metrics.y_scale;
2839 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2841 FIXME("Can't find OS/2 table - not TT font?\n");
2846 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2848 FIXME("Can't find HHEA table - not TT font?\n");
2853 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2855 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",
2856 pOS2->usWinAscent, pOS2->usWinDescent,
2857 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2858 ft_face->ascender, ft_face->descender, ft_face->height,
2859 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2860 ft_face->bbox.yMax, ft_face->bbox.yMin);
2862 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2863 font->potm->otmSize = needed;
2865 #define TM font->potm->otmTextMetrics
2867 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2868 ascent = pHori->Ascender;
2869 descent = -pHori->Descender;
2871 ascent = pOS2->usWinAscent;
2872 descent = pOS2->usWinDescent;
2876 TM.tmAscent = font->yMax;
2877 TM.tmDescent = -font->yMin;
2878 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2880 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2881 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2882 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2883 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2886 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2889 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2891 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2892 ((ascent + descent) -
2893 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2895 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2896 if (TM.tmAveCharWidth == 0) {
2897 TM.tmAveCharWidth = 1;
2899 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2900 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2902 TM.tmDigitizedAspectX = 300;
2903 TM.tmDigitizedAspectY = 300;
2904 TM.tmFirstChar = pOS2->usFirstCharIndex;
2905 TM.tmLastChar = pOS2->usLastCharIndex;
2906 TM.tmDefaultChar = pOS2->usDefaultChar;
2907 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2908 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2909 TM.tmUnderlined = font->underline;
2910 TM.tmStruckOut = font->strikeout;
2912 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2913 if(!FT_IS_FIXED_WIDTH(ft_face) &&
2914 (pOS2->version == 0xFFFFU ||
2915 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
2916 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2918 TM.tmPitchAndFamily = 0;
2920 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2921 case PAN_FAMILY_SCRIPT:
2922 TM.tmPitchAndFamily |= FF_SCRIPT;
2924 case PAN_FAMILY_DECORATIVE:
2925 case PAN_FAMILY_PICTORIAL:
2926 TM.tmPitchAndFamily |= FF_DECORATIVE;
2928 case PAN_FAMILY_TEXT_DISPLAY:
2929 if(TM.tmPitchAndFamily == 0) /* fixed */
2930 TM.tmPitchAndFamily = FF_MODERN;
2932 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2933 case PAN_SERIF_NORMAL_SANS:
2934 case PAN_SERIF_OBTUSE_SANS:
2935 case PAN_SERIF_PERP_SANS:
2936 TM.tmPitchAndFamily |= FF_SWISS;
2939 TM.tmPitchAndFamily |= FF_ROMAN;
2944 TM.tmPitchAndFamily |= FF_DONTCARE;
2947 if(FT_IS_SCALABLE(ft_face))
2948 TM.tmPitchAndFamily |= TMPF_VECTOR;
2949 if(FT_IS_SFNT(ft_face))
2950 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2952 TM.tmCharSet = font->charset;
2955 font->potm->otmFiller = 0;
2956 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2957 font->potm->otmfsSelection = pOS2->fsSelection;
2958 font->potm->otmfsType = pOS2->fsType;
2959 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2960 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2961 font->potm->otmItalicAngle = 0; /* POST table */
2962 font->potm->otmEMSquare = ft_face->units_per_EM;
2963 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2964 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2965 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2966 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2967 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2968 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2969 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2970 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2971 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2972 font->potm->otmMacAscent = 0; /* where do these come from ? */
2973 font->potm->otmMacDescent = 0;
2974 font->potm->otmMacLineGap = 0;
2975 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2976 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2977 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2978 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2979 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2980 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2981 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2982 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2983 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2984 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2985 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2987 font->potm->otmsUnderscoreSize = 0;
2988 font->potm->otmsUnderscorePosition = 0;
2990 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2991 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2994 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2995 cp = (char*)font->potm + sizeof(*font->potm);
2996 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2997 strcpyW((WCHAR*)cp, family_nameW);
2999 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3000 strcpyW((WCHAR*)cp, style_nameW);
3002 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3003 strcpyW((WCHAR*)cp, family_nameW);
3004 if(strcasecmp(ft_face->style_name, "regular")) {
3005 strcatW((WCHAR*)cp, spaceW);
3006 strcatW((WCHAR*)cp, style_nameW);
3007 cp += lenfam + lensty;
3010 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3011 strcpyW((WCHAR*)cp, family_nameW);
3012 strcatW((WCHAR*)cp, spaceW);
3013 strcatW((WCHAR*)cp, style_nameW);
3016 if(potm && needed <= cbSize)
3017 memcpy(potm, font->potm, font->potm->otmSize);
3020 HeapFree(GetProcessHeap(), 0, style_nameW);
3021 HeapFree(GetProcessHeap(), 0, family_nameW);
3027 /*************************************************************
3028 * WineEngGetCharWidth
3031 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3036 FT_UInt glyph_index;
3038 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3040 for(c = firstChar; c <= lastChar; c++) {
3041 glyph_index = get_glyph_index(font, c);
3042 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3043 &gm, 0, NULL, NULL);
3044 buffer[c - firstChar] = font->gm[glyph_index].adv;
3049 /*************************************************************
3050 * WineEngGetCharABCWidths
3053 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3058 FT_UInt glyph_index;
3060 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3062 if(!FT_IS_SCALABLE(font->ft_face))
3065 for(c = firstChar; c <= lastChar; c++) {
3066 glyph_index = get_glyph_index(font, c);
3067 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3068 &gm, 0, NULL, NULL);
3069 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3070 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3071 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3072 font->gm[glyph_index].bbx;
3077 /*************************************************************
3078 * WineEngGetTextExtentPoint
3081 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3087 FT_UInt glyph_index;
3089 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3093 WineEngGetTextMetrics(font, &tm);
3094 size->cy = tm.tmHeight;
3096 for(idx = 0; idx < count; idx++) {
3097 glyph_index = get_glyph_index(font, wstr[idx]);
3098 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3099 &gm, 0, NULL, NULL);
3100 size->cx += font->gm[glyph_index].adv;
3102 TRACE("return %ld,%ld\n", size->cx, size->cy);
3106 /*************************************************************
3107 * WineEngGetTextExtentPointI
3110 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3117 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3120 WineEngGetTextMetrics(font, &tm);
3121 size->cy = tm.tmHeight;
3123 for(idx = 0; idx < count; idx++) {
3124 WineEngGetGlyphOutline(font, indices[idx],
3125 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3127 size->cx += font->gm[indices[idx]].adv;
3129 TRACE("return %ld,%ld\n", size->cx, size->cy);
3133 /*************************************************************
3134 * WineEngGetFontData
3137 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3140 FT_Face ft_face = font->ft_face;
3144 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3145 font, table, offset, buf, cbData);
3147 if(!FT_IS_SFNT(ft_face))
3155 if(table) { /* MS tags differ in endidness from FT ones */
3156 table = table >> 24 | table << 24 |
3157 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3160 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3161 if(pFT_Load_Sfnt_Table)
3162 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3163 else { /* Do it the hard way */
3164 TT_Face tt_face = (TT_Face) ft_face;
3165 SFNT_Interface *sfnt;
3166 if (FT_Version.major==2 && FT_Version.minor==0)
3169 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3173 /* A field was added in the middle of the structure in 2.1.x */
3174 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3176 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3179 TRACE("Can't find table %08lx.\n", table);
3185 /*************************************************************
3186 * WineEngGetTextFace
3189 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3192 lstrcpynW(str, font->name, count);
3193 return strlenW(font->name);
3195 return strlenW(font->name) + 1;
3198 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3200 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3201 return font->charset;
3204 #else /* HAVE_FREETYPE */
3206 BOOL WineEngInit(void)
3210 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3214 BOOL WineEngDestroyFontInstance(HFONT hfont)
3219 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3224 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3225 LPWORD pgi, DWORD flags)
3230 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3231 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3234 ERR("called but we don't have FreeType\n");
3238 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3240 ERR("called but we don't have FreeType\n");
3244 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3245 OUTLINETEXTMETRICW *potm)
3247 ERR("called but we don't have FreeType\n");
3251 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3254 ERR("called but we don't have FreeType\n");
3258 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3261 ERR("called but we don't have FreeType\n");
3265 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3268 ERR("called but we don't have FreeType\n");
3272 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3275 ERR("called but we don't have FreeType\n");
3279 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3282 ERR("called but we don't have FreeType\n");
3286 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3288 ERR("called but we don't have FreeType\n");
3292 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3298 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3304 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3307 return DEFAULT_CHARSET;
3310 #endif /* HAVE_FREETYPE */