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;
2472 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2473 return pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2476 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2477 glyph = glyph + 0xf000;
2478 return pFT_Get_Char_Index(font->ft_face, glyph);
2481 /*************************************************************
2482 * WineEngGetGlyphIndices
2484 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2486 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2487 LPWORD pgi, DWORD flags)
2491 for(i = 0; i < count; i++)
2492 pgi[i] = get_glyph_index(font, lpstr[i]);
2497 /*************************************************************
2498 * WineEngGetGlyphOutline
2500 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2501 * except that the first parameter is the HWINEENGFONT of the font in
2502 * question rather than an HDC.
2505 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2506 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2509 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2510 FT_Face ft_face = font->ft_face;
2511 FT_UInt glyph_index;
2512 DWORD width, height, pitch, needed = 0;
2513 FT_Bitmap ft_bitmap;
2515 INT left, right, top = 0, bottom = 0;
2517 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2518 float widthRatio = 1.0;
2519 FT_Matrix transMat = identityMat;
2520 BOOL needsTransform = FALSE;
2523 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2524 buflen, buf, lpmat);
2526 if(format & GGO_GLYPH_INDEX) {
2527 glyph_index = glyph;
2528 format &= ~GGO_GLYPH_INDEX;
2530 glyph_index = get_glyph_index(font, glyph);
2532 if(glyph_index >= font->gmsize) {
2533 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2534 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2535 font->gmsize * sizeof(*font->gm));
2537 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2538 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2539 return 1; /* FIXME */
2543 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2544 load_flags |= FT_LOAD_NO_BITMAP;
2546 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2549 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2553 /* Scaling factor */
2554 if (font->aveWidth && font->potm) {
2555 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2558 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2559 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2561 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2562 font->gm[glyph_index].lsb = left >> 6;
2563 font->gm[glyph_index].bbx = (right - left) >> 6;
2565 /* Scaling transform */
2566 if(font->aveWidth) {
2568 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2571 scaleMat.yy = (1 << 16);
2573 pFT_Matrix_Multiply(&scaleMat, &transMat);
2574 needsTransform = TRUE;
2577 /* Rotation transform */
2578 if(font->orientation) {
2579 FT_Matrix rotationMat;
2581 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2582 pFT_Vector_Unit(&vecAngle, angle);
2583 rotationMat.xx = vecAngle.x;
2584 rotationMat.xy = -vecAngle.y;
2585 rotationMat.yx = -rotationMat.xy;
2586 rotationMat.yy = rotationMat.xx;
2588 pFT_Matrix_Multiply(&rotationMat, &transMat);
2589 needsTransform = TRUE;
2592 /* Extra transformation specified by caller */
2595 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2596 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2597 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2598 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2599 pFT_Matrix_Multiply(&extraMat, &transMat);
2600 needsTransform = TRUE;
2603 if(!needsTransform) {
2604 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2605 bottom = (ft_face->glyph->metrics.horiBearingY -
2606 ft_face->glyph->metrics.height) & -64;
2607 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2608 lpgm->gmCellIncY = 0;
2612 for(xc = 0; xc < 2; xc++) {
2613 for(yc = 0; yc < 2; yc++) {
2614 vec.x = (ft_face->glyph->metrics.horiBearingX +
2615 xc * ft_face->glyph->metrics.width);
2616 vec.y = ft_face->glyph->metrics.horiBearingY -
2617 yc * ft_face->glyph->metrics.height;
2618 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2619 pFT_Vector_Transform(&vec, &transMat);
2620 if(xc == 0 && yc == 0) {
2621 left = right = vec.x;
2622 top = bottom = vec.y;
2624 if(vec.x < left) left = vec.x;
2625 else if(vec.x > right) right = vec.x;
2626 if(vec.y < bottom) bottom = vec.y;
2627 else if(vec.y > top) top = vec.y;
2632 right = (right + 63) & -64;
2633 bottom = bottom & -64;
2634 top = (top + 63) & -64;
2636 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2637 vec.x = ft_face->glyph->metrics.horiAdvance;
2639 pFT_Vector_Transform(&vec, &transMat);
2640 lpgm->gmCellIncX = (vec.x+63) >> 6;
2641 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2643 lpgm->gmBlackBoxX = (right - left) >> 6;
2644 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2645 lpgm->gmptGlyphOrigin.x = left >> 6;
2646 lpgm->gmptGlyphOrigin.y = top >> 6;
2648 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2649 font->gm[glyph_index].init = TRUE;
2651 if(format == GGO_METRICS)
2652 return 1; /* FIXME */
2654 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2655 TRACE("loaded a bitmap\n");
2661 width = lpgm->gmBlackBoxX;
2662 height = lpgm->gmBlackBoxY;
2663 pitch = ((width + 31) >> 5) << 2;
2664 needed = pitch * height;
2666 if(!buf || !buflen) break;
2668 switch(ft_face->glyph->format) {
2669 case ft_glyph_format_bitmap:
2671 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2672 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2673 INT h = ft_face->glyph->bitmap.rows;
2675 memcpy(dst, src, w);
2676 src += ft_face->glyph->bitmap.pitch;
2682 case ft_glyph_format_outline:
2683 ft_bitmap.width = width;
2684 ft_bitmap.rows = height;
2685 ft_bitmap.pitch = pitch;
2686 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2687 ft_bitmap.buffer = buf;
2689 if(needsTransform) {
2690 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2693 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2695 /* Note: FreeType will only set 'black' bits for us. */
2696 memset(buf, 0, needed);
2697 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2701 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2706 case GGO_GRAY2_BITMAP:
2707 case GGO_GRAY4_BITMAP:
2708 case GGO_GRAY8_BITMAP:
2709 case WINE_GGO_GRAY16_BITMAP:
2711 unsigned int mult, row, col;
2714 width = lpgm->gmBlackBoxX;
2715 height = lpgm->gmBlackBoxY;
2716 pitch = (width + 3) / 4 * 4;
2717 needed = pitch * height;
2719 if(!buf || !buflen) break;
2720 ft_bitmap.width = width;
2721 ft_bitmap.rows = height;
2722 ft_bitmap.pitch = pitch;
2723 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2724 ft_bitmap.buffer = buf;
2726 if(needsTransform) {
2727 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2730 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2732 memset(ft_bitmap.buffer, 0, buflen);
2734 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2736 if(format == GGO_GRAY2_BITMAP)
2738 else if(format == GGO_GRAY4_BITMAP)
2740 else if(format == GGO_GRAY8_BITMAP)
2742 else if(format == WINE_GGO_GRAY16_BITMAP)
2750 for(row = 0; row < height; row++) {
2752 for(col = 0; col < width; col++, ptr++) {
2753 *ptr = (((int)*ptr) * mult + 128) / 256;
2762 int contour, point = 0, first_pt;
2763 FT_Outline *outline = &ft_face->glyph->outline;
2764 TTPOLYGONHEADER *pph;
2766 DWORD pph_start, cpfx, type;
2768 if(buflen == 0) buf = NULL;
2770 if (needsTransform && buf) {
2771 pFT_Outline_Transform(outline, &transMat);
2774 for(contour = 0; contour < outline->n_contours; contour++) {
2776 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2779 pph->dwType = TT_POLYGON_TYPE;
2780 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2782 needed += sizeof(*pph);
2784 while(point <= outline->contours[contour]) {
2785 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2786 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2787 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2791 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2794 } while(point <= outline->contours[contour] &&
2795 (outline->tags[point] & FT_Curve_Tag_On) ==
2796 (outline->tags[point-1] & FT_Curve_Tag_On));
2797 /* At the end of a contour Windows adds the start point, but
2799 if(point > outline->contours[contour] &&
2800 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2802 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2804 } else if(point <= outline->contours[contour] &&
2805 outline->tags[point] & FT_Curve_Tag_On) {
2806 /* add closing pt for bezier */
2808 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2816 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2819 pph->cb = needed - pph_start;
2825 /* Convert the quadratic Beziers to cubic Beziers.
2826 The parametric eqn for a cubic Bezier is, from PLRM:
2827 r(t) = at^3 + bt^2 + ct + r0
2828 with the control points:
2833 A quadratic Beizer has the form:
2834 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2836 So equating powers of t leads to:
2837 r1 = 2/3 p1 + 1/3 p0
2838 r2 = 2/3 p1 + 1/3 p2
2839 and of course r0 = p0, r3 = p2
2842 int contour, point = 0, first_pt;
2843 FT_Outline *outline = &ft_face->glyph->outline;
2844 TTPOLYGONHEADER *pph;
2846 DWORD pph_start, cpfx, type;
2847 FT_Vector cubic_control[4];
2848 if(buflen == 0) buf = NULL;
2850 if (needsTransform && buf) {
2851 pFT_Outline_Transform(outline, &transMat);
2854 for(contour = 0; contour < outline->n_contours; contour++) {
2856 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2859 pph->dwType = TT_POLYGON_TYPE;
2860 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2862 needed += sizeof(*pph);
2864 while(point <= outline->contours[contour]) {
2865 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2866 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2867 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2870 if(type == TT_PRIM_LINE) {
2872 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2876 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2879 /* FIXME: Possible optimization in endpoint calculation
2880 if there are two consecutive curves */
2881 cubic_control[0] = outline->points[point-1];
2882 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2883 cubic_control[0].x += outline->points[point].x + 1;
2884 cubic_control[0].y += outline->points[point].y + 1;
2885 cubic_control[0].x >>= 1;
2886 cubic_control[0].y >>= 1;
2888 if(point+1 > outline->contours[contour])
2889 cubic_control[3] = outline->points[first_pt];
2891 cubic_control[3] = outline->points[point+1];
2892 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2893 cubic_control[3].x += outline->points[point].x + 1;
2894 cubic_control[3].y += outline->points[point].y + 1;
2895 cubic_control[3].x >>= 1;
2896 cubic_control[3].y >>= 1;
2899 /* r1 = 1/3 p0 + 2/3 p1
2900 r2 = 1/3 p2 + 2/3 p1 */
2901 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2902 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2903 cubic_control[2] = cubic_control[1];
2904 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2905 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2906 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2907 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2909 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2910 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2911 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2916 } while(point <= outline->contours[contour] &&
2917 (outline->tags[point] & FT_Curve_Tag_On) ==
2918 (outline->tags[point-1] & FT_Curve_Tag_On));
2919 /* At the end of a contour Windows adds the start point,
2920 but only for Beziers and we've already done that.
2922 if(point <= outline->contours[contour] &&
2923 outline->tags[point] & FT_Curve_Tag_On) {
2924 /* This is the closing pt of a bezier, but we've already
2925 added it, so just inc point and carry on */
2932 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2935 pph->cb = needed - pph_start;
2941 FIXME("Unsupported format %d\n", format);
2947 static BOOL get_bitmap_text_metrics(GdiFont font)
2949 FT_Face ft_face = font->ft_face;
2950 #ifdef HAVE_FREETYPE_FTWINFNT_H
2951 FT_WinFNT_HeaderRec winfnt_header;
2953 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2954 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2955 font->potm->otmSize = size;
2957 #define TM font->potm->otmTextMetrics
2958 #ifdef HAVE_FREETYPE_FTWINFNT_H
2959 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2961 TM.tmHeight = winfnt_header.pixel_height;
2962 TM.tmAscent = winfnt_header.ascent;
2963 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2964 TM.tmInternalLeading = winfnt_header.internal_leading;
2965 TM.tmExternalLeading = winfnt_header.external_leading;
2966 TM.tmAveCharWidth = winfnt_header.avg_width;
2967 TM.tmMaxCharWidth = winfnt_header.max_width;
2968 TM.tmWeight = winfnt_header.weight;
2970 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2971 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2972 TM.tmFirstChar = winfnt_header.first_char;
2973 TM.tmLastChar = winfnt_header.last_char;
2974 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2975 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2976 TM.tmItalic = winfnt_header.italic;
2977 TM.tmUnderlined = font->underline;
2978 TM.tmStruckOut = font->strikeout;
2979 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2980 TM.tmCharSet = winfnt_header.charset;
2985 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2986 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2987 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2988 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2989 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2990 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2991 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2992 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2994 TM.tmDigitizedAspectX = 96; /* FIXME */
2995 TM.tmDigitizedAspectY = 96; /* FIXME */
2997 TM.tmLastChar = 255;
2998 TM.tmDefaultChar = 32;
2999 TM.tmBreakChar = 32;
3000 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3001 TM.tmUnderlined = font->underline;
3002 TM.tmStruckOut = font->strikeout;
3003 /* NB inverted meaning of TMPF_FIXED_PITCH */
3004 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3005 TM.tmCharSet = font->charset;
3012 /*************************************************************
3013 * WineEngGetTextMetrics
3016 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3019 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3020 if(!get_bitmap_text_metrics(font))
3023 if(!font->potm) return FALSE;
3024 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3026 if (font->aveWidth) {
3027 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3033 /*************************************************************
3034 * WineEngGetOutlineTextMetrics
3037 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3038 OUTLINETEXTMETRICW *potm)
3040 FT_Face ft_face = font->ft_face;
3041 UINT needed, lenfam, lensty, ret;
3043 TT_HoriHeader *pHori;
3044 TT_Postscript *pPost;
3045 FT_Fixed x_scale, y_scale;
3046 WCHAR *family_nameW, *style_nameW;
3047 static const WCHAR spaceW[] = {' ', '\0'};
3049 INT ascent, descent;
3051 TRACE("font=%p\n", font);
3053 if(!FT_IS_SCALABLE(ft_face))
3057 if(cbSize >= font->potm->otmSize)
3058 memcpy(potm, font->potm, font->potm->otmSize);
3059 return font->potm->otmSize;
3063 needed = sizeof(*potm);
3065 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3066 family_nameW = strdupW(font->name);
3068 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3070 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3071 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3072 style_nameW, lensty);
3074 /* These names should be read from the TT name table */
3076 /* length of otmpFamilyName */
3079 /* length of otmpFaceName */
3080 if(!strcasecmp(ft_face->style_name, "regular")) {
3081 needed += lenfam; /* just the family name */
3083 needed += lenfam + lensty; /* family + " " + style */
3086 /* length of otmpStyleName */
3089 /* length of otmpFullName */
3090 needed += lenfam + lensty;
3093 x_scale = ft_face->size->metrics.x_scale;
3094 y_scale = ft_face->size->metrics.y_scale;
3096 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3098 FIXME("Can't find OS/2 table - not TT font?\n");
3103 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3105 FIXME("Can't find HHEA table - not TT font?\n");
3110 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3112 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",
3113 pOS2->usWinAscent, pOS2->usWinDescent,
3114 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3115 ft_face->ascender, ft_face->descender, ft_face->height,
3116 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3117 ft_face->bbox.yMax, ft_face->bbox.yMin);
3119 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3120 font->potm->otmSize = needed;
3122 #define TM font->potm->otmTextMetrics
3124 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3125 ascent = pHori->Ascender;
3126 descent = -pHori->Descender;
3128 ascent = pOS2->usWinAscent;
3129 descent = pOS2->usWinDescent;
3133 TM.tmAscent = font->yMax;
3134 TM.tmDescent = -font->yMin;
3135 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3137 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3138 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3139 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3140 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3143 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3146 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3148 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3149 ((ascent + descent) -
3150 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3152 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3153 if (TM.tmAveCharWidth == 0) {
3154 TM.tmAveCharWidth = 1;
3156 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3157 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3159 TM.tmDigitizedAspectX = 300;
3160 TM.tmDigitizedAspectY = 300;
3161 TM.tmFirstChar = pOS2->usFirstCharIndex;
3162 TM.tmLastChar = pOS2->usLastCharIndex;
3163 TM.tmDefaultChar = pOS2->usDefaultChar;
3164 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3165 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3166 TM.tmUnderlined = font->underline;
3167 TM.tmStruckOut = font->strikeout;
3169 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3170 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3171 (pOS2->version == 0xFFFFU ||
3172 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3173 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3175 TM.tmPitchAndFamily = 0;
3177 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3178 case PAN_FAMILY_SCRIPT:
3179 TM.tmPitchAndFamily |= FF_SCRIPT;
3181 case PAN_FAMILY_DECORATIVE:
3182 case PAN_FAMILY_PICTORIAL:
3183 TM.tmPitchAndFamily |= FF_DECORATIVE;
3185 case PAN_FAMILY_TEXT_DISPLAY:
3186 if(TM.tmPitchAndFamily == 0) /* fixed */
3187 TM.tmPitchAndFamily = FF_MODERN;
3189 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3190 case PAN_SERIF_NORMAL_SANS:
3191 case PAN_SERIF_OBTUSE_SANS:
3192 case PAN_SERIF_PERP_SANS:
3193 TM.tmPitchAndFamily |= FF_SWISS;
3196 TM.tmPitchAndFamily |= FF_ROMAN;
3201 TM.tmPitchAndFamily |= FF_DONTCARE;
3204 if(FT_IS_SCALABLE(ft_face))
3205 TM.tmPitchAndFamily |= TMPF_VECTOR;
3206 if(FT_IS_SFNT(ft_face))
3207 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3209 TM.tmCharSet = font->charset;
3212 font->potm->otmFiller = 0;
3213 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3214 font->potm->otmfsSelection = pOS2->fsSelection;
3215 font->potm->otmfsType = pOS2->fsType;
3216 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3217 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3218 font->potm->otmItalicAngle = 0; /* POST table */
3219 font->potm->otmEMSquare = ft_face->units_per_EM;
3220 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3221 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3222 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3223 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3224 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3225 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3226 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3227 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3228 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3229 font->potm->otmMacAscent = 0; /* where do these come from ? */
3230 font->potm->otmMacDescent = 0;
3231 font->potm->otmMacLineGap = 0;
3232 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3233 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3234 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3235 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3236 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3237 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3238 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3239 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3240 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3241 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3242 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3244 font->potm->otmsUnderscoreSize = 0;
3245 font->potm->otmsUnderscorePosition = 0;
3247 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3248 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3251 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3252 cp = (char*)font->potm + sizeof(*font->potm);
3253 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3254 strcpyW((WCHAR*)cp, family_nameW);
3256 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3257 strcpyW((WCHAR*)cp, style_nameW);
3259 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3260 strcpyW((WCHAR*)cp, family_nameW);
3261 if(strcasecmp(ft_face->style_name, "regular")) {
3262 strcatW((WCHAR*)cp, spaceW);
3263 strcatW((WCHAR*)cp, style_nameW);
3264 cp += lenfam + lensty;
3267 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3268 strcpyW((WCHAR*)cp, family_nameW);
3269 strcatW((WCHAR*)cp, spaceW);
3270 strcatW((WCHAR*)cp, style_nameW);
3273 if(potm && needed <= cbSize)
3274 memcpy(potm, font->potm, font->potm->otmSize);
3277 HeapFree(GetProcessHeap(), 0, style_nameW);
3278 HeapFree(GetProcessHeap(), 0, family_nameW);
3283 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3285 HFONTLIST *hfontlist;
3286 child->font = alloc_font();
3287 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3288 if(!child->font->ft_face)
3291 child->font->orientation = font->orientation;
3292 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3293 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3294 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3295 child->font->base_font = font;
3296 list_add_head(&child_font_list, &child->font->entry);
3297 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3301 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3304 CHILD_FONT *child_font;
3307 font = font->base_font;
3309 *linked_font = font;
3311 if((*glyph = get_glyph_index(font, c)))
3314 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3316 if(!child_font->font)
3317 if(!load_child_font(font, child_font))
3320 if(!child_font->font->ft_face)
3322 g = get_glyph_index(child_font->font, c);
3326 *linked_font = child_font->font;
3333 /*************************************************************
3334 * WineEngGetCharWidth
3337 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3342 FT_UInt glyph_index;
3344 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3346 for(c = firstChar; c <= lastChar; c++) {
3347 glyph_index = get_glyph_index(font, c);
3348 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3349 &gm, 0, NULL, NULL);
3350 buffer[c - firstChar] = font->gm[glyph_index].adv;
3355 /*************************************************************
3356 * WineEngGetCharABCWidths
3359 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3364 FT_UInt glyph_index;
3366 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3368 if(!FT_IS_SCALABLE(font->ft_face))
3371 for(c = firstChar; c <= lastChar; c++) {
3372 glyph_index = get_glyph_index(font, c);
3373 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3374 &gm, 0, NULL, NULL);
3375 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3376 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3377 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3378 font->gm[glyph_index].bbx;
3383 /*************************************************************
3384 * WineEngGetTextExtentPoint
3387 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3393 FT_UInt glyph_index;
3395 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3399 WineEngGetTextMetrics(font, &tm);
3400 size->cy = tm.tmHeight;
3402 for(idx = 0; idx < count; idx++) {
3403 glyph_index = get_glyph_index(font, wstr[idx]);
3404 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3405 &gm, 0, NULL, NULL);
3406 size->cx += font->gm[glyph_index].adv;
3408 TRACE("return %ld,%ld\n", size->cx, size->cy);
3412 /*************************************************************
3413 * WineEngGetTextExtentPointI
3416 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3423 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3426 WineEngGetTextMetrics(font, &tm);
3427 size->cy = tm.tmHeight;
3429 for(idx = 0; idx < count; idx++) {
3430 WineEngGetGlyphOutline(font, indices[idx],
3431 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3433 size->cx += font->gm[indices[idx]].adv;
3435 TRACE("return %ld,%ld\n", size->cx, size->cy);
3439 /*************************************************************
3440 * WineEngGetFontData
3443 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3446 FT_Face ft_face = font->ft_face;
3450 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3451 font, table, offset, buf, cbData);
3453 if(!FT_IS_SFNT(ft_face))
3461 if(table) { /* MS tags differ in endidness from FT ones */
3462 table = table >> 24 | table << 24 |
3463 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3466 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3467 if(pFT_Load_Sfnt_Table)
3468 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3469 else { /* Do it the hard way */
3470 TT_Face tt_face = (TT_Face) ft_face;
3471 SFNT_Interface *sfnt;
3472 if (FT_Version.major==2 && FT_Version.minor==0)
3475 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3479 /* A field was added in the middle of the structure in 2.1.x */
3480 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3482 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3485 TRACE("Can't find table %08lx.\n", table);
3491 /*************************************************************
3492 * WineEngGetTextFace
3495 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3498 lstrcpynW(str, font->name, count);
3499 return strlenW(font->name);
3501 return strlenW(font->name) + 1;
3504 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3506 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3507 return font->charset;
3510 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3512 GdiFont font = dc->gdiFont, linked_font;
3513 struct list *first_hfont;
3516 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3517 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3518 if(font == linked_font)
3519 *new_hfont = dc->hFont;
3522 first_hfont = list_head(&linked_font->hfontlist);
3523 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3529 #else /* HAVE_FREETYPE */
3531 BOOL WineEngInit(void)
3535 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3539 BOOL WineEngDestroyFontInstance(HFONT hfont)
3544 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3549 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3550 LPWORD pgi, DWORD flags)
3555 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3556 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3559 ERR("called but we don't have FreeType\n");
3563 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3565 ERR("called but we don't have FreeType\n");
3569 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3570 OUTLINETEXTMETRICW *potm)
3572 ERR("called but we don't have FreeType\n");
3576 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3579 ERR("called but we don't have FreeType\n");
3583 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3586 ERR("called but we don't have FreeType\n");
3590 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3593 ERR("called but we don't have FreeType\n");
3597 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3600 ERR("called but we don't have FreeType\n");
3604 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3607 ERR("called but we don't have FreeType\n");
3611 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3613 ERR("called but we don't have FreeType\n");
3617 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3623 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3629 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3632 return DEFAULT_CHARSET;
3635 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3639 #endif /* HAVE_FREETYPE */