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>
85 #ifdef HAVE_FREETYPE_FTMODAPI_H
86 #include <freetype/ftmodapi.h>
89 #ifndef SONAME_LIBFREETYPE
90 #define SONAME_LIBFREETYPE "libfreetype.so"
93 #ifndef HAVE_FT_TRUETYPEENGINETYPE
96 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
97 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
98 FT_TRUETYPE_ENGINE_TYPE_PATENTED
99 } FT_TrueTypeEngineType;
102 static FT_Library library = 0;
109 static FT_Version_t FT_Version;
110 static DWORD FT_SimpleVersion;
112 static void *ft_handle = NULL;
114 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
115 MAKE_FUNCPTR(FT_Vector_Unit);
116 MAKE_FUNCPTR(FT_Done_Face);
117 MAKE_FUNCPTR(FT_Get_Char_Index);
118 MAKE_FUNCPTR(FT_Get_Module);
119 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
120 MAKE_FUNCPTR(FT_Init_FreeType);
121 MAKE_FUNCPTR(FT_Load_Glyph);
122 MAKE_FUNCPTR(FT_Matrix_Multiply);
123 MAKE_FUNCPTR(FT_MulFix);
124 MAKE_FUNCPTR(FT_New_Face);
125 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
126 MAKE_FUNCPTR(FT_Outline_Transform);
127 MAKE_FUNCPTR(FT_Outline_Translate);
128 MAKE_FUNCPTR(FT_Select_Charmap);
129 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
130 MAKE_FUNCPTR(FT_Vector_Transform);
131 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
132 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
133 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
134 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
135 #ifdef HAVE_FREETYPE_FTWINFNT_H
136 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
139 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
140 #include <fontconfig/fontconfig.h>
141 MAKE_FUNCPTR(FcConfigGetCurrent);
142 MAKE_FUNCPTR(FcFontList);
143 MAKE_FUNCPTR(FcFontSetDestroy);
144 MAKE_FUNCPTR(FcInit);
145 MAKE_FUNCPTR(FcObjectSetAdd);
146 MAKE_FUNCPTR(FcObjectSetCreate);
147 MAKE_FUNCPTR(FcObjectSetDestroy);
148 MAKE_FUNCPTR(FcPatternCreate);
149 MAKE_FUNCPTR(FcPatternDestroy);
150 MAKE_FUNCPTR(FcPatternGet);
151 #ifndef SONAME_LIBFONTCONFIG
152 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
158 #ifndef ft_encoding_none
159 #define FT_ENCODING_NONE ft_encoding_none
161 #ifndef ft_encoding_ms_symbol
162 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
164 #ifndef ft_encoding_unicode
165 #define FT_ENCODING_UNICODE ft_encoding_unicode
167 #ifndef ft_encoding_apple_roman
168 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
171 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
173 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
180 FT_Short internal_leading;
183 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
184 So to let this compile on older versions of FreeType we'll define the
185 new structure here. */
187 FT_Short height, width;
188 FT_Pos size, x_ppem, y_ppem;
191 typedef struct tagFace {
199 FONTSIGNATURE fs_links;
200 FT_Fixed font_version;
202 Bitmap_Size size; /* set if face is a bitmap */
203 BOOL external; /* TRUE if we should manually add this font to the registry */
204 struct tagFamily *family;
207 typedef struct tagFamily {
215 INT adv; /* These three hold to widths of the unrotated chars */
232 typedef struct tagHFONTLIST {
257 struct list hfontlist;
262 OUTLINETEXTMETRICW *potm;
265 struct list child_fonts;
275 #define INIT_GM_SIZE 128
277 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
278 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
279 #define UNUSED_CACHE_SIZE 10
280 static struct list child_font_list = LIST_INIT(child_font_list);
281 static struct list system_links = LIST_INIT(system_links);
283 static struct list font_list = LIST_INIT(font_list);
285 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
286 'R','o','m','a','n','\0'};
287 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
288 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
290 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
291 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
292 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
293 'S','e','r','i','f','\0'};
294 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
295 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
297 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
298 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
299 'W','i','n','d','o','w','s','\\',
300 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
301 'F','o','n','t','s','\0'};
303 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
304 'W','i','n','d','o','w','s',' ','N','T','\\',
305 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
306 'F','o','n','t','s','\0'};
308 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
309 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
310 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
311 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
313 static const WCHAR *SystemFontValues[4] = {
320 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
321 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
323 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
324 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
325 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
326 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
327 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
328 'E','u','r','o','p','e','a','n','\0'};
329 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
330 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
331 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
332 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
333 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
334 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
335 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
336 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
337 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
338 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
339 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
340 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
342 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
352 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
360 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
369 typedef struct tagFontSubst {
372 struct tagFontSubst *next;
375 static FontSubst *substlist = NULL;
376 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
378 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
381 /****************************************
382 * Notes on .fon files
384 * The fonts System, FixedSys and Terminal are special. There are typically multiple
385 * versions installed for different resolutions and codepages. Windows stores which one to use
386 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
388 * FIXEDFON.FON FixedSys
390 * OEMFONT.FON Terminal
391 * LogPixels Current dpi set by the display control panel applet
392 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
393 * also has a LogPixels value that appears to mirror this)
395 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
396 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
397 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
398 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
399 * so that makes sense.
401 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
402 * to be mapped into the registry on Windows 2000 at least).
405 * ega80woa.fon=ega80850.fon
406 * ega40woa.fon=ega40850.fon
407 * cga80woa.fon=cga80850.fon
408 * cga40woa.fon=cga40850.fon
412 static inline BOOL is_win9x(void)
414 return GetVersion() & 0x80000000;
417 This function builds an FT_Fixed from a float. It puts the integer part
418 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
419 It fails if the integer part of the float number is greater than SHORT_MAX.
421 static inline FT_Fixed FT_FixedFromFloat(float f)
424 unsigned short fract = (f - value) * 0xFFFF;
425 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
429 This function builds an FT_Fixed from a FIXED. It simply put f.value
430 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
432 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
434 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
437 #define ADDFONT_EXTERNAL_FONT 0x01
438 #define ADDFONT_FORCE_BITMAP 0x02
439 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
443 TT_Header *pHeader = NULL;
444 WCHAR *FamilyW, *StyleW;
448 struct list *family_elem_ptr, *face_elem_ptr;
450 FT_Long face_index = 0, num_faces;
451 #ifdef HAVE_FREETYPE_FTWINFNT_H
452 FT_WinFNT_HeaderRec winfnt_header;
454 int i, bitmap_num, internal_leading;
458 char *family_name = fake_family;
460 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
461 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
462 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
466 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*/
467 WARN("Ignoring font %s\n", debugstr_a(file));
468 pFT_Done_Face(ft_face);
472 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
473 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
474 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
475 pFT_Done_Face(ft_face);
479 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
480 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
481 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
482 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
483 "Skipping this font.\n", debugstr_a(file));
484 pFT_Done_Face(ft_face);
488 if(!ft_face->family_name || !ft_face->style_name) {
489 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
490 pFT_Done_Face(ft_face);
495 family_name = ft_face->family_name;
499 My_FT_Bitmap_Size *size = NULL;
501 if(!FT_IS_SCALABLE(ft_face))
502 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
504 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
505 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
506 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
509 LIST_FOR_EACH(family_elem_ptr, &font_list) {
510 family = LIST_ENTRY(family_elem_ptr, Family, entry);
511 if(!strcmpW(family->FamilyName, FamilyW))
516 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
517 family->FamilyName = FamilyW;
518 list_init(&family->faces);
519 list_add_tail(&font_list, &family->entry);
521 HeapFree(GetProcessHeap(), 0, FamilyW);
524 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
525 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
526 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
528 internal_leading = 0;
529 memset(&fs, 0, sizeof(fs));
531 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
533 fs.fsCsb[0] = pOS2->ulCodePageRange1;
534 fs.fsCsb[1] = pOS2->ulCodePageRange2;
535 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
536 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
537 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
538 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
539 if(pOS2->version == 0) {
542 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
545 fs.fsCsb[0] |= 1L << 31;
548 #ifdef HAVE_FREETYPE_FTWINFNT_H
549 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
551 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
552 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
553 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
554 memcpy(&fs, &csi.fs, sizeof(csi.fs));
555 internal_leading = winfnt_header.internal_leading;
559 face_elem_ptr = list_head(&family->faces);
560 while(face_elem_ptr) {
561 face = LIST_ENTRY(face_elem_ptr, Face, entry);
562 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
563 if(!strcmpW(face->StyleName, StyleW) &&
564 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
565 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
566 debugstr_w(family->FamilyName), debugstr_w(StyleW),
567 face->font_version, pHeader ? pHeader->Font_Revision : 0);
570 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
571 HeapFree(GetProcessHeap(), 0, StyleW);
572 pFT_Done_Face(ft_face);
575 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
576 TRACE("Original font is newer so skipping this one\n");
577 HeapFree(GetProcessHeap(), 0, StyleW);
578 pFT_Done_Face(ft_face);
581 TRACE("Replacing original with this one\n");
582 list_remove(&face->entry);
583 HeapFree(GetProcessHeap(), 0, face->file);
584 HeapFree(GetProcessHeap(), 0, face->StyleName);
585 HeapFree(GetProcessHeap(), 0, face);
590 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
591 list_add_tail(&family->faces, &face->entry);
592 face->StyleName = StyleW;
593 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
594 strcpy(face->file, file);
595 face->face_index = face_index;
596 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
597 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
598 face->font_version = pHeader ? pHeader->Font_Revision : 0;
599 face->family = family;
600 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
601 memcpy(&face->fs, &fs, sizeof(face->fs));
602 memset(&face->fs_links, 0, sizeof(face->fs_links));
604 if(FT_IS_SCALABLE(ft_face)) {
605 memset(&face->size, 0, sizeof(face->size));
606 face->scalable = TRUE;
608 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
609 size->height, size->width, size->size >> 6,
610 size->x_ppem >> 6, size->y_ppem >> 6);
611 face->size.height = size->height;
612 face->size.width = size->width;
613 face->size.size = size->size;
614 face->size.x_ppem = size->x_ppem;
615 face->size.y_ppem = size->y_ppem;
616 face->size.internal_leading = internal_leading;
617 face->scalable = FALSE;
620 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
621 face->fs.fsCsb[0], face->fs.fsCsb[1],
622 face->fs.fsUsb[0], face->fs.fsUsb[1],
623 face->fs.fsUsb[2], face->fs.fsUsb[3]);
626 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
627 for(i = 0; i < ft_face->num_charmaps; i++) {
628 switch(ft_face->charmaps[i]->encoding) {
629 case FT_ENCODING_UNICODE:
630 case FT_ENCODING_APPLE_ROMAN:
631 face->fs.fsCsb[0] |= 1;
633 case FT_ENCODING_MS_SYMBOL:
634 face->fs.fsCsb[0] |= 1L << 31;
642 if(face->fs.fsCsb[0] & ~(1L << 31))
643 have_installed_roman_font = TRUE;
644 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
646 num_faces = ft_face->num_faces;
647 pFT_Done_Face(ft_face);
648 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
650 } while(num_faces > ++face_index);
654 static void DumpFontList(void)
658 struct list *family_elem_ptr, *face_elem_ptr;
660 LIST_FOR_EACH(family_elem_ptr, &font_list) {
661 family = LIST_ENTRY(family_elem_ptr, Family, entry);
662 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
663 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
664 face = LIST_ENTRY(face_elem_ptr, Face, entry);
665 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
667 TRACE(" %ld", face->size.y_ppem >> 6);
674 static Face *find_face_from_filename(const WCHAR *name)
679 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
680 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
683 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
684 TRACE("looking for %s\n", debugstr_a(nameA));
686 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
688 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
690 file = strrchr(face->file, '/');
695 if(!strcmp(file, nameA))
700 HeapFree(GetProcessHeap(), 0, nameA);
704 static Family *find_family_from_name(const WCHAR *name)
708 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
710 if(!strcmpiW(family->FamilyName, name))
717 static void DumpSubstList(void)
721 for(psub = substlist; psub; psub = psub->next)
722 if(psub->from.charset != -1 || psub->to.charset != -1)
723 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
724 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
726 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
727 debugstr_w(psub->to.name));
731 static LPWSTR strdupW(LPCWSTR p)
734 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
735 ret = HeapAlloc(GetProcessHeap(), 0, len);
740 static LPSTR strdupA(LPCSTR p)
743 DWORD len = (strlen(p) + 1);
744 ret = HeapAlloc(GetProcessHeap(), 0, len);
749 static void split_subst_info(NameCs *nc, LPSTR str)
751 CHAR *p = strrchr(str, ',');
756 nc->charset = strtol(p+1, NULL, 10);
759 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
760 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
761 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
764 static void LoadSubstList(void)
766 FontSubst *psub, **ppsub;
768 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
773 for(psub = substlist; psub;) {
775 HeapFree(GetProcessHeap(), 0, psub->to.name);
776 HeapFree(GetProcessHeap(), 0, psub->from.name);
779 HeapFree(GetProcessHeap(), 0, ptmp);
784 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
785 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
786 &hkey) == ERROR_SUCCESS) {
788 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
789 &valuelen, &datalen, NULL, NULL);
791 valuelen++; /* returned value doesn't include room for '\0' */
792 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
793 data = HeapAlloc(GetProcessHeap(), 0, datalen);
798 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
799 &dlen) == ERROR_SUCCESS) {
800 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
802 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
803 (*ppsub)->next = NULL;
804 split_subst_info(&((*ppsub)->from), value);
805 split_subst_info(&((*ppsub)->to), data);
807 /* Win 2000 doesn't allow mapping between different charsets
808 or mapping of DEFAULT_CHARSET */
809 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
810 (*ppsub)->to.charset == DEFAULT_CHARSET) {
811 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
812 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
813 HeapFree(GetProcessHeap(), 0, *ppsub);
816 ppsub = &((*ppsub)->next);
818 /* reset dlen and vlen */
822 HeapFree(GetProcessHeap(), 0, data);
823 HeapFree(GetProcessHeap(), 0, value);
828 /***********************************************************
829 * The replacement list is a way to map an entire font
830 * family onto another family. For example adding
832 * [HKCU\Software\Wine\Fonts\Replacements]
833 * "Wingdings"="Winedings"
835 * would enumerate the Winedings font both as Winedings and
836 * Wingdings. However if a real Wingdings font is present the
837 * replacement does not take place.
840 static void LoadReplaceList(void)
843 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
848 struct list *family_elem_ptr, *face_elem_ptr;
849 WCHAR old_nameW[200];
851 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
852 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
854 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
855 &valuelen, &datalen, NULL, NULL);
857 valuelen++; /* returned value doesn't include room for '\0' */
858 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
859 data = HeapAlloc(GetProcessHeap(), 0, datalen);
863 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
864 &dlen) == ERROR_SUCCESS) {
865 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
866 /* "NewName"="Oldname" */
867 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
870 /* Find the old family and hence all of the font files
872 LIST_FOR_EACH(family_elem_ptr, &font_list) {
873 family = LIST_ENTRY(family_elem_ptr, Family, entry);
874 if(!strcmpiW(family->FamilyName, old_nameW)) {
875 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
876 face = LIST_ENTRY(face_elem_ptr, Face, entry);
877 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
878 debugstr_w(face->StyleName), value);
879 /* Now add a new entry with the new family name */
880 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
885 /* reset dlen and vlen */
889 HeapFree(GetProcessHeap(), 0, data);
890 HeapFree(GetProcessHeap(), 0, value);
895 /*************************************************************
898 static BOOL init_system_links(void)
900 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
901 'W','i','n','d','o','w','s',' ','N','T','\\',
902 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
903 'S','y','s','t','e','m','L','i','n','k',0};
906 DWORD type, max_val, max_data, val_len, data_len, index;
909 SYSTEM_LINKS *font_link, *system_font_link;
910 CHILD_FONT *child_font;
911 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
912 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
913 static const WCHAR System[] = {'S','y','s','t','e','m',0};
918 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
920 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
921 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
922 data = HeapAlloc(GetProcessHeap(), 0, max_data);
923 val_len = max_val + 1;
926 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
928 TRACE("%s:\n", debugstr_w(value));
930 memset(&fs, 0, sizeof(fs));
931 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
932 font_link->font_name = strdupW(value);
933 list_init(&font_link->links);
934 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
938 CHILD_FONT *child_font;
940 TRACE("\t%s\n", debugstr_w(entry));
942 next = entry + strlenW(entry) + 1;
944 face_name = strchrW(entry, ',');
949 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
951 while(isspaceW(*face_name))
956 face = find_face_from_filename(entry);
959 TRACE("Unable to find file %s\n", debugstr_w(entry));
963 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
964 child_font->file_name = strdupA(face->file);
965 child_font->index = index;
966 child_font->font = NULL;
967 fs.fsCsb[0] |= face->fs.fsCsb[0];
968 fs.fsCsb[1] |= face->fs.fsCsb[1];
969 list_add_tail(&font_link->links, &child_font->entry);
971 family = find_family_from_name(font_link->font_name);
974 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
976 memcpy(&face->fs_links, &fs, sizeof(fs));
979 list_add_tail(&system_links, &font_link->entry);
980 val_len = max_val + 1;
984 HeapFree(GetProcessHeap(), 0, value);
985 HeapFree(GetProcessHeap(), 0, data);
989 /* Explicitly add an entry for the system font, this links to Tahoma and any links
992 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
993 system_font_link->font_name = strdupW(System);
994 list_init(&system_font_link->links);
996 face = find_face_from_filename(tahoma_ttf);
999 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1000 child_font->file_name = strdupA(face->file);
1001 child_font->index = 0;
1002 child_font->font = NULL;
1003 list_add_tail(&system_font_link->links, &child_font->entry);
1005 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1007 if(!strcmpiW(font_link->font_name, Tahoma))
1009 CHILD_FONT *font_link_entry;
1010 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1012 CHILD_FONT *new_child;
1013 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1014 new_child->file_name = strdupA(font_link_entry->file_name);
1015 new_child->index = font_link_entry->index;
1016 new_child->font = NULL;
1017 list_add_tail(&system_font_link->links, &new_child->entry);
1022 list_add_tail(&system_links, &system_font_link->entry);
1026 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1029 struct dirent *dent;
1030 char path[MAX_PATH];
1032 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1034 dir = opendir(dirname);
1036 ERR("Can't open directory %s\n", debugstr_a(dirname));
1039 while((dent = readdir(dir)) != NULL) {
1040 struct stat statbuf;
1042 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1045 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1047 sprintf(path, "%s/%s", dirname, dent->d_name);
1049 if(stat(path, &statbuf) == -1)
1051 WARN("Can't stat %s\n", debugstr_a(path));
1054 if(S_ISDIR(statbuf.st_mode))
1055 ReadFontDir(path, external_fonts);
1057 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1063 static void load_fontconfig_fonts(void)
1065 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1066 void *fc_handle = NULL;
1073 const char *file, *ext;
1075 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1077 TRACE("Wine cannot find the fontconfig library (%s).\n",
1078 SONAME_LIBFONTCONFIG);
1081 #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;}
1082 LOAD_FUNCPTR(FcConfigGetCurrent);
1083 LOAD_FUNCPTR(FcFontList);
1084 LOAD_FUNCPTR(FcFontSetDestroy);
1085 LOAD_FUNCPTR(FcInit);
1086 LOAD_FUNCPTR(FcObjectSetAdd);
1087 LOAD_FUNCPTR(FcObjectSetCreate);
1088 LOAD_FUNCPTR(FcObjectSetDestroy);
1089 LOAD_FUNCPTR(FcPatternCreate);
1090 LOAD_FUNCPTR(FcPatternDestroy);
1091 LOAD_FUNCPTR(FcPatternGet);
1094 if(!pFcInit()) return;
1096 config = pFcConfigGetCurrent();
1097 pat = pFcPatternCreate();
1098 os = pFcObjectSetCreate();
1099 pFcObjectSetAdd(os, FC_FILE);
1100 fontset = pFcFontList(config, pat, os);
1101 if(!fontset) return;
1102 for(i = 0; i < fontset->nfont; i++) {
1103 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1105 if(v.type != FcTypeString) continue;
1106 file = (LPCSTR) v.u.s;
1107 TRACE("fontconfig: %s\n", file);
1109 /* We're just interested in OT/TT fonts for now, so this hack just
1110 picks up the standard extensions to save time loading every other
1112 len = strlen( file );
1113 if(len < 4) continue;
1114 ext = &file[ len - 3 ];
1115 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1116 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1118 pFcFontSetDestroy(fontset);
1119 pFcObjectSetDestroy(os);
1120 pFcPatternDestroy(pat);
1126 static BOOL load_font_from_data_dir(LPCWSTR file)
1129 const char *data_dir = wine_get_data_dir();
1131 if (!data_dir) data_dir = wine_get_build_dir();
1138 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1140 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1142 strcpy(unix_name, data_dir);
1143 strcat(unix_name, "/fonts/");
1145 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1147 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1148 HeapFree(GetProcessHeap(), 0, unix_name);
1153 static void load_system_fonts(void)
1156 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1157 const WCHAR **value;
1159 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1162 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1163 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1164 strcatW(windowsdir, fontsW);
1165 for(value = SystemFontValues; *value; value++) {
1166 dlen = sizeof(data);
1167 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1171 sprintfW(pathW, fmtW, windowsdir, data);
1172 if((unixname = wine_get_unix_file_name(pathW))) {
1173 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1174 HeapFree(GetProcessHeap(), 0, unixname);
1177 load_font_from_data_dir(data);
1184 /*************************************************************
1186 * This adds registry entries for any externally loaded fonts
1187 * (fonts from fontconfig or FontDirs). It also deletes entries
1188 * of no longer existing fonts.
1191 static void update_reg_entries(void)
1193 HKEY winkey = 0, externalkey = 0;
1196 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1199 struct list *family_elem_ptr, *face_elem_ptr;
1201 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1202 static const WCHAR spaceW[] = {' ', '\0'};
1205 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1206 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1207 ERR("Can't create Windows font reg key\n");
1210 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1211 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1212 ERR("Can't create external font reg key\n");
1216 /* Delete all external fonts added last time */
1218 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1219 &valuelen, &datalen, NULL, NULL);
1220 valuelen++; /* returned value doesn't include room for '\0' */
1221 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1222 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1224 dlen = datalen * sizeof(WCHAR);
1227 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1228 &dlen) == ERROR_SUCCESS) {
1230 RegDeleteValueW(winkey, valueW);
1231 /* reset dlen and vlen */
1235 HeapFree(GetProcessHeap(), 0, data);
1236 HeapFree(GetProcessHeap(), 0, valueW);
1238 /* Delete the old external fonts key */
1239 RegCloseKey(externalkey);
1241 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1243 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1244 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1245 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1246 ERR("Can't create external font reg key\n");
1250 /* enumerate the fonts and add external ones to the two keys */
1252 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1253 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1254 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1255 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1256 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1257 if(!face->external) continue;
1259 if(strcmpiW(face->StyleName, RegularW))
1260 len = len_fam + strlenW(face->StyleName) + 1;
1261 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1262 strcpyW(valueW, family->FamilyName);
1263 if(len != len_fam) {
1264 strcatW(valueW, spaceW);
1265 strcatW(valueW, face->StyleName);
1267 strcatW(valueW, TrueType);
1268 if((path = strrchr(face->file, '/')) == NULL)
1272 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1274 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1275 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1276 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1277 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1279 HeapFree(GetProcessHeap(), 0, file);
1280 HeapFree(GetProcessHeap(), 0, valueW);
1285 RegCloseKey(externalkey);
1287 RegCloseKey(winkey);
1292 /*************************************************************
1293 * WineEngAddFontResourceEx
1296 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1298 if (ft_handle) /* do it only if we have freetype up and running */
1303 FIXME("Ignoring flags %lx\n", flags);
1305 if((unixname = wine_get_unix_file_name(file)))
1307 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1308 HeapFree(GetProcessHeap(), 0, unixname);
1314 /*************************************************************
1315 * WineEngRemoveFontResourceEx
1318 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1324 static const struct nls_update_font_list
1326 UINT ansi_cp, oem_cp;
1327 const char *oem, *fixed, *system;
1328 const char *courier, *serif, *small, *sserif;
1329 } nls_update_font_list[] =
1331 /* Latin 1 (United States) */
1332 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1335 /* Latin 1 (Multilingual) */
1336 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1337 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1339 /* Eastern Europe */
1340 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1341 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1344 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1345 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1348 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1349 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1352 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1353 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1356 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1357 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1360 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1361 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1364 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1365 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1368 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1369 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1372 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1373 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1376 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1377 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1379 /* Chinese Simplified */
1380 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1381 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1384 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1385 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1387 /* Chinese Traditional */
1388 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1389 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1393 inline static HKEY create_fonts_NT_registry_key(void)
1397 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1398 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1402 inline static HKEY create_fonts_9x_registry_key(void)
1406 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1407 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1411 inline static HKEY create_config_fonts_registry_key(void)
1415 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1416 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1420 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1422 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1423 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1424 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1425 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1428 static void update_font_info(void)
1433 UINT i, ansi_cp = 0, oem_cp = 0;
1434 LCID lcid = GetUserDefaultLCID();
1436 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1440 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1442 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1447 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1449 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1451 sprintf(buf, "%08lx", lcid);
1452 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1455 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1456 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1457 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1458 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1460 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1462 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1463 nls_update_font_list[i].oem_cp == oem_cp)
1467 hkey = create_config_fonts_registry_key();
1468 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1469 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1470 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1473 hkey = create_fonts_NT_registry_key();
1474 add_font_list(hkey, &nls_update_font_list[i]);
1477 hkey = create_fonts_9x_registry_key();
1478 add_font_list(hkey, &nls_update_font_list[i]);
1484 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1487 /*************************************************************
1490 * Initialize FreeType library and create a list of available faces
1492 BOOL WineEngInit(void)
1494 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1495 static const WCHAR pathW[] = {'P','a','t','h',0};
1497 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1499 WCHAR windowsdir[MAX_PATH];
1502 const char *data_dir;
1506 /* update locale dependent font info in registry */
1509 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1512 "Wine cannot find the FreeType font library. To enable Wine to\n"
1513 "use TrueType fonts please install a version of FreeType greater than\n"
1514 "or equal to 2.0.5.\n"
1515 "http://www.freetype.org\n");
1519 #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;}
1521 LOAD_FUNCPTR(FT_Vector_Unit)
1522 LOAD_FUNCPTR(FT_Done_Face)
1523 LOAD_FUNCPTR(FT_Get_Char_Index)
1524 LOAD_FUNCPTR(FT_Get_Module)
1525 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1526 LOAD_FUNCPTR(FT_Init_FreeType)
1527 LOAD_FUNCPTR(FT_Load_Glyph)
1528 LOAD_FUNCPTR(FT_Matrix_Multiply)
1529 LOAD_FUNCPTR(FT_MulFix)
1530 LOAD_FUNCPTR(FT_New_Face)
1531 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1532 LOAD_FUNCPTR(FT_Outline_Transform)
1533 LOAD_FUNCPTR(FT_Outline_Translate)
1534 LOAD_FUNCPTR(FT_Select_Charmap)
1535 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1536 LOAD_FUNCPTR(FT_Vector_Transform)
1539 /* Don't warn if this one is missing */
1540 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1541 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1542 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1543 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1544 #ifdef HAVE_FREETYPE_FTWINFNT_H
1545 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1547 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1548 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1549 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1550 <= 2.0.3 has FT_Sqrt64 */
1554 if(pFT_Init_FreeType(&library) != 0) {
1555 ERR("Can't init FreeType library\n");
1556 wine_dlclose(ft_handle, NULL, 0);
1560 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1561 if (pFT_Library_Version)
1563 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1565 if (FT_Version.major<=0)
1571 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1572 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1573 ((FT_Version.minor << 8) & 0x00ff00) |
1574 ((FT_Version.patch ) & 0x0000ff);
1576 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1577 ERR("Failed to create font mutex\n");
1580 WaitForSingleObject(font_mutex, INFINITE);
1582 /* load the system bitmap fonts */
1583 load_system_fonts();
1585 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1586 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1587 strcatW(windowsdir, fontsW);
1588 if((unixname = wine_get_unix_file_name(windowsdir)))
1590 ReadFontDir(unixname, FALSE);
1591 HeapFree(GetProcessHeap(), 0, unixname);
1594 /* load the system truetype fonts */
1595 data_dir = wine_get_data_dir();
1596 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1597 strcpy(unixname, data_dir);
1598 strcat(unixname, "/fonts/");
1599 ReadFontDir(unixname, FALSE);
1600 HeapFree(GetProcessHeap(), 0, unixname);
1603 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1604 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1605 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1607 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1608 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1609 &hkey) == ERROR_SUCCESS) {
1611 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1612 &valuelen, &datalen, NULL, NULL);
1614 valuelen++; /* returned value doesn't include room for '\0' */
1615 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1616 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1619 dlen = datalen * sizeof(WCHAR);
1621 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1622 &dlen) == ERROR_SUCCESS) {
1623 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1625 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1627 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1628 HeapFree(GetProcessHeap(), 0, unixname);
1631 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1633 WCHAR pathW[MAX_PATH];
1634 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1637 sprintfW(pathW, fmtW, windowsdir, data);
1638 if((unixname = wine_get_unix_file_name(pathW)))
1640 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1641 HeapFree(GetProcessHeap(), 0, unixname);
1644 load_font_from_data_dir(data);
1646 /* reset dlen and vlen */
1651 HeapFree(GetProcessHeap(), 0, data);
1652 HeapFree(GetProcessHeap(), 0, valueW);
1656 load_fontconfig_fonts();
1658 /* then look in any directories that we've specified in the config file */
1659 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1660 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1666 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1668 len += sizeof(WCHAR);
1669 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1670 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1672 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1673 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1674 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1675 TRACE( "got font path %s\n", debugstr_a(valueA) );
1679 LPSTR next = strchr( ptr, ':' );
1680 if (next) *next++ = 0;
1681 ReadFontDir( ptr, TRUE );
1684 HeapFree( GetProcessHeap(), 0, valueA );
1686 HeapFree( GetProcessHeap(), 0, valueW );
1695 update_reg_entries();
1697 init_system_links();
1699 ReleaseMutex(font_mutex);
1703 "Wine cannot find certain functions that it needs inside the FreeType\n"
1704 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1705 "FreeType to at least version 2.0.5.\n"
1706 "http://www.freetype.org\n");
1707 wine_dlclose(ft_handle, NULL, 0);
1713 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1716 TT_HoriHeader *pHori;
1720 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1721 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1723 if(height == 0) height = 16;
1725 /* Calc. height of EM square:
1727 * For +ve lfHeight we have
1728 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1729 * Re-arranging gives:
1730 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1732 * For -ve lfHeight we have
1734 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1735 * with il = winAscent + winDescent - units_per_em]
1740 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1741 ppem = ft_face->units_per_EM * height /
1742 (pHori->Ascender - pHori->Descender);
1744 ppem = ft_face->units_per_EM * height /
1745 (pOS2->usWinAscent + pOS2->usWinDescent);
1753 static LONG load_VDMX(GdiFont, LONG);
1755 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1760 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1761 err = pFT_New_Face(library, file, face_index, &ft_face);
1763 ERR("FT_New_Face rets %d\n", err);
1767 /* set it here, as load_VDMX needs it */
1768 font->ft_face = ft_face;
1770 if(FT_IS_SCALABLE(ft_face)) {
1771 /* load the VDMX table if we have one */
1772 font->ppem = load_VDMX(font, height);
1774 font->ppem = calc_ppem_for_height(ft_face, height);
1776 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1777 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1779 font->ppem = height;
1780 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1781 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1787 static int get_nearest_charset(Face *face, int *cp)
1789 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1790 a single face with the requested charset. The idea is to check if
1791 the selected font supports the current ANSI codepage, if it does
1792 return the corresponding charset, else return the first charset */
1795 int acp = GetACP(), i;
1799 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1800 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1801 return csi.ciCharset;
1803 for(i = 0; i < 32; i++) {
1805 if(face->fs.fsCsb[0] & fs0) {
1806 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1808 return csi.ciCharset;
1811 FIXME("TCI failing on %lx\n", fs0);
1815 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1816 face->fs.fsCsb[0], face->file);
1818 return DEFAULT_CHARSET;
1821 static GdiFont alloc_font(void)
1823 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1824 ret->gmsize = INIT_GM_SIZE;
1825 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1826 ret->gmsize * sizeof(*ret->gm));
1828 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1829 list_init(&ret->hfontlist);
1830 list_init(&ret->child_fonts);
1834 static void free_font(GdiFont font)
1836 struct list *cursor, *cursor2;
1838 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1840 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1841 struct list *first_hfont;
1842 HFONTLIST *hfontlist;
1843 list_remove(cursor);
1846 first_hfont = list_head(&child->font->hfontlist);
1847 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1848 DeleteObject(hfontlist->hfont);
1849 HeapFree(GetProcessHeap(), 0, hfontlist);
1850 free_font(child->font);
1852 HeapFree(GetProcessHeap(), 0, child->file_name);
1853 HeapFree(GetProcessHeap(), 0, child);
1856 if (font->ft_face) pFT_Done_Face(font->ft_face);
1857 HeapFree(GetProcessHeap(), 0, font->potm);
1858 HeapFree(GetProcessHeap(), 0, font->name);
1859 HeapFree(GetProcessHeap(), 0, font->gm);
1860 HeapFree(GetProcessHeap(), 0, font);
1864 /*************************************************************
1867 * load the vdmx entry for the specified height
1870 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1871 ( ( (FT_ULong)_x4 << 24 ) | \
1872 ( (FT_ULong)_x3 << 16 ) | \
1873 ( (FT_ULong)_x2 << 8 ) | \
1876 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1886 static LONG load_VDMX(GdiFont font, LONG height)
1888 BYTE hdr[6], tmp[2], group[4];
1889 BYTE devXRatio, devYRatio;
1890 USHORT numRecs, numRatios;
1891 DWORD result, offset = -1;
1895 /* For documentation on VDMX records, see
1896 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1899 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1901 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1904 /* FIXME: need the real device aspect ratio */
1908 numRecs = GET_BE_WORD(&hdr[2]);
1909 numRatios = GET_BE_WORD(&hdr[4]);
1911 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1912 for(i = 0; i < numRatios; i++) {
1915 offset = (3 * 2) + (i * sizeof(Ratios));
1916 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1919 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1921 if((ratio.xRatio == 0 &&
1922 ratio.yStartRatio == 0 &&
1923 ratio.yEndRatio == 0) ||
1924 (devXRatio == ratio.xRatio &&
1925 devYRatio >= ratio.yStartRatio &&
1926 devYRatio <= ratio.yEndRatio))
1928 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1929 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1930 offset = GET_BE_WORD(tmp);
1936 FIXME("No suitable ratio found\n");
1940 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1942 BYTE startsz, endsz;
1945 recs = GET_BE_WORD(group);
1949 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1951 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1952 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1953 if(result == GDI_ERROR) {
1954 FIXME("Failed to retrieve vTable\n");
1959 for(i = 0; i < recs; i++) {
1960 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1961 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1962 ppem = GET_BE_WORD(&vTable[i * 6]);
1964 if(yMax + -yMin == height) {
1967 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1970 if(yMax + -yMin > height) {
1973 goto end; /* failed */
1975 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1976 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1977 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1983 TRACE("ppem not found for height %ld\n", height);
1987 if(ppem < startsz || ppem > endsz)
1990 for(i = 0; i < recs; i++) {
1992 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1994 if(yPelHeight > ppem)
1997 if(yPelHeight == ppem) {
1998 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1999 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
2000 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2006 HeapFree(GetProcessHeap(), 0, vTable);
2012 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
2014 if(font->font_desc.hash != fd->hash) return TRUE;
2015 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2016 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2017 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2020 static void calc_hash(FONT_DESC *pfd)
2022 DWORD hash = 0, *ptr, two_chars;
2026 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2028 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2030 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2032 pwc = (WCHAR *)&two_chars;
2034 *pwc = toupperW(*pwc);
2036 *pwc = toupperW(*pwc);
2044 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2049 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2051 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2052 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2055 /* try the in-use list */
2056 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2057 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2058 if(!fontcmp(ret, &fd)) {
2059 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2060 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2061 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2062 if(hflist->hfont == hfont)
2065 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2066 hflist->hfont = hfont;
2067 list_add_head(&ret->hfontlist, &hflist->entry);
2072 /* then the unused list */
2073 font_elem_ptr = list_head(&unused_gdi_font_list);
2074 while(font_elem_ptr) {
2075 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2076 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2077 if(!fontcmp(ret, &fd)) {
2078 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2079 assert(list_empty(&ret->hfontlist));
2080 TRACE("Found %p in unused list\n", ret);
2081 list_remove(&ret->entry);
2082 list_add_head(&gdi_font_list, &ret->entry);
2083 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2084 hflist->hfont = hfont;
2085 list_add_head(&ret->hfontlist, &hflist->entry);
2093 /*************************************************************
2094 * create_child_font_list
2096 static BOOL create_child_font_list(GdiFont font)
2099 SYSTEM_LINKS *font_link;
2100 CHILD_FONT *font_link_entry, *new_child;
2102 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2104 if(!strcmpW(font_link->font_name, font->name))
2106 TRACE("found entry in system list\n");
2107 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2109 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2110 new_child->file_name = strdupA(font_link_entry->file_name);
2111 new_child->index = font_link_entry->index;
2112 new_child->font = NULL;
2113 list_add_tail(&font->child_fonts, &new_child->entry);
2114 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2124 /*************************************************************
2125 * WineEngCreateFontInstance
2128 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2132 Family *family, *last_resort_family;
2133 struct list *family_elem_ptr, *face_elem_ptr;
2134 INT height, width = 0;
2135 signed int diff = 0, newdiff;
2136 BOOL bd, it, can_use_bitmap;
2141 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2143 struct list *first_hfont = list_head(&ret->hfontlist);
2144 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2145 if(hflist->hfont == hfont)
2149 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2150 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2152 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2153 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2154 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2157 /* check the cache first */
2158 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2159 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2163 TRACE("not in cache\n");
2164 if(list_empty(&font_list)) /* No fonts installed */
2166 TRACE("No fonts installed\n");
2169 if(!have_installed_roman_font)
2171 TRACE("No roman font installed\n");
2177 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2178 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2179 calc_hash(&ret->font_desc);
2180 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2181 hflist->hfont = hfont;
2182 list_add_head(&ret->hfontlist, &hflist->entry);
2185 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2186 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2187 original value lfCharSet. Note this is a special case for
2188 Symbol and doesn't happen at least for "Wingdings*" */
2190 if(!strcmpiW(lf.lfFaceName, SymbolW))
2191 lf.lfCharSet = SYMBOL_CHARSET;
2193 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2194 switch(lf.lfCharSet) {
2195 case DEFAULT_CHARSET:
2196 csi.fs.fsCsb[0] = 0;
2199 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2200 csi.fs.fsCsb[0] = 0;
2206 if(lf.lfFaceName[0] != '\0') {
2208 for(psub = substlist; psub; psub = psub->next)
2209 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
2210 (psub->from.charset == -1 ||
2211 psub->from.charset == lf.lfCharSet))
2214 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2215 debugstr_w(psub->to.name));
2216 strcpyW(lf.lfFaceName, psub->to.name);
2219 /* We want a match on name and charset or just name if
2220 charset was DEFAULT_CHARSET. If the latter then
2221 we fixup the returned charset later in get_nearest_charset
2222 where we'll either use the charset of the current ansi codepage
2223 or if that's unavailable the first charset that the font supports.
2225 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2226 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2227 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2228 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2229 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2230 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2231 if(face->scalable || can_use_bitmap)
2238 /* If requested charset was DEFAULT_CHARSET then try using charset
2239 corresponding to the current ansi codepage */
2240 if(!csi.fs.fsCsb[0]) {
2242 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2243 FIXME("TCI failed on codepage %d\n", acp);
2244 csi.fs.fsCsb[0] = 0;
2246 lf.lfCharSet = csi.ciCharset;
2249 /* Face families are in the top 4 bits of lfPitchAndFamily,
2250 so mask with 0xF0 before testing */
2252 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2253 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2254 strcpyW(lf.lfFaceName, defFixed);
2255 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2256 strcpyW(lf.lfFaceName, defSerif);
2257 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2258 strcpyW(lf.lfFaceName, defSans);
2260 strcpyW(lf.lfFaceName, defSans);
2261 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2262 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2263 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2264 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2265 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2266 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2267 if(face->scalable || can_use_bitmap)
2273 last_resort_family = NULL;
2274 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2275 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2276 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2277 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2278 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2281 if(can_use_bitmap && !last_resort_family)
2282 last_resort_family = family;
2287 if(last_resort_family) {
2288 family = last_resort_family;
2289 csi.fs.fsCsb[0] = 0;
2293 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2294 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2295 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2296 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2297 if(face->scalable) {
2298 csi.fs.fsCsb[0] = 0;
2299 FIXME("just using first face for now\n");
2302 if(can_use_bitmap && !last_resort_family)
2303 last_resort_family = family;
2306 if(!last_resort_family) {
2307 FIXME("can't find a single appropriate font - bailing\n");
2312 WARN("could only find a bitmap font - this will probably look awful!\n");
2313 family = last_resort_family;
2314 csi.fs.fsCsb[0] = 0;
2317 it = lf.lfItalic ? 1 : 0;
2318 bd = lf.lfWeight > 550 ? 1 : 0;
2320 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2321 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2324 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2325 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2326 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2327 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2331 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2333 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2334 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2335 (diff < 0 && newdiff > diff)) {
2336 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2349 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2350 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2351 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2355 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2357 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2358 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2359 (diff < 0 && newdiff > diff)) {
2360 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2371 if(it && !face->Italic) ret->fake_italic = TRUE;
2372 if(bd && !face->Bold) ret->fake_bold = TRUE;
2375 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2377 if(csi.fs.fsCsb[0]) {
2378 ret->charset = lf.lfCharSet;
2379 ret->codepage = csi.ciACP;
2382 ret->charset = get_nearest_charset(face, &ret->codepage);
2384 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2385 debugstr_w(face->StyleName), face->file, face->face_index);
2387 if(!face->scalable) {
2388 width = face->size.x_ppem >> 6;
2389 height = face->size.y_ppem >> 6;
2391 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2399 if (ret->charset == SYMBOL_CHARSET &&
2400 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2403 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2407 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2410 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2411 ret->name = strdupW(family->FamilyName);
2412 ret->underline = lf.lfUnderline ? 0xff : 0;
2413 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2414 create_child_font_list(ret);
2416 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2418 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2419 list_add_head(&gdi_font_list, &ret->entry);
2423 static void dump_gdi_font_list(void)
2426 struct list *elem_ptr;
2428 TRACE("---------- gdiFont Cache ----------\n");
2429 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2430 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2431 TRACE("gdiFont=%p %s %ld\n",
2432 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2435 TRACE("---------- Unused gdiFont Cache ----------\n");
2436 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2437 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2438 TRACE("gdiFont=%p %s %ld\n",
2439 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2443 /*************************************************************
2444 * WineEngDestroyFontInstance
2446 * free the gdiFont associated with this handle
2449 BOOL WineEngDestroyFontInstance(HFONT handle)
2454 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2457 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2459 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2460 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2461 if(hflist->hfont == handle)
2463 TRACE("removing child font %p from child list\n", gdiFont);
2464 list_remove(&gdiFont->entry);
2469 TRACE("destroying hfont=%p\n", handle);
2471 dump_gdi_font_list();
2473 font_elem_ptr = list_head(&gdi_font_list);
2474 while(font_elem_ptr) {
2475 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2476 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2478 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2479 while(hfontlist_elem_ptr) {
2480 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2481 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2482 if(hflist->hfont == handle) {
2483 list_remove(&hflist->entry);
2484 HeapFree(GetProcessHeap(), 0, hflist);
2488 if(list_empty(&gdiFont->hfontlist)) {
2489 TRACE("Moving to Unused list\n");
2490 list_remove(&gdiFont->entry);
2491 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2496 font_elem_ptr = list_head(&unused_gdi_font_list);
2497 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2498 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2499 while(font_elem_ptr) {
2500 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2501 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2502 TRACE("freeing %p\n", gdiFont);
2503 list_remove(&gdiFont->entry);
2509 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2510 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2512 OUTLINETEXTMETRICW *potm = NULL;
2514 TEXTMETRICW tm, *ptm;
2515 GdiFont font = alloc_font();
2518 if(face->scalable) {
2522 height = face->size.y_ppem >> 6;
2523 width = face->size.x_ppem >> 6;
2526 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2532 font->name = strdupW(face->family->FamilyName);
2534 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2536 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2538 potm = HeapAlloc(GetProcessHeap(), 0, size);
2539 WineEngGetOutlineTextMetrics(font, size, potm);
2540 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2542 WineEngGetTextMetrics(font, &tm);
2546 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2547 pntm->ntmTm.tmAscent = ptm->tmAscent;
2548 pntm->ntmTm.tmDescent = ptm->tmDescent;
2549 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2550 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2551 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2552 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2553 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2554 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2555 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2556 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2557 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2558 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2559 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2560 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2561 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2562 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2563 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2564 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2565 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2566 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2567 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2568 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2569 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2571 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2572 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2573 *ptype |= RASTER_FONTTYPE;
2575 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2576 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2577 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2579 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2580 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2581 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2584 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2586 lstrcpynW(pelf->elfLogFont.lfFaceName,
2587 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2589 lstrcpynW(pelf->elfFullName,
2590 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2592 lstrcpynW(pelf->elfStyle,
2593 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2596 HeapFree(GetProcessHeap(), 0, potm);
2598 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2600 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2601 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2602 pelf->elfStyle[0] = '\0';
2605 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2610 /*************************************************************
2614 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2618 struct list *family_elem_ptr, *face_elem_ptr;
2620 NEWTEXTMETRICEXW ntm;
2621 DWORD type, ret = 1;
2627 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2629 if(plf->lfFaceName[0]) {
2631 for(psub = substlist; psub; psub = psub->next)
2632 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2633 (psub->from.charset == -1 ||
2634 psub->from.charset == plf->lfCharSet))
2637 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2638 debugstr_w(psub->to.name));
2639 memcpy(&lf, plf, sizeof(lf));
2640 strcpyW(lf.lfFaceName, psub->to.name);
2644 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2645 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2646 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2647 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2648 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2649 GetEnumStructs(face, &elf, &ntm, &type);
2650 for(i = 0; i < 32; i++) {
2651 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2652 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2653 strcpyW(elf.elfScript, OEM_DOSW);
2654 i = 32; /* break out of loop */
2655 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2658 fs.fsCsb[0] = 1L << i;
2660 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2662 csi.ciCharset = DEFAULT_CHARSET;
2663 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2664 if(csi.ciCharset != DEFAULT_CHARSET) {
2665 elf.elfLogFont.lfCharSet =
2666 ntm.ntmTm.tmCharSet = csi.ciCharset;
2668 strcpyW(elf.elfScript, ElfScriptsW[i]);
2670 FIXME("Unknown elfscript for bit %d\n", i);
2673 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2674 debugstr_w(elf.elfLogFont.lfFaceName),
2675 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2676 csi.ciCharset, type, debugstr_w(elf.elfScript),
2677 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2678 ntm.ntmTm.ntmFlags);
2679 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2686 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2687 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2688 face_elem_ptr = list_head(&family->faces);
2689 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2690 GetEnumStructs(face, &elf, &ntm, &type);
2691 for(i = 0; i < 32; i++) {
2692 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2693 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2694 strcpyW(elf.elfScript, OEM_DOSW);
2695 i = 32; /* break out of loop */
2696 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2699 fs.fsCsb[0] = 1L << i;
2701 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2703 csi.ciCharset = DEFAULT_CHARSET;
2704 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2705 if(csi.ciCharset != DEFAULT_CHARSET) {
2706 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2709 strcpyW(elf.elfScript, ElfScriptsW[i]);
2711 FIXME("Unknown elfscript for bit %d\n", i);
2714 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2715 debugstr_w(elf.elfLogFont.lfFaceName),
2716 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2717 csi.ciCharset, type, debugstr_w(elf.elfScript),
2718 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2719 ntm.ntmTm.ntmFlags);
2720 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2729 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2731 pt->x.value = vec->x >> 6;
2732 pt->x.fract = (vec->x & 0x3f) << 10;
2733 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2734 pt->y.value = vec->y >> 6;
2735 pt->y.fract = (vec->y & 0x3f) << 10;
2736 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2740 /***************************************************
2741 * According to the MSDN documentation on WideCharToMultiByte,
2742 * certain codepages cannot set the default_used parameter.
2743 * This returns TRUE if the codepage can set that parameter, false else
2744 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2746 static BOOL codepage_sets_default_used(UINT codepage)
2759 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2761 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2762 WCHAR wc = (WCHAR)glyph;
2764 BOOL *default_used_pointer;
2767 default_used_pointer = NULL;
2768 default_used = FALSE;
2769 if (codepage_sets_default_used(font->codepage))
2770 default_used_pointer = &default_used;
2771 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2774 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2775 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2779 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2780 glyph = glyph + 0xf000;
2781 return pFT_Get_Char_Index(font->ft_face, glyph);
2784 /*************************************************************
2785 * WineEngGetGlyphIndices
2787 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2789 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2790 LPWORD pgi, DWORD flags)
2794 for(i = 0; i < count; i++)
2795 pgi[i] = get_glyph_index(font, lpstr[i]);
2800 /*************************************************************
2801 * WineEngGetGlyphOutline
2803 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2804 * except that the first parameter is the HWINEENGFONT of the font in
2805 * question rather than an HDC.
2808 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2809 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2812 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2813 FT_Face ft_face = font->ft_face;
2814 FT_UInt glyph_index;
2815 DWORD width, height, pitch, needed = 0;
2816 FT_Bitmap ft_bitmap;
2818 INT left, right, top = 0, bottom = 0;
2820 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2821 float widthRatio = 1.0;
2822 FT_Matrix transMat = identityMat;
2823 BOOL needsTransform = FALSE;
2826 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2827 buflen, buf, lpmat);
2829 if(format & GGO_GLYPH_INDEX) {
2830 glyph_index = glyph;
2831 format &= ~GGO_GLYPH_INDEX;
2833 glyph_index = get_glyph_index(font, glyph);
2835 if(glyph_index >= font->gmsize) {
2836 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2837 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2838 font->gmsize * sizeof(*font->gm));
2840 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2841 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2842 return 1; /* FIXME */
2846 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2847 load_flags |= FT_LOAD_NO_BITMAP;
2849 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2852 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2856 /* Scaling factor */
2857 if (font->aveWidth && font->potm) {
2858 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2861 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2862 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2864 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2865 font->gm[glyph_index].lsb = left >> 6;
2866 font->gm[glyph_index].bbx = (right - left) >> 6;
2868 /* Scaling transform */
2869 if(font->aveWidth) {
2871 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2874 scaleMat.yy = (1 << 16);
2876 pFT_Matrix_Multiply(&scaleMat, &transMat);
2877 needsTransform = TRUE;
2880 /* Slant transform */
2881 if (font->fake_italic) {
2884 slantMat.xx = (1 << 16);
2885 slantMat.xy = ((1 << 16) >> 2);
2887 slantMat.yy = (1 << 16);
2888 pFT_Matrix_Multiply(&slantMat, &transMat);
2889 needsTransform = TRUE;
2892 /* Rotation transform */
2893 if(font->orientation) {
2894 FT_Matrix rotationMat;
2896 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2897 pFT_Vector_Unit(&vecAngle, angle);
2898 rotationMat.xx = vecAngle.x;
2899 rotationMat.xy = -vecAngle.y;
2900 rotationMat.yx = -rotationMat.xy;
2901 rotationMat.yy = rotationMat.xx;
2903 pFT_Matrix_Multiply(&rotationMat, &transMat);
2904 needsTransform = TRUE;
2907 /* Extra transformation specified by caller */
2910 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2911 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2912 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2913 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2914 pFT_Matrix_Multiply(&extraMat, &transMat);
2915 needsTransform = TRUE;
2918 if(!needsTransform) {
2919 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2920 bottom = (ft_face->glyph->metrics.horiBearingY -
2921 ft_face->glyph->metrics.height) & -64;
2922 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2923 lpgm->gmCellIncY = 0;
2927 for(xc = 0; xc < 2; xc++) {
2928 for(yc = 0; yc < 2; yc++) {
2929 vec.x = (ft_face->glyph->metrics.horiBearingX +
2930 xc * ft_face->glyph->metrics.width);
2931 vec.y = ft_face->glyph->metrics.horiBearingY -
2932 yc * ft_face->glyph->metrics.height;
2933 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2934 pFT_Vector_Transform(&vec, &transMat);
2935 if(xc == 0 && yc == 0) {
2936 left = right = vec.x;
2937 top = bottom = vec.y;
2939 if(vec.x < left) left = vec.x;
2940 else if(vec.x > right) right = vec.x;
2941 if(vec.y < bottom) bottom = vec.y;
2942 else if(vec.y > top) top = vec.y;
2947 right = (right + 63) & -64;
2948 bottom = bottom & -64;
2949 top = (top + 63) & -64;
2951 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2952 vec.x = ft_face->glyph->metrics.horiAdvance;
2954 pFT_Vector_Transform(&vec, &transMat);
2955 lpgm->gmCellIncX = (vec.x+63) >> 6;
2956 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2958 lpgm->gmBlackBoxX = (right - left) >> 6;
2959 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2960 lpgm->gmptGlyphOrigin.x = left >> 6;
2961 lpgm->gmptGlyphOrigin.y = top >> 6;
2963 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2964 font->gm[glyph_index].init = TRUE;
2966 if(format == GGO_METRICS)
2967 return 1; /* FIXME */
2969 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2970 TRACE("loaded a bitmap\n");
2976 width = lpgm->gmBlackBoxX;
2977 height = lpgm->gmBlackBoxY;
2978 pitch = ((width + 31) >> 5) << 2;
2979 needed = pitch * height;
2981 if(!buf || !buflen) break;
2983 switch(ft_face->glyph->format) {
2984 case ft_glyph_format_bitmap:
2986 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2987 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2988 INT h = ft_face->glyph->bitmap.rows;
2990 memcpy(dst, src, w);
2991 src += ft_face->glyph->bitmap.pitch;
2997 case ft_glyph_format_outline:
2998 ft_bitmap.width = width;
2999 ft_bitmap.rows = height;
3000 ft_bitmap.pitch = pitch;
3001 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3002 ft_bitmap.buffer = buf;
3004 if(needsTransform) {
3005 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3008 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3010 /* Note: FreeType will only set 'black' bits for us. */
3011 memset(buf, 0, needed);
3012 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3016 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3021 case GGO_GRAY2_BITMAP:
3022 case GGO_GRAY4_BITMAP:
3023 case GGO_GRAY8_BITMAP:
3024 case WINE_GGO_GRAY16_BITMAP:
3026 unsigned int mult, row, col;
3029 width = lpgm->gmBlackBoxX;
3030 height = lpgm->gmBlackBoxY;
3031 pitch = (width + 3) / 4 * 4;
3032 needed = pitch * height;
3034 if(!buf || !buflen) break;
3035 ft_bitmap.width = width;
3036 ft_bitmap.rows = height;
3037 ft_bitmap.pitch = pitch;
3038 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3039 ft_bitmap.buffer = buf;
3041 if(needsTransform) {
3042 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3045 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3047 memset(ft_bitmap.buffer, 0, buflen);
3049 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3051 if(format == GGO_GRAY2_BITMAP)
3053 else if(format == GGO_GRAY4_BITMAP)
3055 else if(format == GGO_GRAY8_BITMAP)
3057 else if(format == WINE_GGO_GRAY16_BITMAP)
3065 for(row = 0; row < height; row++) {
3067 for(col = 0; col < width; col++, ptr++) {
3068 *ptr = (((int)*ptr) * mult + 128) / 256;
3077 int contour, point = 0, first_pt;
3078 FT_Outline *outline = &ft_face->glyph->outline;
3079 TTPOLYGONHEADER *pph;
3081 DWORD pph_start, cpfx, type;
3083 if(buflen == 0) buf = NULL;
3085 if (needsTransform && buf) {
3086 pFT_Outline_Transform(outline, &transMat);
3089 for(contour = 0; contour < outline->n_contours; contour++) {
3091 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3094 pph->dwType = TT_POLYGON_TYPE;
3095 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3097 needed += sizeof(*pph);
3099 while(point <= outline->contours[contour]) {
3100 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3101 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3102 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3106 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3109 } while(point <= outline->contours[contour] &&
3110 (outline->tags[point] & FT_Curve_Tag_On) ==
3111 (outline->tags[point-1] & FT_Curve_Tag_On));
3112 /* At the end of a contour Windows adds the start point, but
3114 if(point > outline->contours[contour] &&
3115 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3117 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3119 } else if(point <= outline->contours[contour] &&
3120 outline->tags[point] & FT_Curve_Tag_On) {
3121 /* add closing pt for bezier */
3123 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3131 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3134 pph->cb = needed - pph_start;
3140 /* Convert the quadratic Beziers to cubic Beziers.
3141 The parametric eqn for a cubic Bezier is, from PLRM:
3142 r(t) = at^3 + bt^2 + ct + r0
3143 with the control points:
3148 A quadratic Beizer has the form:
3149 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3151 So equating powers of t leads to:
3152 r1 = 2/3 p1 + 1/3 p0
3153 r2 = 2/3 p1 + 1/3 p2
3154 and of course r0 = p0, r3 = p2
3157 int contour, point = 0, first_pt;
3158 FT_Outline *outline = &ft_face->glyph->outline;
3159 TTPOLYGONHEADER *pph;
3161 DWORD pph_start, cpfx, type;
3162 FT_Vector cubic_control[4];
3163 if(buflen == 0) buf = NULL;
3165 if (needsTransform && buf) {
3166 pFT_Outline_Transform(outline, &transMat);
3169 for(contour = 0; contour < outline->n_contours; contour++) {
3171 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3174 pph->dwType = TT_POLYGON_TYPE;
3175 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3177 needed += sizeof(*pph);
3179 while(point <= outline->contours[contour]) {
3180 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3181 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3182 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3185 if(type == TT_PRIM_LINE) {
3187 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3191 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3194 /* FIXME: Possible optimization in endpoint calculation
3195 if there are two consecutive curves */
3196 cubic_control[0] = outline->points[point-1];
3197 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3198 cubic_control[0].x += outline->points[point].x + 1;
3199 cubic_control[0].y += outline->points[point].y + 1;
3200 cubic_control[0].x >>= 1;
3201 cubic_control[0].y >>= 1;
3203 if(point+1 > outline->contours[contour])
3204 cubic_control[3] = outline->points[first_pt];
3206 cubic_control[3] = outline->points[point+1];
3207 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3208 cubic_control[3].x += outline->points[point].x + 1;
3209 cubic_control[3].y += outline->points[point].y + 1;
3210 cubic_control[3].x >>= 1;
3211 cubic_control[3].y >>= 1;
3214 /* r1 = 1/3 p0 + 2/3 p1
3215 r2 = 1/3 p2 + 2/3 p1 */
3216 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3217 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3218 cubic_control[2] = cubic_control[1];
3219 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3220 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3221 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3222 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3224 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3225 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3226 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3231 } while(point <= outline->contours[contour] &&
3232 (outline->tags[point] & FT_Curve_Tag_On) ==
3233 (outline->tags[point-1] & FT_Curve_Tag_On));
3234 /* At the end of a contour Windows adds the start point,
3235 but only for Beziers and we've already done that.
3237 if(point <= outline->contours[contour] &&
3238 outline->tags[point] & FT_Curve_Tag_On) {
3239 /* This is the closing pt of a bezier, but we've already
3240 added it, so just inc point and carry on */
3247 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3250 pph->cb = needed - pph_start;
3256 FIXME("Unsupported format %d\n", format);
3262 static BOOL get_bitmap_text_metrics(GdiFont font)
3264 FT_Face ft_face = font->ft_face;
3265 #ifdef HAVE_FREETYPE_FTWINFNT_H
3266 FT_WinFNT_HeaderRec winfnt_header;
3268 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3269 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3270 font->potm->otmSize = size;
3272 #define TM font->potm->otmTextMetrics
3273 #ifdef HAVE_FREETYPE_FTWINFNT_H
3274 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3276 TM.tmHeight = winfnt_header.pixel_height;
3277 TM.tmAscent = winfnt_header.ascent;
3278 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3279 TM.tmInternalLeading = winfnt_header.internal_leading;
3280 TM.tmExternalLeading = winfnt_header.external_leading;
3281 TM.tmAveCharWidth = winfnt_header.avg_width;
3282 TM.tmMaxCharWidth = winfnt_header.max_width;
3283 TM.tmWeight = winfnt_header.weight;
3285 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3286 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3287 TM.tmFirstChar = winfnt_header.first_char;
3288 TM.tmLastChar = winfnt_header.last_char;
3289 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3290 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3291 TM.tmItalic = winfnt_header.italic;
3292 TM.tmUnderlined = font->underline;
3293 TM.tmStruckOut = font->strikeout;
3294 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3295 TM.tmCharSet = winfnt_header.charset;
3300 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3301 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3302 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3303 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3304 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3305 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3306 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3307 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3309 TM.tmDigitizedAspectX = 96; /* FIXME */
3310 TM.tmDigitizedAspectY = 96; /* FIXME */
3312 TM.tmLastChar = 255;
3313 TM.tmDefaultChar = 32;
3314 TM.tmBreakChar = 32;
3315 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3316 TM.tmUnderlined = font->underline;
3317 TM.tmStruckOut = font->strikeout;
3318 /* NB inverted meaning of TMPF_FIXED_PITCH */
3319 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3320 TM.tmCharSet = font->charset;
3327 /*************************************************************
3328 * WineEngGetTextMetrics
3331 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3334 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3335 if(!get_bitmap_text_metrics(font))
3338 if(!font->potm) return FALSE;
3339 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3341 if (font->aveWidth) {
3342 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3348 /*************************************************************
3349 * WineEngGetOutlineTextMetrics
3352 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3353 OUTLINETEXTMETRICW *potm)
3355 FT_Face ft_face = font->ft_face;
3356 UINT needed, lenfam, lensty, ret;
3358 TT_HoriHeader *pHori;
3359 TT_Postscript *pPost;
3360 FT_Fixed x_scale, y_scale;
3361 WCHAR *family_nameW, *style_nameW;
3362 static const WCHAR spaceW[] = {' ', '\0'};
3364 INT ascent, descent;
3366 TRACE("font=%p\n", font);
3368 if(!FT_IS_SCALABLE(ft_face))
3372 if(cbSize >= font->potm->otmSize)
3373 memcpy(potm, font->potm, font->potm->otmSize);
3374 return font->potm->otmSize;
3378 needed = sizeof(*potm);
3380 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3381 family_nameW = strdupW(font->name);
3383 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3385 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3386 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3387 style_nameW, lensty/sizeof(WCHAR));
3389 /* These names should be read from the TT name table */
3391 /* length of otmpFamilyName */
3394 /* length of otmpFaceName */
3395 if(!strcasecmp(ft_face->style_name, "regular")) {
3396 needed += lenfam; /* just the family name */
3398 needed += lenfam + lensty; /* family + " " + style */
3401 /* length of otmpStyleName */
3404 /* length of otmpFullName */
3405 needed += lenfam + lensty;
3408 x_scale = ft_face->size->metrics.x_scale;
3409 y_scale = ft_face->size->metrics.y_scale;
3411 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3413 FIXME("Can't find OS/2 table - not TT font?\n");
3418 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3420 FIXME("Can't find HHEA table - not TT font?\n");
3425 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3427 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",
3428 pOS2->usWinAscent, pOS2->usWinDescent,
3429 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3430 ft_face->ascender, ft_face->descender, ft_face->height,
3431 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3432 ft_face->bbox.yMax, ft_face->bbox.yMin);
3434 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3435 font->potm->otmSize = needed;
3437 #define TM font->potm->otmTextMetrics
3439 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3440 ascent = pHori->Ascender;
3441 descent = -pHori->Descender;
3443 ascent = pOS2->usWinAscent;
3444 descent = pOS2->usWinDescent;
3448 TM.tmAscent = font->yMax;
3449 TM.tmDescent = -font->yMin;
3450 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3452 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3453 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3454 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3455 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3458 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3461 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3463 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3464 ((ascent + descent) -
3465 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3467 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3468 if (TM.tmAveCharWidth == 0) {
3469 TM.tmAveCharWidth = 1;
3471 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3472 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3474 TM.tmDigitizedAspectX = 300;
3475 TM.tmDigitizedAspectY = 300;
3476 TM.tmFirstChar = pOS2->usFirstCharIndex;
3477 TM.tmLastChar = pOS2->usLastCharIndex;
3478 TM.tmDefaultChar = pOS2->usDefaultChar;
3479 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3480 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3481 TM.tmUnderlined = font->underline;
3482 TM.tmStruckOut = font->strikeout;
3484 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3485 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3486 (pOS2->version == 0xFFFFU ||
3487 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3488 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3490 TM.tmPitchAndFamily = 0;
3492 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3493 case PAN_FAMILY_SCRIPT:
3494 TM.tmPitchAndFamily |= FF_SCRIPT;
3496 case PAN_FAMILY_DECORATIVE:
3497 case PAN_FAMILY_PICTORIAL:
3498 TM.tmPitchAndFamily |= FF_DECORATIVE;
3500 case PAN_FAMILY_TEXT_DISPLAY:
3501 if(TM.tmPitchAndFamily == 0) /* fixed */
3502 TM.tmPitchAndFamily = FF_MODERN;
3504 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3505 case PAN_SERIF_NORMAL_SANS:
3506 case PAN_SERIF_OBTUSE_SANS:
3507 case PAN_SERIF_PERP_SANS:
3508 TM.tmPitchAndFamily |= FF_SWISS;
3511 TM.tmPitchAndFamily |= FF_ROMAN;
3516 TM.tmPitchAndFamily |= FF_DONTCARE;
3519 if(FT_IS_SCALABLE(ft_face))
3520 TM.tmPitchAndFamily |= TMPF_VECTOR;
3521 if(FT_IS_SFNT(ft_face))
3522 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3524 TM.tmCharSet = font->charset;
3527 font->potm->otmFiller = 0;
3528 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3529 font->potm->otmfsSelection = pOS2->fsSelection;
3530 font->potm->otmfsType = pOS2->fsType;
3531 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3532 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3533 font->potm->otmItalicAngle = 0; /* POST table */
3534 font->potm->otmEMSquare = ft_face->units_per_EM;
3535 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3536 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3537 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3538 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3539 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3540 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3541 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3542 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3543 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3544 font->potm->otmMacAscent = 0; /* where do these come from ? */
3545 font->potm->otmMacDescent = 0;
3546 font->potm->otmMacLineGap = 0;
3547 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3548 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3549 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3550 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3551 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3552 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3553 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3554 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3555 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3556 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3557 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3559 font->potm->otmsUnderscoreSize = 0;
3560 font->potm->otmsUnderscorePosition = 0;
3562 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3563 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3566 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3567 cp = (char*)font->potm + sizeof(*font->potm);
3568 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3569 strcpyW((WCHAR*)cp, family_nameW);
3571 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3572 strcpyW((WCHAR*)cp, style_nameW);
3574 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3575 strcpyW((WCHAR*)cp, family_nameW);
3576 if(strcasecmp(ft_face->style_name, "regular")) {
3577 strcatW((WCHAR*)cp, spaceW);
3578 strcatW((WCHAR*)cp, style_nameW);
3579 cp += lenfam + lensty;
3582 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3583 strcpyW((WCHAR*)cp, family_nameW);
3584 strcatW((WCHAR*)cp, spaceW);
3585 strcatW((WCHAR*)cp, style_nameW);
3588 if(potm && needed <= cbSize)
3589 memcpy(potm, font->potm, font->potm->otmSize);
3592 HeapFree(GetProcessHeap(), 0, style_nameW);
3593 HeapFree(GetProcessHeap(), 0, family_nameW);
3598 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3600 HFONTLIST *hfontlist;
3601 child->font = alloc_font();
3602 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3603 if(!child->font->ft_face)
3605 free_font(child->font);
3610 child->font->orientation = font->orientation;
3611 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3612 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3613 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3614 child->font->base_font = font;
3615 list_add_head(&child_font_list, &child->font->entry);
3616 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3620 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3623 CHILD_FONT *child_font;
3626 font = font->base_font;
3628 *linked_font = font;
3630 if((*glyph = get_glyph_index(font, c)))
3633 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3635 if(!child_font->font)
3636 if(!load_child_font(font, child_font))
3639 if(!child_font->font->ft_face)
3641 g = get_glyph_index(child_font->font, c);
3645 *linked_font = child_font->font;
3652 /*************************************************************
3653 * WineEngGetCharWidth
3656 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3661 FT_UInt glyph_index;
3662 GdiFont linked_font;
3664 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3666 for(c = firstChar; c <= lastChar; c++) {
3667 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3668 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3669 &gm, 0, NULL, NULL);
3670 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3675 /*************************************************************
3676 * WineEngGetCharABCWidths
3679 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3684 FT_UInt glyph_index;
3685 GdiFont linked_font;
3687 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3689 if(!FT_IS_SCALABLE(font->ft_face))
3692 for(c = firstChar; c <= lastChar; c++) {
3693 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3694 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3695 &gm, 0, NULL, NULL);
3696 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3697 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3698 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3699 linked_font->gm[glyph_index].bbx;
3704 /*************************************************************
3705 * WineEngGetTextExtentPoint
3708 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3714 FT_UInt glyph_index;
3715 GdiFont linked_font;
3717 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3721 WineEngGetTextMetrics(font, &tm);
3722 size->cy = tm.tmHeight;
3724 for(idx = 0; idx < count; idx++) {
3725 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3726 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3727 &gm, 0, NULL, NULL);
3728 size->cx += linked_font->gm[glyph_index].adv;
3730 TRACE("return %ld,%ld\n", size->cx, size->cy);
3734 /*************************************************************
3735 * WineEngGetTextExtentPointI
3738 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3745 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3748 WineEngGetTextMetrics(font, &tm);
3749 size->cy = tm.tmHeight;
3751 for(idx = 0; idx < count; idx++) {
3752 WineEngGetGlyphOutline(font, indices[idx],
3753 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3755 size->cx += font->gm[indices[idx]].adv;
3757 TRACE("return %ld,%ld\n", size->cx, size->cy);
3761 /*************************************************************
3762 * WineEngGetFontData
3765 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3768 FT_Face ft_face = font->ft_face;
3772 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3773 font, table, offset, buf, cbData);
3775 if(!FT_IS_SFNT(ft_face))
3783 if(table) { /* MS tags differ in endidness from FT ones */
3784 table = table >> 24 | table << 24 |
3785 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3788 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3789 if(pFT_Load_Sfnt_Table) {
3790 /* make sure value of len is the value freetype says it needs */
3793 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3794 if( !err && needed < len) len = needed;
3796 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3798 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3799 else { /* Do it the hard way */
3800 TT_Face tt_face = (TT_Face) ft_face;
3801 SFNT_Interface *sfnt;
3802 if (FT_Version.major==2 && FT_Version.minor==0)
3805 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3809 /* A field was added in the middle of the structure in 2.1.x */
3810 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3812 /* make sure value of len is the value freetype says it needs */
3815 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3816 if( !err && needed < len) len = needed;
3818 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3824 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3825 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3826 "Please upgrade your freetype library.\n");
3829 err = FT_Err_Unimplemented_Feature;
3833 TRACE("Can't find table %08lx.\n", table);
3839 /*************************************************************
3840 * WineEngGetTextFace
3843 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3846 lstrcpynW(str, font->name, count);
3847 return strlenW(font->name);
3849 return strlenW(font->name) + 1;
3852 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3854 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3855 return font->charset;
3858 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3860 GdiFont font = dc->gdiFont, linked_font;
3861 struct list *first_hfont;
3864 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3865 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3866 if(font == linked_font)
3867 *new_hfont = dc->hFont;
3870 first_hfont = list_head(&linked_font->hfontlist);
3871 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3878 /*************************************************************
3881 BOOL WINAPI FontIsLinked(HDC hdc)
3883 DC *dc = DC_GetDCPtr(hdc);
3886 if(!dc) return FALSE;
3887 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3889 GDI_ReleaseObj(hdc);
3890 TRACE("returning %d\n", ret);
3894 static BOOL is_hinting_enabled(void)
3898 /* Use the >= 2.2.0 function if available */
3899 if(pFT_Get_TrueType_Engine_Type)
3901 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
3902 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
3905 /* otherwise if we've been compiled with < 2.2.0 headers
3906 use the internal macro */
3907 #ifdef FT_DRIVER_HAS_HINTER
3908 mod = pFT_Get_Module(library, "truetype");
3909 if(mod && FT_DRIVER_HAS_HINTER(mod))
3916 /*************************************************************************
3917 * GetRasterizerCaps (GDI32.@)
3919 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3921 static int hinting = -1;
3924 hinting = is_hinting_enabled();
3926 lprs->nSize = sizeof(RASTERIZER_STATUS);
3927 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
3928 lprs->nLanguageID = 0;
3933 #else /* HAVE_FREETYPE */
3935 BOOL WineEngInit(void)
3939 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3943 BOOL WineEngDestroyFontInstance(HFONT hfont)
3948 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3953 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3954 LPWORD pgi, DWORD flags)
3959 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3960 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3963 ERR("called but we don't have FreeType\n");
3967 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3969 ERR("called but we don't have FreeType\n");
3973 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3974 OUTLINETEXTMETRICW *potm)
3976 ERR("called but we don't have FreeType\n");
3980 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3983 ERR("called but we don't have FreeType\n");
3987 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3990 ERR("called but we don't have FreeType\n");
3994 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3997 ERR("called but we don't have FreeType\n");
4001 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
4004 ERR("called but we don't have FreeType\n");
4008 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
4011 ERR("called but we don't have FreeType\n");
4015 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4017 ERR("called but we don't have FreeType\n");
4021 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4027 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4033 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4036 return DEFAULT_CHARSET;
4039 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4044 BOOL WINAPI FontIsLinked(HDC hdc)
4049 /*************************************************************************
4050 * GetRasterizerCaps (GDI32.@)
4052 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4054 lprs->nSize = sizeof(RASTERIZER_STATUS);
4056 lprs->nLanguageID = 0;
4060 #endif /* HAVE_FREETYPE */