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 FT_MODULE_DRIVER_HAS_HINTER
94 #define FT_MODULE_DRIVER_HAS_HINTER 0x400
97 static FT_Library library = 0;
104 static FT_Version_t FT_Version;
105 static DWORD FT_SimpleVersion;
107 static void *ft_handle = NULL;
109 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
110 MAKE_FUNCPTR(FT_Vector_Unit);
111 MAKE_FUNCPTR(FT_Done_Face);
112 MAKE_FUNCPTR(FT_Get_Char_Index);
113 MAKE_FUNCPTR(FT_Get_Module);
114 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
115 MAKE_FUNCPTR(FT_Init_FreeType);
116 MAKE_FUNCPTR(FT_Load_Glyph);
117 MAKE_FUNCPTR(FT_Matrix_Multiply);
118 MAKE_FUNCPTR(FT_MulFix);
119 MAKE_FUNCPTR(FT_New_Face);
120 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
121 MAKE_FUNCPTR(FT_Outline_Transform);
122 MAKE_FUNCPTR(FT_Outline_Translate);
123 MAKE_FUNCPTR(FT_Select_Charmap);
124 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
125 MAKE_FUNCPTR(FT_Vector_Transform);
126 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
127 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
128 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
129 static FT_Error (*pFT_Module_Get_Flags)(FT_Module,FT_ULong*);
130 #ifdef HAVE_FREETYPE_FTWINFNT_H
131 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
134 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
135 #include <fontconfig/fontconfig.h>
136 MAKE_FUNCPTR(FcConfigGetCurrent);
137 MAKE_FUNCPTR(FcFontList);
138 MAKE_FUNCPTR(FcFontSetDestroy);
139 MAKE_FUNCPTR(FcInit);
140 MAKE_FUNCPTR(FcObjectSetAdd);
141 MAKE_FUNCPTR(FcObjectSetCreate);
142 MAKE_FUNCPTR(FcObjectSetDestroy);
143 MAKE_FUNCPTR(FcPatternCreate);
144 MAKE_FUNCPTR(FcPatternDestroy);
145 MAKE_FUNCPTR(FcPatternGet);
146 #ifndef SONAME_LIBFONTCONFIG
147 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
153 #ifndef ft_encoding_none
154 #define FT_ENCODING_NONE ft_encoding_none
156 #ifndef ft_encoding_ms_symbol
157 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
159 #ifndef ft_encoding_unicode
160 #define FT_ENCODING_UNICODE ft_encoding_unicode
162 #ifndef ft_encoding_apple_roman
163 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
166 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
168 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
175 FT_Short internal_leading;
178 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
179 So to let this compile on older versions of FreeType we'll define the
180 new structure here. */
182 FT_Short height, width;
183 FT_Pos size, x_ppem, y_ppem;
186 typedef struct tagFace {
194 FONTSIGNATURE fs_links;
195 FT_Fixed font_version;
197 Bitmap_Size size; /* set if face is a bitmap */
198 BOOL external; /* TRUE if we should manually add this font to the registry */
199 struct tagFamily *family;
202 typedef struct tagFamily {
210 INT adv; /* These three hold to widths of the unrotated chars */
227 typedef struct tagHFONTLIST {
252 struct list hfontlist;
257 OUTLINETEXTMETRICW *potm;
260 struct list child_fonts;
270 #define INIT_GM_SIZE 128
272 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
273 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
274 #define UNUSED_CACHE_SIZE 10
275 static struct list child_font_list = LIST_INIT(child_font_list);
276 static struct list system_links = LIST_INIT(system_links);
278 static struct list font_list = LIST_INIT(font_list);
280 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
281 'R','o','m','a','n','\0'};
282 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
283 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
285 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
286 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
287 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
288 'S','e','r','i','f','\0'};
289 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
290 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
292 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
293 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
294 'W','i','n','d','o','w','s','\\',
295 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
296 'F','o','n','t','s','\0'};
298 static const WCHAR winnt_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',' ','N','T','\\',
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 system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
304 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
305 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
306 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
308 static const WCHAR *SystemFontValues[4] = {
315 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
316 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
318 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
319 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
320 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
321 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
322 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
323 'E','u','r','o','p','e','a','n','\0'};
324 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
325 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
326 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
327 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
328 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
329 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
330 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
331 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
332 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
333 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
334 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
335 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
337 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
347 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
355 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
364 typedef struct tagFontSubst {
367 struct tagFontSubst *next;
370 static FontSubst *substlist = NULL;
371 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
373 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
376 /****************************************
377 * Notes on .fon files
379 * The fonts System, FixedSys and Terminal are special. There are typically multiple
380 * versions installed for different resolutions and codepages. Windows stores which one to use
381 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
383 * FIXEDFON.FON FixedSys
385 * OEMFONT.FON Terminal
386 * LogPixels Current dpi set by the display control panel applet
387 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
388 * also has a LogPixels value that appears to mirror this)
390 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
391 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
392 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
393 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
394 * so that makes sense.
396 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
397 * to be mapped into the registry on Windows 2000 at least).
400 * ega80woa.fon=ega80850.fon
401 * ega40woa.fon=ega40850.fon
402 * cga80woa.fon=cga80850.fon
403 * cga40woa.fon=cga40850.fon
407 static inline BOOL is_win9x(void)
409 return GetVersion() & 0x80000000;
412 This function builds an FT_Fixed from a float. It puts the integer part
413 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
414 It fails if the integer part of the float number is greater than SHORT_MAX.
416 static inline FT_Fixed FT_FixedFromFloat(float f)
419 unsigned short fract = (f - value) * 0xFFFF;
420 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
424 This function builds an FT_Fixed from a FIXED. It simply put f.value
425 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
427 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
429 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
432 #define ADDFONT_EXTERNAL_FONT 0x01
433 #define ADDFONT_FORCE_BITMAP 0x02
434 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
438 TT_Header *pHeader = NULL;
439 WCHAR *FamilyW, *StyleW;
443 struct list *family_elem_ptr, *face_elem_ptr;
445 FT_Long face_index = 0, num_faces;
446 #ifdef HAVE_FREETYPE_FTWINFNT_H
447 FT_WinFNT_HeaderRec winfnt_header;
449 int i, bitmap_num, internal_leading;
453 char *family_name = fake_family;
455 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
456 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
457 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
461 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*/
462 WARN("Ignoring font %s\n", debugstr_a(file));
463 pFT_Done_Face(ft_face);
467 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
468 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
469 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
470 pFT_Done_Face(ft_face);
474 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
475 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
476 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
477 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
478 "Skipping this font.\n", debugstr_a(file));
479 pFT_Done_Face(ft_face);
483 if(!ft_face->family_name || !ft_face->style_name) {
484 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
485 pFT_Done_Face(ft_face);
490 family_name = ft_face->family_name;
494 My_FT_Bitmap_Size *size = NULL;
496 if(!FT_IS_SCALABLE(ft_face))
497 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
499 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
500 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
501 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
504 LIST_FOR_EACH(family_elem_ptr, &font_list) {
505 family = LIST_ENTRY(family_elem_ptr, Family, entry);
506 if(!strcmpW(family->FamilyName, FamilyW))
511 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
512 family->FamilyName = FamilyW;
513 list_init(&family->faces);
514 list_add_tail(&font_list, &family->entry);
516 HeapFree(GetProcessHeap(), 0, FamilyW);
519 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
520 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
521 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
523 internal_leading = 0;
524 memset(&fs, 0, sizeof(fs));
526 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
528 fs.fsCsb[0] = pOS2->ulCodePageRange1;
529 fs.fsCsb[1] = pOS2->ulCodePageRange2;
530 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
531 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
532 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
533 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
534 if(pOS2->version == 0) {
537 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
540 fs.fsCsb[0] |= 1L << 31;
543 #ifdef HAVE_FREETYPE_FTWINFNT_H
544 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
546 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
547 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
548 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
549 memcpy(&fs, &csi.fs, sizeof(csi.fs));
550 internal_leading = winfnt_header.internal_leading;
554 face_elem_ptr = list_head(&family->faces);
555 while(face_elem_ptr) {
556 face = LIST_ENTRY(face_elem_ptr, Face, entry);
557 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
558 if(!strcmpW(face->StyleName, StyleW) &&
559 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
560 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
561 debugstr_w(family->FamilyName), debugstr_w(StyleW),
562 face->font_version, pHeader ? pHeader->Font_Revision : 0);
565 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
566 HeapFree(GetProcessHeap(), 0, StyleW);
567 pFT_Done_Face(ft_face);
570 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
571 TRACE("Original font is newer so skipping this one\n");
572 HeapFree(GetProcessHeap(), 0, StyleW);
573 pFT_Done_Face(ft_face);
576 TRACE("Replacing original with this one\n");
577 list_remove(&face->entry);
578 HeapFree(GetProcessHeap(), 0, face->file);
579 HeapFree(GetProcessHeap(), 0, face->StyleName);
580 HeapFree(GetProcessHeap(), 0, face);
585 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
586 list_add_tail(&family->faces, &face->entry);
587 face->StyleName = StyleW;
588 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
589 strcpy(face->file, file);
590 face->face_index = face_index;
591 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
592 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
593 face->font_version = pHeader ? pHeader->Font_Revision : 0;
594 face->family = family;
595 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
596 memcpy(&face->fs, &fs, sizeof(face->fs));
597 memset(&face->fs_links, 0, sizeof(face->fs_links));
599 if(FT_IS_SCALABLE(ft_face)) {
600 memset(&face->size, 0, sizeof(face->size));
601 face->scalable = TRUE;
603 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
604 size->height, size->width, size->size >> 6,
605 size->x_ppem >> 6, size->y_ppem >> 6);
606 face->size.height = size->height;
607 face->size.width = size->width;
608 face->size.size = size->size;
609 face->size.x_ppem = size->x_ppem;
610 face->size.y_ppem = size->y_ppem;
611 face->size.internal_leading = internal_leading;
612 face->scalable = FALSE;
615 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
616 face->fs.fsCsb[0], face->fs.fsCsb[1],
617 face->fs.fsUsb[0], face->fs.fsUsb[1],
618 face->fs.fsUsb[2], face->fs.fsUsb[3]);
621 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
622 for(i = 0; i < ft_face->num_charmaps; i++) {
623 switch(ft_face->charmaps[i]->encoding) {
624 case FT_ENCODING_UNICODE:
625 case FT_ENCODING_APPLE_ROMAN:
626 face->fs.fsCsb[0] |= 1;
628 case FT_ENCODING_MS_SYMBOL:
629 face->fs.fsCsb[0] |= 1L << 31;
637 if(face->fs.fsCsb[0] & ~(1L << 31))
638 have_installed_roman_font = TRUE;
639 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
641 num_faces = ft_face->num_faces;
642 pFT_Done_Face(ft_face);
643 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
645 } while(num_faces > ++face_index);
649 static void DumpFontList(void)
653 struct list *family_elem_ptr, *face_elem_ptr;
655 LIST_FOR_EACH(family_elem_ptr, &font_list) {
656 family = LIST_ENTRY(family_elem_ptr, Family, entry);
657 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
658 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
659 face = LIST_ENTRY(face_elem_ptr, Face, entry);
660 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
662 TRACE(" %ld", face->size.y_ppem >> 6);
669 static Face *find_face_from_filename(const WCHAR *name)
674 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
675 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
678 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
679 TRACE("looking for %s\n", debugstr_a(nameA));
681 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
683 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
685 file = strrchr(face->file, '/');
690 if(!strcmp(file, nameA))
695 HeapFree(GetProcessHeap(), 0, nameA);
699 static Family *find_family_from_name(const WCHAR *name)
703 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
705 if(!strcmpiW(family->FamilyName, name))
712 static void DumpSubstList(void)
716 for(psub = substlist; psub; psub = psub->next)
717 if(psub->from.charset != -1 || psub->to.charset != -1)
718 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
719 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
721 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
722 debugstr_w(psub->to.name));
726 static LPWSTR strdupW(LPCWSTR p)
729 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
730 ret = HeapAlloc(GetProcessHeap(), 0, len);
735 static LPSTR strdupA(LPCSTR p)
738 DWORD len = (strlen(p) + 1);
739 ret = HeapAlloc(GetProcessHeap(), 0, len);
744 static void split_subst_info(NameCs *nc, LPSTR str)
746 CHAR *p = strrchr(str, ',');
751 nc->charset = strtol(p+1, NULL, 10);
754 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
755 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
756 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
759 static void LoadSubstList(void)
761 FontSubst *psub, **ppsub;
763 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
768 for(psub = substlist; psub;) {
770 HeapFree(GetProcessHeap(), 0, psub->to.name);
771 HeapFree(GetProcessHeap(), 0, psub->from.name);
774 HeapFree(GetProcessHeap(), 0, ptmp);
779 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
780 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
781 &hkey) == ERROR_SUCCESS) {
783 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
784 &valuelen, &datalen, NULL, NULL);
786 valuelen++; /* returned value doesn't include room for '\0' */
787 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
788 data = HeapAlloc(GetProcessHeap(), 0, datalen);
793 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
794 &dlen) == ERROR_SUCCESS) {
795 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
797 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
798 (*ppsub)->next = NULL;
799 split_subst_info(&((*ppsub)->from), value);
800 split_subst_info(&((*ppsub)->to), data);
802 /* Win 2000 doesn't allow mapping between different charsets
803 or mapping of DEFAULT_CHARSET */
804 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
805 (*ppsub)->to.charset == DEFAULT_CHARSET) {
806 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
807 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
808 HeapFree(GetProcessHeap(), 0, *ppsub);
811 ppsub = &((*ppsub)->next);
813 /* reset dlen and vlen */
817 HeapFree(GetProcessHeap(), 0, data);
818 HeapFree(GetProcessHeap(), 0, value);
823 /***********************************************************
824 * The replacement list is a way to map an entire font
825 * family onto another family. For example adding
827 * [HKCU\Software\Wine\Fonts\Replacements]
828 * "Wingdings"="Winedings"
830 * would enumerate the Winedings font both as Winedings and
831 * Wingdings. However if a real Wingdings font is present the
832 * replacement does not take place.
835 static void LoadReplaceList(void)
838 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
843 struct list *family_elem_ptr, *face_elem_ptr;
844 WCHAR old_nameW[200];
846 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
847 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
849 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
850 &valuelen, &datalen, NULL, NULL);
852 valuelen++; /* returned value doesn't include room for '\0' */
853 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
854 data = HeapAlloc(GetProcessHeap(), 0, datalen);
858 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
859 &dlen) == ERROR_SUCCESS) {
860 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
861 /* "NewName"="Oldname" */
862 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
865 /* Find the old family and hence all of the font files
867 LIST_FOR_EACH(family_elem_ptr, &font_list) {
868 family = LIST_ENTRY(family_elem_ptr, Family, entry);
869 if(!strcmpiW(family->FamilyName, old_nameW)) {
870 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
871 face = LIST_ENTRY(face_elem_ptr, Face, entry);
872 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
873 debugstr_w(face->StyleName), value);
874 /* Now add a new entry with the new family name */
875 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
880 /* reset dlen and vlen */
884 HeapFree(GetProcessHeap(), 0, data);
885 HeapFree(GetProcessHeap(), 0, value);
890 /*************************************************************
893 static BOOL init_system_links(void)
895 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
896 'W','i','n','d','o','w','s',' ','N','T','\\',
897 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
898 'S','y','s','t','e','m','L','i','n','k',0};
901 DWORD type, max_val, max_data, val_len, data_len, index;
904 SYSTEM_LINKS *font_link, *system_font_link;
905 CHILD_FONT *child_font;
906 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
907 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
908 static const WCHAR System[] = {'S','y','s','t','e','m',0};
913 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
915 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
916 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
917 data = HeapAlloc(GetProcessHeap(), 0, max_data);
918 val_len = max_val + 1;
921 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
923 TRACE("%s:\n", debugstr_w(value));
925 memset(&fs, 0, sizeof(fs));
926 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
927 font_link->font_name = strdupW(value);
928 list_init(&font_link->links);
929 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
933 CHILD_FONT *child_font;
935 TRACE("\t%s\n", debugstr_w(entry));
937 next = entry + strlenW(entry) + 1;
939 face_name = strchrW(entry, ',');
944 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
946 while(isspaceW(*face_name))
951 face = find_face_from_filename(entry);
954 TRACE("Unable to find file %s\n", debugstr_w(entry));
958 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
959 child_font->file_name = strdupA(face->file);
960 child_font->index = index;
961 child_font->font = NULL;
962 fs.fsCsb[0] |= face->fs.fsCsb[0];
963 fs.fsCsb[1] |= face->fs.fsCsb[1];
964 list_add_tail(&font_link->links, &child_font->entry);
966 family = find_family_from_name(font_link->font_name);
969 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
971 memcpy(&face->fs_links, &fs, sizeof(fs));
974 list_add_tail(&system_links, &font_link->entry);
975 val_len = max_val + 1;
979 HeapFree(GetProcessHeap(), 0, value);
980 HeapFree(GetProcessHeap(), 0, data);
984 /* Explicitly add an entry for the system font, this links to Tahoma and any links
987 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
988 system_font_link->font_name = strdupW(System);
989 list_init(&system_font_link->links);
991 face = find_face_from_filename(tahoma_ttf);
994 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
995 child_font->file_name = strdupA(face->file);
996 child_font->index = 0;
997 child_font->font = NULL;
998 list_add_tail(&system_font_link->links, &child_font->entry);
1000 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1002 if(!strcmpiW(font_link->font_name, Tahoma))
1004 CHILD_FONT *font_link_entry;
1005 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1007 CHILD_FONT *new_child;
1008 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1009 new_child->file_name = strdupA(font_link_entry->file_name);
1010 new_child->index = font_link_entry->index;
1011 new_child->font = NULL;
1012 list_add_tail(&system_font_link->links, &new_child->entry);
1017 list_add_tail(&system_links, &system_font_link->entry);
1021 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1024 struct dirent *dent;
1025 char path[MAX_PATH];
1027 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1029 dir = opendir(dirname);
1031 ERR("Can't open directory %s\n", debugstr_a(dirname));
1034 while((dent = readdir(dir)) != NULL) {
1035 struct stat statbuf;
1037 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1040 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1042 sprintf(path, "%s/%s", dirname, dent->d_name);
1044 if(stat(path, &statbuf) == -1)
1046 WARN("Can't stat %s\n", debugstr_a(path));
1049 if(S_ISDIR(statbuf.st_mode))
1050 ReadFontDir(path, external_fonts);
1052 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1058 static void load_fontconfig_fonts(void)
1060 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1061 void *fc_handle = NULL;
1068 const char *file, *ext;
1070 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1072 TRACE("Wine cannot find the fontconfig library (%s).\n",
1073 SONAME_LIBFONTCONFIG);
1076 #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;}
1077 LOAD_FUNCPTR(FcConfigGetCurrent);
1078 LOAD_FUNCPTR(FcFontList);
1079 LOAD_FUNCPTR(FcFontSetDestroy);
1080 LOAD_FUNCPTR(FcInit);
1081 LOAD_FUNCPTR(FcObjectSetAdd);
1082 LOAD_FUNCPTR(FcObjectSetCreate);
1083 LOAD_FUNCPTR(FcObjectSetDestroy);
1084 LOAD_FUNCPTR(FcPatternCreate);
1085 LOAD_FUNCPTR(FcPatternDestroy);
1086 LOAD_FUNCPTR(FcPatternGet);
1089 if(!pFcInit()) return;
1091 config = pFcConfigGetCurrent();
1092 pat = pFcPatternCreate();
1093 os = pFcObjectSetCreate();
1094 pFcObjectSetAdd(os, FC_FILE);
1095 fontset = pFcFontList(config, pat, os);
1096 if(!fontset) return;
1097 for(i = 0; i < fontset->nfont; i++) {
1098 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1100 if(v.type != FcTypeString) continue;
1101 file = (LPCSTR) v.u.s;
1102 TRACE("fontconfig: %s\n", file);
1104 /* We're just interested in OT/TT fonts for now, so this hack just
1105 picks up the standard extensions to save time loading every other
1107 len = strlen( file );
1108 if(len < 4) continue;
1109 ext = &file[ len - 3 ];
1110 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1111 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1113 pFcFontSetDestroy(fontset);
1114 pFcObjectSetDestroy(os);
1115 pFcPatternDestroy(pat);
1122 static void load_system_fonts(void)
1125 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1126 const WCHAR **value;
1128 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1131 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1132 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1133 strcatW(windowsdir, fontsW);
1134 for(value = SystemFontValues; *value; value++) {
1135 dlen = sizeof(data);
1136 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1138 sprintfW(pathW, fmtW, windowsdir, data);
1139 if((unixname = wine_get_unix_file_name(pathW))) {
1140 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1141 HeapFree(GetProcessHeap(), 0, unixname);
1149 /*************************************************************
1151 * This adds registry entries for any externally loaded fonts
1152 * (fonts from fontconfig or FontDirs). It also deletes entries
1153 * of no longer existing fonts.
1156 static void update_reg_entries(void)
1158 HKEY winkey = 0, externalkey = 0;
1161 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1164 struct list *family_elem_ptr, *face_elem_ptr;
1166 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1167 static const WCHAR spaceW[] = {' ', '\0'};
1170 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1171 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1172 ERR("Can't create Windows font reg key\n");
1175 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1176 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1177 ERR("Can't create external font reg key\n");
1181 /* Delete all external fonts added last time */
1183 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1184 &valuelen, &datalen, NULL, NULL);
1185 valuelen++; /* returned value doesn't include room for '\0' */
1186 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1187 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1189 dlen = datalen * sizeof(WCHAR);
1192 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1193 &dlen) == ERROR_SUCCESS) {
1195 RegDeleteValueW(winkey, valueW);
1196 /* reset dlen and vlen */
1200 HeapFree(GetProcessHeap(), 0, data);
1201 HeapFree(GetProcessHeap(), 0, valueW);
1203 /* Delete the old external fonts key */
1204 RegCloseKey(externalkey);
1206 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1208 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1209 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1210 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1211 ERR("Can't create external font reg key\n");
1215 /* enumerate the fonts and add external ones to the two keys */
1217 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1218 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1219 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1220 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1221 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1222 if(!face->external) continue;
1224 if(strcmpiW(face->StyleName, RegularW))
1225 len = len_fam + strlenW(face->StyleName) + 1;
1226 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1227 strcpyW(valueW, family->FamilyName);
1228 if(len != len_fam) {
1229 strcatW(valueW, spaceW);
1230 strcatW(valueW, face->StyleName);
1232 strcatW(valueW, TrueType);
1233 if((path = strrchr(face->file, '/')) == NULL)
1237 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1239 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1240 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1241 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1242 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1244 HeapFree(GetProcessHeap(), 0, file);
1245 HeapFree(GetProcessHeap(), 0, valueW);
1250 RegCloseKey(externalkey);
1252 RegCloseKey(winkey);
1257 /*************************************************************
1258 * WineEngAddFontResourceEx
1261 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1263 if (ft_handle) /* do it only if we have freetype up and running */
1268 FIXME("Ignoring flags %lx\n", flags);
1270 if((unixname = wine_get_unix_file_name(file)))
1272 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1273 HeapFree(GetProcessHeap(), 0, unixname);
1279 /*************************************************************
1280 * WineEngRemoveFontResourceEx
1283 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1289 static const struct nls_update_font_list
1291 UINT ansi_cp, oem_cp;
1292 const char *oem, *fixed, *system;
1293 const char *courier, *serif, *small, *sserif;
1294 } nls_update_font_list[] =
1296 /* Latin 1 (United States) */
1297 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1300 /* Latin 1 (Multilingual) */
1301 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1302 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1304 /* Eastern Europe */
1305 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1306 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1309 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1310 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1313 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1314 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1317 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1318 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1321 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1322 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1325 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1326 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1329 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1330 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1333 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1334 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1337 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1338 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1341 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1342 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1344 /* Chinese Simplified */
1345 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1346 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1349 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1350 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1352 /* Chinese Traditional */
1353 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1354 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1358 inline static HKEY create_fonts_NT_registry_key(void)
1362 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1363 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1367 inline static HKEY create_fonts_9x_registry_key(void)
1371 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1372 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1376 inline static HKEY create_config_fonts_registry_key(void)
1380 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1381 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1385 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1387 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1388 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1389 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1390 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1393 static void update_font_info(void)
1398 UINT i, ansi_cp = 0, oem_cp = 0;
1399 LCID lcid = GetUserDefaultLCID();
1401 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1405 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1407 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1412 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1414 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1416 sprintf(buf, "%08lx", lcid);
1417 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1420 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1421 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1422 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1423 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1425 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1427 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1428 nls_update_font_list[i].oem_cp == oem_cp)
1432 hkey = create_config_fonts_registry_key();
1433 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1434 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1435 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1438 hkey = create_fonts_NT_registry_key();
1439 add_font_list(hkey, &nls_update_font_list[i]);
1442 hkey = create_fonts_9x_registry_key();
1443 add_font_list(hkey, &nls_update_font_list[i]);
1449 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1452 /*************************************************************
1455 * Initialize FreeType library and create a list of available faces
1457 BOOL WineEngInit(void)
1459 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1460 static const WCHAR pathW[] = {'P','a','t','h',0};
1462 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1464 WCHAR windowsdir[MAX_PATH];
1470 /* update locale dependent font info in registry */
1473 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1476 "Wine cannot find the FreeType font library. To enable Wine to\n"
1477 "use TrueType fonts please install a version of FreeType greater than\n"
1478 "or equal to 2.0.5.\n"
1479 "http://www.freetype.org\n");
1483 #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;}
1485 LOAD_FUNCPTR(FT_Vector_Unit)
1486 LOAD_FUNCPTR(FT_Done_Face)
1487 LOAD_FUNCPTR(FT_Get_Char_Index)
1488 LOAD_FUNCPTR(FT_Get_Module)
1489 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1490 LOAD_FUNCPTR(FT_Init_FreeType)
1491 LOAD_FUNCPTR(FT_Load_Glyph)
1492 LOAD_FUNCPTR(FT_Matrix_Multiply)
1493 LOAD_FUNCPTR(FT_MulFix)
1494 LOAD_FUNCPTR(FT_New_Face)
1495 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1496 LOAD_FUNCPTR(FT_Outline_Transform)
1497 LOAD_FUNCPTR(FT_Outline_Translate)
1498 LOAD_FUNCPTR(FT_Select_Charmap)
1499 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1500 LOAD_FUNCPTR(FT_Vector_Transform)
1503 /* Don't warn if this one is missing */
1504 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1505 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1506 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1507 pFT_Module_Get_Flags = wine_dlsym(ft_handle, "FT_Module_Get_Flags", NULL, 0);
1508 #ifdef HAVE_FREETYPE_FTWINFNT_H
1509 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1511 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1512 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1513 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1514 <= 2.0.3 has FT_Sqrt64 */
1518 if(pFT_Init_FreeType(&library) != 0) {
1519 ERR("Can't init FreeType library\n");
1520 wine_dlclose(ft_handle, NULL, 0);
1524 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1525 if (pFT_Library_Version)
1527 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1529 if (FT_Version.major<=0)
1535 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1536 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1537 ((FT_Version.minor << 8) & 0x00ff00) |
1538 ((FT_Version.patch ) & 0x0000ff);
1540 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1541 ERR("Failed to create font mutex\n");
1544 WaitForSingleObject(font_mutex, INFINITE);
1546 /* load the system fonts */
1547 load_system_fonts();
1549 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1550 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1551 strcatW(windowsdir, fontsW);
1552 if((unixname = wine_get_unix_file_name(windowsdir)))
1554 ReadFontDir(unixname, FALSE);
1555 HeapFree(GetProcessHeap(), 0, unixname);
1558 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1559 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1560 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1562 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1563 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1564 &hkey) == ERROR_SUCCESS) {
1566 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1567 &valuelen, &datalen, NULL, NULL);
1569 valuelen++; /* returned value doesn't include room for '\0' */
1570 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1571 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1574 dlen = datalen * sizeof(WCHAR);
1576 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1577 &dlen) == ERROR_SUCCESS) {
1578 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1580 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1582 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1583 HeapFree(GetProcessHeap(), 0, unixname);
1586 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1588 WCHAR pathW[MAX_PATH];
1589 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1590 sprintfW(pathW, fmtW, windowsdir, data);
1591 if((unixname = wine_get_unix_file_name(pathW)))
1593 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1594 HeapFree(GetProcessHeap(), 0, unixname);
1597 /* reset dlen and vlen */
1602 HeapFree(GetProcessHeap(), 0, data);
1603 HeapFree(GetProcessHeap(), 0, valueW);
1607 load_fontconfig_fonts();
1609 /* then look in any directories that we've specified in the config file */
1610 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1611 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1617 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1619 len += sizeof(WCHAR);
1620 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1621 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1623 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1624 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1625 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1626 TRACE( "got font path %s\n", debugstr_a(valueA) );
1630 LPSTR next = strchr( ptr, ':' );
1631 if (next) *next++ = 0;
1632 ReadFontDir( ptr, TRUE );
1635 HeapFree( GetProcessHeap(), 0, valueA );
1637 HeapFree( GetProcessHeap(), 0, valueW );
1646 update_reg_entries();
1648 init_system_links();
1650 ReleaseMutex(font_mutex);
1654 "Wine cannot find certain functions that it needs inside the FreeType\n"
1655 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1656 "FreeType to at least version 2.0.5.\n"
1657 "http://www.freetype.org\n");
1658 wine_dlclose(ft_handle, NULL, 0);
1664 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1667 TT_HoriHeader *pHori;
1671 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1672 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1674 if(height == 0) height = 16;
1676 /* Calc. height of EM square:
1678 * For +ve lfHeight we have
1679 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1680 * Re-arranging gives:
1681 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1683 * For -ve lfHeight we have
1685 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1686 * with il = winAscent + winDescent - units_per_em]
1691 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1692 ppem = ft_face->units_per_EM * height /
1693 (pHori->Ascender - pHori->Descender);
1695 ppem = ft_face->units_per_EM * height /
1696 (pOS2->usWinAscent + pOS2->usWinDescent);
1704 static LONG load_VDMX(GdiFont, LONG);
1706 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1711 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1712 err = pFT_New_Face(library, file, face_index, &ft_face);
1714 ERR("FT_New_Face rets %d\n", err);
1718 /* set it here, as load_VDMX needs it */
1719 font->ft_face = ft_face;
1721 if(FT_IS_SCALABLE(ft_face)) {
1722 /* load the VDMX table if we have one */
1723 font->ppem = load_VDMX(font, height);
1725 font->ppem = calc_ppem_for_height(ft_face, height);
1727 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1728 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1730 font->ppem = height;
1731 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1732 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1738 static int get_nearest_charset(Face *face, int *cp)
1740 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1741 a single face with the requested charset. The idea is to check if
1742 the selected font supports the current ANSI codepage, if it does
1743 return the corresponding charset, else return the first charset */
1746 int acp = GetACP(), i;
1750 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1751 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1752 return csi.ciCharset;
1754 for(i = 0; i < 32; i++) {
1756 if(face->fs.fsCsb[0] & fs0) {
1757 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1759 return csi.ciCharset;
1762 FIXME("TCI failing on %lx\n", fs0);
1766 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1767 face->fs.fsCsb[0], face->file);
1769 return DEFAULT_CHARSET;
1772 static GdiFont alloc_font(void)
1774 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1775 ret->gmsize = INIT_GM_SIZE;
1776 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1777 ret->gmsize * sizeof(*ret->gm));
1779 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1780 list_init(&ret->hfontlist);
1781 list_init(&ret->child_fonts);
1785 static void free_font(GdiFont font)
1787 struct list *cursor, *cursor2;
1789 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1791 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1792 struct list *first_hfont;
1793 HFONTLIST *hfontlist;
1794 list_remove(cursor);
1797 first_hfont = list_head(&child->font->hfontlist);
1798 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1799 DeleteObject(hfontlist->hfont);
1800 HeapFree(GetProcessHeap(), 0, hfontlist);
1801 free_font(child->font);
1803 HeapFree(GetProcessHeap(), 0, child->file_name);
1804 HeapFree(GetProcessHeap(), 0, child);
1807 if (font->ft_face) pFT_Done_Face(font->ft_face);
1808 HeapFree(GetProcessHeap(), 0, font->potm);
1809 HeapFree(GetProcessHeap(), 0, font->name);
1810 HeapFree(GetProcessHeap(), 0, font->gm);
1811 HeapFree(GetProcessHeap(), 0, font);
1815 /*************************************************************
1818 * load the vdmx entry for the specified height
1821 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1822 ( ( (FT_ULong)_x4 << 24 ) | \
1823 ( (FT_ULong)_x3 << 16 ) | \
1824 ( (FT_ULong)_x2 << 8 ) | \
1827 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1837 static LONG load_VDMX(GdiFont font, LONG height)
1839 BYTE hdr[6], tmp[2], group[4];
1840 BYTE devXRatio, devYRatio;
1841 USHORT numRecs, numRatios;
1842 DWORD result, offset = -1;
1846 /* For documentation on VDMX records, see
1847 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1850 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1852 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1855 /* FIXME: need the real device aspect ratio */
1859 numRecs = GET_BE_WORD(&hdr[2]);
1860 numRatios = GET_BE_WORD(&hdr[4]);
1862 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1863 for(i = 0; i < numRatios; i++) {
1866 offset = (3 * 2) + (i * sizeof(Ratios));
1867 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1870 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1872 if((ratio.xRatio == 0 &&
1873 ratio.yStartRatio == 0 &&
1874 ratio.yEndRatio == 0) ||
1875 (devXRatio == ratio.xRatio &&
1876 devYRatio >= ratio.yStartRatio &&
1877 devYRatio <= ratio.yEndRatio))
1879 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1880 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1881 offset = GET_BE_WORD(tmp);
1887 FIXME("No suitable ratio found\n");
1891 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1893 BYTE startsz, endsz;
1896 recs = GET_BE_WORD(group);
1900 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1902 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1903 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1904 if(result == GDI_ERROR) {
1905 FIXME("Failed to retrieve vTable\n");
1910 for(i = 0; i < recs; i++) {
1911 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1912 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1913 ppem = GET_BE_WORD(&vTable[i * 6]);
1915 if(yMax + -yMin == height) {
1918 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1921 if(yMax + -yMin > height) {
1924 goto end; /* failed */
1926 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1927 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1928 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1934 TRACE("ppem not found for height %ld\n", height);
1938 if(ppem < startsz || ppem > endsz)
1941 for(i = 0; i < recs; i++) {
1943 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1945 if(yPelHeight > ppem)
1948 if(yPelHeight == ppem) {
1949 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1950 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1951 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1957 HeapFree(GetProcessHeap(), 0, vTable);
1963 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1965 if(font->font_desc.hash != fd->hash) return TRUE;
1966 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1967 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1968 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1971 static void calc_hash(FONT_DESC *pfd)
1973 DWORD hash = 0, *ptr, two_chars;
1977 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1979 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1981 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1983 pwc = (WCHAR *)&two_chars;
1985 *pwc = toupperW(*pwc);
1987 *pwc = toupperW(*pwc);
1995 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2000 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2002 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2003 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2006 /* try the in-use list */
2007 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2008 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2009 if(!fontcmp(ret, &fd)) {
2010 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2011 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2012 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2013 if(hflist->hfont == hfont)
2016 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2017 hflist->hfont = hfont;
2018 list_add_head(&ret->hfontlist, &hflist->entry);
2023 /* then the unused list */
2024 font_elem_ptr = list_head(&unused_gdi_font_list);
2025 while(font_elem_ptr) {
2026 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2027 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2028 if(!fontcmp(ret, &fd)) {
2029 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2030 assert(list_empty(&ret->hfontlist));
2031 TRACE("Found %p in unused list\n", ret);
2032 list_remove(&ret->entry);
2033 list_add_head(&gdi_font_list, &ret->entry);
2034 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2035 hflist->hfont = hfont;
2036 list_add_head(&ret->hfontlist, &hflist->entry);
2044 /*************************************************************
2045 * create_child_font_list
2047 static BOOL create_child_font_list(GdiFont font)
2050 SYSTEM_LINKS *font_link;
2051 CHILD_FONT *font_link_entry, *new_child;
2053 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2055 if(!strcmpW(font_link->font_name, font->name))
2057 TRACE("found entry in system list\n");
2058 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2060 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2061 new_child->file_name = strdupA(font_link_entry->file_name);
2062 new_child->index = font_link_entry->index;
2063 new_child->font = NULL;
2064 list_add_tail(&font->child_fonts, &new_child->entry);
2065 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2075 /*************************************************************
2076 * WineEngCreateFontInstance
2079 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2083 Family *family, *last_resort_family;
2084 struct list *family_elem_ptr, *face_elem_ptr;
2085 INT height, width = 0;
2086 signed int diff = 0, newdiff;
2087 BOOL bd, it, can_use_bitmap;
2092 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2094 struct list *first_hfont = list_head(&ret->hfontlist);
2095 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2096 if(hflist->hfont == hfont)
2100 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2101 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2103 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2104 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2105 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2108 /* check the cache first */
2109 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2110 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2114 TRACE("not in cache\n");
2115 if(list_empty(&font_list)) /* No fonts installed */
2117 TRACE("No fonts installed\n");
2120 if(!have_installed_roman_font)
2122 TRACE("No roman font installed\n");
2128 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2129 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2130 calc_hash(&ret->font_desc);
2131 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2132 hflist->hfont = hfont;
2133 list_add_head(&ret->hfontlist, &hflist->entry);
2136 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2137 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2138 original value lfCharSet. Note this is a special case for
2139 Symbol and doesn't happen at least for "Wingdings*" */
2141 if(!strcmpiW(lf.lfFaceName, SymbolW))
2142 lf.lfCharSet = SYMBOL_CHARSET;
2144 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2145 switch(lf.lfCharSet) {
2146 case DEFAULT_CHARSET:
2147 csi.fs.fsCsb[0] = 0;
2150 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2151 csi.fs.fsCsb[0] = 0;
2157 if(lf.lfFaceName[0] != '\0') {
2159 for(psub = substlist; psub; psub = psub->next)
2160 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
2161 (psub->from.charset == -1 ||
2162 psub->from.charset == lf.lfCharSet))
2165 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2166 debugstr_w(psub->to.name));
2167 strcpyW(lf.lfFaceName, psub->to.name);
2170 /* We want a match on name and charset or just name if
2171 charset was DEFAULT_CHARSET. If the latter then
2172 we fixup the returned charset later in get_nearest_charset
2173 where we'll either use the charset of the current ansi codepage
2174 or if that's unavailable the first charset that the font supports.
2176 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2177 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2178 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2179 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2180 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2181 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2182 if(face->scalable || can_use_bitmap)
2189 /* If requested charset was DEFAULT_CHARSET then try using charset
2190 corresponding to the current ansi codepage */
2191 if(!csi.fs.fsCsb[0]) {
2193 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2194 FIXME("TCI failed on codepage %d\n", acp);
2195 csi.fs.fsCsb[0] = 0;
2197 lf.lfCharSet = csi.ciCharset;
2200 /* Face families are in the top 4 bits of lfPitchAndFamily,
2201 so mask with 0xF0 before testing */
2203 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2204 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2205 strcpyW(lf.lfFaceName, defFixed);
2206 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2207 strcpyW(lf.lfFaceName, defSerif);
2208 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2209 strcpyW(lf.lfFaceName, defSans);
2211 strcpyW(lf.lfFaceName, defSans);
2212 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2213 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2214 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2215 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2216 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2217 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2218 if(face->scalable || can_use_bitmap)
2224 last_resort_family = NULL;
2225 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2226 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2227 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2228 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2229 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2232 if(can_use_bitmap && !last_resort_family)
2233 last_resort_family = family;
2238 if(last_resort_family) {
2239 family = last_resort_family;
2240 csi.fs.fsCsb[0] = 0;
2244 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2245 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2246 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2247 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2248 if(face->scalable) {
2249 csi.fs.fsCsb[0] = 0;
2250 FIXME("just using first face for now\n");
2253 if(can_use_bitmap && !last_resort_family)
2254 last_resort_family = family;
2257 if(!last_resort_family) {
2258 FIXME("can't find a single appropriate font - bailing\n");
2263 WARN("could only find a bitmap font - this will probably look awful!\n");
2264 family = last_resort_family;
2265 csi.fs.fsCsb[0] = 0;
2268 it = lf.lfItalic ? 1 : 0;
2269 bd = lf.lfWeight > 550 ? 1 : 0;
2271 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2272 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2275 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2276 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2277 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2278 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2282 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2284 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2285 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2286 (diff < 0 && newdiff > diff)) {
2287 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2300 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2301 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2302 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2306 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2308 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2309 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2310 (diff < 0 && newdiff > diff)) {
2311 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2322 if(it && !face->Italic) ret->fake_italic = TRUE;
2323 if(bd && !face->Bold) ret->fake_bold = TRUE;
2326 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2328 if(csi.fs.fsCsb[0]) {
2329 ret->charset = lf.lfCharSet;
2330 ret->codepage = csi.ciACP;
2333 ret->charset = get_nearest_charset(face, &ret->codepage);
2335 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2336 debugstr_w(face->StyleName), face->file, face->face_index);
2338 if(!face->scalable) {
2339 width = face->size.x_ppem >> 6;
2340 height = face->size.y_ppem >> 6;
2342 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2350 if (ret->charset == SYMBOL_CHARSET &&
2351 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2354 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2358 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2361 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2362 ret->name = strdupW(family->FamilyName);
2363 ret->underline = lf.lfUnderline ? 0xff : 0;
2364 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2365 create_child_font_list(ret);
2367 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2369 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2370 list_add_head(&gdi_font_list, &ret->entry);
2374 static void dump_gdi_font_list(void)
2377 struct list *elem_ptr;
2379 TRACE("---------- gdiFont Cache ----------\n");
2380 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2381 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2382 TRACE("gdiFont=%p %s %ld\n",
2383 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2386 TRACE("---------- Unused gdiFont Cache ----------\n");
2387 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2388 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2389 TRACE("gdiFont=%p %s %ld\n",
2390 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2394 /*************************************************************
2395 * WineEngDestroyFontInstance
2397 * free the gdiFont associated with this handle
2400 BOOL WineEngDestroyFontInstance(HFONT handle)
2405 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2408 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2410 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2411 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2412 if(hflist->hfont == handle)
2414 TRACE("removing child font %p from child list\n", gdiFont);
2415 list_remove(&gdiFont->entry);
2420 TRACE("destroying hfont=%p\n", handle);
2422 dump_gdi_font_list();
2424 font_elem_ptr = list_head(&gdi_font_list);
2425 while(font_elem_ptr) {
2426 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2427 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2429 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2430 while(hfontlist_elem_ptr) {
2431 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2432 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2433 if(hflist->hfont == handle) {
2434 list_remove(&hflist->entry);
2435 HeapFree(GetProcessHeap(), 0, hflist);
2439 if(list_empty(&gdiFont->hfontlist)) {
2440 TRACE("Moving to Unused list\n");
2441 list_remove(&gdiFont->entry);
2442 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2447 font_elem_ptr = list_head(&unused_gdi_font_list);
2448 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2449 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2450 while(font_elem_ptr) {
2451 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2452 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2453 TRACE("freeing %p\n", gdiFont);
2454 list_remove(&gdiFont->entry);
2460 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2461 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2463 OUTLINETEXTMETRICW *potm = NULL;
2465 TEXTMETRICW tm, *ptm;
2466 GdiFont font = alloc_font();
2469 if(face->scalable) {
2473 height = face->size.y_ppem >> 6;
2474 width = face->size.x_ppem >> 6;
2477 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2483 font->name = strdupW(face->family->FamilyName);
2485 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2487 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2489 potm = HeapAlloc(GetProcessHeap(), 0, size);
2490 WineEngGetOutlineTextMetrics(font, size, potm);
2491 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2493 WineEngGetTextMetrics(font, &tm);
2497 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2498 pntm->ntmTm.tmAscent = ptm->tmAscent;
2499 pntm->ntmTm.tmDescent = ptm->tmDescent;
2500 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2501 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2502 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2503 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2504 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2505 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2506 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2507 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2508 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2509 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2510 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2511 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2512 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2513 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2514 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2515 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2516 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2517 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2518 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2519 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2520 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2522 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2523 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2524 *ptype |= RASTER_FONTTYPE;
2526 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2527 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2528 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2530 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2531 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2532 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2535 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2537 lstrcpynW(pelf->elfLogFont.lfFaceName,
2538 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2540 lstrcpynW(pelf->elfFullName,
2541 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2543 lstrcpynW(pelf->elfStyle,
2544 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2547 HeapFree(GetProcessHeap(), 0, potm);
2549 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2551 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2552 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2553 pelf->elfStyle[0] = '\0';
2556 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2561 /*************************************************************
2565 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2569 struct list *family_elem_ptr, *face_elem_ptr;
2571 NEWTEXTMETRICEXW ntm;
2572 DWORD type, ret = 1;
2578 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2580 if(plf->lfFaceName[0]) {
2582 for(psub = substlist; psub; psub = psub->next)
2583 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2584 (psub->from.charset == -1 ||
2585 psub->from.charset == plf->lfCharSet))
2588 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2589 debugstr_w(psub->to.name));
2590 memcpy(&lf, plf, sizeof(lf));
2591 strcpyW(lf.lfFaceName, psub->to.name);
2595 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2596 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2597 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2598 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2599 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2600 GetEnumStructs(face, &elf, &ntm, &type);
2601 for(i = 0; i < 32; i++) {
2602 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2603 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2604 strcpyW(elf.elfScript, OEM_DOSW);
2605 i = 32; /* break out of loop */
2606 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2609 fs.fsCsb[0] = 1L << i;
2611 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2613 csi.ciCharset = DEFAULT_CHARSET;
2614 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2615 if(csi.ciCharset != DEFAULT_CHARSET) {
2616 elf.elfLogFont.lfCharSet =
2617 ntm.ntmTm.tmCharSet = csi.ciCharset;
2619 strcpyW(elf.elfScript, ElfScriptsW[i]);
2621 FIXME("Unknown elfscript for bit %d\n", i);
2624 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2625 debugstr_w(elf.elfLogFont.lfFaceName),
2626 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2627 csi.ciCharset, type, debugstr_w(elf.elfScript),
2628 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2629 ntm.ntmTm.ntmFlags);
2630 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2637 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2638 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2639 face_elem_ptr = list_head(&family->faces);
2640 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2641 GetEnumStructs(face, &elf, &ntm, &type);
2642 for(i = 0; i < 32; i++) {
2643 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2644 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2645 strcpyW(elf.elfScript, OEM_DOSW);
2646 i = 32; /* break out of loop */
2647 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2650 fs.fsCsb[0] = 1L << i;
2652 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2654 csi.ciCharset = DEFAULT_CHARSET;
2655 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2656 if(csi.ciCharset != DEFAULT_CHARSET) {
2657 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2660 strcpyW(elf.elfScript, ElfScriptsW[i]);
2662 FIXME("Unknown elfscript for bit %d\n", i);
2665 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2666 debugstr_w(elf.elfLogFont.lfFaceName),
2667 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2668 csi.ciCharset, type, debugstr_w(elf.elfScript),
2669 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2670 ntm.ntmTm.ntmFlags);
2671 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2680 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2682 pt->x.value = vec->x >> 6;
2683 pt->x.fract = (vec->x & 0x3f) << 10;
2684 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2685 pt->y.value = vec->y >> 6;
2686 pt->y.fract = (vec->y & 0x3f) << 10;
2687 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2691 /***************************************************
2692 * According to the MSDN documentation on WideCharToMultiByte,
2693 * certain codepages cannot set the default_used parameter.
2694 * This returns TRUE if the codepage can set that parameter, false else
2695 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2697 static BOOL codepage_sets_default_used(UINT codepage)
2710 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2712 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2713 WCHAR wc = (WCHAR)glyph;
2715 BOOL *default_used_pointer;
2718 default_used_pointer = NULL;
2719 default_used = FALSE;
2720 if (codepage_sets_default_used(font->codepage))
2721 default_used_pointer = &default_used;
2722 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2725 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2726 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2730 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2731 glyph = glyph + 0xf000;
2732 return pFT_Get_Char_Index(font->ft_face, glyph);
2735 /*************************************************************
2736 * WineEngGetGlyphIndices
2738 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2740 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2741 LPWORD pgi, DWORD flags)
2745 for(i = 0; i < count; i++)
2746 pgi[i] = get_glyph_index(font, lpstr[i]);
2751 /*************************************************************
2752 * WineEngGetGlyphOutline
2754 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2755 * except that the first parameter is the HWINEENGFONT of the font in
2756 * question rather than an HDC.
2759 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2760 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2763 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2764 FT_Face ft_face = font->ft_face;
2765 FT_UInt glyph_index;
2766 DWORD width, height, pitch, needed = 0;
2767 FT_Bitmap ft_bitmap;
2769 INT left, right, top = 0, bottom = 0;
2771 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2772 float widthRatio = 1.0;
2773 FT_Matrix transMat = identityMat;
2774 BOOL needsTransform = FALSE;
2777 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2778 buflen, buf, lpmat);
2780 if(format & GGO_GLYPH_INDEX) {
2781 glyph_index = glyph;
2782 format &= ~GGO_GLYPH_INDEX;
2784 glyph_index = get_glyph_index(font, glyph);
2786 if(glyph_index >= font->gmsize) {
2787 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2788 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2789 font->gmsize * sizeof(*font->gm));
2791 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2792 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2793 return 1; /* FIXME */
2797 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2798 load_flags |= FT_LOAD_NO_BITMAP;
2800 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2803 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2807 /* Scaling factor */
2808 if (font->aveWidth && font->potm) {
2809 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2812 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2813 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2815 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2816 font->gm[glyph_index].lsb = left >> 6;
2817 font->gm[glyph_index].bbx = (right - left) >> 6;
2819 /* Scaling transform */
2820 if(font->aveWidth) {
2822 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2825 scaleMat.yy = (1 << 16);
2827 pFT_Matrix_Multiply(&scaleMat, &transMat);
2828 needsTransform = TRUE;
2831 /* Rotation transform */
2832 if(font->orientation) {
2833 FT_Matrix rotationMat;
2835 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2836 pFT_Vector_Unit(&vecAngle, angle);
2837 rotationMat.xx = vecAngle.x;
2838 rotationMat.xy = -vecAngle.y;
2839 rotationMat.yx = -rotationMat.xy;
2840 rotationMat.yy = rotationMat.xx;
2842 pFT_Matrix_Multiply(&rotationMat, &transMat);
2843 needsTransform = TRUE;
2846 /* Extra transformation specified by caller */
2849 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2850 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2851 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2852 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2853 pFT_Matrix_Multiply(&extraMat, &transMat);
2854 needsTransform = TRUE;
2857 if(!needsTransform) {
2858 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2859 bottom = (ft_face->glyph->metrics.horiBearingY -
2860 ft_face->glyph->metrics.height) & -64;
2861 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2862 lpgm->gmCellIncY = 0;
2866 for(xc = 0; xc < 2; xc++) {
2867 for(yc = 0; yc < 2; yc++) {
2868 vec.x = (ft_face->glyph->metrics.horiBearingX +
2869 xc * ft_face->glyph->metrics.width);
2870 vec.y = ft_face->glyph->metrics.horiBearingY -
2871 yc * ft_face->glyph->metrics.height;
2872 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2873 pFT_Vector_Transform(&vec, &transMat);
2874 if(xc == 0 && yc == 0) {
2875 left = right = vec.x;
2876 top = bottom = vec.y;
2878 if(vec.x < left) left = vec.x;
2879 else if(vec.x > right) right = vec.x;
2880 if(vec.y < bottom) bottom = vec.y;
2881 else if(vec.y > top) top = vec.y;
2886 right = (right + 63) & -64;
2887 bottom = bottom & -64;
2888 top = (top + 63) & -64;
2890 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2891 vec.x = ft_face->glyph->metrics.horiAdvance;
2893 pFT_Vector_Transform(&vec, &transMat);
2894 lpgm->gmCellIncX = (vec.x+63) >> 6;
2895 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2897 lpgm->gmBlackBoxX = (right - left) >> 6;
2898 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2899 lpgm->gmptGlyphOrigin.x = left >> 6;
2900 lpgm->gmptGlyphOrigin.y = top >> 6;
2902 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2903 font->gm[glyph_index].init = TRUE;
2905 if(format == GGO_METRICS)
2906 return 1; /* FIXME */
2908 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2909 TRACE("loaded a bitmap\n");
2915 width = lpgm->gmBlackBoxX;
2916 height = lpgm->gmBlackBoxY;
2917 pitch = ((width + 31) >> 5) << 2;
2918 needed = pitch * height;
2920 if(!buf || !buflen) break;
2922 switch(ft_face->glyph->format) {
2923 case ft_glyph_format_bitmap:
2925 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2926 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2927 INT h = ft_face->glyph->bitmap.rows;
2929 memcpy(dst, src, w);
2930 src += ft_face->glyph->bitmap.pitch;
2936 case ft_glyph_format_outline:
2937 ft_bitmap.width = width;
2938 ft_bitmap.rows = height;
2939 ft_bitmap.pitch = pitch;
2940 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2941 ft_bitmap.buffer = buf;
2943 if(needsTransform) {
2944 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2947 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2949 /* Note: FreeType will only set 'black' bits for us. */
2950 memset(buf, 0, needed);
2951 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2955 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2960 case GGO_GRAY2_BITMAP:
2961 case GGO_GRAY4_BITMAP:
2962 case GGO_GRAY8_BITMAP:
2963 case WINE_GGO_GRAY16_BITMAP:
2965 unsigned int mult, row, col;
2968 width = lpgm->gmBlackBoxX;
2969 height = lpgm->gmBlackBoxY;
2970 pitch = (width + 3) / 4 * 4;
2971 needed = pitch * height;
2973 if(!buf || !buflen) break;
2974 ft_bitmap.width = width;
2975 ft_bitmap.rows = height;
2976 ft_bitmap.pitch = pitch;
2977 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2978 ft_bitmap.buffer = buf;
2980 if(needsTransform) {
2981 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2984 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2986 memset(ft_bitmap.buffer, 0, buflen);
2988 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2990 if(format == GGO_GRAY2_BITMAP)
2992 else if(format == GGO_GRAY4_BITMAP)
2994 else if(format == GGO_GRAY8_BITMAP)
2996 else if(format == WINE_GGO_GRAY16_BITMAP)
3004 for(row = 0; row < height; row++) {
3006 for(col = 0; col < width; col++, ptr++) {
3007 *ptr = (((int)*ptr) * mult + 128) / 256;
3016 int contour, point = 0, first_pt;
3017 FT_Outline *outline = &ft_face->glyph->outline;
3018 TTPOLYGONHEADER *pph;
3020 DWORD pph_start, cpfx, type;
3022 if(buflen == 0) buf = NULL;
3024 if (needsTransform && buf) {
3025 pFT_Outline_Transform(outline, &transMat);
3028 for(contour = 0; contour < outline->n_contours; contour++) {
3030 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3033 pph->dwType = TT_POLYGON_TYPE;
3034 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3036 needed += sizeof(*pph);
3038 while(point <= outline->contours[contour]) {
3039 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3040 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3041 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3045 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3048 } while(point <= outline->contours[contour] &&
3049 (outline->tags[point] & FT_Curve_Tag_On) ==
3050 (outline->tags[point-1] & FT_Curve_Tag_On));
3051 /* At the end of a contour Windows adds the start point, but
3053 if(point > outline->contours[contour] &&
3054 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3056 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3058 } else if(point <= outline->contours[contour] &&
3059 outline->tags[point] & FT_Curve_Tag_On) {
3060 /* add closing pt for bezier */
3062 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3070 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3073 pph->cb = needed - pph_start;
3079 /* Convert the quadratic Beziers to cubic Beziers.
3080 The parametric eqn for a cubic Bezier is, from PLRM:
3081 r(t) = at^3 + bt^2 + ct + r0
3082 with the control points:
3087 A quadratic Beizer has the form:
3088 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3090 So equating powers of t leads to:
3091 r1 = 2/3 p1 + 1/3 p0
3092 r2 = 2/3 p1 + 1/3 p2
3093 and of course r0 = p0, r3 = p2
3096 int contour, point = 0, first_pt;
3097 FT_Outline *outline = &ft_face->glyph->outline;
3098 TTPOLYGONHEADER *pph;
3100 DWORD pph_start, cpfx, type;
3101 FT_Vector cubic_control[4];
3102 if(buflen == 0) buf = NULL;
3104 if (needsTransform && buf) {
3105 pFT_Outline_Transform(outline, &transMat);
3108 for(contour = 0; contour < outline->n_contours; contour++) {
3110 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3113 pph->dwType = TT_POLYGON_TYPE;
3114 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3116 needed += sizeof(*pph);
3118 while(point <= outline->contours[contour]) {
3119 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3120 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3121 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3124 if(type == TT_PRIM_LINE) {
3126 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3130 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3133 /* FIXME: Possible optimization in endpoint calculation
3134 if there are two consecutive curves */
3135 cubic_control[0] = outline->points[point-1];
3136 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3137 cubic_control[0].x += outline->points[point].x + 1;
3138 cubic_control[0].y += outline->points[point].y + 1;
3139 cubic_control[0].x >>= 1;
3140 cubic_control[0].y >>= 1;
3142 if(point+1 > outline->contours[contour])
3143 cubic_control[3] = outline->points[first_pt];
3145 cubic_control[3] = outline->points[point+1];
3146 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3147 cubic_control[3].x += outline->points[point].x + 1;
3148 cubic_control[3].y += outline->points[point].y + 1;
3149 cubic_control[3].x >>= 1;
3150 cubic_control[3].y >>= 1;
3153 /* r1 = 1/3 p0 + 2/3 p1
3154 r2 = 1/3 p2 + 2/3 p1 */
3155 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3156 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3157 cubic_control[2] = cubic_control[1];
3158 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3159 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3160 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3161 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3163 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3164 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3165 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3170 } while(point <= outline->contours[contour] &&
3171 (outline->tags[point] & FT_Curve_Tag_On) ==
3172 (outline->tags[point-1] & FT_Curve_Tag_On));
3173 /* At the end of a contour Windows adds the start point,
3174 but only for Beziers and we've already done that.
3176 if(point <= outline->contours[contour] &&
3177 outline->tags[point] & FT_Curve_Tag_On) {
3178 /* This is the closing pt of a bezier, but we've already
3179 added it, so just inc point and carry on */
3186 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3189 pph->cb = needed - pph_start;
3195 FIXME("Unsupported format %d\n", format);
3201 static BOOL get_bitmap_text_metrics(GdiFont font)
3203 FT_Face ft_face = font->ft_face;
3204 #ifdef HAVE_FREETYPE_FTWINFNT_H
3205 FT_WinFNT_HeaderRec winfnt_header;
3207 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3208 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3209 font->potm->otmSize = size;
3211 #define TM font->potm->otmTextMetrics
3212 #ifdef HAVE_FREETYPE_FTWINFNT_H
3213 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3215 TM.tmHeight = winfnt_header.pixel_height;
3216 TM.tmAscent = winfnt_header.ascent;
3217 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3218 TM.tmInternalLeading = winfnt_header.internal_leading;
3219 TM.tmExternalLeading = winfnt_header.external_leading;
3220 TM.tmAveCharWidth = winfnt_header.avg_width;
3221 TM.tmMaxCharWidth = winfnt_header.max_width;
3222 TM.tmWeight = winfnt_header.weight;
3224 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3225 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3226 TM.tmFirstChar = winfnt_header.first_char;
3227 TM.tmLastChar = winfnt_header.last_char;
3228 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3229 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3230 TM.tmItalic = winfnt_header.italic;
3231 TM.tmUnderlined = font->underline;
3232 TM.tmStruckOut = font->strikeout;
3233 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3234 TM.tmCharSet = winfnt_header.charset;
3239 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3240 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3241 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3242 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3243 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3244 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3245 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3246 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3248 TM.tmDigitizedAspectX = 96; /* FIXME */
3249 TM.tmDigitizedAspectY = 96; /* FIXME */
3251 TM.tmLastChar = 255;
3252 TM.tmDefaultChar = 32;
3253 TM.tmBreakChar = 32;
3254 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3255 TM.tmUnderlined = font->underline;
3256 TM.tmStruckOut = font->strikeout;
3257 /* NB inverted meaning of TMPF_FIXED_PITCH */
3258 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3259 TM.tmCharSet = font->charset;
3266 /*************************************************************
3267 * WineEngGetTextMetrics
3270 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3273 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3274 if(!get_bitmap_text_metrics(font))
3277 if(!font->potm) return FALSE;
3278 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3280 if (font->aveWidth) {
3281 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3287 /*************************************************************
3288 * WineEngGetOutlineTextMetrics
3291 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3292 OUTLINETEXTMETRICW *potm)
3294 FT_Face ft_face = font->ft_face;
3295 UINT needed, lenfam, lensty, ret;
3297 TT_HoriHeader *pHori;
3298 TT_Postscript *pPost;
3299 FT_Fixed x_scale, y_scale;
3300 WCHAR *family_nameW, *style_nameW;
3301 static const WCHAR spaceW[] = {' ', '\0'};
3303 INT ascent, descent;
3305 TRACE("font=%p\n", font);
3307 if(!FT_IS_SCALABLE(ft_face))
3311 if(cbSize >= font->potm->otmSize)
3312 memcpy(potm, font->potm, font->potm->otmSize);
3313 return font->potm->otmSize;
3317 needed = sizeof(*potm);
3319 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3320 family_nameW = strdupW(font->name);
3322 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3324 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3325 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3326 style_nameW, lensty/sizeof(WCHAR));
3328 /* These names should be read from the TT name table */
3330 /* length of otmpFamilyName */
3333 /* length of otmpFaceName */
3334 if(!strcasecmp(ft_face->style_name, "regular")) {
3335 needed += lenfam; /* just the family name */
3337 needed += lenfam + lensty; /* family + " " + style */
3340 /* length of otmpStyleName */
3343 /* length of otmpFullName */
3344 needed += lenfam + lensty;
3347 x_scale = ft_face->size->metrics.x_scale;
3348 y_scale = ft_face->size->metrics.y_scale;
3350 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3352 FIXME("Can't find OS/2 table - not TT font?\n");
3357 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3359 FIXME("Can't find HHEA table - not TT font?\n");
3364 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3366 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",
3367 pOS2->usWinAscent, pOS2->usWinDescent,
3368 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3369 ft_face->ascender, ft_face->descender, ft_face->height,
3370 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3371 ft_face->bbox.yMax, ft_face->bbox.yMin);
3373 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3374 font->potm->otmSize = needed;
3376 #define TM font->potm->otmTextMetrics
3378 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3379 ascent = pHori->Ascender;
3380 descent = -pHori->Descender;
3382 ascent = pOS2->usWinAscent;
3383 descent = pOS2->usWinDescent;
3387 TM.tmAscent = font->yMax;
3388 TM.tmDescent = -font->yMin;
3389 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3391 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3392 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3393 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3394 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3397 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3400 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3402 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3403 ((ascent + descent) -
3404 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3406 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3407 if (TM.tmAveCharWidth == 0) {
3408 TM.tmAveCharWidth = 1;
3410 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3411 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3413 TM.tmDigitizedAspectX = 300;
3414 TM.tmDigitizedAspectY = 300;
3415 TM.tmFirstChar = pOS2->usFirstCharIndex;
3416 TM.tmLastChar = pOS2->usLastCharIndex;
3417 TM.tmDefaultChar = pOS2->usDefaultChar;
3418 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3419 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3420 TM.tmUnderlined = font->underline;
3421 TM.tmStruckOut = font->strikeout;
3423 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3424 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3425 (pOS2->version == 0xFFFFU ||
3426 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3427 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3429 TM.tmPitchAndFamily = 0;
3431 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3432 case PAN_FAMILY_SCRIPT:
3433 TM.tmPitchAndFamily |= FF_SCRIPT;
3435 case PAN_FAMILY_DECORATIVE:
3436 case PAN_FAMILY_PICTORIAL:
3437 TM.tmPitchAndFamily |= FF_DECORATIVE;
3439 case PAN_FAMILY_TEXT_DISPLAY:
3440 if(TM.tmPitchAndFamily == 0) /* fixed */
3441 TM.tmPitchAndFamily = FF_MODERN;
3443 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3444 case PAN_SERIF_NORMAL_SANS:
3445 case PAN_SERIF_OBTUSE_SANS:
3446 case PAN_SERIF_PERP_SANS:
3447 TM.tmPitchAndFamily |= FF_SWISS;
3450 TM.tmPitchAndFamily |= FF_ROMAN;
3455 TM.tmPitchAndFamily |= FF_DONTCARE;
3458 if(FT_IS_SCALABLE(ft_face))
3459 TM.tmPitchAndFamily |= TMPF_VECTOR;
3460 if(FT_IS_SFNT(ft_face))
3461 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3463 TM.tmCharSet = font->charset;
3466 font->potm->otmFiller = 0;
3467 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3468 font->potm->otmfsSelection = pOS2->fsSelection;
3469 font->potm->otmfsType = pOS2->fsType;
3470 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3471 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3472 font->potm->otmItalicAngle = 0; /* POST table */
3473 font->potm->otmEMSquare = ft_face->units_per_EM;
3474 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3475 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3476 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3477 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3478 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3479 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3480 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3481 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3482 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3483 font->potm->otmMacAscent = 0; /* where do these come from ? */
3484 font->potm->otmMacDescent = 0;
3485 font->potm->otmMacLineGap = 0;
3486 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3487 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3488 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3489 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3490 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3491 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3492 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3493 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3494 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3495 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3496 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3498 font->potm->otmsUnderscoreSize = 0;
3499 font->potm->otmsUnderscorePosition = 0;
3501 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3502 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3505 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3506 cp = (char*)font->potm + sizeof(*font->potm);
3507 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3508 strcpyW((WCHAR*)cp, family_nameW);
3510 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3511 strcpyW((WCHAR*)cp, style_nameW);
3513 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3514 strcpyW((WCHAR*)cp, family_nameW);
3515 if(strcasecmp(ft_face->style_name, "regular")) {
3516 strcatW((WCHAR*)cp, spaceW);
3517 strcatW((WCHAR*)cp, style_nameW);
3518 cp += lenfam + lensty;
3521 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3522 strcpyW((WCHAR*)cp, family_nameW);
3523 strcatW((WCHAR*)cp, spaceW);
3524 strcatW((WCHAR*)cp, style_nameW);
3527 if(potm && needed <= cbSize)
3528 memcpy(potm, font->potm, font->potm->otmSize);
3531 HeapFree(GetProcessHeap(), 0, style_nameW);
3532 HeapFree(GetProcessHeap(), 0, family_nameW);
3537 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3539 HFONTLIST *hfontlist;
3540 child->font = alloc_font();
3541 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3542 if(!child->font->ft_face)
3544 free_font(child->font);
3549 child->font->orientation = font->orientation;
3550 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3551 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3552 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3553 child->font->base_font = font;
3554 list_add_head(&child_font_list, &child->font->entry);
3555 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3559 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3562 CHILD_FONT *child_font;
3565 font = font->base_font;
3567 *linked_font = font;
3569 if((*glyph = get_glyph_index(font, c)))
3572 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3574 if(!child_font->font)
3575 if(!load_child_font(font, child_font))
3578 if(!child_font->font->ft_face)
3580 g = get_glyph_index(child_font->font, c);
3584 *linked_font = child_font->font;
3591 /*************************************************************
3592 * WineEngGetCharWidth
3595 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3600 FT_UInt glyph_index;
3601 GdiFont linked_font;
3603 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3605 for(c = firstChar; c <= lastChar; c++) {
3606 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3607 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3608 &gm, 0, NULL, NULL);
3609 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3614 /*************************************************************
3615 * WineEngGetCharABCWidths
3618 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3623 FT_UInt glyph_index;
3624 GdiFont linked_font;
3626 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3628 if(!FT_IS_SCALABLE(font->ft_face))
3631 for(c = firstChar; c <= lastChar; c++) {
3632 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3633 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3634 &gm, 0, NULL, NULL);
3635 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3636 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3637 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3638 linked_font->gm[glyph_index].bbx;
3643 /*************************************************************
3644 * WineEngGetTextExtentPoint
3647 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3653 FT_UInt glyph_index;
3654 GdiFont linked_font;
3656 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3660 WineEngGetTextMetrics(font, &tm);
3661 size->cy = tm.tmHeight;
3663 for(idx = 0; idx < count; idx++) {
3664 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3665 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3666 &gm, 0, NULL, NULL);
3667 size->cx += linked_font->gm[glyph_index].adv;
3669 TRACE("return %ld,%ld\n", size->cx, size->cy);
3673 /*************************************************************
3674 * WineEngGetTextExtentPointI
3677 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3684 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3687 WineEngGetTextMetrics(font, &tm);
3688 size->cy = tm.tmHeight;
3690 for(idx = 0; idx < count; idx++) {
3691 WineEngGetGlyphOutline(font, indices[idx],
3692 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3694 size->cx += font->gm[indices[idx]].adv;
3696 TRACE("return %ld,%ld\n", size->cx, size->cy);
3700 /*************************************************************
3701 * WineEngGetFontData
3704 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3707 FT_Face ft_face = font->ft_face;
3711 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3712 font, table, offset, buf, cbData);
3714 if(!FT_IS_SFNT(ft_face))
3722 if(table) { /* MS tags differ in endidness from FT ones */
3723 table = table >> 24 | table << 24 |
3724 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3727 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3728 if(pFT_Load_Sfnt_Table) {
3729 /* make sure value of len is the value freetype says it needs */
3732 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3733 if( !err && needed < len) len = needed;
3735 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3737 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3738 else { /* Do it the hard way */
3739 TT_Face tt_face = (TT_Face) ft_face;
3740 SFNT_Interface *sfnt;
3741 if (FT_Version.major==2 && FT_Version.minor==0)
3744 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3748 /* A field was added in the middle of the structure in 2.1.x */
3749 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3751 /* make sure value of len is the value freetype says it needs */
3754 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3755 if( !err && needed < len) len = needed;
3757 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3763 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3764 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3765 "Please upgrade your freetype library.\n");
3768 err = FT_Err_Unimplemented_Feature;
3772 TRACE("Can't find table %08lx.\n", table);
3778 /*************************************************************
3779 * WineEngGetTextFace
3782 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3785 lstrcpynW(str, font->name, count);
3786 return strlenW(font->name);
3788 return strlenW(font->name) + 1;
3791 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3793 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3794 return font->charset;
3797 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3799 GdiFont font = dc->gdiFont, linked_font;
3800 struct list *first_hfont;
3803 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3804 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3805 if(font == linked_font)
3806 *new_hfont = dc->hFont;
3809 first_hfont = list_head(&linked_font->hfontlist);
3810 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3817 /*************************************************************
3820 BOOL WINAPI FontIsLinked(HDC hdc)
3822 DC *dc = DC_GetDCPtr(hdc);
3825 if(!dc) return FALSE;
3826 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3828 GDI_ReleaseObj(hdc);
3829 TRACE("returning %d\n", ret);
3833 static BOOL is_hinting_enabled(void)
3835 FT_Module mod = pFT_Get_Module(library, "truetype");
3837 /* Use the >= 2.2.0 function if available */
3838 if(pFT_Module_Get_Flags)
3841 pFT_Module_Get_Flags(mod, &flags);
3842 return flags & FT_MODULE_DRIVER_HAS_HINTER;
3845 /* otherwise if we've been compiled with < 2.2.0 headers
3846 use the internal macro */
3847 #ifdef FT_DRIVER_HAS_HINTER
3848 if(mod && FT_DRIVER_HAS_HINTER(mod))
3855 /*************************************************************************
3856 * GetRasterizerCaps (GDI32.@)
3858 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3860 static int hinting = -1;
3863 hinting = is_hinting_enabled();
3865 lprs->nSize = sizeof(RASTERIZER_STATUS);
3866 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
3867 lprs->nLanguageID = 0;
3872 #else /* HAVE_FREETYPE */
3874 BOOL WineEngInit(void)
3878 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3882 BOOL WineEngDestroyFontInstance(HFONT hfont)
3887 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3892 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3893 LPWORD pgi, DWORD flags)
3898 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3899 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3902 ERR("called but we don't have FreeType\n");
3906 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3908 ERR("called but we don't have FreeType\n");
3912 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3913 OUTLINETEXTMETRICW *potm)
3915 ERR("called but we don't have FreeType\n");
3919 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3922 ERR("called but we don't have FreeType\n");
3926 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3929 ERR("called but we don't have FreeType\n");
3933 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3936 ERR("called but we don't have FreeType\n");
3940 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3943 ERR("called but we don't have FreeType\n");
3947 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3950 ERR("called but we don't have FreeType\n");
3954 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3956 ERR("called but we don't have FreeType\n");
3960 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3966 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3972 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3975 return DEFAULT_CHARSET;
3978 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3983 BOOL WINAPI FontIsLinked(HDC hdc)
3988 /*************************************************************************
3989 * GetRasterizerCaps (GDI32.@)
3991 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3993 lprs->nSize = sizeof(RASTERIZER_STATUS);
3995 lprs->nLanguageID = 0;
3999 #endif /* HAVE_FREETYPE */