2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
42 #include "gdi_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(font);
51 #ifdef HAVE_FT2BUILD_H
54 #ifdef HAVE_FREETYPE_FREETYPE_H
55 #include <freetype/freetype.h>
57 #ifdef HAVE_FREETYPE_FTGLYPH_H
58 #include <freetype/ftglyph.h>
60 #ifdef HAVE_FREETYPE_TTTABLES_H
61 #include <freetype/tttables.h>
63 #ifdef HAVE_FREETYPE_FTSNAMES_H
64 #include <freetype/ftsnames.h>
66 # ifdef HAVE_FREETYPE_FTNAMES_H
67 # include <freetype/ftnames.h>
70 #ifdef HAVE_FREETYPE_TTNAMEID_H
71 #include <freetype/ttnameid.h>
73 #ifdef HAVE_FREETYPE_FTOUTLN_H
74 #include <freetype/ftoutln.h>
76 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
77 #include <freetype/internal/sfnt.h>
79 #ifdef HAVE_FREETYPE_FTTRIGON_H
80 #include <freetype/fttrigon.h>
82 #ifdef HAVE_FREETYPE_FTWINFNT_H
83 #include <freetype/ftwinfnt.h>
86 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
90 static FT_Library library = 0;
97 static FT_Version_t FT_Version;
98 static DWORD FT_SimpleVersion;
100 static void *ft_handle = NULL;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
103 MAKE_FUNCPTR(FT_Vector_Unit);
104 MAKE_FUNCPTR(FT_Done_Face);
105 MAKE_FUNCPTR(FT_Get_Char_Index);
106 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
107 MAKE_FUNCPTR(FT_Init_FreeType);
108 MAKE_FUNCPTR(FT_Load_Glyph);
109 MAKE_FUNCPTR(FT_Matrix_Multiply);
110 MAKE_FUNCPTR(FT_MulFix);
111 MAKE_FUNCPTR(FT_New_Face);
112 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
113 MAKE_FUNCPTR(FT_Outline_Transform);
114 MAKE_FUNCPTR(FT_Outline_Translate);
115 MAKE_FUNCPTR(FT_Select_Charmap);
116 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
117 MAKE_FUNCPTR(FT_Vector_Transform);
118 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
119 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
120 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
121 #ifdef HAVE_FREETYPE_FTWINFNT_H
122 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
125 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
126 #include <fontconfig/fontconfig.h>
127 MAKE_FUNCPTR(FcConfigGetCurrent);
128 MAKE_FUNCPTR(FcFontList);
129 MAKE_FUNCPTR(FcFontSetDestroy);
130 MAKE_FUNCPTR(FcInit);
131 MAKE_FUNCPTR(FcObjectSetAdd);
132 MAKE_FUNCPTR(FcObjectSetCreate);
133 MAKE_FUNCPTR(FcObjectSetDestroy);
134 MAKE_FUNCPTR(FcPatternCreate);
135 MAKE_FUNCPTR(FcPatternDestroy);
136 MAKE_FUNCPTR(FcPatternGet);
137 #ifndef SONAME_LIBFONTCONFIG
138 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
144 #ifndef ft_encoding_none
145 #define FT_ENCODING_NONE ft_encoding_none
147 #ifndef ft_encoding_ms_symbol
148 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
150 #ifndef ft_encoding_unicode
151 #define FT_ENCODING_UNICODE ft_encoding_unicode
153 #ifndef ft_encoding_apple_roman
154 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
157 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
159 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
166 FT_Short internal_leading;
169 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
170 So to let this compile on older versions of FreeType we'll define the
171 new structure here. */
173 FT_Short height, width;
174 FT_Pos size, x_ppem, y_ppem;
177 typedef struct tagFace {
185 FONTSIGNATURE fs_links;
186 FT_Fixed font_version;
188 Bitmap_Size size; /* set if face is a bitmap */
189 BOOL external; /* TRUE if we should manually add this font to the registry */
190 struct tagFamily *family;
193 typedef struct tagFamily {
201 INT adv; /* These three hold to widths of the unrotated chars */
218 typedef struct tagHFONTLIST {
243 struct list hfontlist;
248 OUTLINETEXTMETRICW *potm;
251 struct list child_fonts;
261 #define INIT_GM_SIZE 128
263 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
264 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
265 #define UNUSED_CACHE_SIZE 10
266 static struct list child_font_list = LIST_INIT(child_font_list);
267 static struct list system_links = LIST_INIT(system_links);
269 static struct list font_list = LIST_INIT(font_list);
271 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
272 'R','o','m','a','n','\0'};
273 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
274 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
276 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
277 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
278 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
279 'S','e','r','i','f','\0'};
280 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
281 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
283 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
284 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
285 'W','i','n','d','o','w','s','\\',
286 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
287 'F','o','n','t','s','\0'};
289 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
290 'W','i','n','d','o','w','s',' ','N','T','\\',
291 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
292 'F','o','n','t','s','\0'};
294 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
295 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
296 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
297 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
299 static const WCHAR *SystemFontValues[4] = {
306 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
307 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
309 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
310 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
311 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
312 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
313 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
314 'E','u','r','o','p','e','a','n','\0'};
315 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
316 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
317 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
318 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
319 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
320 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
321 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
322 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
323 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
324 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
325 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
326 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
328 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
338 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
346 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
355 typedef struct tagFontSubst {
358 struct tagFontSubst *next;
361 static FontSubst *substlist = NULL;
362 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
364 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
367 /****************************************
368 * Notes on .fon files
370 * The fonts System, FixedSys and Terminal are special. There are typically multiple
371 * versions installed for different resolutions and codepages. Windows stores which one to use
372 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
374 * FIXEDFON.FON FixedSys
376 * OEMFONT.FON Terminal
377 * LogPixels Current dpi set by the display control panel applet
378 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
379 * also has a LogPixels value that appears to mirror this)
381 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
382 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
383 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
384 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
385 * so that makes sense.
387 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
388 * to be mapped into the registry on Windows 2000 at least).
391 * ega80woa.fon=ega80850.fon
392 * ega40woa.fon=ega40850.fon
393 * cga80woa.fon=cga80850.fon
394 * cga40woa.fon=cga40850.fon
398 static inline BOOL is_win9x(void)
400 return GetVersion() & 0x80000000;
403 This function builds an FT_Fixed from a float. It puts the integer part
404 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
405 It fails if the integer part of the float number is greater than SHORT_MAX.
407 static inline FT_Fixed FT_FixedFromFloat(float f)
410 unsigned short fract = (f - value) * 0xFFFF;
411 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
415 This function builds an FT_Fixed from a FIXED. It simply put f.value
416 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
418 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
420 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
423 #define ADDFONT_EXTERNAL_FONT 0x01
424 #define ADDFONT_FORCE_BITMAP 0x02
425 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
429 TT_Header *pHeader = NULL;
430 WCHAR *FamilyW, *StyleW;
434 struct list *family_elem_ptr, *face_elem_ptr;
436 FT_Long face_index = 0, num_faces;
437 #ifdef HAVE_FREETYPE_FTWINFNT_H
438 FT_WinFNT_HeaderRec winfnt_header;
440 int i, bitmap_num, internal_leading;
444 char *family_name = fake_family;
446 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
447 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
448 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
452 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*/
453 pFT_Done_Face(ft_face);
457 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
458 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
459 pFT_Done_Face(ft_face);
463 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
464 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
465 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
466 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
467 "Skipping this font.\n", debugstr_a(file));
468 pFT_Done_Face(ft_face);
472 if(!ft_face->family_name || !ft_face->style_name) {
473 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
474 pFT_Done_Face(ft_face);
479 family_name = ft_face->family_name;
483 My_FT_Bitmap_Size *size = NULL;
485 if(!FT_IS_SCALABLE(ft_face))
486 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
488 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
489 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
490 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
493 LIST_FOR_EACH(family_elem_ptr, &font_list) {
494 family = LIST_ENTRY(family_elem_ptr, Family, entry);
495 if(!strcmpW(family->FamilyName, FamilyW))
500 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
501 family->FamilyName = FamilyW;
502 list_init(&family->faces);
503 list_add_tail(&font_list, &family->entry);
505 HeapFree(GetProcessHeap(), 0, FamilyW);
508 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
509 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
510 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
512 internal_leading = 0;
513 memset(&fs, 0, sizeof(fs));
515 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
517 fs.fsCsb[0] = pOS2->ulCodePageRange1;
518 fs.fsCsb[1] = pOS2->ulCodePageRange2;
519 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
520 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
521 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
522 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
523 if(pOS2->version == 0) {
526 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
529 fs.fsCsb[0] |= 1L << 31;
532 #ifdef HAVE_FREETYPE_FTWINFNT_H
533 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
535 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
536 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
537 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
538 memcpy(&fs, &csi.fs, sizeof(csi.fs));
539 internal_leading = winfnt_header.internal_leading;
543 face_elem_ptr = list_head(&family->faces);
544 while(face_elem_ptr) {
545 face = LIST_ENTRY(face_elem_ptr, Face, entry);
546 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
547 if(!strcmpW(face->StyleName, StyleW) &&
548 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
549 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
550 debugstr_w(family->FamilyName), debugstr_w(StyleW),
551 face->font_version, pHeader ? pHeader->Font_Revision : 0);
554 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
555 HeapFree(GetProcessHeap(), 0, StyleW);
556 pFT_Done_Face(ft_face);
559 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
560 TRACE("Original font is newer so skipping this one\n");
561 HeapFree(GetProcessHeap(), 0, StyleW);
562 pFT_Done_Face(ft_face);
565 TRACE("Replacing original with this one\n");
566 list_remove(&face->entry);
567 HeapFree(GetProcessHeap(), 0, face->file);
568 HeapFree(GetProcessHeap(), 0, face->StyleName);
569 HeapFree(GetProcessHeap(), 0, face);
574 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
575 list_add_tail(&family->faces, &face->entry);
576 face->StyleName = StyleW;
577 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
578 strcpy(face->file, file);
579 face->face_index = face_index;
580 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
581 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
582 face->font_version = pHeader ? pHeader->Font_Revision : 0;
583 face->family = family;
584 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
585 memcpy(&face->fs, &fs, sizeof(face->fs));
586 memset(&face->fs_links, 0, sizeof(face->fs_links));
588 if(FT_IS_SCALABLE(ft_face)) {
589 memset(&face->size, 0, sizeof(face->size));
590 face->scalable = TRUE;
592 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
593 size->height, size->width, size->size >> 6,
594 size->x_ppem >> 6, size->y_ppem >> 6);
595 face->size.height = size->height;
596 face->size.width = size->width;
597 face->size.size = size->size;
598 face->size.x_ppem = size->x_ppem;
599 face->size.y_ppem = size->y_ppem;
600 face->size.internal_leading = internal_leading;
601 face->scalable = FALSE;
604 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
605 face->fs.fsCsb[0], face->fs.fsCsb[1],
606 face->fs.fsUsb[0], face->fs.fsUsb[1],
607 face->fs.fsUsb[2], face->fs.fsUsb[3]);
610 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
611 for(i = 0; i < ft_face->num_charmaps; i++) {
612 switch(ft_face->charmaps[i]->encoding) {
613 case FT_ENCODING_UNICODE:
614 case FT_ENCODING_APPLE_ROMAN:
615 face->fs.fsCsb[0] |= 1;
617 case FT_ENCODING_MS_SYMBOL:
618 face->fs.fsCsb[0] |= 1L << 31;
626 if(face->fs.fsCsb[0] & ~(1L << 31))
627 have_installed_roman_font = TRUE;
628 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
630 num_faces = ft_face->num_faces;
631 pFT_Done_Face(ft_face);
632 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
634 } while(num_faces > ++face_index);
638 static void DumpFontList(void)
642 struct list *family_elem_ptr, *face_elem_ptr;
644 LIST_FOR_EACH(family_elem_ptr, &font_list) {
645 family = LIST_ENTRY(family_elem_ptr, Family, entry);
646 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
647 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
648 face = LIST_ENTRY(face_elem_ptr, Face, entry);
649 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
651 TRACE(" %ld", face->size.y_ppem >> 6);
658 static Face *find_face_from_filename(WCHAR *name)
663 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
664 char *nameA = HeapAlloc(GetProcessHeap(), 0, len);
667 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, nameA, len, NULL, NULL);
668 TRACE("looking for %s\n", debugstr_a(nameA));
670 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
672 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
674 file = strrchr(face->file, '/');
679 if(!strcmp(file, nameA))
684 HeapFree(GetProcessHeap(), 0, nameA);
688 static Family *find_family_from_name(WCHAR *name)
692 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
694 if(!strcmpiW(family->FamilyName, name))
701 static void DumpSubstList(void)
705 for(psub = substlist; psub; psub = psub->next)
706 if(psub->from.charset != -1 || psub->to.charset != -1)
707 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
708 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
710 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
711 debugstr_w(psub->to.name));
715 static LPWSTR strdupW(LPCWSTR p)
718 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
719 ret = HeapAlloc(GetProcessHeap(), 0, len);
724 static LPSTR strdupA(LPCSTR p)
727 DWORD len = (strlen(p) + 1);
728 ret = HeapAlloc(GetProcessHeap(), 0, len);
733 static void split_subst_info(NameCs *nc, LPSTR str)
735 CHAR *p = strrchr(str, ',');
740 nc->charset = strtol(p+1, NULL, 10);
743 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
744 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
745 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
748 static void LoadSubstList(void)
750 FontSubst *psub, **ppsub;
752 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
757 for(psub = substlist; psub;) {
759 HeapFree(GetProcessHeap(), 0, psub->to.name);
760 HeapFree(GetProcessHeap(), 0, psub->from.name);
763 HeapFree(GetProcessHeap(), 0, ptmp);
768 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
769 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
770 &hkey) == ERROR_SUCCESS) {
772 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
773 &valuelen, &datalen, NULL, NULL);
775 valuelen++; /* returned value doesn't include room for '\0' */
776 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
777 data = HeapAlloc(GetProcessHeap(), 0, datalen);
782 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
783 &dlen) == ERROR_SUCCESS) {
784 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
786 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
787 (*ppsub)->next = NULL;
788 split_subst_info(&((*ppsub)->from), value);
789 split_subst_info(&((*ppsub)->to), data);
791 /* Win 2000 doesn't allow mapping between different charsets
792 or mapping of DEFAULT_CHARSET */
793 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
794 (*ppsub)->to.charset == DEFAULT_CHARSET) {
795 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
796 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
797 HeapFree(GetProcessHeap(), 0, *ppsub);
800 ppsub = &((*ppsub)->next);
802 /* reset dlen and vlen */
806 HeapFree(GetProcessHeap(), 0, data);
807 HeapFree(GetProcessHeap(), 0, value);
812 /***********************************************************
813 * The replacement list is a way to map an entire font
814 * family onto another family. For example adding
816 * [HKCU\Software\Wine\Fonts\Replacements]
817 * "Wingdings"="Winedings"
819 * would enumerate the Winedings font both as Winedings and
820 * Wingdings. However if a real Wingdings font is present the
821 * replacement does not take place.
824 static void LoadReplaceList(void)
827 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
832 struct list *family_elem_ptr, *face_elem_ptr;
833 WCHAR old_nameW[200];
835 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
836 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
838 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
839 &valuelen, &datalen, NULL, NULL);
841 valuelen++; /* returned value doesn't include room for '\0' */
842 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
843 data = HeapAlloc(GetProcessHeap(), 0, datalen);
847 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
848 &dlen) == ERROR_SUCCESS) {
849 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
850 /* "NewName"="Oldname" */
851 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
854 /* Find the old family and hence all of the font files
856 LIST_FOR_EACH(family_elem_ptr, &font_list) {
857 family = LIST_ENTRY(family_elem_ptr, Family, entry);
858 if(!strcmpiW(family->FamilyName, old_nameW)) {
859 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
860 face = LIST_ENTRY(face_elem_ptr, Face, entry);
861 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
862 debugstr_w(face->StyleName), value);
863 /* Now add a new entry with the new family name */
864 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
869 /* reset dlen and vlen */
873 HeapFree(GetProcessHeap(), 0, data);
874 HeapFree(GetProcessHeap(), 0, value);
879 /*************************************************************
882 static BOOL init_system_links(void)
884 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
885 'W','i','n','d','o','w','s',' ','N','T','\\',
886 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
887 'S','y','s','t','e','m','L','i','n','k',0};
890 DWORD type, max_val, max_data, val_len, data_len, index;
893 SYSTEM_LINKS *font_link, *system_font_link;
894 CHILD_FONT *child_font;
895 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
896 static const WCHAR System[] = {'S','y','s','t','e','m',0};
901 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
903 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
904 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
905 data = HeapAlloc(GetProcessHeap(), 0, max_data);
906 val_len = max_val + 1;
909 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
911 TRACE("%s:\n", debugstr_w(value));
913 memset(&fs, 0, sizeof(fs));
914 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
915 font_link->font_name = strdupW(value);
916 list_init(&font_link->links);
917 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
921 CHILD_FONT *child_font;
923 TRACE("\t%s\n", debugstr_w(entry));
925 next = entry + strlenW(entry) + 1;
927 face_name = strchrW(entry, ',');
932 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
934 while(isspaceW(*face_name))
939 face = find_face_from_filename(entry);
942 TRACE("Unable to find file %s\n", debugstr_w(entry));
946 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
947 child_font->file_name = strdupA(face->file);
948 child_font->index = index;
949 child_font->font = NULL;
950 fs.fsCsb[0] |= face->fs.fsCsb[0];
951 fs.fsCsb[1] |= face->fs.fsCsb[1];
952 list_add_tail(&font_link->links, &child_font->entry);
954 family = find_family_from_name(font_link->font_name);
957 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
959 memcpy(&face->fs_links, &fs, sizeof(fs));
962 list_add_tail(&system_links, &font_link->entry);
963 val_len = max_val + 1;
967 HeapFree(GetProcessHeap(), 0, value);
968 HeapFree(GetProcessHeap(), 0, data);
972 /* Explicitly add an entry for the system font, this links to Tahoma and any links
974 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
975 system_font_link->font_name = strdupW(System);
976 list_init(&system_font_link->links);
977 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
978 child_font->file_name = strdupA("Tahoma.ttf");
979 child_font->index = 0;
980 child_font->font = NULL;
981 list_add_tail(&system_font_link->links, &child_font->entry);
982 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
984 if(!strcmpW(font_link->font_name, Tahoma))
986 CHILD_FONT *font_link_entry;
987 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
989 CHILD_FONT *new_child;
990 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
991 new_child->file_name = strdupA(font_link_entry->file_name);
992 new_child->index = font_link_entry->index;
993 new_child->font = NULL;
994 list_add_tail(&system_font_link->links, &new_child->entry);
999 list_add_tail(&system_links, &system_font_link->entry);
1003 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1006 struct dirent *dent;
1007 char path[MAX_PATH];
1009 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1011 dir = opendir(dirname);
1013 ERR("Can't open directory %s\n", debugstr_a(dirname));
1016 while((dent = readdir(dir)) != NULL) {
1017 struct stat statbuf;
1019 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1022 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1024 sprintf(path, "%s/%s", dirname, dent->d_name);
1026 if(stat(path, &statbuf) == -1)
1028 WARN("Can't stat %s\n", debugstr_a(path));
1031 if(S_ISDIR(statbuf.st_mode))
1032 ReadFontDir(path, external_fonts);
1034 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1040 static void load_fontconfig_fonts(void)
1042 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1043 void *fc_handle = NULL;
1050 const char *file, *ext;
1052 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1054 TRACE("Wine cannot find the fontconfig library (%s).\n",
1055 SONAME_LIBFONTCONFIG);
1058 #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;}
1059 LOAD_FUNCPTR(FcConfigGetCurrent);
1060 LOAD_FUNCPTR(FcFontList);
1061 LOAD_FUNCPTR(FcFontSetDestroy);
1062 LOAD_FUNCPTR(FcInit);
1063 LOAD_FUNCPTR(FcObjectSetAdd);
1064 LOAD_FUNCPTR(FcObjectSetCreate);
1065 LOAD_FUNCPTR(FcObjectSetDestroy);
1066 LOAD_FUNCPTR(FcPatternCreate);
1067 LOAD_FUNCPTR(FcPatternDestroy);
1068 LOAD_FUNCPTR(FcPatternGet);
1071 if(!pFcInit()) return;
1073 config = pFcConfigGetCurrent();
1074 pat = pFcPatternCreate();
1075 os = pFcObjectSetCreate();
1076 pFcObjectSetAdd(os, FC_FILE);
1077 fontset = pFcFontList(config, pat, os);
1078 if(!fontset) return;
1079 for(i = 0; i < fontset->nfont; i++) {
1080 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1082 if(v.type != FcTypeString) continue;
1083 file = (LPCSTR) v.u.s;
1084 TRACE("fontconfig: %s\n", file);
1086 /* We're just interested in OT/TT fonts for now, so this hack just
1087 picks up the standard extensions to save time loading every other
1089 len = strlen( file );
1090 if(len < 4) continue;
1091 ext = &file[ len - 3 ];
1092 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1093 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1095 pFcFontSetDestroy(fontset);
1096 pFcObjectSetDestroy(os);
1097 pFcPatternDestroy(pat);
1104 static void load_system_fonts(void)
1107 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1108 const WCHAR **value;
1110 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1113 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1114 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1115 strcatW(windowsdir, fontsW);
1116 for(value = SystemFontValues; *value; value++) {
1117 dlen = sizeof(data);
1118 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1120 sprintfW(pathW, fmtW, windowsdir, data);
1121 if((unixname = wine_get_unix_file_name(pathW))) {
1122 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1123 HeapFree(GetProcessHeap(), 0, unixname);
1131 /*************************************************************
1133 * This adds registry entries for any externally loaded fonts
1134 * (fonts from fontconfig or FontDirs). It also deletes entries
1135 * of no longer existing fonts.
1138 static void update_reg_entries(void)
1140 HKEY winkey = 0, externalkey = 0;
1143 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1146 struct list *family_elem_ptr, *face_elem_ptr;
1148 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1149 static const WCHAR spaceW[] = {' ', '\0'};
1152 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1153 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1154 ERR("Can't create Windows font reg key\n");
1157 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1158 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1159 ERR("Can't create external font reg key\n");
1163 /* Delete all external fonts added last time */
1165 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1166 &valuelen, &datalen, NULL, NULL);
1167 valuelen++; /* returned value doesn't include room for '\0' */
1168 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1169 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1171 dlen = datalen * sizeof(WCHAR);
1174 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1175 &dlen) == ERROR_SUCCESS) {
1177 RegDeleteValueW(winkey, valueW);
1178 /* reset dlen and vlen */
1182 HeapFree(GetProcessHeap(), 0, data);
1183 HeapFree(GetProcessHeap(), 0, valueW);
1185 /* Delete the old external fonts key */
1186 RegCloseKey(externalkey);
1188 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1190 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1191 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1192 ERR("Can't create external font reg key\n");
1196 /* enumerate the fonts and add external ones to the two keys */
1198 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1199 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1200 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1201 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1202 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1203 if(!face->external) continue;
1205 if(strcmpiW(face->StyleName, RegularW))
1206 len = len_fam + strlenW(face->StyleName) + 1;
1207 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1208 strcpyW(valueW, family->FamilyName);
1209 if(len != len_fam) {
1210 strcatW(valueW, spaceW);
1211 strcatW(valueW, face->StyleName);
1213 strcatW(valueW, TrueType);
1214 if((path = strrchr(face->file, '/')) == NULL)
1218 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1220 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1221 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1222 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1223 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1225 HeapFree(GetProcessHeap(), 0, file);
1226 HeapFree(GetProcessHeap(), 0, valueW);
1231 RegCloseKey(externalkey);
1233 RegCloseKey(winkey);
1238 /*************************************************************
1239 * WineEngAddFontResourceEx
1242 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1244 if (ft_handle) /* do it only if we have freetype up and running */
1249 FIXME("Ignoring flags %lx\n", flags);
1251 if((unixname = wine_get_unix_file_name(file)))
1253 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1254 HeapFree(GetProcessHeap(), 0, unixname);
1260 /*************************************************************
1261 * WineEngRemoveFontResourceEx
1264 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1270 /*************************************************************
1273 * Initialize FreeType library and create a list of available faces
1275 BOOL WineEngInit(void)
1277 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1278 static const WCHAR pathW[] = {'P','a','t','h',0};
1280 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1282 WCHAR windowsdir[MAX_PATH];
1288 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1291 "Wine cannot find the FreeType font library. To enable Wine to\n"
1292 "use TrueType fonts please install a version of FreeType greater than\n"
1293 "or equal to 2.0.5.\n"
1294 "http://www.freetype.org\n");
1298 #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;}
1300 LOAD_FUNCPTR(FT_Vector_Unit)
1301 LOAD_FUNCPTR(FT_Done_Face)
1302 LOAD_FUNCPTR(FT_Get_Char_Index)
1303 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1304 LOAD_FUNCPTR(FT_Init_FreeType)
1305 LOAD_FUNCPTR(FT_Load_Glyph)
1306 LOAD_FUNCPTR(FT_Matrix_Multiply)
1307 LOAD_FUNCPTR(FT_MulFix)
1308 LOAD_FUNCPTR(FT_New_Face)
1309 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1310 LOAD_FUNCPTR(FT_Outline_Transform)
1311 LOAD_FUNCPTR(FT_Outline_Translate)
1312 LOAD_FUNCPTR(FT_Select_Charmap)
1313 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1314 LOAD_FUNCPTR(FT_Vector_Transform)
1317 /* Don't warn if this one is missing */
1318 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1319 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1320 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1321 #ifdef HAVE_FREETYPE_FTWINFNT_H
1322 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1324 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1325 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1326 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1327 <= 2.0.3 has FT_Sqrt64 */
1331 if(pFT_Init_FreeType(&library) != 0) {
1332 ERR("Can't init FreeType library\n");
1333 wine_dlclose(ft_handle, NULL, 0);
1337 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1338 if (pFT_Library_Version)
1340 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1342 if (FT_Version.major<=0)
1348 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1349 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1350 ((FT_Version.minor << 8) & 0x00ff00) |
1351 ((FT_Version.patch ) & 0x0000ff);
1353 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1354 ERR("Failed to create font mutex\n");
1357 WaitForSingleObject(font_mutex, INFINITE);
1359 /* load the system fonts */
1360 load_system_fonts();
1362 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1363 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1364 strcatW(windowsdir, fontsW);
1365 if((unixname = wine_get_unix_file_name(windowsdir)))
1367 ReadFontDir(unixname, FALSE);
1368 HeapFree(GetProcessHeap(), 0, unixname);
1371 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1372 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1373 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1375 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1376 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1377 &hkey) == ERROR_SUCCESS) {
1379 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1380 &valuelen, &datalen, NULL, NULL);
1382 valuelen++; /* returned value doesn't include room for '\0' */
1383 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1384 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1387 dlen = datalen * sizeof(WCHAR);
1389 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1390 &dlen) == ERROR_SUCCESS) {
1391 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1393 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1395 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1396 HeapFree(GetProcessHeap(), 0, unixname);
1399 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1401 WCHAR pathW[MAX_PATH];
1402 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1403 sprintfW(pathW, fmtW, windowsdir, data);
1404 if((unixname = wine_get_unix_file_name(pathW)))
1406 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1407 HeapFree(GetProcessHeap(), 0, unixname);
1410 /* reset dlen and vlen */
1415 HeapFree(GetProcessHeap(), 0, data);
1416 HeapFree(GetProcessHeap(), 0, valueW);
1420 load_fontconfig_fonts();
1422 /* then look in any directories that we've specified in the config file */
1423 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1424 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1430 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1432 len += sizeof(WCHAR);
1433 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1434 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1436 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1437 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1438 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1439 TRACE( "got font path %s\n", debugstr_a(valueA) );
1443 LPSTR next = strchr( ptr, ':' );
1444 if (next) *next++ = 0;
1445 ReadFontDir( ptr, TRUE );
1448 HeapFree( GetProcessHeap(), 0, valueA );
1450 HeapFree( GetProcessHeap(), 0, valueW );
1459 update_reg_entries();
1461 init_system_links();
1463 ReleaseMutex(font_mutex);
1467 "Wine cannot find certain functions that it needs inside the FreeType\n"
1468 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1469 "FreeType to at least version 2.0.5.\n"
1470 "http://www.freetype.org\n");
1471 wine_dlclose(ft_handle, NULL, 0);
1477 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1480 TT_HoriHeader *pHori;
1484 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1485 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1487 if(height == 0) height = 16;
1489 /* Calc. height of EM square:
1491 * For +ve lfHeight we have
1492 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1493 * Re-arranging gives:
1494 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1496 * For -ve lfHeight we have
1498 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1499 * with il = winAscent + winDescent - units_per_em]
1504 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1505 ppem = ft_face->units_per_EM * height /
1506 (pHori->Ascender - pHori->Descender);
1508 ppem = ft_face->units_per_EM * height /
1509 (pOS2->usWinAscent + pOS2->usWinDescent);
1517 static LONG load_VDMX(GdiFont, LONG);
1519 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1524 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1525 err = pFT_New_Face(library, file, face_index, &ft_face);
1527 ERR("FT_New_Face rets %d\n", err);
1531 /* set it here, as load_VDMX needs it */
1532 font->ft_face = ft_face;
1534 if(FT_IS_SCALABLE(ft_face)) {
1535 /* load the VDMX table if we have one */
1536 font->ppem = load_VDMX(font, height);
1538 font->ppem = calc_ppem_for_height(ft_face, height);
1540 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1541 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1543 font->ppem = height;
1544 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1545 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1551 static int get_nearest_charset(Face *face, int *cp)
1553 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1554 a single face with the requested charset. The idea is to check if
1555 the selected font supports the current ANSI codepage, if it does
1556 return the corresponding charset, else return the first charset */
1559 int acp = GetACP(), i;
1563 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1564 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1565 return csi.ciCharset;
1567 for(i = 0; i < 32; i++) {
1569 if(face->fs.fsCsb[0] & fs0) {
1570 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1572 return csi.ciCharset;
1575 FIXME("TCI failing on %lx\n", fs0);
1579 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1580 face->fs.fsCsb[0], face->file);
1582 return DEFAULT_CHARSET;
1585 static GdiFont alloc_font(void)
1587 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1588 ret->gmsize = INIT_GM_SIZE;
1589 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1590 ret->gmsize * sizeof(*ret->gm));
1592 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1593 list_init(&ret->hfontlist);
1594 list_init(&ret->child_fonts);
1598 static void free_font(GdiFont font)
1600 struct list *cursor, *cursor2;
1602 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1604 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1605 struct list *first_hfont;
1606 HFONTLIST *hfontlist;
1607 list_remove(cursor);
1608 first_hfont = list_head(&child->font->hfontlist);
1609 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1610 DeleteObject(hfontlist->hfont);
1611 HeapFree(GetProcessHeap(), 0, hfontlist);
1612 free_font(child->font);
1613 HeapFree(GetProcessHeap(), 0, child->file_name);
1614 HeapFree(GetProcessHeap(), 0, child);
1617 if (font->ft_face) pFT_Done_Face(font->ft_face);
1618 HeapFree(GetProcessHeap(), 0, font->potm);
1619 HeapFree(GetProcessHeap(), 0, font->name);
1620 HeapFree(GetProcessHeap(), 0, font->gm);
1621 HeapFree(GetProcessHeap(), 0, font);
1625 /*************************************************************
1628 * load the vdmx entry for the specified height
1631 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1632 ( ( (FT_ULong)_x4 << 24 ) | \
1633 ( (FT_ULong)_x3 << 16 ) | \
1634 ( (FT_ULong)_x2 << 8 ) | \
1637 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1647 static LONG load_VDMX(GdiFont font, LONG height)
1649 BYTE hdr[6], tmp[2], group[4];
1650 BYTE devXRatio, devYRatio;
1651 USHORT numRecs, numRatios;
1652 DWORD result, offset = -1;
1656 /* For documentation on VDMX records, see
1657 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1660 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1662 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1665 /* FIXME: need the real device aspect ratio */
1669 numRecs = GET_BE_WORD(&hdr[2]);
1670 numRatios = GET_BE_WORD(&hdr[4]);
1672 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1673 for(i = 0; i < numRatios; i++) {
1676 offset = (3 * 2) + (i * sizeof(Ratios));
1677 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1680 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1682 if((ratio.xRatio == 0 &&
1683 ratio.yStartRatio == 0 &&
1684 ratio.yEndRatio == 0) ||
1685 (devXRatio == ratio.xRatio &&
1686 devYRatio >= ratio.yStartRatio &&
1687 devYRatio <= ratio.yEndRatio))
1689 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1690 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1691 offset = GET_BE_WORD(tmp);
1697 FIXME("No suitable ratio found\n");
1701 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1703 BYTE startsz, endsz;
1706 recs = GET_BE_WORD(group);
1710 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1712 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1713 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1714 if(result == GDI_ERROR) {
1715 FIXME("Failed to retrieve vTable\n");
1720 for(i = 0; i < recs; i++) {
1721 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1722 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1723 ppem = GET_BE_WORD(&vTable[i * 6]);
1725 if(yMax + -yMin == height) {
1728 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1731 if(yMax + -yMin > height) {
1734 goto end; /* failed */
1736 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1737 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1738 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1744 TRACE("ppem not found for height %ld\n", height);
1748 if(ppem < startsz || ppem > endsz)
1751 for(i = 0; i < recs; i++) {
1753 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1755 if(yPelHeight > ppem)
1758 if(yPelHeight == ppem) {
1759 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1760 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1761 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1767 HeapFree(GetProcessHeap(), 0, vTable);
1773 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1775 if(font->font_desc.hash != fd->hash) return TRUE;
1776 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1777 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1778 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1781 static void calc_hash(FONT_DESC *pfd)
1783 DWORD hash = 0, *ptr, two_chars;
1787 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1789 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1791 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1793 pwc = (WCHAR *)&two_chars;
1795 *pwc = toupperW(*pwc);
1797 *pwc = toupperW(*pwc);
1805 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1810 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1812 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1813 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1816 /* try the in-use list */
1817 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1818 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1819 if(!fontcmp(ret, &fd)) {
1820 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1821 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1822 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1823 if(hflist->hfont == hfont)
1826 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1827 hflist->hfont = hfont;
1828 list_add_head(&ret->hfontlist, &hflist->entry);
1833 /* then the unused list */
1834 font_elem_ptr = list_head(&unused_gdi_font_list);
1835 while(font_elem_ptr) {
1836 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1837 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1838 if(!fontcmp(ret, &fd)) {
1839 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1840 assert(list_empty(&ret->hfontlist));
1841 TRACE("Found %p in unused list\n", ret);
1842 list_remove(&ret->entry);
1843 list_add_head(&gdi_font_list, &ret->entry);
1844 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1845 hflist->hfont = hfont;
1846 list_add_head(&ret->hfontlist, &hflist->entry);
1854 /*************************************************************
1855 * create_child_font_list
1857 static BOOL create_child_font_list(GdiFont font)
1860 SYSTEM_LINKS *font_link;
1861 CHILD_FONT *font_link_entry, *new_child;
1863 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1865 if(!strcmpW(font_link->font_name, font->name))
1867 TRACE("found entry in system list\n");
1868 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1870 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1871 new_child->file_name = strdupA(font_link_entry->file_name);
1872 new_child->index = font_link_entry->index;
1873 new_child->font = NULL;
1874 list_add_tail(&font->child_fonts, &new_child->entry);
1875 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
1885 /*************************************************************
1886 * WineEngCreateFontInstance
1889 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1894 struct list *family_elem_ptr, *face_elem_ptr;
1895 INT height, width = 0;
1896 signed int diff = 0, newdiff;
1897 BOOL bd, it, can_use_bitmap;
1902 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
1904 struct list *first_hfont = list_head(&ret->hfontlist);
1905 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1906 if(hflist->hfont == hfont)
1910 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1911 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1913 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1914 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1915 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1918 /* check the cache first */
1919 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1920 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1924 TRACE("not in cache\n");
1925 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1927 TRACE("No fonts installed\n");
1933 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1934 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1935 calc_hash(&ret->font_desc);
1936 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1937 hflist->hfont = hfont;
1938 list_add_head(&ret->hfontlist, &hflist->entry);
1941 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1942 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1943 original value lfCharSet. Note this is a special case for
1944 Symbol and doesn't happen at least for "Wingdings*" */
1946 if(!strcmpiW(lf.lfFaceName, SymbolW))
1947 lf.lfCharSet = SYMBOL_CHARSET;
1949 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1950 switch(lf.lfCharSet) {
1951 case DEFAULT_CHARSET:
1952 csi.fs.fsCsb[0] = 0;
1955 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1956 csi.fs.fsCsb[0] = 0;
1962 if(lf.lfFaceName[0] != '\0') {
1964 for(psub = substlist; psub; psub = psub->next)
1965 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1966 (psub->from.charset == -1 ||
1967 psub->from.charset == lf.lfCharSet))
1970 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1971 debugstr_w(psub->to.name));
1972 strcpyW(lf.lfFaceName, psub->to.name);
1975 /* We want a match on name and charset or just name if
1976 charset was DEFAULT_CHARSET. If the latter then
1977 we fixup the returned charset later in get_nearest_charset
1978 where we'll either use the charset of the current ansi codepage
1979 or if that's unavailable the first charset that the font supports.
1981 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1982 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1983 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1984 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1985 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1986 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
1987 if(face->scalable || can_use_bitmap)
1994 /* If requested charset was DEFAULT_CHARSET then try using charset
1995 corresponding to the current ansi codepage */
1996 if(!csi.fs.fsCsb[0]) {
1998 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1999 FIXME("TCI failed on codepage %d\n", acp);
2000 csi.fs.fsCsb[0] = 0;
2002 lf.lfCharSet = csi.ciCharset;
2005 /* Face families are in the top 4 bits of lfPitchAndFamily,
2006 so mask with 0xF0 before testing */
2008 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2009 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2010 strcpyW(lf.lfFaceName, defFixed);
2011 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2012 strcpyW(lf.lfFaceName, defSerif);
2013 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2014 strcpyW(lf.lfFaceName, defSans);
2016 strcpyW(lf.lfFaceName, defSans);
2017 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2018 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2019 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2020 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2021 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2022 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2023 if(face->scalable || can_use_bitmap)
2029 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2030 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2031 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2032 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2033 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2034 if(face->scalable || can_use_bitmap)
2040 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2041 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2042 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2043 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2044 if(face->scalable || can_use_bitmap) {
2045 csi.fs.fsCsb[0] = 0;
2046 FIXME("just using first face for now\n");
2051 FIXME("can't find a single appropriate font - bailing\n");
2056 it = lf.lfItalic ? 1 : 0;
2057 bd = lf.lfWeight > 550 ? 1 : 0;
2059 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2060 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2063 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2064 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2065 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2066 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2070 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2072 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2073 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2074 (diff < 0 && newdiff > diff)) {
2075 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2088 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2089 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2090 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2094 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2096 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2097 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2098 (diff < 0 && newdiff > diff)) {
2099 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2110 if(it && !face->Italic) ret->fake_italic = TRUE;
2111 if(bd && !face->Bold) ret->fake_bold = TRUE;
2114 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2116 if(csi.fs.fsCsb[0]) {
2117 ret->charset = lf.lfCharSet;
2118 ret->codepage = csi.ciACP;
2121 ret->charset = get_nearest_charset(face, &ret->codepage);
2123 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2124 debugstr_w(face->StyleName), face->file, face->face_index);
2126 if(!face->scalable) {
2127 width = face->size.x_ppem >> 6;
2128 height = face->size.y_ppem >> 6;
2130 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2138 if (ret->charset == SYMBOL_CHARSET &&
2139 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2142 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2146 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2149 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2150 ret->name = strdupW(family->FamilyName);
2151 ret->underline = lf.lfUnderline ? 0xff : 0;
2152 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2153 create_child_font_list(ret);
2155 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2157 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2158 list_add_head(&gdi_font_list, &ret->entry);
2162 static void dump_gdi_font_list(void)
2165 struct list *elem_ptr;
2167 TRACE("---------- gdiFont Cache ----------\n");
2168 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2169 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2170 TRACE("gdiFont=%p %s %ld\n",
2171 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2174 TRACE("---------- Unused gdiFont Cache ----------\n");
2175 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2176 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2177 TRACE("gdiFont=%p %s %ld\n",
2178 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2182 /*************************************************************
2183 * WineEngDestroyFontInstance
2185 * free the gdiFont associated with this handle
2188 BOOL WineEngDestroyFontInstance(HFONT handle)
2193 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2196 TRACE("destroying hfont=%p\n", handle);
2198 dump_gdi_font_list();
2200 font_elem_ptr = list_head(&gdi_font_list);
2201 while(font_elem_ptr) {
2202 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2203 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2205 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2206 while(hfontlist_elem_ptr) {
2207 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2208 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2209 if(hflist->hfont == handle) {
2210 list_remove(&hflist->entry);
2211 HeapFree(GetProcessHeap(), 0, hflist);
2215 if(list_empty(&gdiFont->hfontlist)) {
2216 TRACE("Moving to Unused list\n");
2217 list_remove(&gdiFont->entry);
2218 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2223 font_elem_ptr = list_head(&unused_gdi_font_list);
2224 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2225 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2226 while(font_elem_ptr) {
2227 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2228 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2229 TRACE("freeing %p\n", gdiFont);
2230 list_remove(&gdiFont->entry);
2236 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2237 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2239 OUTLINETEXTMETRICW *potm = NULL;
2241 TEXTMETRICW tm, *ptm;
2242 GdiFont font = alloc_font();
2245 if(face->scalable) {
2249 height = face->size.y_ppem >> 6;
2250 width = face->size.x_ppem >> 6;
2253 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2259 font->name = strdupW(face->family->FamilyName);
2261 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2263 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2265 potm = HeapAlloc(GetProcessHeap(), 0, size);
2266 WineEngGetOutlineTextMetrics(font, size, potm);
2267 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2269 WineEngGetTextMetrics(font, &tm);
2273 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2274 pntm->ntmTm.tmAscent = ptm->tmAscent;
2275 pntm->ntmTm.tmDescent = ptm->tmDescent;
2276 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2277 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2278 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2279 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2280 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2281 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2282 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2283 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2284 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2285 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2286 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2287 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2288 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2289 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2290 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2291 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2292 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2293 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2294 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2295 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2296 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2298 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2299 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2300 *ptype |= RASTER_FONTTYPE;
2302 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2303 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2304 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2306 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2307 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2308 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2311 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2313 lstrcpynW(pelf->elfLogFont.lfFaceName,
2314 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2316 lstrcpynW(pelf->elfFullName,
2317 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2319 lstrcpynW(pelf->elfStyle,
2320 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2323 HeapFree(GetProcessHeap(), 0, potm);
2325 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2327 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2328 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2329 pelf->elfStyle[0] = '\0';
2332 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2337 /*************************************************************
2341 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2345 struct list *family_elem_ptr, *face_elem_ptr;
2347 NEWTEXTMETRICEXW ntm;
2348 DWORD type, ret = 1;
2354 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2356 if(plf->lfFaceName[0]) {
2358 for(psub = substlist; psub; psub = psub->next)
2359 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2360 (psub->from.charset == -1 ||
2361 psub->from.charset == plf->lfCharSet))
2364 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2365 debugstr_w(psub->to.name));
2366 memcpy(&lf, plf, sizeof(lf));
2367 strcpyW(lf.lfFaceName, psub->to.name);
2371 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2372 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2373 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2374 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2375 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2376 GetEnumStructs(face, &elf, &ntm, &type);
2377 for(i = 0; i < 32; i++) {
2378 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2379 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2380 strcpyW(elf.elfScript, OEM_DOSW);
2381 i = 32; /* break out of loop */
2382 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2385 fs.fsCsb[0] = 1L << i;
2387 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2389 csi.ciCharset = DEFAULT_CHARSET;
2390 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2391 if(csi.ciCharset != DEFAULT_CHARSET) {
2392 elf.elfLogFont.lfCharSet =
2393 ntm.ntmTm.tmCharSet = csi.ciCharset;
2395 strcpyW(elf.elfScript, ElfScriptsW[i]);
2397 FIXME("Unknown elfscript for bit %d\n", i);
2400 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2401 debugstr_w(elf.elfLogFont.lfFaceName),
2402 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2403 csi.ciCharset, type, debugstr_w(elf.elfScript),
2404 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2405 ntm.ntmTm.ntmFlags);
2406 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2413 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2414 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2415 face_elem_ptr = list_head(&family->faces);
2416 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2417 GetEnumStructs(face, &elf, &ntm, &type);
2418 for(i = 0; i < 32; i++) {
2419 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2420 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2421 strcpyW(elf.elfScript, OEM_DOSW);
2422 i = 32; /* break out of loop */
2423 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2426 fs.fsCsb[0] = 1L << i;
2428 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2430 csi.ciCharset = DEFAULT_CHARSET;
2431 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2432 if(csi.ciCharset != DEFAULT_CHARSET) {
2433 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2436 strcpyW(elf.elfScript, ElfScriptsW[i]);
2438 FIXME("Unknown elfscript for bit %d\n", i);
2441 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2442 debugstr_w(elf.elfLogFont.lfFaceName),
2443 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2444 csi.ciCharset, type, debugstr_w(elf.elfScript),
2445 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2446 ntm.ntmTm.ntmFlags);
2447 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2456 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2458 pt->x.value = vec->x >> 6;
2459 pt->x.fract = (vec->x & 0x3f) << 10;
2460 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2461 pt->y.value = vec->y >> 6;
2462 pt->y.fract = (vec->y & 0x3f) << 10;
2463 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2467 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2469 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2470 WCHAR wc = (WCHAR)glyph;
2474 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, &default_used) || default_used)
2477 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2478 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2482 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2483 glyph = glyph + 0xf000;
2484 return pFT_Get_Char_Index(font->ft_face, glyph);
2487 /*************************************************************
2488 * WineEngGetGlyphIndices
2490 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2492 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2493 LPWORD pgi, DWORD flags)
2497 for(i = 0; i < count; i++)
2498 pgi[i] = get_glyph_index(font, lpstr[i]);
2503 /*************************************************************
2504 * WineEngGetGlyphOutline
2506 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2507 * except that the first parameter is the HWINEENGFONT of the font in
2508 * question rather than an HDC.
2511 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2512 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2515 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2516 FT_Face ft_face = font->ft_face;
2517 FT_UInt glyph_index;
2518 DWORD width, height, pitch, needed = 0;
2519 FT_Bitmap ft_bitmap;
2521 INT left, right, top = 0, bottom = 0;
2523 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2524 float widthRatio = 1.0;
2525 FT_Matrix transMat = identityMat;
2526 BOOL needsTransform = FALSE;
2529 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2530 buflen, buf, lpmat);
2532 if(format & GGO_GLYPH_INDEX) {
2533 glyph_index = glyph;
2534 format &= ~GGO_GLYPH_INDEX;
2536 glyph_index = get_glyph_index(font, glyph);
2538 if(glyph_index >= font->gmsize) {
2539 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2540 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2541 font->gmsize * sizeof(*font->gm));
2543 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2544 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2545 return 1; /* FIXME */
2549 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2550 load_flags |= FT_LOAD_NO_BITMAP;
2552 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2555 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2559 /* Scaling factor */
2560 if (font->aveWidth && font->potm) {
2561 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2564 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2565 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2567 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2568 font->gm[glyph_index].lsb = left >> 6;
2569 font->gm[glyph_index].bbx = (right - left) >> 6;
2571 /* Scaling transform */
2572 if(font->aveWidth) {
2574 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2577 scaleMat.yy = (1 << 16);
2579 pFT_Matrix_Multiply(&scaleMat, &transMat);
2580 needsTransform = TRUE;
2583 /* Rotation transform */
2584 if(font->orientation) {
2585 FT_Matrix rotationMat;
2587 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2588 pFT_Vector_Unit(&vecAngle, angle);
2589 rotationMat.xx = vecAngle.x;
2590 rotationMat.xy = -vecAngle.y;
2591 rotationMat.yx = -rotationMat.xy;
2592 rotationMat.yy = rotationMat.xx;
2594 pFT_Matrix_Multiply(&rotationMat, &transMat);
2595 needsTransform = TRUE;
2598 /* Extra transformation specified by caller */
2601 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2602 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2603 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2604 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2605 pFT_Matrix_Multiply(&extraMat, &transMat);
2606 needsTransform = TRUE;
2609 if(!needsTransform) {
2610 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2611 bottom = (ft_face->glyph->metrics.horiBearingY -
2612 ft_face->glyph->metrics.height) & -64;
2613 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2614 lpgm->gmCellIncY = 0;
2618 for(xc = 0; xc < 2; xc++) {
2619 for(yc = 0; yc < 2; yc++) {
2620 vec.x = (ft_face->glyph->metrics.horiBearingX +
2621 xc * ft_face->glyph->metrics.width);
2622 vec.y = ft_face->glyph->metrics.horiBearingY -
2623 yc * ft_face->glyph->metrics.height;
2624 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2625 pFT_Vector_Transform(&vec, &transMat);
2626 if(xc == 0 && yc == 0) {
2627 left = right = vec.x;
2628 top = bottom = vec.y;
2630 if(vec.x < left) left = vec.x;
2631 else if(vec.x > right) right = vec.x;
2632 if(vec.y < bottom) bottom = vec.y;
2633 else if(vec.y > top) top = vec.y;
2638 right = (right + 63) & -64;
2639 bottom = bottom & -64;
2640 top = (top + 63) & -64;
2642 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2643 vec.x = ft_face->glyph->metrics.horiAdvance;
2645 pFT_Vector_Transform(&vec, &transMat);
2646 lpgm->gmCellIncX = (vec.x+63) >> 6;
2647 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2649 lpgm->gmBlackBoxX = (right - left) >> 6;
2650 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2651 lpgm->gmptGlyphOrigin.x = left >> 6;
2652 lpgm->gmptGlyphOrigin.y = top >> 6;
2654 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2655 font->gm[glyph_index].init = TRUE;
2657 if(format == GGO_METRICS)
2658 return 1; /* FIXME */
2660 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2661 TRACE("loaded a bitmap\n");
2667 width = lpgm->gmBlackBoxX;
2668 height = lpgm->gmBlackBoxY;
2669 pitch = ((width + 31) >> 5) << 2;
2670 needed = pitch * height;
2672 if(!buf || !buflen) break;
2674 switch(ft_face->glyph->format) {
2675 case ft_glyph_format_bitmap:
2677 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2678 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2679 INT h = ft_face->glyph->bitmap.rows;
2681 memcpy(dst, src, w);
2682 src += ft_face->glyph->bitmap.pitch;
2688 case ft_glyph_format_outline:
2689 ft_bitmap.width = width;
2690 ft_bitmap.rows = height;
2691 ft_bitmap.pitch = pitch;
2692 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2693 ft_bitmap.buffer = buf;
2695 if(needsTransform) {
2696 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2699 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2701 /* Note: FreeType will only set 'black' bits for us. */
2702 memset(buf, 0, needed);
2703 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2707 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2712 case GGO_GRAY2_BITMAP:
2713 case GGO_GRAY4_BITMAP:
2714 case GGO_GRAY8_BITMAP:
2715 case WINE_GGO_GRAY16_BITMAP:
2717 unsigned int mult, row, col;
2720 width = lpgm->gmBlackBoxX;
2721 height = lpgm->gmBlackBoxY;
2722 pitch = (width + 3) / 4 * 4;
2723 needed = pitch * height;
2725 if(!buf || !buflen) break;
2726 ft_bitmap.width = width;
2727 ft_bitmap.rows = height;
2728 ft_bitmap.pitch = pitch;
2729 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2730 ft_bitmap.buffer = buf;
2732 if(needsTransform) {
2733 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2736 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2738 memset(ft_bitmap.buffer, 0, buflen);
2740 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2742 if(format == GGO_GRAY2_BITMAP)
2744 else if(format == GGO_GRAY4_BITMAP)
2746 else if(format == GGO_GRAY8_BITMAP)
2748 else if(format == WINE_GGO_GRAY16_BITMAP)
2756 for(row = 0; row < height; row++) {
2758 for(col = 0; col < width; col++, ptr++) {
2759 *ptr = (((int)*ptr) * mult + 128) / 256;
2768 int contour, point = 0, first_pt;
2769 FT_Outline *outline = &ft_face->glyph->outline;
2770 TTPOLYGONHEADER *pph;
2772 DWORD pph_start, cpfx, type;
2774 if(buflen == 0) buf = NULL;
2776 if (needsTransform && buf) {
2777 pFT_Outline_Transform(outline, &transMat);
2780 for(contour = 0; contour < outline->n_contours; contour++) {
2782 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2785 pph->dwType = TT_POLYGON_TYPE;
2786 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2788 needed += sizeof(*pph);
2790 while(point <= outline->contours[contour]) {
2791 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2792 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2793 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2797 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2800 } while(point <= outline->contours[contour] &&
2801 (outline->tags[point] & FT_Curve_Tag_On) ==
2802 (outline->tags[point-1] & FT_Curve_Tag_On));
2803 /* At the end of a contour Windows adds the start point, but
2805 if(point > outline->contours[contour] &&
2806 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2808 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2810 } else if(point <= outline->contours[contour] &&
2811 outline->tags[point] & FT_Curve_Tag_On) {
2812 /* add closing pt for bezier */
2814 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2822 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2825 pph->cb = needed - pph_start;
2831 /* Convert the quadratic Beziers to cubic Beziers.
2832 The parametric eqn for a cubic Bezier is, from PLRM:
2833 r(t) = at^3 + bt^2 + ct + r0
2834 with the control points:
2839 A quadratic Beizer has the form:
2840 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2842 So equating powers of t leads to:
2843 r1 = 2/3 p1 + 1/3 p0
2844 r2 = 2/3 p1 + 1/3 p2
2845 and of course r0 = p0, r3 = p2
2848 int contour, point = 0, first_pt;
2849 FT_Outline *outline = &ft_face->glyph->outline;
2850 TTPOLYGONHEADER *pph;
2852 DWORD pph_start, cpfx, type;
2853 FT_Vector cubic_control[4];
2854 if(buflen == 0) buf = NULL;
2856 if (needsTransform && buf) {
2857 pFT_Outline_Transform(outline, &transMat);
2860 for(contour = 0; contour < outline->n_contours; contour++) {
2862 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2865 pph->dwType = TT_POLYGON_TYPE;
2866 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2868 needed += sizeof(*pph);
2870 while(point <= outline->contours[contour]) {
2871 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2872 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2873 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2876 if(type == TT_PRIM_LINE) {
2878 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2882 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2885 /* FIXME: Possible optimization in endpoint calculation
2886 if there are two consecutive curves */
2887 cubic_control[0] = outline->points[point-1];
2888 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2889 cubic_control[0].x += outline->points[point].x + 1;
2890 cubic_control[0].y += outline->points[point].y + 1;
2891 cubic_control[0].x >>= 1;
2892 cubic_control[0].y >>= 1;
2894 if(point+1 > outline->contours[contour])
2895 cubic_control[3] = outline->points[first_pt];
2897 cubic_control[3] = outline->points[point+1];
2898 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2899 cubic_control[3].x += outline->points[point].x + 1;
2900 cubic_control[3].y += outline->points[point].y + 1;
2901 cubic_control[3].x >>= 1;
2902 cubic_control[3].y >>= 1;
2905 /* r1 = 1/3 p0 + 2/3 p1
2906 r2 = 1/3 p2 + 2/3 p1 */
2907 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2908 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2909 cubic_control[2] = cubic_control[1];
2910 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2911 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2912 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2913 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2915 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2916 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2917 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2922 } while(point <= outline->contours[contour] &&
2923 (outline->tags[point] & FT_Curve_Tag_On) ==
2924 (outline->tags[point-1] & FT_Curve_Tag_On));
2925 /* At the end of a contour Windows adds the start point,
2926 but only for Beziers and we've already done that.
2928 if(point <= outline->contours[contour] &&
2929 outline->tags[point] & FT_Curve_Tag_On) {
2930 /* This is the closing pt of a bezier, but we've already
2931 added it, so just inc point and carry on */
2938 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2941 pph->cb = needed - pph_start;
2947 FIXME("Unsupported format %d\n", format);
2953 static BOOL get_bitmap_text_metrics(GdiFont font)
2955 FT_Face ft_face = font->ft_face;
2956 #ifdef HAVE_FREETYPE_FTWINFNT_H
2957 FT_WinFNT_HeaderRec winfnt_header;
2959 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2960 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2961 font->potm->otmSize = size;
2963 #define TM font->potm->otmTextMetrics
2964 #ifdef HAVE_FREETYPE_FTWINFNT_H
2965 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2967 TM.tmHeight = winfnt_header.pixel_height;
2968 TM.tmAscent = winfnt_header.ascent;
2969 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2970 TM.tmInternalLeading = winfnt_header.internal_leading;
2971 TM.tmExternalLeading = winfnt_header.external_leading;
2972 TM.tmAveCharWidth = winfnt_header.avg_width;
2973 TM.tmMaxCharWidth = winfnt_header.max_width;
2974 TM.tmWeight = winfnt_header.weight;
2976 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2977 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2978 TM.tmFirstChar = winfnt_header.first_char;
2979 TM.tmLastChar = winfnt_header.last_char;
2980 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2981 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2982 TM.tmItalic = winfnt_header.italic;
2983 TM.tmUnderlined = font->underline;
2984 TM.tmStruckOut = font->strikeout;
2985 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2986 TM.tmCharSet = winfnt_header.charset;
2991 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2992 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2993 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2994 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2995 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2996 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2997 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2998 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3000 TM.tmDigitizedAspectX = 96; /* FIXME */
3001 TM.tmDigitizedAspectY = 96; /* FIXME */
3003 TM.tmLastChar = 255;
3004 TM.tmDefaultChar = 32;
3005 TM.tmBreakChar = 32;
3006 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3007 TM.tmUnderlined = font->underline;
3008 TM.tmStruckOut = font->strikeout;
3009 /* NB inverted meaning of TMPF_FIXED_PITCH */
3010 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3011 TM.tmCharSet = font->charset;
3018 /*************************************************************
3019 * WineEngGetTextMetrics
3022 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3025 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3026 if(!get_bitmap_text_metrics(font))
3029 if(!font->potm) return FALSE;
3030 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3032 if (font->aveWidth) {
3033 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3039 /*************************************************************
3040 * WineEngGetOutlineTextMetrics
3043 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3044 OUTLINETEXTMETRICW *potm)
3046 FT_Face ft_face = font->ft_face;
3047 UINT needed, lenfam, lensty, ret;
3049 TT_HoriHeader *pHori;
3050 TT_Postscript *pPost;
3051 FT_Fixed x_scale, y_scale;
3052 WCHAR *family_nameW, *style_nameW;
3053 static const WCHAR spaceW[] = {' ', '\0'};
3055 INT ascent, descent;
3057 TRACE("font=%p\n", font);
3059 if(!FT_IS_SCALABLE(ft_face))
3063 if(cbSize >= font->potm->otmSize)
3064 memcpy(potm, font->potm, font->potm->otmSize);
3065 return font->potm->otmSize;
3069 needed = sizeof(*potm);
3071 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3072 family_nameW = strdupW(font->name);
3074 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3076 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3077 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3078 style_nameW, lensty);
3080 /* These names should be read from the TT name table */
3082 /* length of otmpFamilyName */
3085 /* length of otmpFaceName */
3086 if(!strcasecmp(ft_face->style_name, "regular")) {
3087 needed += lenfam; /* just the family name */
3089 needed += lenfam + lensty; /* family + " " + style */
3092 /* length of otmpStyleName */
3095 /* length of otmpFullName */
3096 needed += lenfam + lensty;
3099 x_scale = ft_face->size->metrics.x_scale;
3100 y_scale = ft_face->size->metrics.y_scale;
3102 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3104 FIXME("Can't find OS/2 table - not TT font?\n");
3109 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3111 FIXME("Can't find HHEA table - not TT font?\n");
3116 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3118 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",
3119 pOS2->usWinAscent, pOS2->usWinDescent,
3120 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3121 ft_face->ascender, ft_face->descender, ft_face->height,
3122 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3123 ft_face->bbox.yMax, ft_face->bbox.yMin);
3125 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3126 font->potm->otmSize = needed;
3128 #define TM font->potm->otmTextMetrics
3130 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3131 ascent = pHori->Ascender;
3132 descent = -pHori->Descender;
3134 ascent = pOS2->usWinAscent;
3135 descent = pOS2->usWinDescent;
3139 TM.tmAscent = font->yMax;
3140 TM.tmDescent = -font->yMin;
3141 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3143 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3144 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3145 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3146 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3149 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3152 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3154 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3155 ((ascent + descent) -
3156 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3158 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3159 if (TM.tmAveCharWidth == 0) {
3160 TM.tmAveCharWidth = 1;
3162 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3163 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3165 TM.tmDigitizedAspectX = 300;
3166 TM.tmDigitizedAspectY = 300;
3167 TM.tmFirstChar = pOS2->usFirstCharIndex;
3168 TM.tmLastChar = pOS2->usLastCharIndex;
3169 TM.tmDefaultChar = pOS2->usDefaultChar;
3170 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3171 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3172 TM.tmUnderlined = font->underline;
3173 TM.tmStruckOut = font->strikeout;
3175 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3176 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3177 (pOS2->version == 0xFFFFU ||
3178 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3179 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3181 TM.tmPitchAndFamily = 0;
3183 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3184 case PAN_FAMILY_SCRIPT:
3185 TM.tmPitchAndFamily |= FF_SCRIPT;
3187 case PAN_FAMILY_DECORATIVE:
3188 case PAN_FAMILY_PICTORIAL:
3189 TM.tmPitchAndFamily |= FF_DECORATIVE;
3191 case PAN_FAMILY_TEXT_DISPLAY:
3192 if(TM.tmPitchAndFamily == 0) /* fixed */
3193 TM.tmPitchAndFamily = FF_MODERN;
3195 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3196 case PAN_SERIF_NORMAL_SANS:
3197 case PAN_SERIF_OBTUSE_SANS:
3198 case PAN_SERIF_PERP_SANS:
3199 TM.tmPitchAndFamily |= FF_SWISS;
3202 TM.tmPitchAndFamily |= FF_ROMAN;
3207 TM.tmPitchAndFamily |= FF_DONTCARE;
3210 if(FT_IS_SCALABLE(ft_face))
3211 TM.tmPitchAndFamily |= TMPF_VECTOR;
3212 if(FT_IS_SFNT(ft_face))
3213 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3215 TM.tmCharSet = font->charset;
3218 font->potm->otmFiller = 0;
3219 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3220 font->potm->otmfsSelection = pOS2->fsSelection;
3221 font->potm->otmfsType = pOS2->fsType;
3222 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3223 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3224 font->potm->otmItalicAngle = 0; /* POST table */
3225 font->potm->otmEMSquare = ft_face->units_per_EM;
3226 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3227 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3228 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3229 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3230 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3231 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3232 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3233 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3234 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3235 font->potm->otmMacAscent = 0; /* where do these come from ? */
3236 font->potm->otmMacDescent = 0;
3237 font->potm->otmMacLineGap = 0;
3238 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3239 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3240 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3241 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3242 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3243 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3244 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3245 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3246 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3247 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3248 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3250 font->potm->otmsUnderscoreSize = 0;
3251 font->potm->otmsUnderscorePosition = 0;
3253 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3254 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3257 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3258 cp = (char*)font->potm + sizeof(*font->potm);
3259 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3260 strcpyW((WCHAR*)cp, family_nameW);
3262 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3263 strcpyW((WCHAR*)cp, style_nameW);
3265 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3266 strcpyW((WCHAR*)cp, family_nameW);
3267 if(strcasecmp(ft_face->style_name, "regular")) {
3268 strcatW((WCHAR*)cp, spaceW);
3269 strcatW((WCHAR*)cp, style_nameW);
3270 cp += lenfam + lensty;
3273 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3274 strcpyW((WCHAR*)cp, family_nameW);
3275 strcatW((WCHAR*)cp, spaceW);
3276 strcatW((WCHAR*)cp, style_nameW);
3279 if(potm && needed <= cbSize)
3280 memcpy(potm, font->potm, font->potm->otmSize);
3283 HeapFree(GetProcessHeap(), 0, style_nameW);
3284 HeapFree(GetProcessHeap(), 0, family_nameW);
3289 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3291 HFONTLIST *hfontlist;
3292 child->font = alloc_font();
3293 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3294 if(!child->font->ft_face)
3297 child->font->orientation = font->orientation;
3298 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3299 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3300 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3301 child->font->base_font = font;
3302 list_add_head(&child_font_list, &child->font->entry);
3303 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3307 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3310 CHILD_FONT *child_font;
3313 font = font->base_font;
3315 *linked_font = font;
3317 if((*glyph = get_glyph_index(font, c)))
3320 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3322 if(!child_font->font)
3323 if(!load_child_font(font, child_font))
3326 if(!child_font->font->ft_face)
3328 g = get_glyph_index(child_font->font, c);
3332 *linked_font = child_font->font;
3339 /*************************************************************
3340 * WineEngGetCharWidth
3343 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3348 FT_UInt glyph_index;
3349 GdiFont linked_font;
3351 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3353 for(c = firstChar; c <= lastChar; c++) {
3354 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3355 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3356 &gm, 0, NULL, NULL);
3357 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3362 /*************************************************************
3363 * WineEngGetCharABCWidths
3366 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3371 FT_UInt glyph_index;
3372 GdiFont linked_font;
3374 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3376 if(!FT_IS_SCALABLE(font->ft_face))
3379 for(c = firstChar; c <= lastChar; c++) {
3380 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3381 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3382 &gm, 0, NULL, NULL);
3383 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3384 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3385 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3386 linked_font->gm[glyph_index].bbx;
3391 /*************************************************************
3392 * WineEngGetTextExtentPoint
3395 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3401 FT_UInt glyph_index;
3402 GdiFont linked_font;
3404 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3408 WineEngGetTextMetrics(font, &tm);
3409 size->cy = tm.tmHeight;
3411 for(idx = 0; idx < count; idx++) {
3412 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3413 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3414 &gm, 0, NULL, NULL);
3415 size->cx += linked_font->gm[glyph_index].adv;
3417 TRACE("return %ld,%ld\n", size->cx, size->cy);
3421 /*************************************************************
3422 * WineEngGetTextExtentPointI
3425 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3432 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3435 WineEngGetTextMetrics(font, &tm);
3436 size->cy = tm.tmHeight;
3438 for(idx = 0; idx < count; idx++) {
3439 WineEngGetGlyphOutline(font, indices[idx],
3440 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3442 size->cx += font->gm[indices[idx]].adv;
3444 TRACE("return %ld,%ld\n", size->cx, size->cy);
3448 /*************************************************************
3449 * WineEngGetFontData
3452 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3455 FT_Face ft_face = font->ft_face;
3459 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3460 font, table, offset, buf, cbData);
3462 if(!FT_IS_SFNT(ft_face))
3470 if(table) { /* MS tags differ in endidness from FT ones */
3471 table = table >> 24 | table << 24 |
3472 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3475 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3476 if(pFT_Load_Sfnt_Table)
3477 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3478 else { /* Do it the hard way */
3479 TT_Face tt_face = (TT_Face) ft_face;
3480 SFNT_Interface *sfnt;
3481 if (FT_Version.major==2 && FT_Version.minor==0)
3484 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3488 /* A field was added in the middle of the structure in 2.1.x */
3489 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3491 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3494 TRACE("Can't find table %08lx.\n", table);
3500 /*************************************************************
3501 * WineEngGetTextFace
3504 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3507 lstrcpynW(str, font->name, count);
3508 return strlenW(font->name);
3510 return strlenW(font->name) + 1;
3513 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3515 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3516 return font->charset;
3519 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3521 GdiFont font = dc->gdiFont, linked_font;
3522 struct list *first_hfont;
3525 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3526 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3527 if(font == linked_font)
3528 *new_hfont = dc->hFont;
3531 first_hfont = list_head(&linked_font->hfontlist);
3532 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3539 /*************************************************************
3542 BOOL WINAPI FontIsLinked(HDC hdc)
3544 DC *dc = DC_GetDCPtr(hdc);
3547 if(!dc) return FALSE;
3548 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3550 GDI_ReleaseObj(hdc);
3551 TRACE("returning %d\n", ret);
3555 #else /* HAVE_FREETYPE */
3557 BOOL WineEngInit(void)
3561 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3565 BOOL WineEngDestroyFontInstance(HFONT hfont)
3570 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3575 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3576 LPWORD pgi, DWORD flags)
3581 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3582 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3585 ERR("called but we don't have FreeType\n");
3589 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3591 ERR("called but we don't have FreeType\n");
3595 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3596 OUTLINETEXTMETRICW *potm)
3598 ERR("called but we don't have FreeType\n");
3602 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3605 ERR("called but we don't have FreeType\n");
3609 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3612 ERR("called but we don't have FreeType\n");
3616 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3619 ERR("called but we don't have FreeType\n");
3623 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3626 ERR("called but we don't have FreeType\n");
3630 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3633 ERR("called but we don't have FreeType\n");
3637 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3639 ERR("called but we don't have FreeType\n");
3643 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3649 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3655 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3658 return DEFAULT_CHARSET;
3661 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3666 BOOL WINAPI FontIsLinked(HDC hdc)
3670 #endif /* HAVE_FREETYPE */