2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
42 #include "gdi_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(font);
51 #ifdef HAVE_FT2BUILD_H
54 #ifdef HAVE_FREETYPE_FREETYPE_H
55 #include <freetype/freetype.h>
57 #ifdef HAVE_FREETYPE_FTGLYPH_H
58 #include <freetype/ftglyph.h>
60 #ifdef HAVE_FREETYPE_TTTABLES_H
61 #include <freetype/tttables.h>
63 #ifdef HAVE_FREETYPE_FTSNAMES_H
64 #include <freetype/ftsnames.h>
66 # ifdef HAVE_FREETYPE_FTNAMES_H
67 # include <freetype/ftnames.h>
70 #ifdef HAVE_FREETYPE_TTNAMEID_H
71 #include <freetype/ttnameid.h>
73 #ifdef HAVE_FREETYPE_FTOUTLN_H
74 #include <freetype/ftoutln.h>
76 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
77 #include <freetype/internal/sfnt.h>
79 #ifdef HAVE_FREETYPE_FTTRIGON_H
80 #include <freetype/fttrigon.h>
82 #ifdef HAVE_FREETYPE_FTWINFNT_H
83 #include <freetype/ftwinfnt.h>
86 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
90 static FT_Library library = 0;
97 static FT_Version_t FT_Version;
98 static DWORD FT_SimpleVersion;
100 static void *ft_handle = NULL;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
103 MAKE_FUNCPTR(FT_Vector_Unit);
104 MAKE_FUNCPTR(FT_Done_Face);
105 MAKE_FUNCPTR(FT_Get_Char_Index);
106 MAKE_FUNCPTR(FT_Get_Module);
107 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
108 MAKE_FUNCPTR(FT_Init_FreeType);
109 MAKE_FUNCPTR(FT_Load_Glyph);
110 MAKE_FUNCPTR(FT_Matrix_Multiply);
111 MAKE_FUNCPTR(FT_MulFix);
112 MAKE_FUNCPTR(FT_New_Face);
113 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
114 MAKE_FUNCPTR(FT_Outline_Transform);
115 MAKE_FUNCPTR(FT_Outline_Translate);
116 MAKE_FUNCPTR(FT_Select_Charmap);
117 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
118 MAKE_FUNCPTR(FT_Vector_Transform);
119 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
120 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
121 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
122 #ifdef HAVE_FREETYPE_FTWINFNT_H
123 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
126 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
127 #include <fontconfig/fontconfig.h>
128 MAKE_FUNCPTR(FcConfigGetCurrent);
129 MAKE_FUNCPTR(FcFontList);
130 MAKE_FUNCPTR(FcFontSetDestroy);
131 MAKE_FUNCPTR(FcInit);
132 MAKE_FUNCPTR(FcObjectSetAdd);
133 MAKE_FUNCPTR(FcObjectSetCreate);
134 MAKE_FUNCPTR(FcObjectSetDestroy);
135 MAKE_FUNCPTR(FcPatternCreate);
136 MAKE_FUNCPTR(FcPatternDestroy);
137 MAKE_FUNCPTR(FcPatternGet);
138 #ifndef SONAME_LIBFONTCONFIG
139 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
145 #ifndef ft_encoding_none
146 #define FT_ENCODING_NONE ft_encoding_none
148 #ifndef ft_encoding_ms_symbol
149 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
151 #ifndef ft_encoding_unicode
152 #define FT_ENCODING_UNICODE ft_encoding_unicode
154 #ifndef ft_encoding_apple_roman
155 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
158 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
160 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
167 FT_Short internal_leading;
170 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
171 So to let this compile on older versions of FreeType we'll define the
172 new structure here. */
174 FT_Short height, width;
175 FT_Pos size, x_ppem, y_ppem;
178 typedef struct tagFace {
186 FONTSIGNATURE fs_links;
187 FT_Fixed font_version;
189 Bitmap_Size size; /* set if face is a bitmap */
190 BOOL external; /* TRUE if we should manually add this font to the registry */
191 struct tagFamily *family;
194 typedef struct tagFamily {
202 INT adv; /* These three hold to widths of the unrotated chars */
219 typedef struct tagHFONTLIST {
244 struct list hfontlist;
249 OUTLINETEXTMETRICW *potm;
252 struct list child_fonts;
262 #define INIT_GM_SIZE 128
264 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
265 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
266 #define UNUSED_CACHE_SIZE 10
267 static struct list child_font_list = LIST_INIT(child_font_list);
268 static struct list system_links = LIST_INIT(system_links);
270 static struct list font_list = LIST_INIT(font_list);
272 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
273 'R','o','m','a','n','\0'};
274 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
275 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
277 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
278 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
279 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
280 'S','e','r','i','f','\0'};
281 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
282 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
284 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
285 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
286 'W','i','n','d','o','w','s','\\',
287 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
288 'F','o','n','t','s','\0'};
290 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
291 'W','i','n','d','o','w','s',' ','N','T','\\',
292 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
293 'F','o','n','t','s','\0'};
295 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
296 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
297 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
298 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
300 static const WCHAR *SystemFontValues[4] = {
307 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
308 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
310 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
311 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
312 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
313 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
314 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
315 'E','u','r','o','p','e','a','n','\0'};
316 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
317 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
318 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
319 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
320 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
321 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
322 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
323 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
324 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
325 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
326 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
327 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
329 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
339 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
347 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
356 typedef struct tagFontSubst {
359 struct tagFontSubst *next;
362 static FontSubst *substlist = NULL;
363 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
365 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
368 /****************************************
369 * Notes on .fon files
371 * The fonts System, FixedSys and Terminal are special. There are typically multiple
372 * versions installed for different resolutions and codepages. Windows stores which one to use
373 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
375 * FIXEDFON.FON FixedSys
377 * OEMFONT.FON Terminal
378 * LogPixels Current dpi set by the display control panel applet
379 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
380 * also has a LogPixels value that appears to mirror this)
382 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
383 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
384 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
385 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
386 * so that makes sense.
388 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
389 * to be mapped into the registry on Windows 2000 at least).
392 * ega80woa.fon=ega80850.fon
393 * ega40woa.fon=ega40850.fon
394 * cga80woa.fon=cga80850.fon
395 * cga40woa.fon=cga40850.fon
399 static inline BOOL is_win9x(void)
401 return GetVersion() & 0x80000000;
404 This function builds an FT_Fixed from a float. It puts the integer part
405 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
406 It fails if the integer part of the float number is greater than SHORT_MAX.
408 static inline FT_Fixed FT_FixedFromFloat(float f)
411 unsigned short fract = (f - value) * 0xFFFF;
412 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
416 This function builds an FT_Fixed from a FIXED. It simply put f.value
417 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
419 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
421 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
424 #define ADDFONT_EXTERNAL_FONT 0x01
425 #define ADDFONT_FORCE_BITMAP 0x02
426 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
430 TT_Header *pHeader = NULL;
431 WCHAR *FamilyW, *StyleW;
435 struct list *family_elem_ptr, *face_elem_ptr;
437 FT_Long face_index = 0, num_faces;
438 #ifdef HAVE_FREETYPE_FTWINFNT_H
439 FT_WinFNT_HeaderRec winfnt_header;
441 int i, bitmap_num, internal_leading;
445 char *family_name = fake_family;
447 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
448 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
449 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
453 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*/
454 WARN("Ignoring font %s\n", debugstr_a(file));
455 pFT_Done_Face(ft_face);
459 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
460 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
461 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
462 pFT_Done_Face(ft_face);
466 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
467 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
468 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
469 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
470 "Skipping this font.\n", debugstr_a(file));
471 pFT_Done_Face(ft_face);
475 if(!ft_face->family_name || !ft_face->style_name) {
476 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
477 pFT_Done_Face(ft_face);
482 family_name = ft_face->family_name;
486 My_FT_Bitmap_Size *size = NULL;
488 if(!FT_IS_SCALABLE(ft_face))
489 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
491 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
492 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
493 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
496 LIST_FOR_EACH(family_elem_ptr, &font_list) {
497 family = LIST_ENTRY(family_elem_ptr, Family, entry);
498 if(!strcmpW(family->FamilyName, FamilyW))
503 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
504 family->FamilyName = FamilyW;
505 list_init(&family->faces);
506 list_add_tail(&font_list, &family->entry);
508 HeapFree(GetProcessHeap(), 0, FamilyW);
511 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
512 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
513 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
515 internal_leading = 0;
516 memset(&fs, 0, sizeof(fs));
518 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
520 fs.fsCsb[0] = pOS2->ulCodePageRange1;
521 fs.fsCsb[1] = pOS2->ulCodePageRange2;
522 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
523 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
524 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
525 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
526 if(pOS2->version == 0) {
529 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
532 fs.fsCsb[0] |= 1L << 31;
535 #ifdef HAVE_FREETYPE_FTWINFNT_H
536 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
538 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
539 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
540 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
541 memcpy(&fs, &csi.fs, sizeof(csi.fs));
542 internal_leading = winfnt_header.internal_leading;
546 face_elem_ptr = list_head(&family->faces);
547 while(face_elem_ptr) {
548 face = LIST_ENTRY(face_elem_ptr, Face, entry);
549 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
550 if(!strcmpW(face->StyleName, StyleW) &&
551 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
552 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
553 debugstr_w(family->FamilyName), debugstr_w(StyleW),
554 face->font_version, pHeader ? pHeader->Font_Revision : 0);
557 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
558 HeapFree(GetProcessHeap(), 0, StyleW);
559 pFT_Done_Face(ft_face);
562 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
563 TRACE("Original font is newer so skipping this one\n");
564 HeapFree(GetProcessHeap(), 0, StyleW);
565 pFT_Done_Face(ft_face);
568 TRACE("Replacing original with this one\n");
569 list_remove(&face->entry);
570 HeapFree(GetProcessHeap(), 0, face->file);
571 HeapFree(GetProcessHeap(), 0, face->StyleName);
572 HeapFree(GetProcessHeap(), 0, face);
577 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
578 list_add_tail(&family->faces, &face->entry);
579 face->StyleName = StyleW;
580 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
581 strcpy(face->file, file);
582 face->face_index = face_index;
583 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
584 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
585 face->font_version = pHeader ? pHeader->Font_Revision : 0;
586 face->family = family;
587 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
588 memcpy(&face->fs, &fs, sizeof(face->fs));
589 memset(&face->fs_links, 0, sizeof(face->fs_links));
591 if(FT_IS_SCALABLE(ft_face)) {
592 memset(&face->size, 0, sizeof(face->size));
593 face->scalable = TRUE;
595 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
596 size->height, size->width, size->size >> 6,
597 size->x_ppem >> 6, size->y_ppem >> 6);
598 face->size.height = size->height;
599 face->size.width = size->width;
600 face->size.size = size->size;
601 face->size.x_ppem = size->x_ppem;
602 face->size.y_ppem = size->y_ppem;
603 face->size.internal_leading = internal_leading;
604 face->scalable = FALSE;
607 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
608 face->fs.fsCsb[0], face->fs.fsCsb[1],
609 face->fs.fsUsb[0], face->fs.fsUsb[1],
610 face->fs.fsUsb[2], face->fs.fsUsb[3]);
613 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
614 for(i = 0; i < ft_face->num_charmaps; i++) {
615 switch(ft_face->charmaps[i]->encoding) {
616 case FT_ENCODING_UNICODE:
617 case FT_ENCODING_APPLE_ROMAN:
618 face->fs.fsCsb[0] |= 1;
620 case FT_ENCODING_MS_SYMBOL:
621 face->fs.fsCsb[0] |= 1L << 31;
629 if(face->fs.fsCsb[0] & ~(1L << 31))
630 have_installed_roman_font = TRUE;
631 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
633 num_faces = ft_face->num_faces;
634 pFT_Done_Face(ft_face);
635 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
637 } while(num_faces > ++face_index);
641 static void DumpFontList(void)
645 struct list *family_elem_ptr, *face_elem_ptr;
647 LIST_FOR_EACH(family_elem_ptr, &font_list) {
648 family = LIST_ENTRY(family_elem_ptr, Family, entry);
649 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
650 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
651 face = LIST_ENTRY(face_elem_ptr, Face, entry);
652 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
654 TRACE(" %ld", face->size.y_ppem >> 6);
661 static Face *find_face_from_filename(const WCHAR *name)
666 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
667 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
670 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
671 TRACE("looking for %s\n", debugstr_a(nameA));
673 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
675 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
677 file = strrchr(face->file, '/');
682 if(!strcmp(file, nameA))
687 HeapFree(GetProcessHeap(), 0, nameA);
691 static Family *find_family_from_name(const WCHAR *name)
695 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
697 if(!strcmpiW(family->FamilyName, name))
704 static void DumpSubstList(void)
708 for(psub = substlist; psub; psub = psub->next)
709 if(psub->from.charset != -1 || psub->to.charset != -1)
710 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
711 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
713 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
714 debugstr_w(psub->to.name));
718 static LPWSTR strdupW(LPCWSTR p)
721 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
722 ret = HeapAlloc(GetProcessHeap(), 0, len);
727 static LPSTR strdupA(LPCSTR p)
730 DWORD len = (strlen(p) + 1);
731 ret = HeapAlloc(GetProcessHeap(), 0, len);
736 static void split_subst_info(NameCs *nc, LPSTR str)
738 CHAR *p = strrchr(str, ',');
743 nc->charset = strtol(p+1, NULL, 10);
746 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
747 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
748 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
751 static void LoadSubstList(void)
753 FontSubst *psub, **ppsub;
755 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
760 for(psub = substlist; psub;) {
762 HeapFree(GetProcessHeap(), 0, psub->to.name);
763 HeapFree(GetProcessHeap(), 0, psub->from.name);
766 HeapFree(GetProcessHeap(), 0, ptmp);
771 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
772 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
773 &hkey) == ERROR_SUCCESS) {
775 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
776 &valuelen, &datalen, NULL, NULL);
778 valuelen++; /* returned value doesn't include room for '\0' */
779 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
780 data = HeapAlloc(GetProcessHeap(), 0, datalen);
785 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
786 &dlen) == ERROR_SUCCESS) {
787 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
789 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
790 (*ppsub)->next = NULL;
791 split_subst_info(&((*ppsub)->from), value);
792 split_subst_info(&((*ppsub)->to), data);
794 /* Win 2000 doesn't allow mapping between different charsets
795 or mapping of DEFAULT_CHARSET */
796 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
797 (*ppsub)->to.charset == DEFAULT_CHARSET) {
798 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
799 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
800 HeapFree(GetProcessHeap(), 0, *ppsub);
803 ppsub = &((*ppsub)->next);
805 /* reset dlen and vlen */
809 HeapFree(GetProcessHeap(), 0, data);
810 HeapFree(GetProcessHeap(), 0, value);
815 /***********************************************************
816 * The replacement list is a way to map an entire font
817 * family onto another family. For example adding
819 * [HKCU\Software\Wine\Fonts\Replacements]
820 * "Wingdings"="Winedings"
822 * would enumerate the Winedings font both as Winedings and
823 * Wingdings. However if a real Wingdings font is present the
824 * replacement does not take place.
827 static void LoadReplaceList(void)
830 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
835 struct list *family_elem_ptr, *face_elem_ptr;
836 WCHAR old_nameW[200];
838 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
839 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
841 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
842 &valuelen, &datalen, NULL, NULL);
844 valuelen++; /* returned value doesn't include room for '\0' */
845 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
846 data = HeapAlloc(GetProcessHeap(), 0, datalen);
850 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
851 &dlen) == ERROR_SUCCESS) {
852 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
853 /* "NewName"="Oldname" */
854 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
857 /* Find the old family and hence all of the font files
859 LIST_FOR_EACH(family_elem_ptr, &font_list) {
860 family = LIST_ENTRY(family_elem_ptr, Family, entry);
861 if(!strcmpiW(family->FamilyName, old_nameW)) {
862 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
863 face = LIST_ENTRY(face_elem_ptr, Face, entry);
864 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
865 debugstr_w(face->StyleName), value);
866 /* Now add a new entry with the new family name */
867 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
872 /* reset dlen and vlen */
876 HeapFree(GetProcessHeap(), 0, data);
877 HeapFree(GetProcessHeap(), 0, value);
882 /*************************************************************
885 static BOOL init_system_links(void)
887 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
888 'W','i','n','d','o','w','s',' ','N','T','\\',
889 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
890 'S','y','s','t','e','m','L','i','n','k',0};
893 DWORD type, max_val, max_data, val_len, data_len, index;
896 SYSTEM_LINKS *font_link, *system_font_link;
897 CHILD_FONT *child_font;
898 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
899 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
900 static const WCHAR System[] = {'S','y','s','t','e','m',0};
905 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
907 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
908 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
909 data = HeapAlloc(GetProcessHeap(), 0, max_data);
910 val_len = max_val + 1;
913 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
915 TRACE("%s:\n", debugstr_w(value));
917 memset(&fs, 0, sizeof(fs));
918 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
919 font_link->font_name = strdupW(value);
920 list_init(&font_link->links);
921 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
925 CHILD_FONT *child_font;
927 TRACE("\t%s\n", debugstr_w(entry));
929 next = entry + strlenW(entry) + 1;
931 face_name = strchrW(entry, ',');
936 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
938 while(isspaceW(*face_name))
943 face = find_face_from_filename(entry);
946 TRACE("Unable to find file %s\n", debugstr_w(entry));
950 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
951 child_font->file_name = strdupA(face->file);
952 child_font->index = index;
953 child_font->font = NULL;
954 fs.fsCsb[0] |= face->fs.fsCsb[0];
955 fs.fsCsb[1] |= face->fs.fsCsb[1];
956 list_add_tail(&font_link->links, &child_font->entry);
958 family = find_family_from_name(font_link->font_name);
961 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
963 memcpy(&face->fs_links, &fs, sizeof(fs));
966 list_add_tail(&system_links, &font_link->entry);
967 val_len = max_val + 1;
971 HeapFree(GetProcessHeap(), 0, value);
972 HeapFree(GetProcessHeap(), 0, data);
976 /* Explicitly add an entry for the system font, this links to Tahoma and any links
979 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
980 system_font_link->font_name = strdupW(System);
981 list_init(&system_font_link->links);
983 face = find_face_from_filename(tahoma_ttf);
986 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
987 child_font->file_name = strdupA(face->file);
988 child_font->index = 0;
989 child_font->font = NULL;
990 list_add_tail(&system_font_link->links, &child_font->entry);
992 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
994 if(!strcmpiW(font_link->font_name, Tahoma))
996 CHILD_FONT *font_link_entry;
997 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
999 CHILD_FONT *new_child;
1000 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1001 new_child->file_name = strdupA(font_link_entry->file_name);
1002 new_child->index = font_link_entry->index;
1003 new_child->font = NULL;
1004 list_add_tail(&system_font_link->links, &new_child->entry);
1009 list_add_tail(&system_links, &system_font_link->entry);
1013 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1016 struct dirent *dent;
1017 char path[MAX_PATH];
1019 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1021 dir = opendir(dirname);
1023 ERR("Can't open directory %s\n", debugstr_a(dirname));
1026 while((dent = readdir(dir)) != NULL) {
1027 struct stat statbuf;
1029 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1032 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1034 sprintf(path, "%s/%s", dirname, dent->d_name);
1036 if(stat(path, &statbuf) == -1)
1038 WARN("Can't stat %s\n", debugstr_a(path));
1041 if(S_ISDIR(statbuf.st_mode))
1042 ReadFontDir(path, external_fonts);
1044 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1050 static void load_fontconfig_fonts(void)
1052 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1053 void *fc_handle = NULL;
1060 const char *file, *ext;
1062 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1064 TRACE("Wine cannot find the fontconfig library (%s).\n",
1065 SONAME_LIBFONTCONFIG);
1068 #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;}
1069 LOAD_FUNCPTR(FcConfigGetCurrent);
1070 LOAD_FUNCPTR(FcFontList);
1071 LOAD_FUNCPTR(FcFontSetDestroy);
1072 LOAD_FUNCPTR(FcInit);
1073 LOAD_FUNCPTR(FcObjectSetAdd);
1074 LOAD_FUNCPTR(FcObjectSetCreate);
1075 LOAD_FUNCPTR(FcObjectSetDestroy);
1076 LOAD_FUNCPTR(FcPatternCreate);
1077 LOAD_FUNCPTR(FcPatternDestroy);
1078 LOAD_FUNCPTR(FcPatternGet);
1081 if(!pFcInit()) return;
1083 config = pFcConfigGetCurrent();
1084 pat = pFcPatternCreate();
1085 os = pFcObjectSetCreate();
1086 pFcObjectSetAdd(os, FC_FILE);
1087 fontset = pFcFontList(config, pat, os);
1088 if(!fontset) return;
1089 for(i = 0; i < fontset->nfont; i++) {
1090 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1092 if(v.type != FcTypeString) continue;
1093 file = (LPCSTR) v.u.s;
1094 TRACE("fontconfig: %s\n", file);
1096 /* We're just interested in OT/TT fonts for now, so this hack just
1097 picks up the standard extensions to save time loading every other
1099 len = strlen( file );
1100 if(len < 4) continue;
1101 ext = &file[ len - 3 ];
1102 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1103 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1105 pFcFontSetDestroy(fontset);
1106 pFcObjectSetDestroy(os);
1107 pFcPatternDestroy(pat);
1114 static void load_system_fonts(void)
1117 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1118 const WCHAR **value;
1120 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1123 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1124 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1125 strcatW(windowsdir, fontsW);
1126 for(value = SystemFontValues; *value; value++) {
1127 dlen = sizeof(data);
1128 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1130 sprintfW(pathW, fmtW, windowsdir, data);
1131 if((unixname = wine_get_unix_file_name(pathW))) {
1132 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1133 HeapFree(GetProcessHeap(), 0, unixname);
1141 /*************************************************************
1143 * This adds registry entries for any externally loaded fonts
1144 * (fonts from fontconfig or FontDirs). It also deletes entries
1145 * of no longer existing fonts.
1148 static void update_reg_entries(void)
1150 HKEY winkey = 0, externalkey = 0;
1153 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1156 struct list *family_elem_ptr, *face_elem_ptr;
1158 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1159 static const WCHAR spaceW[] = {' ', '\0'};
1162 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1163 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1164 ERR("Can't create Windows font reg key\n");
1167 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1168 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1169 ERR("Can't create external font reg key\n");
1173 /* Delete all external fonts added last time */
1175 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1176 &valuelen, &datalen, NULL, NULL);
1177 valuelen++; /* returned value doesn't include room for '\0' */
1178 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1179 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1181 dlen = datalen * sizeof(WCHAR);
1184 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1185 &dlen) == ERROR_SUCCESS) {
1187 RegDeleteValueW(winkey, valueW);
1188 /* reset dlen and vlen */
1192 HeapFree(GetProcessHeap(), 0, data);
1193 HeapFree(GetProcessHeap(), 0, valueW);
1195 /* Delete the old external fonts key */
1196 RegCloseKey(externalkey);
1198 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1200 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1201 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1202 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1203 ERR("Can't create external font reg key\n");
1207 /* enumerate the fonts and add external ones to the two keys */
1209 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1210 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1211 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1212 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1213 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1214 if(!face->external) continue;
1216 if(strcmpiW(face->StyleName, RegularW))
1217 len = len_fam + strlenW(face->StyleName) + 1;
1218 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1219 strcpyW(valueW, family->FamilyName);
1220 if(len != len_fam) {
1221 strcatW(valueW, spaceW);
1222 strcatW(valueW, face->StyleName);
1224 strcatW(valueW, TrueType);
1225 if((path = strrchr(face->file, '/')) == NULL)
1229 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1231 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1232 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1233 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1234 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1236 HeapFree(GetProcessHeap(), 0, file);
1237 HeapFree(GetProcessHeap(), 0, valueW);
1242 RegCloseKey(externalkey);
1244 RegCloseKey(winkey);
1249 /*************************************************************
1250 * WineEngAddFontResourceEx
1253 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1255 if (ft_handle) /* do it only if we have freetype up and running */
1260 FIXME("Ignoring flags %lx\n", flags);
1262 if((unixname = wine_get_unix_file_name(file)))
1264 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1265 HeapFree(GetProcessHeap(), 0, unixname);
1271 /*************************************************************
1272 * WineEngRemoveFontResourceEx
1275 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1281 static const struct nls_update_font_list
1283 UINT ansi_cp, oem_cp;
1284 const char *oem, *fixed, *system;
1285 const char *courier, *serif, *small, *sserif;
1286 } nls_update_font_list[] =
1288 /* Latin 1 (United States) */
1289 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1292 /* Latin 1 (Multilingual) */
1293 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1294 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1296 /* Eastern Europe */
1297 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1298 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1301 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1302 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1305 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1306 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1309 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1310 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1313 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1314 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1317 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1318 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1321 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1322 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1325 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1329 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1330 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1333 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1334 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1336 /* Chinese Simplified */
1337 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1338 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1341 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1342 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1344 /* Chinese Traditional */
1345 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1346 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1350 inline static HKEY create_fonts_NT_registry_key(void)
1354 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1355 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1359 inline static HKEY create_fonts_9x_registry_key(void)
1363 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1364 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1368 inline static HKEY create_config_fonts_registry_key(void)
1372 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1373 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1377 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1379 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1380 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1381 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1382 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1385 static void update_font_info(void)
1390 UINT i, ansi_cp = 0, oem_cp = 0;
1391 LCID lcid = GetUserDefaultLCID();
1393 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1397 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1399 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1404 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1406 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1408 sprintf(buf, "%08lx", lcid);
1409 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1412 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1413 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1414 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1415 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1417 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1419 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1420 nls_update_font_list[i].oem_cp == oem_cp)
1424 hkey = create_config_fonts_registry_key();
1425 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1426 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1427 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1430 hkey = create_fonts_NT_registry_key();
1431 add_font_list(hkey, &nls_update_font_list[i]);
1434 hkey = create_fonts_9x_registry_key();
1435 add_font_list(hkey, &nls_update_font_list[i]);
1441 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1444 /*************************************************************
1447 * Initialize FreeType library and create a list of available faces
1449 BOOL WineEngInit(void)
1451 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1452 static const WCHAR pathW[] = {'P','a','t','h',0};
1454 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1456 WCHAR windowsdir[MAX_PATH];
1462 /* update locale dependent font info in registry */
1465 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1468 "Wine cannot find the FreeType font library. To enable Wine to\n"
1469 "use TrueType fonts please install a version of FreeType greater than\n"
1470 "or equal to 2.0.5.\n"
1471 "http://www.freetype.org\n");
1475 #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;}
1477 LOAD_FUNCPTR(FT_Vector_Unit)
1478 LOAD_FUNCPTR(FT_Done_Face)
1479 LOAD_FUNCPTR(FT_Get_Char_Index)
1480 LOAD_FUNCPTR(FT_Get_Module)
1481 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1482 LOAD_FUNCPTR(FT_Init_FreeType)
1483 LOAD_FUNCPTR(FT_Load_Glyph)
1484 LOAD_FUNCPTR(FT_Matrix_Multiply)
1485 LOAD_FUNCPTR(FT_MulFix)
1486 LOAD_FUNCPTR(FT_New_Face)
1487 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1488 LOAD_FUNCPTR(FT_Outline_Transform)
1489 LOAD_FUNCPTR(FT_Outline_Translate)
1490 LOAD_FUNCPTR(FT_Select_Charmap)
1491 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1492 LOAD_FUNCPTR(FT_Vector_Transform)
1495 /* Don't warn if this one is missing */
1496 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1497 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1498 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1499 #ifdef HAVE_FREETYPE_FTWINFNT_H
1500 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1502 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1503 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1504 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1505 <= 2.0.3 has FT_Sqrt64 */
1509 if(pFT_Init_FreeType(&library) != 0) {
1510 ERR("Can't init FreeType library\n");
1511 wine_dlclose(ft_handle, NULL, 0);
1515 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1516 if (pFT_Library_Version)
1518 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1520 if (FT_Version.major<=0)
1526 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1527 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1528 ((FT_Version.minor << 8) & 0x00ff00) |
1529 ((FT_Version.patch ) & 0x0000ff);
1531 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1532 ERR("Failed to create font mutex\n");
1535 WaitForSingleObject(font_mutex, INFINITE);
1537 /* load the system fonts */
1538 load_system_fonts();
1540 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1541 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1542 strcatW(windowsdir, fontsW);
1543 if((unixname = wine_get_unix_file_name(windowsdir)))
1545 ReadFontDir(unixname, FALSE);
1546 HeapFree(GetProcessHeap(), 0, unixname);
1549 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1550 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1551 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1553 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1554 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1555 &hkey) == ERROR_SUCCESS) {
1557 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1558 &valuelen, &datalen, NULL, NULL);
1560 valuelen++; /* returned value doesn't include room for '\0' */
1561 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1562 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1565 dlen = datalen * sizeof(WCHAR);
1567 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1568 &dlen) == ERROR_SUCCESS) {
1569 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1571 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1573 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1574 HeapFree(GetProcessHeap(), 0, unixname);
1577 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1579 WCHAR pathW[MAX_PATH];
1580 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1581 sprintfW(pathW, fmtW, windowsdir, data);
1582 if((unixname = wine_get_unix_file_name(pathW)))
1584 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1585 HeapFree(GetProcessHeap(), 0, unixname);
1588 /* reset dlen and vlen */
1593 HeapFree(GetProcessHeap(), 0, data);
1594 HeapFree(GetProcessHeap(), 0, valueW);
1598 load_fontconfig_fonts();
1600 /* then look in any directories that we've specified in the config file */
1601 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1602 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1608 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1610 len += sizeof(WCHAR);
1611 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1612 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1614 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1615 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1616 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1617 TRACE( "got font path %s\n", debugstr_a(valueA) );
1621 LPSTR next = strchr( ptr, ':' );
1622 if (next) *next++ = 0;
1623 ReadFontDir( ptr, TRUE );
1626 HeapFree( GetProcessHeap(), 0, valueA );
1628 HeapFree( GetProcessHeap(), 0, valueW );
1637 update_reg_entries();
1639 init_system_links();
1641 ReleaseMutex(font_mutex);
1645 "Wine cannot find certain functions that it needs inside the FreeType\n"
1646 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1647 "FreeType to at least version 2.0.5.\n"
1648 "http://www.freetype.org\n");
1649 wine_dlclose(ft_handle, NULL, 0);
1655 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1658 TT_HoriHeader *pHori;
1662 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1663 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1665 if(height == 0) height = 16;
1667 /* Calc. height of EM square:
1669 * For +ve lfHeight we have
1670 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1671 * Re-arranging gives:
1672 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1674 * For -ve lfHeight we have
1676 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1677 * with il = winAscent + winDescent - units_per_em]
1682 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1683 ppem = ft_face->units_per_EM * height /
1684 (pHori->Ascender - pHori->Descender);
1686 ppem = ft_face->units_per_EM * height /
1687 (pOS2->usWinAscent + pOS2->usWinDescent);
1695 static LONG load_VDMX(GdiFont, LONG);
1697 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1702 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1703 err = pFT_New_Face(library, file, face_index, &ft_face);
1705 ERR("FT_New_Face rets %d\n", err);
1709 /* set it here, as load_VDMX needs it */
1710 font->ft_face = ft_face;
1712 if(FT_IS_SCALABLE(ft_face)) {
1713 /* load the VDMX table if we have one */
1714 font->ppem = load_VDMX(font, height);
1716 font->ppem = calc_ppem_for_height(ft_face, height);
1718 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1719 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1721 font->ppem = height;
1722 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1723 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1729 static int get_nearest_charset(Face *face, int *cp)
1731 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1732 a single face with the requested charset. The idea is to check if
1733 the selected font supports the current ANSI codepage, if it does
1734 return the corresponding charset, else return the first charset */
1737 int acp = GetACP(), i;
1741 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1742 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1743 return csi.ciCharset;
1745 for(i = 0; i < 32; i++) {
1747 if(face->fs.fsCsb[0] & fs0) {
1748 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1750 return csi.ciCharset;
1753 FIXME("TCI failing on %lx\n", fs0);
1757 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1758 face->fs.fsCsb[0], face->file);
1760 return DEFAULT_CHARSET;
1763 static GdiFont alloc_font(void)
1765 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1766 ret->gmsize = INIT_GM_SIZE;
1767 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1768 ret->gmsize * sizeof(*ret->gm));
1770 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1771 list_init(&ret->hfontlist);
1772 list_init(&ret->child_fonts);
1776 static void free_font(GdiFont font)
1778 struct list *cursor, *cursor2;
1780 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1782 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1783 struct list *first_hfont;
1784 HFONTLIST *hfontlist;
1785 list_remove(cursor);
1788 first_hfont = list_head(&child->font->hfontlist);
1789 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1790 DeleteObject(hfontlist->hfont);
1791 HeapFree(GetProcessHeap(), 0, hfontlist);
1792 free_font(child->font);
1794 HeapFree(GetProcessHeap(), 0, child->file_name);
1795 HeapFree(GetProcessHeap(), 0, child);
1798 if (font->ft_face) pFT_Done_Face(font->ft_face);
1799 HeapFree(GetProcessHeap(), 0, font->potm);
1800 HeapFree(GetProcessHeap(), 0, font->name);
1801 HeapFree(GetProcessHeap(), 0, font->gm);
1802 HeapFree(GetProcessHeap(), 0, font);
1806 /*************************************************************
1809 * load the vdmx entry for the specified height
1812 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1813 ( ( (FT_ULong)_x4 << 24 ) | \
1814 ( (FT_ULong)_x3 << 16 ) | \
1815 ( (FT_ULong)_x2 << 8 ) | \
1818 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1828 static LONG load_VDMX(GdiFont font, LONG height)
1830 BYTE hdr[6], tmp[2], group[4];
1831 BYTE devXRatio, devYRatio;
1832 USHORT numRecs, numRatios;
1833 DWORD result, offset = -1;
1837 /* For documentation on VDMX records, see
1838 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1841 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1843 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1846 /* FIXME: need the real device aspect ratio */
1850 numRecs = GET_BE_WORD(&hdr[2]);
1851 numRatios = GET_BE_WORD(&hdr[4]);
1853 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1854 for(i = 0; i < numRatios; i++) {
1857 offset = (3 * 2) + (i * sizeof(Ratios));
1858 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1861 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1863 if((ratio.xRatio == 0 &&
1864 ratio.yStartRatio == 0 &&
1865 ratio.yEndRatio == 0) ||
1866 (devXRatio == ratio.xRatio &&
1867 devYRatio >= ratio.yStartRatio &&
1868 devYRatio <= ratio.yEndRatio))
1870 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1871 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1872 offset = GET_BE_WORD(tmp);
1878 FIXME("No suitable ratio found\n");
1882 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1884 BYTE startsz, endsz;
1887 recs = GET_BE_WORD(group);
1891 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1893 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1894 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1895 if(result == GDI_ERROR) {
1896 FIXME("Failed to retrieve vTable\n");
1901 for(i = 0; i < recs; i++) {
1902 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1903 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1904 ppem = GET_BE_WORD(&vTable[i * 6]);
1906 if(yMax + -yMin == height) {
1909 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1912 if(yMax + -yMin > height) {
1915 goto end; /* failed */
1917 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1918 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1919 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1925 TRACE("ppem not found for height %ld\n", height);
1929 if(ppem < startsz || ppem > endsz)
1932 for(i = 0; i < recs; i++) {
1934 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1936 if(yPelHeight > ppem)
1939 if(yPelHeight == ppem) {
1940 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1941 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1942 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1948 HeapFree(GetProcessHeap(), 0, vTable);
1954 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1956 if(font->font_desc.hash != fd->hash) return TRUE;
1957 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1958 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1959 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1962 static void calc_hash(FONT_DESC *pfd)
1964 DWORD hash = 0, *ptr, two_chars;
1968 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1970 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1972 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1974 pwc = (WCHAR *)&two_chars;
1976 *pwc = toupperW(*pwc);
1978 *pwc = toupperW(*pwc);
1986 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1991 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1993 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1994 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1997 /* try the in-use list */
1998 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1999 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2000 if(!fontcmp(ret, &fd)) {
2001 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2002 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2003 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2004 if(hflist->hfont == hfont)
2007 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2008 hflist->hfont = hfont;
2009 list_add_head(&ret->hfontlist, &hflist->entry);
2014 /* then the unused list */
2015 font_elem_ptr = list_head(&unused_gdi_font_list);
2016 while(font_elem_ptr) {
2017 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2018 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2019 if(!fontcmp(ret, &fd)) {
2020 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2021 assert(list_empty(&ret->hfontlist));
2022 TRACE("Found %p in unused list\n", ret);
2023 list_remove(&ret->entry);
2024 list_add_head(&gdi_font_list, &ret->entry);
2025 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2026 hflist->hfont = hfont;
2027 list_add_head(&ret->hfontlist, &hflist->entry);
2035 /*************************************************************
2036 * create_child_font_list
2038 static BOOL create_child_font_list(GdiFont font)
2041 SYSTEM_LINKS *font_link;
2042 CHILD_FONT *font_link_entry, *new_child;
2044 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2046 if(!strcmpW(font_link->font_name, font->name))
2048 TRACE("found entry in system list\n");
2049 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2051 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2052 new_child->file_name = strdupA(font_link_entry->file_name);
2053 new_child->index = font_link_entry->index;
2054 new_child->font = NULL;
2055 list_add_tail(&font->child_fonts, &new_child->entry);
2056 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2066 /*************************************************************
2067 * WineEngCreateFontInstance
2070 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2075 struct list *family_elem_ptr, *face_elem_ptr;
2076 INT height, width = 0;
2077 signed int diff = 0, newdiff;
2078 BOOL bd, it, can_use_bitmap;
2083 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2085 struct list *first_hfont = list_head(&ret->hfontlist);
2086 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2087 if(hflist->hfont == hfont)
2091 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2092 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2094 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2095 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2096 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2099 /* check the cache first */
2100 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2101 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2105 TRACE("not in cache\n");
2106 if(list_empty(&font_list)) /* No fonts installed */
2108 TRACE("No fonts installed\n");
2111 if(!have_installed_roman_font)
2113 TRACE("No roman font installed\n");
2119 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2120 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2121 calc_hash(&ret->font_desc);
2122 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2123 hflist->hfont = hfont;
2124 list_add_head(&ret->hfontlist, &hflist->entry);
2127 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2128 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2129 original value lfCharSet. Note this is a special case for
2130 Symbol and doesn't happen at least for "Wingdings*" */
2132 if(!strcmpiW(lf.lfFaceName, SymbolW))
2133 lf.lfCharSet = SYMBOL_CHARSET;
2135 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2136 switch(lf.lfCharSet) {
2137 case DEFAULT_CHARSET:
2138 csi.fs.fsCsb[0] = 0;
2141 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2142 csi.fs.fsCsb[0] = 0;
2148 if(lf.lfFaceName[0] != '\0') {
2150 for(psub = substlist; psub; psub = psub->next)
2151 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
2152 (psub->from.charset == -1 ||
2153 psub->from.charset == lf.lfCharSet))
2156 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2157 debugstr_w(psub->to.name));
2158 strcpyW(lf.lfFaceName, psub->to.name);
2161 /* We want a match on name and charset or just name if
2162 charset was DEFAULT_CHARSET. If the latter then
2163 we fixup the returned charset later in get_nearest_charset
2164 where we'll either use the charset of the current ansi codepage
2165 or if that's unavailable the first charset that the font supports.
2167 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2168 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2169 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2170 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2171 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2172 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2173 if(face->scalable || can_use_bitmap)
2180 /* If requested charset was DEFAULT_CHARSET then try using charset
2181 corresponding to the current ansi codepage */
2182 if(!csi.fs.fsCsb[0]) {
2184 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2185 FIXME("TCI failed on codepage %d\n", acp);
2186 csi.fs.fsCsb[0] = 0;
2188 lf.lfCharSet = csi.ciCharset;
2191 /* Face families are in the top 4 bits of lfPitchAndFamily,
2192 so mask with 0xF0 before testing */
2194 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2195 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2196 strcpyW(lf.lfFaceName, defFixed);
2197 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2198 strcpyW(lf.lfFaceName, defSerif);
2199 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2200 strcpyW(lf.lfFaceName, defSans);
2202 strcpyW(lf.lfFaceName, defSans);
2203 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2204 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2205 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2206 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2207 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2208 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2209 if(face->scalable || can_use_bitmap)
2215 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2216 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2217 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2218 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2219 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2220 if(face->scalable || can_use_bitmap)
2226 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2227 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2228 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2229 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2230 if(face->scalable || can_use_bitmap) {
2231 csi.fs.fsCsb[0] = 0;
2232 FIXME("just using first face for now\n");
2237 FIXME("can't find a single appropriate font - bailing\n");
2242 it = lf.lfItalic ? 1 : 0;
2243 bd = lf.lfWeight > 550 ? 1 : 0;
2245 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2246 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2249 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2250 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2251 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2252 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2256 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2258 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2259 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2260 (diff < 0 && newdiff > diff)) {
2261 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2274 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2275 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2276 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2280 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2282 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2283 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2284 (diff < 0 && newdiff > diff)) {
2285 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2296 if(it && !face->Italic) ret->fake_italic = TRUE;
2297 if(bd && !face->Bold) ret->fake_bold = TRUE;
2300 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2302 if(csi.fs.fsCsb[0]) {
2303 ret->charset = lf.lfCharSet;
2304 ret->codepage = csi.ciACP;
2307 ret->charset = get_nearest_charset(face, &ret->codepage);
2309 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2310 debugstr_w(face->StyleName), face->file, face->face_index);
2312 if(!face->scalable) {
2313 width = face->size.x_ppem >> 6;
2314 height = face->size.y_ppem >> 6;
2316 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2324 if (ret->charset == SYMBOL_CHARSET &&
2325 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2328 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2332 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2335 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2336 ret->name = strdupW(family->FamilyName);
2337 ret->underline = lf.lfUnderline ? 0xff : 0;
2338 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2339 create_child_font_list(ret);
2341 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2343 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2344 list_add_head(&gdi_font_list, &ret->entry);
2348 static void dump_gdi_font_list(void)
2351 struct list *elem_ptr;
2353 TRACE("---------- gdiFont Cache ----------\n");
2354 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2355 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2356 TRACE("gdiFont=%p %s %ld\n",
2357 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2360 TRACE("---------- Unused gdiFont Cache ----------\n");
2361 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2362 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2363 TRACE("gdiFont=%p %s %ld\n",
2364 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2368 /*************************************************************
2369 * WineEngDestroyFontInstance
2371 * free the gdiFont associated with this handle
2374 BOOL WineEngDestroyFontInstance(HFONT handle)
2379 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2382 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2384 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2385 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2386 if(hflist->hfont == handle)
2388 TRACE("removing child font %p from child list\n", gdiFont);
2389 list_remove(&gdiFont->entry);
2394 TRACE("destroying hfont=%p\n", handle);
2396 dump_gdi_font_list();
2398 font_elem_ptr = list_head(&gdi_font_list);
2399 while(font_elem_ptr) {
2400 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2401 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2403 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2404 while(hfontlist_elem_ptr) {
2405 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2406 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2407 if(hflist->hfont == handle) {
2408 list_remove(&hflist->entry);
2409 HeapFree(GetProcessHeap(), 0, hflist);
2413 if(list_empty(&gdiFont->hfontlist)) {
2414 TRACE("Moving to Unused list\n");
2415 list_remove(&gdiFont->entry);
2416 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2421 font_elem_ptr = list_head(&unused_gdi_font_list);
2422 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2423 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2424 while(font_elem_ptr) {
2425 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2426 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2427 TRACE("freeing %p\n", gdiFont);
2428 list_remove(&gdiFont->entry);
2434 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2435 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2437 OUTLINETEXTMETRICW *potm = NULL;
2439 TEXTMETRICW tm, *ptm;
2440 GdiFont font = alloc_font();
2443 if(face->scalable) {
2447 height = face->size.y_ppem >> 6;
2448 width = face->size.x_ppem >> 6;
2451 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2457 font->name = strdupW(face->family->FamilyName);
2459 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2461 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2463 potm = HeapAlloc(GetProcessHeap(), 0, size);
2464 WineEngGetOutlineTextMetrics(font, size, potm);
2465 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2467 WineEngGetTextMetrics(font, &tm);
2471 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2472 pntm->ntmTm.tmAscent = ptm->tmAscent;
2473 pntm->ntmTm.tmDescent = ptm->tmDescent;
2474 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2475 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2476 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2477 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2478 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2479 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2480 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2481 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2482 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2483 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2484 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2485 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2486 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2487 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2488 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2489 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2490 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2491 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2492 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2493 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2494 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2496 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2497 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2498 *ptype |= RASTER_FONTTYPE;
2500 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2501 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2502 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2504 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2505 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2506 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2509 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2511 lstrcpynW(pelf->elfLogFont.lfFaceName,
2512 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2514 lstrcpynW(pelf->elfFullName,
2515 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2517 lstrcpynW(pelf->elfStyle,
2518 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2521 HeapFree(GetProcessHeap(), 0, potm);
2523 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2525 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2526 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2527 pelf->elfStyle[0] = '\0';
2530 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2535 /*************************************************************
2539 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2543 struct list *family_elem_ptr, *face_elem_ptr;
2545 NEWTEXTMETRICEXW ntm;
2546 DWORD type, ret = 1;
2552 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2554 if(plf->lfFaceName[0]) {
2556 for(psub = substlist; psub; psub = psub->next)
2557 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2558 (psub->from.charset == -1 ||
2559 psub->from.charset == plf->lfCharSet))
2562 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2563 debugstr_w(psub->to.name));
2564 memcpy(&lf, plf, sizeof(lf));
2565 strcpyW(lf.lfFaceName, psub->to.name);
2569 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2570 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2571 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2572 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2573 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2574 GetEnumStructs(face, &elf, &ntm, &type);
2575 for(i = 0; i < 32; i++) {
2576 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2577 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2578 strcpyW(elf.elfScript, OEM_DOSW);
2579 i = 32; /* break out of loop */
2580 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2583 fs.fsCsb[0] = 1L << i;
2585 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2587 csi.ciCharset = DEFAULT_CHARSET;
2588 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2589 if(csi.ciCharset != DEFAULT_CHARSET) {
2590 elf.elfLogFont.lfCharSet =
2591 ntm.ntmTm.tmCharSet = csi.ciCharset;
2593 strcpyW(elf.elfScript, ElfScriptsW[i]);
2595 FIXME("Unknown elfscript for bit %d\n", i);
2598 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2599 debugstr_w(elf.elfLogFont.lfFaceName),
2600 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2601 csi.ciCharset, type, debugstr_w(elf.elfScript),
2602 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2603 ntm.ntmTm.ntmFlags);
2604 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2611 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2612 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2613 face_elem_ptr = list_head(&family->faces);
2614 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2615 GetEnumStructs(face, &elf, &ntm, &type);
2616 for(i = 0; i < 32; i++) {
2617 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2618 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2619 strcpyW(elf.elfScript, OEM_DOSW);
2620 i = 32; /* break out of loop */
2621 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2624 fs.fsCsb[0] = 1L << i;
2626 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2628 csi.ciCharset = DEFAULT_CHARSET;
2629 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2630 if(csi.ciCharset != DEFAULT_CHARSET) {
2631 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2634 strcpyW(elf.elfScript, ElfScriptsW[i]);
2636 FIXME("Unknown elfscript for bit %d\n", i);
2639 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2640 debugstr_w(elf.elfLogFont.lfFaceName),
2641 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2642 csi.ciCharset, type, debugstr_w(elf.elfScript),
2643 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2644 ntm.ntmTm.ntmFlags);
2645 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2654 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2656 pt->x.value = vec->x >> 6;
2657 pt->x.fract = (vec->x & 0x3f) << 10;
2658 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2659 pt->y.value = vec->y >> 6;
2660 pt->y.fract = (vec->y & 0x3f) << 10;
2661 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2665 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2667 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2668 WCHAR wc = (WCHAR)glyph;
2672 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, &default_used) || default_used)
2675 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2676 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2680 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2681 glyph = glyph + 0xf000;
2682 return pFT_Get_Char_Index(font->ft_face, glyph);
2685 /*************************************************************
2686 * WineEngGetGlyphIndices
2688 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2690 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2691 LPWORD pgi, DWORD flags)
2695 for(i = 0; i < count; i++)
2696 pgi[i] = get_glyph_index(font, lpstr[i]);
2701 /*************************************************************
2702 * WineEngGetGlyphOutline
2704 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2705 * except that the first parameter is the HWINEENGFONT of the font in
2706 * question rather than an HDC.
2709 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2710 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2713 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2714 FT_Face ft_face = font->ft_face;
2715 FT_UInt glyph_index;
2716 DWORD width, height, pitch, needed = 0;
2717 FT_Bitmap ft_bitmap;
2719 INT left, right, top = 0, bottom = 0;
2721 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2722 float widthRatio = 1.0;
2723 FT_Matrix transMat = identityMat;
2724 BOOL needsTransform = FALSE;
2727 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2728 buflen, buf, lpmat);
2730 if(format & GGO_GLYPH_INDEX) {
2731 glyph_index = glyph;
2732 format &= ~GGO_GLYPH_INDEX;
2734 glyph_index = get_glyph_index(font, glyph);
2736 if(glyph_index >= font->gmsize) {
2737 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2738 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2739 font->gmsize * sizeof(*font->gm));
2741 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2742 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2743 return 1; /* FIXME */
2747 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2748 load_flags |= FT_LOAD_NO_BITMAP;
2750 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2753 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2757 /* Scaling factor */
2758 if (font->aveWidth && font->potm) {
2759 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2762 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2763 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2765 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2766 font->gm[glyph_index].lsb = left >> 6;
2767 font->gm[glyph_index].bbx = (right - left) >> 6;
2769 /* Scaling transform */
2770 if(font->aveWidth) {
2772 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2775 scaleMat.yy = (1 << 16);
2777 pFT_Matrix_Multiply(&scaleMat, &transMat);
2778 needsTransform = TRUE;
2781 /* Rotation transform */
2782 if(font->orientation) {
2783 FT_Matrix rotationMat;
2785 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2786 pFT_Vector_Unit(&vecAngle, angle);
2787 rotationMat.xx = vecAngle.x;
2788 rotationMat.xy = -vecAngle.y;
2789 rotationMat.yx = -rotationMat.xy;
2790 rotationMat.yy = rotationMat.xx;
2792 pFT_Matrix_Multiply(&rotationMat, &transMat);
2793 needsTransform = TRUE;
2796 /* Extra transformation specified by caller */
2799 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2800 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2801 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2802 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2803 pFT_Matrix_Multiply(&extraMat, &transMat);
2804 needsTransform = TRUE;
2807 if(!needsTransform) {
2808 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2809 bottom = (ft_face->glyph->metrics.horiBearingY -
2810 ft_face->glyph->metrics.height) & -64;
2811 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2812 lpgm->gmCellIncY = 0;
2816 for(xc = 0; xc < 2; xc++) {
2817 for(yc = 0; yc < 2; yc++) {
2818 vec.x = (ft_face->glyph->metrics.horiBearingX +
2819 xc * ft_face->glyph->metrics.width);
2820 vec.y = ft_face->glyph->metrics.horiBearingY -
2821 yc * ft_face->glyph->metrics.height;
2822 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2823 pFT_Vector_Transform(&vec, &transMat);
2824 if(xc == 0 && yc == 0) {
2825 left = right = vec.x;
2826 top = bottom = vec.y;
2828 if(vec.x < left) left = vec.x;
2829 else if(vec.x > right) right = vec.x;
2830 if(vec.y < bottom) bottom = vec.y;
2831 else if(vec.y > top) top = vec.y;
2836 right = (right + 63) & -64;
2837 bottom = bottom & -64;
2838 top = (top + 63) & -64;
2840 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2841 vec.x = ft_face->glyph->metrics.horiAdvance;
2843 pFT_Vector_Transform(&vec, &transMat);
2844 lpgm->gmCellIncX = (vec.x+63) >> 6;
2845 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2847 lpgm->gmBlackBoxX = (right - left) >> 6;
2848 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2849 lpgm->gmptGlyphOrigin.x = left >> 6;
2850 lpgm->gmptGlyphOrigin.y = top >> 6;
2852 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2853 font->gm[glyph_index].init = TRUE;
2855 if(format == GGO_METRICS)
2856 return 1; /* FIXME */
2858 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2859 TRACE("loaded a bitmap\n");
2865 width = lpgm->gmBlackBoxX;
2866 height = lpgm->gmBlackBoxY;
2867 pitch = ((width + 31) >> 5) << 2;
2868 needed = pitch * height;
2870 if(!buf || !buflen) break;
2872 switch(ft_face->glyph->format) {
2873 case ft_glyph_format_bitmap:
2875 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2876 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2877 INT h = ft_face->glyph->bitmap.rows;
2879 memcpy(dst, src, w);
2880 src += ft_face->glyph->bitmap.pitch;
2886 case ft_glyph_format_outline:
2887 ft_bitmap.width = width;
2888 ft_bitmap.rows = height;
2889 ft_bitmap.pitch = pitch;
2890 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2891 ft_bitmap.buffer = buf;
2893 if(needsTransform) {
2894 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2897 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2899 /* Note: FreeType will only set 'black' bits for us. */
2900 memset(buf, 0, needed);
2901 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2905 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2910 case GGO_GRAY2_BITMAP:
2911 case GGO_GRAY4_BITMAP:
2912 case GGO_GRAY8_BITMAP:
2913 case WINE_GGO_GRAY16_BITMAP:
2915 unsigned int mult, row, col;
2918 width = lpgm->gmBlackBoxX;
2919 height = lpgm->gmBlackBoxY;
2920 pitch = (width + 3) / 4 * 4;
2921 needed = pitch * height;
2923 if(!buf || !buflen) break;
2924 ft_bitmap.width = width;
2925 ft_bitmap.rows = height;
2926 ft_bitmap.pitch = pitch;
2927 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2928 ft_bitmap.buffer = buf;
2930 if(needsTransform) {
2931 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2934 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2936 memset(ft_bitmap.buffer, 0, buflen);
2938 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2940 if(format == GGO_GRAY2_BITMAP)
2942 else if(format == GGO_GRAY4_BITMAP)
2944 else if(format == GGO_GRAY8_BITMAP)
2946 else if(format == WINE_GGO_GRAY16_BITMAP)
2954 for(row = 0; row < height; row++) {
2956 for(col = 0; col < width; col++, ptr++) {
2957 *ptr = (((int)*ptr) * mult + 128) / 256;
2966 int contour, point = 0, first_pt;
2967 FT_Outline *outline = &ft_face->glyph->outline;
2968 TTPOLYGONHEADER *pph;
2970 DWORD pph_start, cpfx, type;
2972 if(buflen == 0) buf = NULL;
2974 if (needsTransform && buf) {
2975 pFT_Outline_Transform(outline, &transMat);
2978 for(contour = 0; contour < outline->n_contours; contour++) {
2980 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2983 pph->dwType = TT_POLYGON_TYPE;
2984 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2986 needed += sizeof(*pph);
2988 while(point <= outline->contours[contour]) {
2989 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2990 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2991 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2995 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2998 } while(point <= outline->contours[contour] &&
2999 (outline->tags[point] & FT_Curve_Tag_On) ==
3000 (outline->tags[point-1] & FT_Curve_Tag_On));
3001 /* At the end of a contour Windows adds the start point, but
3003 if(point > outline->contours[contour] &&
3004 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3006 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3008 } else if(point <= outline->contours[contour] &&
3009 outline->tags[point] & FT_Curve_Tag_On) {
3010 /* add closing pt for bezier */
3012 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3020 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3023 pph->cb = needed - pph_start;
3029 /* Convert the quadratic Beziers to cubic Beziers.
3030 The parametric eqn for a cubic Bezier is, from PLRM:
3031 r(t) = at^3 + bt^2 + ct + r0
3032 with the control points:
3037 A quadratic Beizer has the form:
3038 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3040 So equating powers of t leads to:
3041 r1 = 2/3 p1 + 1/3 p0
3042 r2 = 2/3 p1 + 1/3 p2
3043 and of course r0 = p0, r3 = p2
3046 int contour, point = 0, first_pt;
3047 FT_Outline *outline = &ft_face->glyph->outline;
3048 TTPOLYGONHEADER *pph;
3050 DWORD pph_start, cpfx, type;
3051 FT_Vector cubic_control[4];
3052 if(buflen == 0) buf = NULL;
3054 if (needsTransform && buf) {
3055 pFT_Outline_Transform(outline, &transMat);
3058 for(contour = 0; contour < outline->n_contours; contour++) {
3060 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3063 pph->dwType = TT_POLYGON_TYPE;
3064 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3066 needed += sizeof(*pph);
3068 while(point <= outline->contours[contour]) {
3069 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3070 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3071 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3074 if(type == TT_PRIM_LINE) {
3076 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3080 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3083 /* FIXME: Possible optimization in endpoint calculation
3084 if there are two consecutive curves */
3085 cubic_control[0] = outline->points[point-1];
3086 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3087 cubic_control[0].x += outline->points[point].x + 1;
3088 cubic_control[0].y += outline->points[point].y + 1;
3089 cubic_control[0].x >>= 1;
3090 cubic_control[0].y >>= 1;
3092 if(point+1 > outline->contours[contour])
3093 cubic_control[3] = outline->points[first_pt];
3095 cubic_control[3] = outline->points[point+1];
3096 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3097 cubic_control[3].x += outline->points[point].x + 1;
3098 cubic_control[3].y += outline->points[point].y + 1;
3099 cubic_control[3].x >>= 1;
3100 cubic_control[3].y >>= 1;
3103 /* r1 = 1/3 p0 + 2/3 p1
3104 r2 = 1/3 p2 + 2/3 p1 */
3105 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3106 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3107 cubic_control[2] = cubic_control[1];
3108 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3109 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3110 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3111 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3113 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3114 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3115 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3120 } while(point <= outline->contours[contour] &&
3121 (outline->tags[point] & FT_Curve_Tag_On) ==
3122 (outline->tags[point-1] & FT_Curve_Tag_On));
3123 /* At the end of a contour Windows adds the start point,
3124 but only for Beziers and we've already done that.
3126 if(point <= outline->contours[contour] &&
3127 outline->tags[point] & FT_Curve_Tag_On) {
3128 /* This is the closing pt of a bezier, but we've already
3129 added it, so just inc point and carry on */
3136 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3139 pph->cb = needed - pph_start;
3145 FIXME("Unsupported format %d\n", format);
3151 static BOOL get_bitmap_text_metrics(GdiFont font)
3153 FT_Face ft_face = font->ft_face;
3154 #ifdef HAVE_FREETYPE_FTWINFNT_H
3155 FT_WinFNT_HeaderRec winfnt_header;
3157 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3158 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3159 font->potm->otmSize = size;
3161 #define TM font->potm->otmTextMetrics
3162 #ifdef HAVE_FREETYPE_FTWINFNT_H
3163 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3165 TM.tmHeight = winfnt_header.pixel_height;
3166 TM.tmAscent = winfnt_header.ascent;
3167 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3168 TM.tmInternalLeading = winfnt_header.internal_leading;
3169 TM.tmExternalLeading = winfnt_header.external_leading;
3170 TM.tmAveCharWidth = winfnt_header.avg_width;
3171 TM.tmMaxCharWidth = winfnt_header.max_width;
3172 TM.tmWeight = winfnt_header.weight;
3174 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3175 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3176 TM.tmFirstChar = winfnt_header.first_char;
3177 TM.tmLastChar = winfnt_header.last_char;
3178 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3179 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3180 TM.tmItalic = winfnt_header.italic;
3181 TM.tmUnderlined = font->underline;
3182 TM.tmStruckOut = font->strikeout;
3183 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3184 TM.tmCharSet = winfnt_header.charset;
3189 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3190 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3191 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3192 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3193 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3194 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3195 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3196 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3198 TM.tmDigitizedAspectX = 96; /* FIXME */
3199 TM.tmDigitizedAspectY = 96; /* FIXME */
3201 TM.tmLastChar = 255;
3202 TM.tmDefaultChar = 32;
3203 TM.tmBreakChar = 32;
3204 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3205 TM.tmUnderlined = font->underline;
3206 TM.tmStruckOut = font->strikeout;
3207 /* NB inverted meaning of TMPF_FIXED_PITCH */
3208 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3209 TM.tmCharSet = font->charset;
3216 /*************************************************************
3217 * WineEngGetTextMetrics
3220 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3223 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3224 if(!get_bitmap_text_metrics(font))
3227 if(!font->potm) return FALSE;
3228 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3230 if (font->aveWidth) {
3231 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3237 /*************************************************************
3238 * WineEngGetOutlineTextMetrics
3241 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3242 OUTLINETEXTMETRICW *potm)
3244 FT_Face ft_face = font->ft_face;
3245 UINT needed, lenfam, lensty, ret;
3247 TT_HoriHeader *pHori;
3248 TT_Postscript *pPost;
3249 FT_Fixed x_scale, y_scale;
3250 WCHAR *family_nameW, *style_nameW;
3251 static const WCHAR spaceW[] = {' ', '\0'};
3253 INT ascent, descent;
3255 TRACE("font=%p\n", font);
3257 if(!FT_IS_SCALABLE(ft_face))
3261 if(cbSize >= font->potm->otmSize)
3262 memcpy(potm, font->potm, font->potm->otmSize);
3263 return font->potm->otmSize;
3267 needed = sizeof(*potm);
3269 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3270 family_nameW = strdupW(font->name);
3272 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3274 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3275 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3276 style_nameW, lensty/sizeof(WCHAR));
3278 /* These names should be read from the TT name table */
3280 /* length of otmpFamilyName */
3283 /* length of otmpFaceName */
3284 if(!strcasecmp(ft_face->style_name, "regular")) {
3285 needed += lenfam; /* just the family name */
3287 needed += lenfam + lensty; /* family + " " + style */
3290 /* length of otmpStyleName */
3293 /* length of otmpFullName */
3294 needed += lenfam + lensty;
3297 x_scale = ft_face->size->metrics.x_scale;
3298 y_scale = ft_face->size->metrics.y_scale;
3300 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3302 FIXME("Can't find OS/2 table - not TT font?\n");
3307 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3309 FIXME("Can't find HHEA table - not TT font?\n");
3314 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3316 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",
3317 pOS2->usWinAscent, pOS2->usWinDescent,
3318 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3319 ft_face->ascender, ft_face->descender, ft_face->height,
3320 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3321 ft_face->bbox.yMax, ft_face->bbox.yMin);
3323 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3324 font->potm->otmSize = needed;
3326 #define TM font->potm->otmTextMetrics
3328 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3329 ascent = pHori->Ascender;
3330 descent = -pHori->Descender;
3332 ascent = pOS2->usWinAscent;
3333 descent = pOS2->usWinDescent;
3337 TM.tmAscent = font->yMax;
3338 TM.tmDescent = -font->yMin;
3339 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3341 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3342 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3343 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3344 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3347 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3350 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3352 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3353 ((ascent + descent) -
3354 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3356 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3357 if (TM.tmAveCharWidth == 0) {
3358 TM.tmAveCharWidth = 1;
3360 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3361 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3363 TM.tmDigitizedAspectX = 300;
3364 TM.tmDigitizedAspectY = 300;
3365 TM.tmFirstChar = pOS2->usFirstCharIndex;
3366 TM.tmLastChar = pOS2->usLastCharIndex;
3367 TM.tmDefaultChar = pOS2->usDefaultChar;
3368 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3369 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3370 TM.tmUnderlined = font->underline;
3371 TM.tmStruckOut = font->strikeout;
3373 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3374 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3375 (pOS2->version == 0xFFFFU ||
3376 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3377 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3379 TM.tmPitchAndFamily = 0;
3381 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3382 case PAN_FAMILY_SCRIPT:
3383 TM.tmPitchAndFamily |= FF_SCRIPT;
3385 case PAN_FAMILY_DECORATIVE:
3386 case PAN_FAMILY_PICTORIAL:
3387 TM.tmPitchAndFamily |= FF_DECORATIVE;
3389 case PAN_FAMILY_TEXT_DISPLAY:
3390 if(TM.tmPitchAndFamily == 0) /* fixed */
3391 TM.tmPitchAndFamily = FF_MODERN;
3393 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3394 case PAN_SERIF_NORMAL_SANS:
3395 case PAN_SERIF_OBTUSE_SANS:
3396 case PAN_SERIF_PERP_SANS:
3397 TM.tmPitchAndFamily |= FF_SWISS;
3400 TM.tmPitchAndFamily |= FF_ROMAN;
3405 TM.tmPitchAndFamily |= FF_DONTCARE;
3408 if(FT_IS_SCALABLE(ft_face))
3409 TM.tmPitchAndFamily |= TMPF_VECTOR;
3410 if(FT_IS_SFNT(ft_face))
3411 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3413 TM.tmCharSet = font->charset;
3416 font->potm->otmFiller = 0;
3417 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3418 font->potm->otmfsSelection = pOS2->fsSelection;
3419 font->potm->otmfsType = pOS2->fsType;
3420 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3421 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3422 font->potm->otmItalicAngle = 0; /* POST table */
3423 font->potm->otmEMSquare = ft_face->units_per_EM;
3424 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3425 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3426 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3427 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3428 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3429 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3430 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3431 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3432 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3433 font->potm->otmMacAscent = 0; /* where do these come from ? */
3434 font->potm->otmMacDescent = 0;
3435 font->potm->otmMacLineGap = 0;
3436 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3437 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3438 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3439 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3440 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3441 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3442 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3443 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3444 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3445 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3446 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3448 font->potm->otmsUnderscoreSize = 0;
3449 font->potm->otmsUnderscorePosition = 0;
3451 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3452 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3455 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3456 cp = (char*)font->potm + sizeof(*font->potm);
3457 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3458 strcpyW((WCHAR*)cp, family_nameW);
3460 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3461 strcpyW((WCHAR*)cp, style_nameW);
3463 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3464 strcpyW((WCHAR*)cp, family_nameW);
3465 if(strcasecmp(ft_face->style_name, "regular")) {
3466 strcatW((WCHAR*)cp, spaceW);
3467 strcatW((WCHAR*)cp, style_nameW);
3468 cp += lenfam + lensty;
3471 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3472 strcpyW((WCHAR*)cp, family_nameW);
3473 strcatW((WCHAR*)cp, spaceW);
3474 strcatW((WCHAR*)cp, style_nameW);
3477 if(potm && needed <= cbSize)
3478 memcpy(potm, font->potm, font->potm->otmSize);
3481 HeapFree(GetProcessHeap(), 0, style_nameW);
3482 HeapFree(GetProcessHeap(), 0, family_nameW);
3487 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3489 HFONTLIST *hfontlist;
3490 child->font = alloc_font();
3491 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3492 if(!child->font->ft_face)
3494 free_font(child->font);
3499 child->font->orientation = font->orientation;
3500 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3501 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3502 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3503 child->font->base_font = font;
3504 list_add_head(&child_font_list, &child->font->entry);
3505 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3509 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3512 CHILD_FONT *child_font;
3515 font = font->base_font;
3517 *linked_font = font;
3519 if((*glyph = get_glyph_index(font, c)))
3522 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3524 if(!child_font->font)
3525 if(!load_child_font(font, child_font))
3528 if(!child_font->font->ft_face)
3530 g = get_glyph_index(child_font->font, c);
3534 *linked_font = child_font->font;
3541 /*************************************************************
3542 * WineEngGetCharWidth
3545 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3550 FT_UInt glyph_index;
3551 GdiFont linked_font;
3553 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3555 for(c = firstChar; c <= lastChar; c++) {
3556 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3557 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3558 &gm, 0, NULL, NULL);
3559 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3564 /*************************************************************
3565 * WineEngGetCharABCWidths
3568 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3573 FT_UInt glyph_index;
3574 GdiFont linked_font;
3576 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3578 if(!FT_IS_SCALABLE(font->ft_face))
3581 for(c = firstChar; c <= lastChar; c++) {
3582 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3583 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3584 &gm, 0, NULL, NULL);
3585 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3586 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3587 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3588 linked_font->gm[glyph_index].bbx;
3593 /*************************************************************
3594 * WineEngGetTextExtentPoint
3597 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3603 FT_UInt glyph_index;
3604 GdiFont linked_font;
3606 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3610 WineEngGetTextMetrics(font, &tm);
3611 size->cy = tm.tmHeight;
3613 for(idx = 0; idx < count; idx++) {
3614 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3615 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3616 &gm, 0, NULL, NULL);
3617 size->cx += linked_font->gm[glyph_index].adv;
3619 TRACE("return %ld,%ld\n", size->cx, size->cy);
3623 /*************************************************************
3624 * WineEngGetTextExtentPointI
3627 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3634 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3637 WineEngGetTextMetrics(font, &tm);
3638 size->cy = tm.tmHeight;
3640 for(idx = 0; idx < count; idx++) {
3641 WineEngGetGlyphOutline(font, indices[idx],
3642 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3644 size->cx += font->gm[indices[idx]].adv;
3646 TRACE("return %ld,%ld\n", size->cx, size->cy);
3650 /*************************************************************
3651 * WineEngGetFontData
3654 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3657 FT_Face ft_face = font->ft_face;
3661 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3662 font, table, offset, buf, cbData);
3664 if(!FT_IS_SFNT(ft_face))
3672 if(table) { /* MS tags differ in endidness from FT ones */
3673 table = table >> 24 | table << 24 |
3674 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3677 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3678 if(pFT_Load_Sfnt_Table)
3679 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3680 else { /* Do it the hard way */
3681 TT_Face tt_face = (TT_Face) ft_face;
3682 SFNT_Interface *sfnt;
3683 if (FT_Version.major==2 && FT_Version.minor==0)
3686 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3690 /* A field was added in the middle of the structure in 2.1.x */
3691 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3693 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3696 TRACE("Can't find table %08lx.\n", table);
3702 /*************************************************************
3703 * WineEngGetTextFace
3706 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3709 lstrcpynW(str, font->name, count);
3710 return strlenW(font->name);
3712 return strlenW(font->name) + 1;
3715 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3717 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3718 return font->charset;
3721 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3723 GdiFont font = dc->gdiFont, linked_font;
3724 struct list *first_hfont;
3727 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3728 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3729 if(font == linked_font)
3730 *new_hfont = dc->hFont;
3733 first_hfont = list_head(&linked_font->hfontlist);
3734 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3741 /*************************************************************
3744 BOOL WINAPI FontIsLinked(HDC hdc)
3746 DC *dc = DC_GetDCPtr(hdc);
3749 if(!dc) return FALSE;
3750 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3752 GDI_ReleaseObj(hdc);
3753 TRACE("returning %d\n", ret);
3757 static BOOL is_hinting_enabled(void)
3759 FT_Module mod = pFT_Get_Module(library, "truetype");
3760 if(mod && FT_DRIVER_HAS_HINTER(mod))
3766 /*************************************************************************
3767 * GetRasterizerCaps (GDI32.@)
3769 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3771 static int hinting = -1;
3774 hinting = is_hinting_enabled();
3776 lprs->nSize = sizeof(RASTERIZER_STATUS);
3777 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
3778 lprs->nLanguageID = 0;
3783 #else /* HAVE_FREETYPE */
3785 BOOL WineEngInit(void)
3789 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3793 BOOL WineEngDestroyFontInstance(HFONT hfont)
3798 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3803 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3804 LPWORD pgi, DWORD flags)
3809 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3810 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3813 ERR("called but we don't have FreeType\n");
3817 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3819 ERR("called but we don't have FreeType\n");
3823 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3824 OUTLINETEXTMETRICW *potm)
3826 ERR("called but we don't have FreeType\n");
3830 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3833 ERR("called but we don't have FreeType\n");
3837 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3840 ERR("called but we don't have FreeType\n");
3844 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3847 ERR("called but we don't have FreeType\n");
3851 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3854 ERR("called but we don't have FreeType\n");
3858 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3861 ERR("called but we don't have FreeType\n");
3865 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3867 ERR("called but we don't have FreeType\n");
3871 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3877 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3883 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3886 return DEFAULT_CHARSET;
3889 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3894 BOOL WINAPI FontIsLinked(HDC hdc)
3899 /*************************************************************************
3900 * GetRasterizerCaps (GDI32.@)
3902 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
3904 lprs->nSize = sizeof(RASTERIZER_STATUS);
3906 lprs->nLanguageID = 0;
3910 #endif /* HAVE_FREETYPE */