2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FT2BUILD_H
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
145 static FT_Library library = 0;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
171 MAKE_FUNCPTR(FT_MulFix);
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
244 FT_Short internal_leading;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
258 NEWTEXTMETRICEXW ntm;
262 typedef struct tagFace {
267 DWORD font_data_size;
270 FONTSIGNATURE fs_links;
272 FT_Fixed font_version;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
281 typedef struct tagFamily {
283 const WCHAR *FamilyName;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
353 const WCHAR *font_name;
357 #define GM_BLOCK_SIZE 128
358 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
360 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
361 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
362 #define UNUSED_CACHE_SIZE 10
363 static struct list child_font_list = LIST_INIT(child_font_list);
364 static struct list system_links = LIST_INIT(system_links);
366 static struct list font_subst_list = LIST_INIT(font_subst_list);
368 static struct list font_list = LIST_INIT(font_list);
370 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
371 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
372 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
374 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
375 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
376 'W','i','n','d','o','w','s','\\',
377 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
378 'F','o','n','t','s','\0'};
380 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
381 'W','i','n','d','o','w','s',' ','N','T','\\',
382 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
383 'F','o','n','t','s','\0'};
385 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
386 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
387 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
388 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
390 static const WCHAR * const SystemFontValues[4] = {
397 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
398 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
400 /* Interesting and well-known (frequently-assumed!) font names */
401 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
402 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
403 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
404 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
405 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
406 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
407 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
408 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
410 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
411 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
412 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
413 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
414 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
415 'E','u','r','o','p','e','a','n','\0'};
416 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
417 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
418 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
419 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
420 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
421 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
422 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
423 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
424 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
425 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
426 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
427 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
429 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
439 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
447 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
456 typedef struct tagFontSubst {
472 static struct list mappings_list = LIST_INIT( mappings_list );
474 static CRITICAL_SECTION freetype_cs;
475 static CRITICAL_SECTION_DEBUG critsect_debug =
478 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
479 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
481 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
483 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
485 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
486 static BOOL use_default_fallback = FALSE;
488 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
490 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
491 'W','i','n','d','o','w','s',' ','N','T','\\',
492 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
493 'S','y','s','t','e','m','L','i','n','k',0};
495 /****************************************
496 * Notes on .fon files
498 * The fonts System, FixedSys and Terminal are special. There are typically multiple
499 * versions installed for different resolutions and codepages. Windows stores which one to use
500 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
502 * FIXEDFON.FON FixedSys
504 * OEMFONT.FON Terminal
505 * LogPixels Current dpi set by the display control panel applet
506 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
507 * also has a LogPixels value that appears to mirror this)
509 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
510 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
511 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
512 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
513 * so that makes sense.
515 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
516 * to be mapped into the registry on Windows 2000 at least).
519 * ega80woa.fon=ega80850.fon
520 * ega40woa.fon=ega40850.fon
521 * cga80woa.fon=cga80850.fon
522 * cga40woa.fon=cga40850.fon
525 /* These are all structures needed for the GSUB table */
527 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
528 #define TATEGAKI_LOWER_BOUND 0x02F1
544 GSUB_ScriptRecord ScriptRecord[1];
550 } GSUB_LangSysRecord;
555 GSUB_LangSysRecord LangSysRecord[1];
559 WORD LookupOrder; /* Reserved */
560 WORD ReqFeatureIndex;
562 WORD FeatureIndex[1];
568 } GSUB_FeatureRecord;
572 GSUB_FeatureRecord FeatureRecord[1];
576 WORD FeatureParams; /* Reserved */
578 WORD LookupListIndex[1];
597 } GSUB_CoverageFormat1;
602 WORD StartCoverageIndex;
608 GSUB_RangeRecord RangeRecord[1];
609 } GSUB_CoverageFormat2;
612 WORD SubstFormat; /* = 1 */
615 } GSUB_SingleSubstFormat1;
618 WORD SubstFormat; /* = 2 */
622 }GSUB_SingleSubstFormat2;
624 #ifdef HAVE_CARBON_CARBON_H
625 static char *find_cache_dir(void)
629 static char cached_path[MAX_PATH];
630 static const char *wine = "/Wine", *fonts = "/Fonts";
632 if(*cached_path) return cached_path;
634 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
637 WARN("can't create cached data folder\n");
640 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
643 WARN("can't create cached data path\n");
647 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
649 ERR("Could not create full path\n");
653 strcat(cached_path, wine);
655 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
657 WARN("Couldn't mkdir %s\n", cached_path);
661 strcat(cached_path, fonts);
662 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
664 WARN("Couldn't mkdir %s\n", cached_path);
671 /******************************************************************
674 * Extracts individual TrueType font files from a Mac suitcase font
675 * and saves them into the user's caches directory (see
677 * Returns a NULL terminated array of filenames.
679 * We do this because they are apps that try to read ttf files
680 * themselves and they don't like Mac suitcase files.
682 static char **expand_mac_font(const char *path)
689 const char *filename;
693 unsigned int size, max_size;
696 TRACE("path %s\n", path);
698 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
701 WARN("failed to get ref\n");
705 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
708 TRACE("no data fork, so trying resource fork\n");
709 res_ref = FSOpenResFile(&ref, fsRdPerm);
712 TRACE("unable to open resource fork\n");
719 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
722 CloseResFile(res_ref);
726 out_dir = find_cache_dir();
728 filename = strrchr(path, '/');
729 if(!filename) filename = path;
732 /* output filename has the form out_dir/filename_%04x.ttf */
733 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
740 unsigned short *num_faces_ptr, num_faces, face;
743 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
745 fond = Get1IndResource(fond_res, idx);
747 TRACE("got fond resource %d\n", idx);
750 fam_rec = *(FamRec**)fond;
751 num_faces_ptr = (unsigned short *)(fam_rec + 1);
752 num_faces = GET_BE_WORD(*num_faces_ptr);
754 assoc = (AsscEntry*)(num_faces_ptr + 1);
755 TRACE("num faces %04x\n", num_faces);
756 for(face = 0; face < num_faces; face++, assoc++)
759 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
760 unsigned short size, font_id;
763 size = GET_BE_WORD(assoc->fontSize);
764 font_id = GET_BE_WORD(assoc->fontID);
767 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
771 TRACE("trying to load sfnt id %04x\n", font_id);
772 sfnt = GetResource(sfnt_res, font_id);
775 TRACE("can't get sfnt resource %04x\n", font_id);
779 output = HeapAlloc(GetProcessHeap(), 0, output_len);
784 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
786 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
787 if(fd != -1 || errno == EEXIST)
791 unsigned char *sfnt_data;
794 sfnt_data = *(unsigned char**)sfnt;
795 write(fd, sfnt_data, GetHandleSize(sfnt));
799 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
802 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
804 ret.array[ret.size++] = output;
808 WARN("unable to create %s\n", output);
809 HeapFree(GetProcessHeap(), 0, output);
812 ReleaseResource(sfnt);
815 ReleaseResource(fond);
818 CloseResFile(res_ref);
823 #endif /* HAVE_CARBON_CARBON_H */
825 static inline BOOL is_win9x(void)
827 return GetVersion() & 0x80000000;
830 This function builds an FT_Fixed from a double. It fails if the absolute
831 value of the float number is greater than 32768.
833 static inline FT_Fixed FT_FixedFromFloat(double f)
839 This function builds an FT_Fixed from a FIXED. It simply put f.value
840 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
842 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
844 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
848 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
853 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
854 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
856 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
857 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
859 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
861 if(face_name && strcmpiW(face_name, family->FamilyName))
863 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
867 file = strrchr(face->file, '/');
872 if(!strcasecmp(file, file_nameA))
874 HeapFree(GetProcessHeap(), 0, file_nameA);
879 HeapFree(GetProcessHeap(), 0, file_nameA);
883 static Family *find_family_from_name(const WCHAR *name)
887 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
889 if(!strcmpiW(family->FamilyName, name))
896 static void DumpSubstList(void)
900 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
902 if(psub->from.charset != -1 || psub->to.charset != -1)
903 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
904 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
906 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
907 debugstr_w(psub->to.name));
912 static LPWSTR strdupW(LPCWSTR p)
915 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
916 ret = HeapAlloc(GetProcessHeap(), 0, len);
921 static LPSTR strdupA(LPCSTR p)
924 DWORD len = (strlen(p) + 1);
925 ret = HeapAlloc(GetProcessHeap(), 0, len);
930 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
935 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
937 if(!strcmpiW(element->from.name, from_name) &&
938 (element->from.charset == from_charset ||
939 element->from.charset == -1))
946 #define ADD_FONT_SUBST_FORCE 1
948 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
950 FontSubst *from_exist, *to_exist;
952 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
954 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
956 list_remove(&from_exist->entry);
957 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
958 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
959 HeapFree(GetProcessHeap(), 0, from_exist);
965 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
969 HeapFree(GetProcessHeap(), 0, subst->to.name);
970 subst->to.name = strdupW(to_exist->to.name);
973 list_add_tail(subst_list, &subst->entry);
978 HeapFree(GetProcessHeap(), 0, subst->from.name);
979 HeapFree(GetProcessHeap(), 0, subst->to.name);
980 HeapFree(GetProcessHeap(), 0, subst);
984 static void split_subst_info(NameCs *nc, LPSTR str)
986 CHAR *p = strrchr(str, ',');
991 nc->charset = strtol(p+1, NULL, 10);
994 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
995 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
996 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
999 static void LoadSubstList(void)
1003 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1007 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1008 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1009 &hkey) == ERROR_SUCCESS) {
1011 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1012 &valuelen, &datalen, NULL, NULL);
1014 valuelen++; /* returned value doesn't include room for '\0' */
1015 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1016 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1020 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1021 &dlen) == ERROR_SUCCESS) {
1022 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1024 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1025 split_subst_info(&psub->from, value);
1026 split_subst_info(&psub->to, data);
1028 /* Win 2000 doesn't allow mapping between different charsets
1029 or mapping of DEFAULT_CHARSET */
1030 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1031 psub->to.charset == DEFAULT_CHARSET) {
1032 HeapFree(GetProcessHeap(), 0, psub->to.name);
1033 HeapFree(GetProcessHeap(), 0, psub->from.name);
1034 HeapFree(GetProcessHeap(), 0, psub);
1036 add_font_subst(&font_subst_list, psub, 0);
1038 /* reset dlen and vlen */
1042 HeapFree(GetProcessHeap(), 0, data);
1043 HeapFree(GetProcessHeap(), 0, value);
1049 /*****************************************************************
1050 * get_name_table_entry
1052 * Supply the platform, encoding, language and name ids in req
1053 * and if the name exists the function will fill in the string
1054 * and string_len members. The string is owned by FreeType so
1055 * don't free it. Returns TRUE if the name is found else FALSE.
1057 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1060 FT_UInt num_names, name_index;
1062 if(FT_IS_SFNT(ft_face))
1064 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1066 for(name_index = 0; name_index < num_names; name_index++)
1068 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1070 if((name.platform_id == req->platform_id) &&
1071 (name.encoding_id == req->encoding_id) &&
1072 (name.language_id == req->language_id) &&
1073 (name.name_id == req->name_id))
1075 req->string = name.string;
1076 req->string_len = name.string_len;
1083 req->string_len = 0;
1087 static WCHAR *get_familyname(FT_Face ft_face)
1089 WCHAR *family = NULL;
1092 name.platform_id = TT_PLATFORM_MICROSOFT;
1093 name.encoding_id = TT_MS_ID_UNICODE_CS;
1094 name.language_id = GetUserDefaultLCID();
1095 name.name_id = TT_NAME_ID_FONT_FAMILY;
1097 if(get_name_table_entry(ft_face, &name))
1101 /* String is not nul terminated and string_len is a byte length. */
1102 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1103 for(i = 0; i < name.string_len / 2; i++)
1105 WORD *tmp = (WORD *)&name.string[i * 2];
1106 family[i] = GET_BE_WORD(*tmp);
1109 TRACE("Got localised name %s\n", debugstr_w(family));
1116 /*****************************************************************
1119 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1120 * of FreeType that don't export this function.
1123 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1128 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1129 if(pFT_Load_Sfnt_Table)
1131 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1133 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1134 else /* Do it the hard way */
1136 TT_Face tt_face = (TT_Face) ft_face;
1137 SFNT_Interface *sfnt;
1138 if (FT_Version.major==2 && FT_Version.minor==0)
1141 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1145 /* A field was added in the middle of the structure in 2.1.x */
1146 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1148 err = sfnt->load_any(tt_face, table, offset, buf, len);
1156 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1157 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1158 "Please upgrade your freetype library.\n");
1161 err = FT_Err_Unimplemented_Feature;
1167 static inline int TestStyles(DWORD flags, DWORD styles)
1169 return (flags & styles) == styles;
1172 static int StyleOrdering(Face *face)
1174 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1176 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1178 if (TestStyles(face->ntmFlags, NTM_BOLD))
1180 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1183 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1184 debugstr_w(face->family->FamilyName),
1185 debugstr_w(face->StyleName),
1191 /* Add a style of face to a font family using an ordering of the list such
1192 that regular fonts come before bold and italic, and single styles come
1193 before compound styles. */
1194 static void AddFaceToFamily(Face *face, Family *family)
1198 LIST_FOR_EACH( entry, &family->faces )
1200 Face *ent = LIST_ENTRY(entry, Face, entry);
1201 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1203 list_add_before( entry, &face->entry );
1206 #define ADDFONT_EXTERNAL_FONT 0x01
1207 #define ADDFONT_FORCE_BITMAP 0x02
1208 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1212 TT_Header *pHeader = NULL;
1213 WCHAR *english_family, *localised_family, *StyleW;
1217 struct list *family_elem_ptr, *face_elem_ptr;
1219 FT_Long face_index = 0, num_faces;
1220 #ifdef HAVE_FREETYPE_FTWINFNT_H
1221 FT_WinFNT_HeaderRec winfnt_header;
1223 int i, bitmap_num, internal_leading;
1226 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1227 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1229 #ifdef HAVE_CARBON_CARBON_H
1230 if(file && !fake_family)
1232 char **mac_list = expand_mac_font(file);
1235 BOOL had_one = FALSE;
1237 for(cursor = mac_list; *cursor; cursor++)
1240 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1241 HeapFree(GetProcessHeap(), 0, *cursor);
1243 HeapFree(GetProcessHeap(), 0, mac_list);
1248 #endif /* HAVE_CARBON_CARBON_H */
1251 char *family_name = fake_family;
1255 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1256 err = pFT_New_Face(library, file, face_index, &ft_face);
1259 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1260 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1264 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1268 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*/
1269 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1270 pFT_Done_Face(ft_face);
1274 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1275 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1276 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1277 pFT_Done_Face(ft_face);
1281 if(FT_IS_SFNT(ft_face))
1283 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1284 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1285 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1287 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1288 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1289 pFT_Done_Face(ft_face);
1293 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1294 we don't want to load these. */
1295 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1299 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1301 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1302 pFT_Done_Face(ft_face);
1308 if(!ft_face->family_name || !ft_face->style_name) {
1309 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1310 pFT_Done_Face(ft_face);
1314 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1316 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1317 pFT_Done_Face(ft_face);
1323 localised_family = get_familyname(ft_face);
1324 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1326 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1327 HeapFree(GetProcessHeap(), 0, localised_family);
1328 num_faces = ft_face->num_faces;
1329 pFT_Done_Face(ft_face);
1332 HeapFree(GetProcessHeap(), 0, localised_family);
1336 family_name = ft_face->family_name;
1340 My_FT_Bitmap_Size *size = NULL;
1343 if(!FT_IS_SCALABLE(ft_face))
1344 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1346 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1347 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1348 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1350 localised_family = NULL;
1352 localised_family = get_familyname(ft_face);
1353 if(localised_family && !strcmpiW(localised_family, english_family)) {
1354 HeapFree(GetProcessHeap(), 0, localised_family);
1355 localised_family = NULL;
1360 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1361 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1362 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1367 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1368 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1369 list_init(&family->faces);
1370 list_add_tail(&font_list, &family->entry);
1372 if(localised_family) {
1373 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1374 subst->from.name = strdupW(english_family);
1375 subst->from.charset = -1;
1376 subst->to.name = strdupW(localised_family);
1377 subst->to.charset = -1;
1378 add_font_subst(&font_subst_list, subst, 0);
1381 HeapFree(GetProcessHeap(), 0, localised_family);
1382 HeapFree(GetProcessHeap(), 0, english_family);
1384 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1385 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1386 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1388 internal_leading = 0;
1389 memset(&fs, 0, sizeof(fs));
1391 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1393 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1394 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1395 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1396 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1397 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1398 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1399 if(pOS2->version == 0) {
1402 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1403 fs.fsCsb[0] |= FS_LATIN1;
1405 fs.fsCsb[0] |= FS_SYMBOL;
1408 #ifdef HAVE_FREETYPE_FTWINFNT_H
1409 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1411 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1412 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1413 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1415 internal_leading = winfnt_header.internal_leading;
1419 face_elem_ptr = list_head(&family->faces);
1420 while(face_elem_ptr) {
1421 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1422 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1423 if(!strcmpiW(face->StyleName, StyleW) &&
1424 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1425 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1426 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1427 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1430 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1431 HeapFree(GetProcessHeap(), 0, StyleW);
1432 pFT_Done_Face(ft_face);
1435 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1436 TRACE("Original font is newer so skipping this one\n");
1437 HeapFree(GetProcessHeap(), 0, StyleW);
1438 pFT_Done_Face(ft_face);
1441 TRACE("Replacing original with this one\n");
1442 list_remove(&face->entry);
1443 HeapFree(GetProcessHeap(), 0, face->file);
1444 HeapFree(GetProcessHeap(), 0, face->StyleName);
1445 HeapFree(GetProcessHeap(), 0, face);
1450 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1451 face->cached_enum_data = NULL;
1452 face->StyleName = StyleW;
1455 face->file = strdupA(file);
1456 face->font_data_ptr = NULL;
1457 face->font_data_size = 0;
1462 face->font_data_ptr = font_data_ptr;
1463 face->font_data_size = font_data_size;
1465 face->face_index = face_index;
1467 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1468 face->ntmFlags |= NTM_ITALIC;
1469 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1470 face->ntmFlags |= NTM_BOLD;
1471 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1472 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1473 face->family = family;
1474 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1476 memset(&face->fs_links, 0, sizeof(face->fs_links));
1478 if(FT_IS_SCALABLE(ft_face)) {
1479 memset(&face->size, 0, sizeof(face->size));
1480 face->scalable = TRUE;
1482 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1483 size->height, size->width, size->size >> 6,
1484 size->x_ppem >> 6, size->y_ppem >> 6);
1485 face->size.height = size->height;
1486 face->size.width = size->width;
1487 face->size.size = size->size;
1488 face->size.x_ppem = size->x_ppem;
1489 face->size.y_ppem = size->y_ppem;
1490 face->size.internal_leading = internal_leading;
1491 face->scalable = FALSE;
1494 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1496 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1498 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1499 face->ntmFlags |= NTM_PS_OPENTYPE;
1502 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1503 face->fs.fsCsb[0], face->fs.fsCsb[1],
1504 face->fs.fsUsb[0], face->fs.fsUsb[1],
1505 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1508 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1509 for(i = 0; i < ft_face->num_charmaps; i++) {
1510 switch(ft_face->charmaps[i]->encoding) {
1511 case FT_ENCODING_UNICODE:
1512 case FT_ENCODING_APPLE_ROMAN:
1513 face->fs.fsCsb[0] |= FS_LATIN1;
1515 case FT_ENCODING_MS_SYMBOL:
1516 face->fs.fsCsb[0] |= FS_SYMBOL;
1524 AddFaceToFamily(face, family);
1526 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1528 num_faces = ft_face->num_faces;
1529 pFT_Done_Face(ft_face);
1530 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1531 debugstr_w(StyleW));
1532 } while(num_faces > ++face_index);
1536 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1538 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1541 static void DumpFontList(void)
1545 struct list *family_elem_ptr, *face_elem_ptr;
1547 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1548 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1549 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1550 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1551 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1552 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1554 TRACE(" %d", face->size.height);
1561 /***********************************************************
1562 * The replacement list is a way to map an entire font
1563 * family onto another family. For example adding
1565 * [HKCU\Software\Wine\Fonts\Replacements]
1566 * "Wingdings"="Winedings"
1568 * would enumerate the Winedings font both as Winedings and
1569 * Wingdings. However if a real Wingdings font is present the
1570 * replacement does not take place.
1573 static void LoadReplaceList(void)
1576 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1581 struct list *family_elem_ptr, *face_elem_ptr;
1584 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1585 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1587 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1588 &valuelen, &datalen, NULL, NULL);
1590 valuelen++; /* returned value doesn't include room for '\0' */
1591 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1592 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1596 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1597 &dlen) == ERROR_SUCCESS) {
1598 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1599 /* "NewName"="Oldname" */
1600 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1602 /* Find the old family and hence all of the font files
1604 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1605 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1606 if(!strcmpiW(family->FamilyName, data)) {
1607 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1608 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1609 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1610 debugstr_w(face->StyleName), familyA);
1611 /* Now add a new entry with the new family name */
1612 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1617 /* reset dlen and vlen */
1621 HeapFree(GetProcessHeap(), 0, data);
1622 HeapFree(GetProcessHeap(), 0, value);
1627 /*************************************************************
1630 static BOOL init_system_links(void)
1634 DWORD type, max_val, max_data, val_len, data_len, index;
1635 WCHAR *value, *data;
1636 WCHAR *entry, *next;
1637 SYSTEM_LINKS *font_link, *system_font_link;
1638 CHILD_FONT *child_font;
1639 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1640 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1646 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1648 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1649 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1650 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1651 val_len = max_val + 1;
1652 data_len = max_data;
1654 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1656 memset(&fs, 0, sizeof(fs));
1657 psub = get_font_subst(&font_subst_list, value, -1);
1658 /* Don't store fonts that are only substitutes for other fonts */
1661 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1664 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1665 font_link->font_name = strdupW(value);
1666 list_init(&font_link->links);
1667 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1670 CHILD_FONT *child_font;
1672 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1674 next = entry + strlenW(entry) + 1;
1676 face_name = strchrW(entry, ',');
1680 while(isspaceW(*face_name))
1683 psub = get_font_subst(&font_subst_list, face_name, -1);
1685 face_name = psub->to.name;
1687 face = find_face_from_filename(entry, face_name);
1690 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1694 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1695 child_font->face = face;
1696 child_font->font = NULL;
1697 fs.fsCsb[0] |= face->fs.fsCsb[0];
1698 fs.fsCsb[1] |= face->fs.fsCsb[1];
1699 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1700 list_add_tail(&font_link->links, &child_font->entry);
1702 family = find_family_from_name(font_link->font_name);
1705 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1707 face->fs_links = fs;
1710 list_add_tail(&system_links, &font_link->entry);
1712 val_len = max_val + 1;
1713 data_len = max_data;
1716 HeapFree(GetProcessHeap(), 0, value);
1717 HeapFree(GetProcessHeap(), 0, data);
1721 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1724 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1725 system_font_link->font_name = strdupW(System);
1726 list_init(&system_font_link->links);
1728 face = find_face_from_filename(tahoma_ttf, Tahoma);
1731 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1732 child_font->face = face;
1733 child_font->font = NULL;
1734 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1735 list_add_tail(&system_font_link->links, &child_font->entry);
1737 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1739 if(!strcmpiW(font_link->font_name, Tahoma))
1741 CHILD_FONT *font_link_entry;
1742 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1744 CHILD_FONT *new_child;
1745 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1746 new_child->face = font_link_entry->face;
1747 new_child->font = NULL;
1748 list_add_tail(&system_font_link->links, &new_child->entry);
1753 list_add_tail(&system_links, &system_font_link->entry);
1757 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1760 struct dirent *dent;
1761 char path[MAX_PATH];
1763 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1765 dir = opendir(dirname);
1767 WARN("Can't open directory %s\n", debugstr_a(dirname));
1770 while((dent = readdir(dir)) != NULL) {
1771 struct stat statbuf;
1773 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1776 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1778 sprintf(path, "%s/%s", dirname, dent->d_name);
1780 if(stat(path, &statbuf) == -1)
1782 WARN("Can't stat %s\n", debugstr_a(path));
1785 if(S_ISDIR(statbuf.st_mode))
1786 ReadFontDir(path, external_fonts);
1788 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1794 static void load_fontconfig_fonts(void)
1796 #ifdef SONAME_LIBFONTCONFIG
1797 void *fc_handle = NULL;
1806 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1808 TRACE("Wine cannot find the fontconfig library (%s).\n",
1809 SONAME_LIBFONTCONFIG);
1812 #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;}
1813 LOAD_FUNCPTR(FcConfigGetCurrent);
1814 LOAD_FUNCPTR(FcFontList);
1815 LOAD_FUNCPTR(FcFontSetDestroy);
1816 LOAD_FUNCPTR(FcInit);
1817 LOAD_FUNCPTR(FcObjectSetAdd);
1818 LOAD_FUNCPTR(FcObjectSetCreate);
1819 LOAD_FUNCPTR(FcObjectSetDestroy);
1820 LOAD_FUNCPTR(FcPatternCreate);
1821 LOAD_FUNCPTR(FcPatternDestroy);
1822 LOAD_FUNCPTR(FcPatternGetBool);
1823 LOAD_FUNCPTR(FcPatternGetString);
1826 if(!pFcInit()) return;
1828 config = pFcConfigGetCurrent();
1829 pat = pFcPatternCreate();
1830 os = pFcObjectSetCreate();
1831 pFcObjectSetAdd(os, FC_FILE);
1832 pFcObjectSetAdd(os, FC_SCALABLE);
1833 fontset = pFcFontList(config, pat, os);
1834 if(!fontset) return;
1835 for(i = 0; i < fontset->nfont; i++) {
1838 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1840 TRACE("fontconfig: %s\n", file);
1842 /* We're just interested in OT/TT fonts for now, so this hack just
1843 picks up the scalable fonts without extensions .pf[ab] to save time
1844 loading every other font */
1846 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1848 TRACE("not scalable\n");
1852 len = strlen( file );
1853 if(len < 4) continue;
1854 ext = &file[ len - 3 ];
1855 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1856 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1858 pFcFontSetDestroy(fontset);
1859 pFcObjectSetDestroy(os);
1860 pFcPatternDestroy(pat);
1866 static BOOL load_font_from_data_dir(LPCWSTR file)
1869 const char *data_dir = wine_get_data_dir();
1871 if (!data_dir) data_dir = wine_get_build_dir();
1878 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1880 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1882 strcpy(unix_name, data_dir);
1883 strcat(unix_name, "/fonts/");
1885 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1887 EnterCriticalSection( &freetype_cs );
1888 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1889 LeaveCriticalSection( &freetype_cs );
1890 HeapFree(GetProcessHeap(), 0, unix_name);
1895 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1897 static const WCHAR slashW[] = {'\\','\0'};
1899 WCHAR windowsdir[MAX_PATH];
1902 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1903 strcatW(windowsdir, fontsW);
1904 strcatW(windowsdir, slashW);
1905 strcatW(windowsdir, file);
1906 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1907 EnterCriticalSection( &freetype_cs );
1908 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1909 LeaveCriticalSection( &freetype_cs );
1910 HeapFree(GetProcessHeap(), 0, unixname);
1915 static void load_system_fonts(void)
1918 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1919 const WCHAR * const *value;
1921 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1924 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1925 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1926 strcatW(windowsdir, fontsW);
1927 for(value = SystemFontValues; *value; value++) {
1928 dlen = sizeof(data);
1929 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1933 sprintfW(pathW, fmtW, windowsdir, data);
1934 if((unixname = wine_get_unix_file_name(pathW))) {
1935 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1936 HeapFree(GetProcessHeap(), 0, unixname);
1939 load_font_from_data_dir(data);
1946 /*************************************************************
1948 * This adds registry entries for any externally loaded fonts
1949 * (fonts from fontconfig or FontDirs). It also deletes entries
1950 * of no longer existing fonts.
1953 static void update_reg_entries(void)
1955 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1960 struct list *family_elem_ptr, *face_elem_ptr;
1962 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1963 static const WCHAR spaceW[] = {' ', '\0'};
1966 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1967 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1968 ERR("Can't create Windows font reg key\n");
1972 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1973 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1974 ERR("Can't create Windows font reg key\n");
1978 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1979 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1980 ERR("Can't create external font reg key\n");
1984 /* enumerate the fonts and add external ones to the two keys */
1986 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1987 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1988 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1989 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1990 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1991 if(!face->external) continue;
1993 if (!(face->ntmFlags & NTM_REGULAR))
1994 len = len_fam + strlenW(face->StyleName) + 1;
1995 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1996 strcpyW(valueW, family->FamilyName);
1997 if(len != len_fam) {
1998 strcatW(valueW, spaceW);
1999 strcatW(valueW, face->StyleName);
2001 strcatW(valueW, TrueType);
2003 file = wine_get_dos_file_name(face->file);
2005 len = strlenW(file) + 1;
2008 if((path = strrchr(face->file, '/')) == NULL)
2012 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2014 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2015 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2017 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2018 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2019 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2021 HeapFree(GetProcessHeap(), 0, file);
2022 HeapFree(GetProcessHeap(), 0, valueW);
2026 if(external_key) RegCloseKey(external_key);
2027 if(win9x_key) RegCloseKey(win9x_key);
2028 if(winnt_key) RegCloseKey(winnt_key);
2032 static void delete_external_font_keys(void)
2034 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2035 DWORD dlen, vlen, datalen, valuelen, i, type;
2039 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2040 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2041 ERR("Can't create Windows font reg key\n");
2045 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2046 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2047 ERR("Can't create Windows font reg key\n");
2051 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2052 ERR("Can't create external font reg key\n");
2056 /* Delete all external fonts added last time */
2058 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2059 &valuelen, &datalen, NULL, NULL);
2060 valuelen++; /* returned value doesn't include room for '\0' */
2061 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2062 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2064 dlen = datalen * sizeof(WCHAR);
2067 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2068 &dlen) == ERROR_SUCCESS) {
2070 RegDeleteValueW(winnt_key, valueW);
2071 RegDeleteValueW(win9x_key, valueW);
2072 /* reset dlen and vlen */
2076 HeapFree(GetProcessHeap(), 0, data);
2077 HeapFree(GetProcessHeap(), 0, valueW);
2079 /* Delete the old external fonts key */
2080 RegCloseKey(external_key);
2081 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2084 if(win9x_key) RegCloseKey(win9x_key);
2085 if(winnt_key) RegCloseKey(winnt_key);
2088 /*************************************************************
2089 * WineEngAddFontResourceEx
2092 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2098 if (ft_handle) /* do it only if we have freetype up and running */
2103 FIXME("Ignoring flags %x\n", flags);
2105 if((unixname = wine_get_unix_file_name(file)))
2107 EnterCriticalSection( &freetype_cs );
2108 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2109 LeaveCriticalSection( &freetype_cs );
2110 HeapFree(GetProcessHeap(), 0, unixname);
2112 if (!ret && !strchrW(file, '\\')) {
2113 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2114 ret = load_font_from_winfonts_dir(file);
2116 /* Try in datadir/fonts (or builddir/fonts),
2117 * needed for Magic the Gathering Online
2119 ret = load_font_from_data_dir(file);
2126 /*************************************************************
2127 * WineEngAddFontMemResourceEx
2130 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2134 if (ft_handle) /* do it only if we have freetype up and running */
2136 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2138 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2139 memcpy(pFontCopy, pbFont, cbFont);
2141 EnterCriticalSection( &freetype_cs );
2142 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2143 LeaveCriticalSection( &freetype_cs );
2147 TRACE("AddFontToList failed\n");
2148 HeapFree(GetProcessHeap(), 0, pFontCopy);
2151 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2152 * For now return something unique but quite random
2154 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2155 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2162 /*************************************************************
2163 * WineEngRemoveFontResourceEx
2166 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2169 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2173 static const struct nls_update_font_list
2175 UINT ansi_cp, oem_cp;
2176 const char *oem, *fixed, *system;
2177 const char *courier, *serif, *small, *sserif;
2178 /* these are for font substitutes */
2179 const char *shelldlg, *tmsrmn;
2180 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2184 const char *from, *to;
2185 } arial_0, courier_new_0, times_new_roman_0;
2186 } nls_update_font_list[] =
2188 /* Latin 1 (United States) */
2189 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2190 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2191 "Tahoma","Times New Roman",
2192 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2195 /* Latin 1 (Multilingual) */
2196 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2197 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2198 "Tahoma","Times New Roman", /* FIXME unverified */
2199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2202 /* Eastern Europe */
2203 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2204 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,238", "System,238",
2207 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2208 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2209 { "Arial CE,0", "Arial,238" },
2210 { "Courier New CE,0", "Courier New,238" },
2211 { "Times New Roman CE,0", "Times New Roman,238" }
2214 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2215 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,204", "System,204",
2218 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2219 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2220 { "Arial Cyr,0", "Arial,204" },
2221 { "Courier New Cyr,0", "Courier New,204" },
2222 { "Times New Roman Cyr,0", "Times New Roman,204" }
2225 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2226 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,161", "System,161",
2229 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2230 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2231 { "Arial Greek,0", "Arial,161" },
2232 { "Courier New Greek,0", "Courier New,161" },
2233 { "Times New Roman Greek,0", "Times New Roman,161" }
2236 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2237 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,162", "System,162",
2240 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2241 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2242 { "Arial Tur,0", "Arial,162" },
2243 { "Courier New Tur,0", "Courier New,162" },
2244 { "Times New Roman Tur,0", "Times New Roman,162" }
2247 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2248 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2249 "Tahoma","Times New Roman", /* FIXME unverified */
2250 "Fixedsys,177", "System,177",
2251 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2252 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2256 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2257 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2258 "Tahoma","Times New Roman", /* FIXME unverified */
2259 "Fixedsys,178", "System,178",
2260 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2261 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2265 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2266 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2267 "Tahoma","Times New Roman", /* FIXME unverified */
2268 "Fixedsys,186", "System,186",
2269 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2270 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2271 { "Arial Baltic,0", "Arial,186" },
2272 { "Courier New Baltic,0", "Courier New,186" },
2273 { "Times New Roman Baltic,0", "Times New Roman,186" }
2276 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2277 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2283 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2284 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2285 "Tahoma","Times New Roman", /* FIXME unverified */
2286 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2290 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2291 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2292 "MS UI Gothic","MS Serif",
2293 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2296 /* Chinese Simplified */
2297 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2299 "SimSun", "NSimSun",
2300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2304 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2310 /* Chinese Traditional */
2311 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2312 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2313 "PMingLiU", "MingLiU",
2314 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2319 static const WCHAR *font_links_list[] =
2321 Lucida_Sans_Unicode,
2322 Microsoft_Sans_Serif,
2326 static const struct font_links_defaults_list
2328 /* Keyed off substitution for "MS Shell Dlg" */
2329 const WCHAR *shelldlg;
2330 /* Maximum of four substitutes, plus terminating NULL pointer */
2331 const WCHAR *substitutes[5];
2332 } font_links_defaults_list[] =
2334 /* Non East-Asian */
2335 { Tahoma, /* FIXME unverified ordering */
2336 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2338 /* Below lists are courtesy of
2339 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2343 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2345 /* Chinese Simplified */
2347 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2351 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2353 /* Chinese Traditional */
2355 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2359 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2361 return ( ansi_cp == 932 /* CP932 for Japanese */
2362 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2363 || ansi_cp == 949 /* CP949 for Korean */
2364 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2367 static inline HKEY create_fonts_NT_registry_key(void)
2371 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2372 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2376 static inline HKEY create_fonts_9x_registry_key(void)
2380 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2381 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2385 static inline HKEY create_config_fonts_registry_key(void)
2389 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2390 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2394 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2396 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2397 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2398 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2399 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2402 static void set_value_key(HKEY hkey, const char *name, const char *value)
2405 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2407 RegDeleteValueA(hkey, name);
2410 static void update_font_info(void)
2412 char buf[40], cpbuf[40];
2415 UINT i, ansi_cp = 0, oem_cp = 0;
2418 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2421 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2422 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2423 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2424 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2425 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2427 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2428 if (is_dbcs_ansi_cp(ansi_cp))
2429 use_default_fallback = TRUE;
2432 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2434 if (!strcmp( buf, cpbuf )) /* already set correctly */
2439 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2441 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2443 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2446 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2450 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2451 nls_update_font_list[i].oem_cp == oem_cp)
2453 hkey = create_config_fonts_registry_key();
2454 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2455 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2456 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2459 hkey = create_fonts_NT_registry_key();
2460 add_font_list(hkey, &nls_update_font_list[i]);
2463 hkey = create_fonts_9x_registry_key();
2464 add_font_list(hkey, &nls_update_font_list[i]);
2467 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2469 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2470 strlen(nls_update_font_list[i].shelldlg)+1);
2471 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2472 strlen(nls_update_font_list[i].tmsrmn)+1);
2474 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2475 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2476 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2477 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2478 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2479 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2480 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2481 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2483 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2484 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2485 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2493 /* Delete the FontSubstitutes from other locales */
2494 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2496 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2497 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2498 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2504 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2506 /* Clear out system links */
2507 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2510 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2520 WCHAR buff[MAX_PATH];
2524 static const WCHAR comma[] = {',',0};
2526 RegDeleteValueW(hkey, name);
2531 for (i = 0; values[i] != NULL; i++)
2534 if (!strcmpiW(name,value))
2536 psub = get_font_subst(&font_subst_list, value, -1);
2538 value = psub->to.name;
2539 family = find_family_from_name(value);
2543 /* Use first extant filename for this Family */
2544 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2548 file = strrchr(face->file, '/');
2557 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2558 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2559 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2560 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2561 if (sizeof(buff)-(data-buff) < entryLen + 1)
2563 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2564 HeapFree(GetProcessHeap(), 0, fileW);
2567 strcpyW(data, fileW);
2568 strcatW(data, comma);
2569 strcatW(data, value);
2571 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2572 HeapFree(GetProcessHeap(), 0, fileW);
2578 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2580 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2582 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2585 static void update_system_links(void)
2593 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2595 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2597 if (disposition == REG_OPENED_EXISTING_KEY)
2599 TRACE("SystemLink key already exists, doing nothing\n");
2604 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2606 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2611 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2613 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2615 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2616 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2618 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2619 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2622 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2624 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2629 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2631 WARN("failed to create SystemLink key\n");
2635 static BOOL init_freetype(void)
2637 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2640 "Wine cannot find the FreeType font library. To enable Wine to\n"
2641 "use TrueType fonts please install a version of FreeType greater than\n"
2642 "or equal to 2.0.5.\n"
2643 "http://www.freetype.org\n");
2647 #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;}
2649 LOAD_FUNCPTR(FT_Vector_Unit)
2650 LOAD_FUNCPTR(FT_Done_Face)
2651 LOAD_FUNCPTR(FT_Get_Char_Index)
2652 LOAD_FUNCPTR(FT_Get_Module)
2653 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2654 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2655 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2656 LOAD_FUNCPTR(FT_Init_FreeType)
2657 LOAD_FUNCPTR(FT_Load_Glyph)
2658 LOAD_FUNCPTR(FT_Matrix_Multiply)
2659 #ifndef FT_MULFIX_INLINED
2660 LOAD_FUNCPTR(FT_MulFix)
2662 LOAD_FUNCPTR(FT_New_Face)
2663 LOAD_FUNCPTR(FT_New_Memory_Face)
2664 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2665 LOAD_FUNCPTR(FT_Outline_Transform)
2666 LOAD_FUNCPTR(FT_Outline_Translate)
2667 LOAD_FUNCPTR(FT_Select_Charmap)
2668 LOAD_FUNCPTR(FT_Set_Charmap)
2669 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2670 LOAD_FUNCPTR(FT_Vector_Transform)
2671 LOAD_FUNCPTR(FT_Render_Glyph)
2674 /* Don't warn if these ones are missing */
2675 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2676 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2677 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2678 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2679 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2680 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2681 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2683 #ifdef HAVE_FREETYPE_FTWINFNT_H
2684 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2686 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2687 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2688 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2689 <= 2.0.3 has FT_Sqrt64 */
2693 if(pFT_Init_FreeType(&library) != 0) {
2694 ERR("Can't init FreeType library\n");
2695 wine_dlclose(ft_handle, NULL, 0);
2699 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2700 if (pFT_Library_Version)
2701 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2703 if (FT_Version.major<=0)
2709 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2710 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2711 ((FT_Version.minor << 8) & 0x00ff00) |
2712 ((FT_Version.patch ) & 0x0000ff);
2718 "Wine cannot find certain functions that it needs inside the FreeType\n"
2719 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2720 "FreeType to at least version 2.0.5.\n"
2721 "http://www.freetype.org\n");
2722 wine_dlclose(ft_handle, NULL, 0);
2727 /*************************************************************
2730 * Initialize FreeType library and create a list of available faces
2732 BOOL WineEngInit(void)
2734 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2735 static const WCHAR pathW[] = {'P','a','t','h',0};
2737 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2738 WCHAR windowsdir[MAX_PATH];
2741 const char *data_dir;
2745 /* update locale dependent font info in registry */
2748 if(!init_freetype()) return FALSE;
2750 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2751 ERR("Failed to create font mutex\n");
2754 WaitForSingleObject(font_mutex, INFINITE);
2756 delete_external_font_keys();
2758 /* load the system bitmap fonts */
2759 load_system_fonts();
2761 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2762 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2763 strcatW(windowsdir, fontsW);
2764 if((unixname = wine_get_unix_file_name(windowsdir)))
2766 ReadFontDir(unixname, FALSE);
2767 HeapFree(GetProcessHeap(), 0, unixname);
2770 /* load the system truetype fonts */
2771 data_dir = wine_get_data_dir();
2772 if (!data_dir) data_dir = wine_get_build_dir();
2773 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2774 strcpy(unixname, data_dir);
2775 strcat(unixname, "/fonts/");
2776 ReadFontDir(unixname, TRUE);
2777 HeapFree(GetProcessHeap(), 0, unixname);
2780 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2781 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2782 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2784 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2785 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2786 &hkey) == ERROR_SUCCESS) {
2787 LPWSTR data, valueW;
2788 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2789 &valuelen, &datalen, NULL, NULL);
2791 valuelen++; /* returned value doesn't include room for '\0' */
2792 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2793 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2796 dlen = datalen * sizeof(WCHAR);
2798 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2799 &dlen) == ERROR_SUCCESS) {
2800 if(data[0] && (data[1] == ':'))
2802 if((unixname = wine_get_unix_file_name(data)))
2804 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2805 HeapFree(GetProcessHeap(), 0, unixname);
2808 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2810 WCHAR pathW[MAX_PATH];
2811 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2814 sprintfW(pathW, fmtW, windowsdir, data);
2815 if((unixname = wine_get_unix_file_name(pathW)))
2817 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2818 HeapFree(GetProcessHeap(), 0, unixname);
2821 load_font_from_data_dir(data);
2823 /* reset dlen and vlen */
2828 HeapFree(GetProcessHeap(), 0, data);
2829 HeapFree(GetProcessHeap(), 0, valueW);
2833 load_fontconfig_fonts();
2835 /* then look in any directories that we've specified in the config file */
2836 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2837 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2843 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2845 len += sizeof(WCHAR);
2846 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2847 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2849 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2850 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2851 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2852 TRACE( "got font path %s\n", debugstr_a(valueA) );
2856 LPSTR next = strchr( ptr, ':' );
2857 if (next) *next++ = 0;
2858 ReadFontDir( ptr, TRUE );
2861 HeapFree( GetProcessHeap(), 0, valueA );
2863 HeapFree( GetProcessHeap(), 0, valueW );
2872 update_reg_entries();
2874 update_system_links();
2875 init_system_links();
2877 ReleaseMutex(font_mutex);
2882 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2885 TT_HoriHeader *pHori;
2889 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2890 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2892 if(height == 0) height = 16;
2894 /* Calc. height of EM square:
2896 * For +ve lfHeight we have
2897 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2898 * Re-arranging gives:
2899 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2901 * For -ve lfHeight we have
2903 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2904 * with il = winAscent + winDescent - units_per_em]
2909 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2910 ppem = MulDiv(ft_face->units_per_EM, height,
2911 pHori->Ascender - pHori->Descender);
2913 ppem = MulDiv(ft_face->units_per_EM, height,
2914 pOS2->usWinAscent + pOS2->usWinDescent);
2922 static struct font_mapping *map_font_file( const char *name )
2924 struct font_mapping *mapping;
2928 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2929 if (fstat( fd, &st ) == -1) goto error;
2931 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2933 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2935 mapping->refcount++;
2940 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2943 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2946 if (mapping->data == MAP_FAILED)
2948 HeapFree( GetProcessHeap(), 0, mapping );
2951 mapping->refcount = 1;
2952 mapping->dev = st.st_dev;
2953 mapping->ino = st.st_ino;
2954 mapping->size = st.st_size;
2955 list_add_tail( &mappings_list, &mapping->entry );
2963 static void unmap_font_file( struct font_mapping *mapping )
2965 if (!--mapping->refcount)
2967 list_remove( &mapping->entry );
2968 munmap( mapping->data, mapping->size );
2969 HeapFree( GetProcessHeap(), 0, mapping );
2973 static LONG load_VDMX(GdiFont*, LONG);
2975 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2982 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2986 if (!(font->mapping = map_font_file( face->file )))
2988 WARN("failed to map %s\n", debugstr_a(face->file));
2991 data_ptr = font->mapping->data;
2992 data_size = font->mapping->size;
2996 data_ptr = face->font_data_ptr;
2997 data_size = face->font_data_size;
3000 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3002 ERR("FT_New_Face rets %d\n", err);
3006 /* set it here, as load_VDMX needs it */
3007 font->ft_face = ft_face;
3009 if(FT_IS_SCALABLE(ft_face)) {
3010 /* load the VDMX table if we have one */
3011 font->ppem = load_VDMX(font, height);
3013 font->ppem = calc_ppem_for_height(ft_face, height);
3014 TRACE("height %d => ppem %d\n", height, font->ppem);
3016 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3017 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3019 font->ppem = height;
3020 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3021 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3027 static int get_nearest_charset(Face *face, int *cp)
3029 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3030 a single face with the requested charset. The idea is to check if
3031 the selected font supports the current ANSI codepage, if it does
3032 return the corresponding charset, else return the first charset */
3035 int acp = GetACP(), i;
3039 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3040 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3041 return csi.ciCharset;
3043 for(i = 0; i < 32; i++) {
3045 if(face->fs.fsCsb[0] & fs0) {
3046 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3048 return csi.ciCharset;
3051 FIXME("TCI failing on %x\n", fs0);
3055 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3056 face->fs.fsCsb[0], face->file);
3058 return DEFAULT_CHARSET;
3061 static GdiFont *alloc_font(void)
3063 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3065 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3066 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3068 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3069 ret->total_kern_pairs = (DWORD)-1;
3070 ret->kern_pairs = NULL;
3071 list_init(&ret->hfontlist);
3072 list_init(&ret->child_fonts);
3076 static void free_font(GdiFont *font)
3078 struct list *cursor, *cursor2;
3081 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3083 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3084 list_remove(cursor);
3086 free_font(child->font);
3087 HeapFree(GetProcessHeap(), 0, child);
3090 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3092 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3093 DeleteObject(hfontlist->hfont);
3094 list_remove(&hfontlist->entry);
3095 HeapFree(GetProcessHeap(), 0, hfontlist);
3098 if (font->ft_face) pFT_Done_Face(font->ft_face);
3099 if (font->mapping) unmap_font_file( font->mapping );
3100 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3101 HeapFree(GetProcessHeap(), 0, font->potm);
3102 HeapFree(GetProcessHeap(), 0, font->name);
3103 for (i = 0; i < font->gmsize; i++)
3104 HeapFree(GetProcessHeap(),0,font->gm[i]);
3105 HeapFree(GetProcessHeap(), 0, font->gm);
3106 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3107 HeapFree(GetProcessHeap(), 0, font);
3111 /*************************************************************
3114 * load the vdmx entry for the specified height
3117 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3118 ( ( (FT_ULong)_x4 << 24 ) | \
3119 ( (FT_ULong)_x3 << 16 ) | \
3120 ( (FT_ULong)_x2 << 8 ) | \
3123 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3138 static LONG load_VDMX(GdiFont *font, LONG height)
3142 BYTE devXRatio, devYRatio;
3143 USHORT numRecs, numRatios;
3144 DWORD result, offset = -1;
3148 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3150 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3153 /* FIXME: need the real device aspect ratio */
3157 numRecs = GET_BE_WORD(hdr[1]);
3158 numRatios = GET_BE_WORD(hdr[2]);
3160 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3161 for(i = 0; i < numRatios; i++) {
3164 offset = (3 * 2) + (i * sizeof(Ratios));
3165 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3168 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3170 if((ratio.xRatio == 0 &&
3171 ratio.yStartRatio == 0 &&
3172 ratio.yEndRatio == 0) ||
3173 (devXRatio == ratio.xRatio &&
3174 devYRatio >= ratio.yStartRatio &&
3175 devYRatio <= ratio.yEndRatio))
3177 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3178 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3179 offset = GET_BE_WORD(tmp);
3185 FIXME("No suitable ratio found\n");
3189 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3191 BYTE startsz, endsz;
3194 recs = GET_BE_WORD(group.recs);
3195 startsz = group.startsz;
3196 endsz = group.endsz;
3198 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3200 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3201 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3202 if(result == GDI_ERROR) {
3203 FIXME("Failed to retrieve vTable\n");
3208 for(i = 0; i < recs; i++) {
3209 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3210 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3211 ppem = GET_BE_WORD(vTable[i * 3]);
3213 if(yMax + -yMin == height) {
3216 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3219 if(yMax + -yMin > height) {
3222 goto end; /* failed */
3224 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3225 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3226 ppem = GET_BE_WORD(vTable[i * 3]);
3227 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3233 TRACE("ppem not found for height %d\n", height);
3237 HeapFree(GetProcessHeap(), 0, vTable);
3243 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3245 if(font->font_desc.hash != fd->hash) return TRUE;
3246 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3247 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3248 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3249 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3252 static void calc_hash(FONT_DESC *pfd)
3254 DWORD hash = 0, *ptr, two_chars;
3258 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3260 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3262 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3264 pwc = (WCHAR *)&two_chars;
3266 *pwc = toupperW(*pwc);
3268 *pwc = toupperW(*pwc);
3272 hash ^= !pfd->can_use_bitmap;
3277 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3282 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3286 fd.can_use_bitmap = can_use_bitmap;
3289 /* try the child list */
3290 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3291 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3292 if(!fontcmp(ret, &fd)) {
3293 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3294 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3295 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3296 if(hflist->hfont == hfont)
3302 /* try the in-use list */
3303 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3304 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3305 if(!fontcmp(ret, &fd)) {
3306 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3307 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3308 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3309 if(hflist->hfont == hfont)
3312 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3313 hflist->hfont = hfont;
3314 list_add_head(&ret->hfontlist, &hflist->entry);
3319 /* then the unused list */
3320 font_elem_ptr = list_head(&unused_gdi_font_list);
3321 while(font_elem_ptr) {
3322 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3323 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3324 if(!fontcmp(ret, &fd)) {
3325 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3326 assert(list_empty(&ret->hfontlist));
3327 TRACE("Found %p in unused list\n", ret);
3328 list_remove(&ret->entry);
3329 list_add_head(&gdi_font_list, &ret->entry);
3330 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3331 hflist->hfont = hfont;
3332 list_add_head(&ret->hfontlist, &hflist->entry);
3339 static void add_to_cache(GdiFont *font)
3341 static DWORD cache_num = 1;
3343 font->cache_num = cache_num++;
3344 list_add_head(&gdi_font_list, &font->entry);
3347 /*************************************************************
3348 * create_child_font_list
3350 static BOOL create_child_font_list(GdiFont *font)
3353 SYSTEM_LINKS *font_link;
3354 CHILD_FONT *font_link_entry, *new_child;
3358 psub = get_font_subst(&font_subst_list, font->name, -1);
3359 font_name = psub ? psub->to.name : font->name;
3360 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3362 if(!strcmpiW(font_link->font_name, font_name))
3364 TRACE("found entry in system list\n");
3365 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3367 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3368 new_child->face = font_link_entry->face;
3369 new_child->font = NULL;
3370 list_add_tail(&font->child_fonts, &new_child->entry);
3371 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3378 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3379 * Sans Serif. This is how asian windows get default fallbacks for fonts
3381 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3382 font->charset != OEM_CHARSET &&
3383 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3384 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3386 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3388 TRACE("found entry in default fallback list\n");
3389 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3391 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3392 new_child->face = font_link_entry->face;
3393 new_child->font = NULL;
3394 list_add_tail(&font->child_fonts, &new_child->entry);
3395 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3405 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3407 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3409 if (pFT_Set_Charmap)
3412 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3414 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3416 for (i = 0; i < ft_face->num_charmaps; i++)
3418 if (ft_face->charmaps[i]->encoding == encoding)
3420 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3421 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3423 switch (ft_face->charmaps[i]->platform_id)
3426 cmap_def = ft_face->charmaps[i];
3428 case 0: /* Apple Unicode */
3429 cmap0 = ft_face->charmaps[i];
3431 case 1: /* Macintosh */
3432 cmap1 = ft_face->charmaps[i];
3435 cmap2 = ft_face->charmaps[i];
3437 case 3: /* Microsoft */
3438 cmap3 = ft_face->charmaps[i];
3443 if (cmap3) /* prefer Microsoft cmap table */
3444 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3446 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3448 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3450 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3452 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3454 return ft_err == FT_Err_Ok;
3457 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3460 /*************************************************************
3461 * WineEngCreateFontInstance
3464 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3467 Face *face, *best, *best_bitmap;
3468 Family *family, *last_resort_family;
3469 struct list *family_elem_ptr, *face_elem_ptr;
3470 INT height, width = 0;
3471 unsigned int score = 0, new_score;
3472 signed int diff = 0, newdiff;
3473 BOOL bd, it, can_use_bitmap;
3478 FontSubst *psub = NULL;
3480 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3481 lf.lfWidth = abs(lf.lfWidth);
3483 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3485 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3486 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3487 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3490 if(dc->GraphicsMode == GM_ADVANCED)
3491 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3494 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3495 font scaling abilities. */
3496 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3497 dcmat.eM21 = dcmat.eM12 = 0;
3500 /* Try to avoid not necessary glyph transformations */
3501 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3503 lf.lfHeight *= fabs(dcmat.eM11);
3504 lf.lfWidth *= fabs(dcmat.eM11);
3505 dcmat.eM11 = dcmat.eM22 = 1.0;
3508 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3509 dcmat.eM21, dcmat.eM22);
3512 EnterCriticalSection( &freetype_cs );
3514 /* check the cache first */
3515 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3516 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3517 LeaveCriticalSection( &freetype_cs );
3521 TRACE("not in cache\n");
3522 if(list_empty(&font_list)) /* No fonts installed */
3524 TRACE("No fonts installed\n");
3525 LeaveCriticalSection( &freetype_cs );
3531 ret->font_desc.matrix = dcmat;
3532 ret->font_desc.lf = lf;
3533 ret->font_desc.can_use_bitmap = can_use_bitmap;
3534 calc_hash(&ret->font_desc);
3535 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3536 hflist->hfont = hfont;
3537 list_add_head(&ret->hfontlist, &hflist->entry);
3539 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3540 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3541 original value lfCharSet. Note this is a special case for
3542 Symbol and doesn't happen at least for "Wingdings*" */
3544 if(!strcmpiW(lf.lfFaceName, SymbolW))
3545 lf.lfCharSet = SYMBOL_CHARSET;
3547 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3548 switch(lf.lfCharSet) {
3549 case DEFAULT_CHARSET:
3550 csi.fs.fsCsb[0] = 0;
3553 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3554 csi.fs.fsCsb[0] = 0;
3560 if(lf.lfFaceName[0] != '\0') {
3561 SYSTEM_LINKS *font_link;
3562 CHILD_FONT *font_link_entry;
3563 LPWSTR FaceName = lf.lfFaceName;
3566 * Check for a leading '@' this signals that the font is being
3567 * requested in tategaki mode (vertical writing substitution) but
3568 * does not affect the fontface that is to be selected.
3570 if (lf.lfFaceName[0]=='@')
3571 FaceName = &lf.lfFaceName[1];
3573 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3576 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3577 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3578 if (psub->to.charset != -1)
3579 lf.lfCharSet = psub->to.charset;
3582 /* We want a match on name and charset or just name if
3583 charset was DEFAULT_CHARSET. If the latter then
3584 we fixup the returned charset later in get_nearest_charset
3585 where we'll either use the charset of the current ansi codepage
3586 or if that's unavailable the first charset that the font supports.
3588 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3589 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3590 if (!strcmpiW(family->FamilyName, FaceName) ||
3591 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3593 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3594 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3595 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3596 if(face->scalable || can_use_bitmap)
3603 * Try check the SystemLink list first for a replacement font.
3604 * We may find good replacements there.
3606 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3608 if(!strcmpiW(font_link->font_name, FaceName) ||
3609 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3611 TRACE("found entry in system list\n");
3612 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3614 face = font_link_entry->face;
3615 family = face->family;
3616 if(csi.fs.fsCsb[0] &
3617 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3619 if(face->scalable || can_use_bitmap)
3627 psub = NULL; /* substitution is no more relevant */
3629 /* If requested charset was DEFAULT_CHARSET then try using charset
3630 corresponding to the current ansi codepage */
3631 if (!csi.fs.fsCsb[0])
3634 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3635 FIXME("TCI failed on codepage %d\n", acp);
3636 csi.fs.fsCsb[0] = 0;
3638 lf.lfCharSet = csi.ciCharset;
3641 /* Face families are in the top 4 bits of lfPitchAndFamily,
3642 so mask with 0xF0 before testing */
3644 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3645 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3646 strcpyW(lf.lfFaceName, defFixed);
3647 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3648 strcpyW(lf.lfFaceName, defSerif);
3649 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3650 strcpyW(lf.lfFaceName, defSans);
3652 strcpyW(lf.lfFaceName, defSans);
3653 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3654 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3655 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3656 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3657 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3658 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3659 if(face->scalable || can_use_bitmap)
3665 last_resort_family = NULL;
3666 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3667 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3668 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3669 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3670 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3673 if(can_use_bitmap && !last_resort_family)
3674 last_resort_family = family;
3679 if(last_resort_family) {
3680 family = last_resort_family;
3681 csi.fs.fsCsb[0] = 0;
3685 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3686 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3687 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3688 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3689 if(face->scalable) {
3690 csi.fs.fsCsb[0] = 0;
3691 WARN("just using first face for now\n");
3694 if(can_use_bitmap && !last_resort_family)
3695 last_resort_family = family;
3698 if(!last_resort_family) {
3699 FIXME("can't find a single appropriate font - bailing\n");
3701 LeaveCriticalSection( &freetype_cs );
3705 WARN("could only find a bitmap font - this will probably look awful!\n");
3706 family = last_resort_family;
3707 csi.fs.fsCsb[0] = 0;
3710 it = lf.lfItalic ? 1 : 0;
3711 bd = lf.lfWeight > 550 ? 1 : 0;
3713 height = lf.lfHeight;
3715 face = best = best_bitmap = NULL;
3716 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3718 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3722 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3723 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3724 new_score = (italic ^ it) + (bold ^ bd);
3725 if(!best || new_score <= score)
3727 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3728 italic, bold, it, bd);
3731 if(best->scalable && score == 0) break;
3735 newdiff = height - (signed int)(best->size.height);
3737 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3738 if(!best_bitmap || new_score < score ||
3739 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3741 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3744 if(score == 0 && diff == 0) break;
3751 face = best->scalable ? best : best_bitmap;
3752 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3753 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3757 if(csi.fs.fsCsb[0]) {
3758 ret->charset = lf.lfCharSet;
3759 ret->codepage = csi.ciACP;
3762 ret->charset = get_nearest_charset(face, &ret->codepage);
3764 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3765 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3767 ret->aveWidth = height ? lf.lfWidth : 0;
3769 if(!face->scalable) {
3770 /* Windows uses integer scaling factors for bitmap fonts */
3771 INT scale, scaled_height;
3772 GdiFont *cachedfont;
3774 /* FIXME: rotation of bitmap fonts is ignored */
3775 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3777 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3778 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3779 dcmat.eM11 = dcmat.eM22 = 1.0;
3780 /* As we changed the matrix, we need to search the cache for the font again,
3781 * otherwise we might explode the cache. */
3782 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3783 TRACE("Found cached font after non-scalable matrix rescale!\n");
3785 LeaveCriticalSection( &freetype_cs );
3788 calc_hash(&ret->font_desc);
3790 if (height != 0) height = diff;
3791 height += face->size.height;
3793 scale = (height + face->size.height - 1) / face->size.height;
3794 scaled_height = scale * face->size.height;
3795 /* Only jump to the next height if the difference <= 25% original height */
3796 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3797 /* The jump between unscaled and doubled is delayed by 1 */
3798 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3799 ret->scale_y = scale;
3801 width = face->size.x_ppem >> 6;
3802 height = face->size.y_ppem >> 6;
3806 TRACE("font scale y: %f\n", ret->scale_y);
3808 ret->ft_face = OpenFontFace(ret, face, width, height);
3813 LeaveCriticalSection( &freetype_cs );
3817 ret->ntmFlags = face->ntmFlags;
3819 if (ret->charset == SYMBOL_CHARSET &&
3820 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3823 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3827 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3830 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3831 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3832 ret->underline = lf.lfUnderline ? 0xff : 0;
3833 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3834 create_child_font_list(ret);
3836 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3838 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3839 if (length != GDI_ERROR)
3841 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3842 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3843 TRACE("Loaded GSUB table of %i bytes\n",length);
3847 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3850 LeaveCriticalSection( &freetype_cs );
3854 static void dump_gdi_font_list(void)
3857 struct list *elem_ptr;
3859 TRACE("---------- gdiFont Cache ----------\n");
3860 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3861 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3862 TRACE("gdiFont=%p %s %d\n",
3863 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3866 TRACE("---------- Unused gdiFont Cache ----------\n");
3867 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3868 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3869 TRACE("gdiFont=%p %s %d\n",
3870 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3873 TRACE("---------- Child gdiFont Cache ----------\n");
3874 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3875 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3876 TRACE("gdiFont=%p %s %d\n",
3877 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3881 /*************************************************************
3882 * WineEngDestroyFontInstance
3884 * free the gdiFont associated with this handle
3887 BOOL WineEngDestroyFontInstance(HFONT handle)
3892 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3896 EnterCriticalSection( &freetype_cs );
3898 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3900 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3901 while(hfontlist_elem_ptr) {
3902 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3903 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3904 if(hflist->hfont == handle) {
3905 TRACE("removing child font %p from child list\n", gdiFont);
3906 list_remove(&gdiFont->entry);
3907 LeaveCriticalSection( &freetype_cs );
3913 TRACE("destroying hfont=%p\n", handle);
3915 dump_gdi_font_list();
3917 font_elem_ptr = list_head(&gdi_font_list);
3918 while(font_elem_ptr) {
3919 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3920 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3922 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3923 while(hfontlist_elem_ptr) {
3924 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3925 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3926 if(hflist->hfont == handle) {
3927 list_remove(&hflist->entry);
3928 HeapFree(GetProcessHeap(), 0, hflist);
3932 if(list_empty(&gdiFont->hfontlist)) {
3933 TRACE("Moving to Unused list\n");
3934 list_remove(&gdiFont->entry);
3935 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3940 font_elem_ptr = list_head(&unused_gdi_font_list);
3941 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3942 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3943 while(font_elem_ptr) {
3944 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3945 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3946 TRACE("freeing %p\n", gdiFont);
3947 list_remove(&gdiFont->entry);
3950 LeaveCriticalSection( &freetype_cs );
3954 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3955 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3960 if (face->cached_enum_data)
3963 *pelf = face->cached_enum_data->elf;
3964 *pntm = face->cached_enum_data->ntm;
3965 *ptype = face->cached_enum_data->type;
3969 font = alloc_font();
3971 if(face->scalable) {
3972 height = -2048; /* 2048 is the most common em size */
3975 height = face->size.y_ppem >> 6;
3976 width = face->size.x_ppem >> 6;
3978 font->scale_y = 1.0;
3980 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3986 font->name = strdupW(face->family->FamilyName);
3987 font->ntmFlags = face->ntmFlags;
3989 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3991 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3993 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3995 lstrcpynW(pelf->elfLogFont.lfFaceName,
3996 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3998 lstrcpynW(pelf->elfFullName,
3999 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4001 lstrcpynW(pelf->elfStyle,
4002 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4007 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4009 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4011 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4012 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4013 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4016 pntm->ntmTm.ntmFlags = face->ntmFlags;
4017 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4018 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4019 pntm->ntmFontSig = face->fs;
4021 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4023 pelf->elfLogFont.lfEscapement = 0;
4024 pelf->elfLogFont.lfOrientation = 0;
4025 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4026 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4027 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4028 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4029 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4030 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4031 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4032 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4033 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4034 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4035 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4038 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4039 *ptype |= TRUETYPE_FONTTYPE;
4040 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4041 *ptype |= DEVICE_FONTTYPE;
4042 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4043 *ptype |= RASTER_FONTTYPE;
4045 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4046 if (face->cached_enum_data)
4048 face->cached_enum_data->elf = *pelf;
4049 face->cached_enum_data->ntm = *pntm;
4050 face->cached_enum_data->type = *ptype;
4056 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4058 struct list *face_elem_ptr;
4060 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4062 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4064 static const WCHAR spaceW[] = { ' ',0 };
4065 WCHAR full_family_name[LF_FULLFACESIZE];
4066 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4068 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4070 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4071 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4075 strcpyW(full_family_name, family->FamilyName);
4076 strcatW(full_family_name, spaceW);
4077 strcatW(full_family_name, face->StyleName);
4078 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4084 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4086 static const WCHAR spaceW[] = { ' ',0 };
4087 WCHAR full_family_name[LF_FULLFACESIZE];
4089 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4091 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4093 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4094 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4098 strcpyW(full_family_name, face->family->FamilyName);
4099 strcatW(full_family_name, spaceW);
4100 strcatW(full_family_name, face->StyleName);
4101 return !strcmpiW(lf->lfFaceName, full_family_name);
4104 /*************************************************************
4108 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4112 struct list *family_elem_ptr, *face_elem_ptr;
4114 NEWTEXTMETRICEXW ntm;
4123 lf.lfCharSet = DEFAULT_CHARSET;
4124 lf.lfPitchAndFamily = 0;
4125 lf.lfFaceName[0] = 0;
4129 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4132 EnterCriticalSection( &freetype_cs );
4133 if(plf->lfFaceName[0]) {
4135 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4138 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4139 debugstr_w(psub->to.name));
4141 strcpyW(lf.lfFaceName, psub->to.name);
4145 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4146 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4147 if(family_matches(family, plf)) {
4148 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4149 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4151 if (!face_matches(face, plf)) continue;
4153 GetEnumStructs(face, &elf, &ntm, &type);
4154 for(i = 0; i < 32; i++) {
4155 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4156 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4157 strcpyW(elf.elfScript, OEM_DOSW);
4158 i = 32; /* break out of loop */
4159 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4162 fs.fsCsb[0] = 1L << i;
4164 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4166 csi.ciCharset = DEFAULT_CHARSET;
4167 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4168 if(csi.ciCharset != DEFAULT_CHARSET) {
4169 elf.elfLogFont.lfCharSet =
4170 ntm.ntmTm.tmCharSet = csi.ciCharset;
4172 strcpyW(elf.elfScript, ElfScriptsW[i]);
4174 FIXME("Unknown elfscript for bit %d\n", i);
4177 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4178 debugstr_w(elf.elfLogFont.lfFaceName),
4179 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4180 csi.ciCharset, type, debugstr_w(elf.elfScript),
4181 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4182 ntm.ntmTm.ntmFlags);
4183 /* release section before callback (FIXME) */
4184 LeaveCriticalSection( &freetype_cs );
4185 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4186 EnterCriticalSection( &freetype_cs );
4192 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4193 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4194 face_elem_ptr = list_head(&family->faces);
4195 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4196 GetEnumStructs(face, &elf, &ntm, &type);
4197 for(i = 0; i < 32; i++) {
4198 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4199 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4200 strcpyW(elf.elfScript, OEM_DOSW);
4201 i = 32; /* break out of loop */
4202 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4205 fs.fsCsb[0] = 1L << i;
4207 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4209 csi.ciCharset = DEFAULT_CHARSET;
4210 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4211 if(csi.ciCharset != DEFAULT_CHARSET) {
4212 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4215 strcpyW(elf.elfScript, ElfScriptsW[i]);
4217 FIXME("Unknown elfscript for bit %d\n", i);
4220 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4221 debugstr_w(elf.elfLogFont.lfFaceName),
4222 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4223 csi.ciCharset, type, debugstr_w(elf.elfScript),
4224 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4225 ntm.ntmTm.ntmFlags);
4226 /* release section before callback (FIXME) */
4227 LeaveCriticalSection( &freetype_cs );
4228 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4229 EnterCriticalSection( &freetype_cs );
4233 LeaveCriticalSection( &freetype_cs );
4237 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4239 pt->x.value = vec->x >> 6;
4240 pt->x.fract = (vec->x & 0x3f) << 10;
4241 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4242 pt->y.value = vec->y >> 6;
4243 pt->y.fract = (vec->y & 0x3f) << 10;
4244 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4248 /***************************************************
4249 * According to the MSDN documentation on WideCharToMultiByte,
4250 * certain codepages cannot set the default_used parameter.
4251 * This returns TRUE if the codepage can set that parameter, false else
4252 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4254 static BOOL codepage_sets_default_used(UINT codepage)
4268 * GSUB Table handling functions
4271 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4273 const GSUB_CoverageFormat1* cf1;
4277 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4279 int count = GET_BE_WORD(cf1->GlyphCount);
4281 TRACE("Coverage Format 1, %i glyphs\n",count);
4282 for (i = 0; i < count; i++)
4283 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4287 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4289 const GSUB_CoverageFormat2* cf2;
4292 cf2 = (const GSUB_CoverageFormat2*)cf1;
4294 count = GET_BE_WORD(cf2->RangeCount);
4295 TRACE("Coverage Format 2, %i ranges\n",count);
4296 for (i = 0; i < count; i++)
4298 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4300 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4301 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4303 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4304 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4310 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4315 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4317 const GSUB_ScriptList *script;
4318 const GSUB_Script *deflt = NULL;
4320 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4322 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4323 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4325 const GSUB_Script *scr;
4328 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4329 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4331 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4333 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4339 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4343 const GSUB_LangSys *Lang;
4345 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4347 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4349 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4350 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4352 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4355 offset = GET_BE_WORD(script->DefaultLangSys);
4358 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4364 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4367 const GSUB_FeatureList *feature;
4368 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4370 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4371 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4373 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4374 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4376 const GSUB_Feature *feat;
4377 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4384 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4388 const GSUB_LookupList *lookup;
4389 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4391 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4392 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4394 const GSUB_LookupTable *look;
4395 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4396 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4397 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4398 if (GET_BE_WORD(look->LookupType) != 1)
4399 FIXME("We only handle SubType 1\n");
4404 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4406 const GSUB_SingleSubstFormat1 *ssf1;
4407 offset = GET_BE_WORD(look->SubTable[j]);
4408 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4409 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4411 int offset = GET_BE_WORD(ssf1->Coverage);
4412 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4413 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4415 TRACE(" Glyph 0x%x ->",glyph);
4416 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4417 TRACE(" 0x%x\n",glyph);
4422 const GSUB_SingleSubstFormat2 *ssf2;
4426 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4427 offset = GET_BE_WORD(ssf1->Coverage);
4428 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4429 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4430 TRACE(" Coverage index %i\n",index);
4433 TRACE(" Glyph is 0x%x ->",glyph);
4434 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4435 TRACE("0x%x\n",glyph);
4444 static const char* get_opentype_script(const GdiFont *font)
4447 * I am not sure if this is the correct way to generate our script tag
4450 switch (font->charset)
4452 case ANSI_CHARSET: return "latn";
4453 case BALTIC_CHARSET: return "latn"; /* ?? */
4454 case CHINESEBIG5_CHARSET: return "hani";
4455 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4456 case GB2312_CHARSET: return "hani";
4457 case GREEK_CHARSET: return "grek";
4458 case HANGUL_CHARSET: return "hang";
4459 case RUSSIAN_CHARSET: return "cyrl";
4460 case SHIFTJIS_CHARSET: return "kana";
4461 case TURKISH_CHARSET: return "latn"; /* ?? */
4462 case VIETNAMESE_CHARSET: return "latn";
4463 case JOHAB_CHARSET: return "latn"; /* ?? */
4464 case ARABIC_CHARSET: return "arab";
4465 case HEBREW_CHARSET: return "hebr";
4466 case THAI_CHARSET: return "thai";
4467 default: return "latn";
4471 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4473 const GSUB_Header *header;
4474 const GSUB_Script *script;
4475 const GSUB_LangSys *language;
4476 const GSUB_Feature *feature;
4478 if (!font->GSUB_Table)
4481 header = font->GSUB_Table;
4483 script = GSUB_get_script_table(header, get_opentype_script(font));
4486 TRACE("Script not found\n");
4489 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4492 TRACE("Language not found\n");
4495 feature = GSUB_get_feature(header, language, "vrt2");
4497 feature = GSUB_get_feature(header, language, "vert");
4500 TRACE("vrt2/vert feature not found\n");
4503 return GSUB_apply_feature(header, feature, glyph);
4506 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4510 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4511 WCHAR wc = (WCHAR)glyph;
4513 BOOL *default_used_pointer;
4516 default_used_pointer = NULL;
4517 default_used = FALSE;
4518 if (codepage_sets_default_used(font->codepage))
4519 default_used_pointer = &default_used;
4520 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4523 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4524 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4525 return get_GSUB_vert_glyph(font,ret);
4528 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4529 glyph = glyph + 0xf000;
4530 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4531 return get_GSUB_vert_glyph(font,glyphId);
4534 /*************************************************************
4535 * WineEngGetGlyphIndices
4538 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4539 LPWORD pgi, DWORD flags)
4542 int default_char = -1;
4544 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4546 for(i = 0; i < count; i++)
4548 pgi[i] = get_glyph_index(font, lpstr[i]);
4551 if (default_char == -1)
4553 if (FT_IS_SFNT(font->ft_face))
4555 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4556 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4561 WineEngGetTextMetrics(font, &textm);
4562 default_char = textm.tmDefaultChar;
4565 pgi[i] = default_char;
4571 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4573 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4574 return !memcmp(matrix, &identity, sizeof(FMAT2));
4577 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4579 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4580 return !memcmp(matrix, &identity, sizeof(MAT2));
4583 /*************************************************************
4584 * WineEngGetGlyphOutline
4586 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4587 * except that the first parameter is the HWINEENGFONT of the font in
4588 * question rather than an HDC.
4591 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4592 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4595 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4596 FT_Face ft_face = incoming_font->ft_face;
4597 GdiFont *font = incoming_font;
4598 FT_UInt glyph_index;
4599 DWORD width, height, pitch, needed = 0;
4600 FT_Bitmap ft_bitmap;
4602 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4604 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4605 double widthRatio = 1.0;
4606 FT_Matrix transMat = identityMat;
4607 FT_Matrix transMatUnrotated;
4608 BOOL needsTransform = FALSE;
4609 BOOL tategaki = (font->GSUB_Table != NULL);
4610 UINT original_index;
4612 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4613 buflen, buf, lpmat);
4615 TRACE("font transform %f %f %f %f\n",
4616 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4617 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4620 EnterCriticalSection( &freetype_cs );
4622 if(format & GGO_GLYPH_INDEX) {
4623 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4624 original_index = glyph;
4625 format &= ~GGO_GLYPH_INDEX;
4627 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4628 ft_face = font->ft_face;
4629 original_index = glyph_index;
4632 if(format & GGO_UNHINTED) {
4633 load_flags |= FT_LOAD_NO_HINTING;
4634 format &= ~GGO_UNHINTED;
4637 /* tategaki never appears to happen to lower glyph index */
4638 if (glyph_index < TATEGAKI_LOWER_BOUND )
4641 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4642 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4643 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4644 font->gmsize * sizeof(GM*));
4646 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4647 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4649 *lpgm = FONT_GM(font,original_index)->gm;
4650 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4651 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4652 lpgm->gmCellIncX, lpgm->gmCellIncY);
4653 LeaveCriticalSection( &freetype_cs );
4654 return 1; /* FIXME */
4658 if (!font->gm[original_index / GM_BLOCK_SIZE])
4659 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4661 /* Scaling factor */
4666 WineEngGetTextMetrics(font, &tm);
4668 widthRatio = (double)font->aveWidth;
4669 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4672 widthRatio = font->scale_y;
4674 /* Scaling transform */
4675 if (widthRatio != 1.0 || font->scale_y != 1.0)
4678 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4681 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4683 pFT_Matrix_Multiply(&scaleMat, &transMat);
4684 needsTransform = TRUE;
4687 /* Slant transform */
4688 if (font->fake_italic) {
4691 slantMat.xx = (1 << 16);
4692 slantMat.xy = ((1 << 16) >> 2);
4694 slantMat.yy = (1 << 16);
4695 pFT_Matrix_Multiply(&slantMat, &transMat);
4696 needsTransform = TRUE;
4699 /* Rotation transform */
4700 transMatUnrotated = transMat;
4701 if(font->orientation && !tategaki) {
4702 FT_Matrix rotationMat;
4704 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4705 pFT_Vector_Unit(&vecAngle, angle);
4706 rotationMat.xx = vecAngle.x;
4707 rotationMat.xy = -vecAngle.y;
4708 rotationMat.yx = -rotationMat.xy;
4709 rotationMat.yy = rotationMat.xx;
4711 pFT_Matrix_Multiply(&rotationMat, &transMat);
4712 needsTransform = TRUE;
4715 /* World transform */
4716 if (!is_identity_FMAT2(&font->font_desc.matrix))
4719 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4720 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4721 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4722 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4723 pFT_Matrix_Multiply(&worldMat, &transMat);
4724 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4725 needsTransform = TRUE;
4728 /* Extra transformation specified by caller */
4729 if (!is_identity_MAT2(lpmat))
4732 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4733 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4734 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4735 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4736 pFT_Matrix_Multiply(&extraMat, &transMat);
4737 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4738 needsTransform = TRUE;
4741 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4742 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4743 format == GGO_GRAY8_BITMAP))
4745 load_flags |= FT_LOAD_NO_BITMAP;
4748 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4751 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4752 LeaveCriticalSection( &freetype_cs );
4756 if(!needsTransform) {
4757 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4758 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4759 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4761 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4762 bottom = (ft_face->glyph->metrics.horiBearingY -
4763 ft_face->glyph->metrics.height) & -64;
4764 lpgm->gmCellIncX = adv;
4765 lpgm->gmCellIncY = 0;
4772 for(xc = 0; xc < 2; xc++) {
4773 for(yc = 0; yc < 2; yc++) {
4774 vec.x = (ft_face->glyph->metrics.horiBearingX +
4775 xc * ft_face->glyph->metrics.width);
4776 vec.y = ft_face->glyph->metrics.horiBearingY -
4777 yc * ft_face->glyph->metrics.height;
4778 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4779 pFT_Vector_Transform(&vec, &transMat);
4780 if(xc == 0 && yc == 0) {
4781 left = right = vec.x;
4782 top = bottom = vec.y;
4784 if(vec.x < left) left = vec.x;
4785 else if(vec.x > right) right = vec.x;
4786 if(vec.y < bottom) bottom = vec.y;
4787 else if(vec.y > top) top = vec.y;
4792 right = (right + 63) & -64;
4793 bottom = bottom & -64;
4794 top = (top + 63) & -64;
4796 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4797 vec.x = ft_face->glyph->metrics.horiAdvance;
4799 pFT_Vector_Transform(&vec, &transMat);
4800 lpgm->gmCellIncX = (vec.x+63) >> 6;
4801 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4803 vec.x = ft_face->glyph->metrics.horiAdvance;
4805 pFT_Vector_Transform(&vec, &transMatUnrotated);
4806 adv = (vec.x+63) >> 6;
4810 bbx = (right - left) >> 6;
4811 lpgm->gmBlackBoxX = (right - left) >> 6;
4812 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4813 lpgm->gmptGlyphOrigin.x = left >> 6;
4814 lpgm->gmptGlyphOrigin.y = top >> 6;
4816 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4817 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4818 lpgm->gmCellIncX, lpgm->gmCellIncY);
4820 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4821 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4823 FONT_GM(font,original_index)->gm = *lpgm;
4824 FONT_GM(font,original_index)->adv = adv;
4825 FONT_GM(font,original_index)->lsb = lsb;
4826 FONT_GM(font,original_index)->bbx = bbx;
4827 FONT_GM(font,original_index)->init = TRUE;
4830 if(format == GGO_METRICS)
4832 LeaveCriticalSection( &freetype_cs );
4833 return 1; /* FIXME */
4836 if(ft_face->glyph->format != ft_glyph_format_outline &&
4837 (format == GGO_NATIVE || format == GGO_BEZIER ||
4838 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4839 format == GGO_GRAY8_BITMAP))
4841 TRACE("loaded a bitmap\n");
4842 LeaveCriticalSection( &freetype_cs );
4848 width = lpgm->gmBlackBoxX;
4849 height = lpgm->gmBlackBoxY;
4850 pitch = ((width + 31) >> 5) << 2;
4851 needed = pitch * height;
4853 if(!buf || !buflen) break;
4855 switch(ft_face->glyph->format) {
4856 case ft_glyph_format_bitmap:
4858 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4859 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4860 INT h = ft_face->glyph->bitmap.rows;
4862 memcpy(dst, src, w);
4863 src += ft_face->glyph->bitmap.pitch;
4869 case ft_glyph_format_outline:
4870 ft_bitmap.width = width;
4871 ft_bitmap.rows = height;
4872 ft_bitmap.pitch = pitch;
4873 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4874 ft_bitmap.buffer = buf;
4877 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4879 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4881 /* Note: FreeType will only set 'black' bits for us. */
4882 memset(buf, 0, needed);
4883 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4887 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4888 LeaveCriticalSection( &freetype_cs );
4893 case GGO_GRAY2_BITMAP:
4894 case GGO_GRAY4_BITMAP:
4895 case GGO_GRAY8_BITMAP:
4896 case WINE_GGO_GRAY16_BITMAP:
4898 unsigned int mult, row, col;
4901 width = lpgm->gmBlackBoxX;
4902 height = lpgm->gmBlackBoxY;
4903 pitch = (width + 3) / 4 * 4;
4904 needed = pitch * height;
4906 if(!buf || !buflen) break;
4908 switch(ft_face->glyph->format) {
4909 case ft_glyph_format_bitmap:
4911 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4912 INT h = ft_face->glyph->bitmap.rows;
4915 for(x = 0; x < pitch; x++)
4917 if(x < ft_face->glyph->bitmap.width)
4918 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4922 src += ft_face->glyph->bitmap.pitch;
4925 LeaveCriticalSection( &freetype_cs );
4928 case ft_glyph_format_outline:
4930 ft_bitmap.width = width;
4931 ft_bitmap.rows = height;
4932 ft_bitmap.pitch = pitch;
4933 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4934 ft_bitmap.buffer = buf;
4937 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4939 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4941 memset(ft_bitmap.buffer, 0, buflen);
4943 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4945 if(format == GGO_GRAY2_BITMAP)
4947 else if(format == GGO_GRAY4_BITMAP)
4949 else if(format == GGO_GRAY8_BITMAP)
4951 else /* format == WINE_GGO_GRAY16_BITMAP */
4953 LeaveCriticalSection( &freetype_cs );
4959 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4960 LeaveCriticalSection( &freetype_cs );
4965 for(row = 0; row < height; row++) {
4967 for(col = 0; col < width; col++, ptr++) {
4968 *ptr = (((int)*ptr) * mult + 128) / 256;
4975 case WINE_GGO_HRGB_BITMAP:
4976 case WINE_GGO_HBGR_BITMAP:
4977 case WINE_GGO_VRGB_BITMAP:
4978 case WINE_GGO_VBGR_BITMAP:
4979 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4981 switch (ft_face->glyph->format)
4983 case FT_GLYPH_FORMAT_BITMAP:
4988 width = lpgm->gmBlackBoxX;
4989 height = lpgm->gmBlackBoxY;
4991 needed = pitch * height;
4993 if (!buf || !buflen) break;
4995 memset(buf, 0, buflen);
4997 src = ft_face->glyph->bitmap.buffer;
4998 src_pitch = ft_face->glyph->bitmap.pitch;
5002 for (x = 0; x < width; x++)
5004 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5005 ((unsigned int *)dst)[x] = ~0u;
5014 case FT_GLYPH_FORMAT_OUTLINE:
5018 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5019 INT x_shift, y_shift;
5021 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5022 FT_Render_Mode render_mode =
5023 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5024 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5026 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5028 if ( render_mode == FT_RENDER_MODE_LCD)
5030 lpgm->gmBlackBoxX += 2;
5031 lpgm->gmptGlyphOrigin.x -= 1;
5035 lpgm->gmBlackBoxY += 2;
5036 lpgm->gmptGlyphOrigin.y += 1;
5040 width = lpgm->gmBlackBoxX;
5041 height = lpgm->gmBlackBoxY;
5043 needed = pitch * height;
5045 if (!buf || !buflen) break;
5047 memset(buf, 0, buflen);
5049 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5051 if ( needsTransform )
5052 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5054 if ( pFT_Library_SetLcdFilter )
5055 pFT_Library_SetLcdFilter( library, lcdfilter );
5056 pFT_Render_Glyph (ft_face->glyph, render_mode);
5058 src = ft_face->glyph->bitmap.buffer;
5059 src_pitch = ft_face->glyph->bitmap.pitch;
5060 src_width = ft_face->glyph->bitmap.width;
5061 src_height = ft_face->glyph->bitmap.rows;
5063 if ( render_mode == FT_RENDER_MODE_LCD)
5071 rgb_interval = src_pitch;
5076 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5077 if ( x_shift < 0 ) x_shift = 0;
5078 if ( x_shift + (src_width / hmul) > width )
5079 x_shift = width - (src_width / hmul);
5081 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5082 if ( y_shift < 0 ) y_shift = 0;
5083 if ( y_shift + (src_height / vmul) > height )
5084 y_shift = height - (src_height / vmul);
5086 dst += x_shift + y_shift * ( pitch / 4 );
5087 while ( src_height )
5089 for ( x = 0; x < src_width / hmul; x++ )
5093 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5094 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5095 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5096 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5100 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5101 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5102 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5103 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5106 src += src_pitch * vmul;
5115 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5116 LeaveCriticalSection ( &freetype_cs );
5123 LeaveCriticalSection( &freetype_cs );
5129 int contour, point = 0, first_pt;
5130 FT_Outline *outline = &ft_face->glyph->outline;
5131 TTPOLYGONHEADER *pph;
5133 DWORD pph_start, cpfx, type;
5135 if(buflen == 0) buf = NULL;
5137 if (needsTransform && buf) {
5138 pFT_Outline_Transform(outline, &transMat);
5141 for(contour = 0; contour < outline->n_contours; contour++) {
5143 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5146 pph->dwType = TT_POLYGON_TYPE;
5147 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5149 needed += sizeof(*pph);
5151 while(point <= outline->contours[contour]) {
5152 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5153 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5154 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5158 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5161 } while(point <= outline->contours[contour] &&
5162 (outline->tags[point] & FT_Curve_Tag_On) ==
5163 (outline->tags[point-1] & FT_Curve_Tag_On));
5164 /* At the end of a contour Windows adds the start point, but
5166 if(point > outline->contours[contour] &&
5167 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5169 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5171 } else if(point <= outline->contours[contour] &&
5172 outline->tags[point] & FT_Curve_Tag_On) {
5173 /* add closing pt for bezier */
5175 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5183 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5186 pph->cb = needed - pph_start;
5192 /* Convert the quadratic Beziers to cubic Beziers.
5193 The parametric eqn for a cubic Bezier is, from PLRM:
5194 r(t) = at^3 + bt^2 + ct + r0
5195 with the control points:
5200 A quadratic Beizer has the form:
5201 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5203 So equating powers of t leads to:
5204 r1 = 2/3 p1 + 1/3 p0
5205 r2 = 2/3 p1 + 1/3 p2
5206 and of course r0 = p0, r3 = p2
5209 int contour, point = 0, first_pt;
5210 FT_Outline *outline = &ft_face->glyph->outline;
5211 TTPOLYGONHEADER *pph;
5213 DWORD pph_start, cpfx, type;
5214 FT_Vector cubic_control[4];
5215 if(buflen == 0) buf = NULL;
5217 if (needsTransform && buf) {
5218 pFT_Outline_Transform(outline, &transMat);
5221 for(contour = 0; contour < outline->n_contours; contour++) {
5223 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5226 pph->dwType = TT_POLYGON_TYPE;
5227 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5229 needed += sizeof(*pph);
5231 while(point <= outline->contours[contour]) {
5232 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5233 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5234 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5237 if(type == TT_PRIM_LINE) {
5239 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5243 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5246 /* FIXME: Possible optimization in endpoint calculation
5247 if there are two consecutive curves */
5248 cubic_control[0] = outline->points[point-1];
5249 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5250 cubic_control[0].x += outline->points[point].x + 1;
5251 cubic_control[0].y += outline->points[point].y + 1;
5252 cubic_control[0].x >>= 1;
5253 cubic_control[0].y >>= 1;
5255 if(point+1 > outline->contours[contour])
5256 cubic_control[3] = outline->points[first_pt];
5258 cubic_control[3] = outline->points[point+1];
5259 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5260 cubic_control[3].x += outline->points[point].x + 1;
5261 cubic_control[3].y += outline->points[point].y + 1;
5262 cubic_control[3].x >>= 1;
5263 cubic_control[3].y >>= 1;
5266 /* r1 = 1/3 p0 + 2/3 p1
5267 r2 = 1/3 p2 + 2/3 p1 */
5268 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5269 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5270 cubic_control[2] = cubic_control[1];
5271 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5272 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5273 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5274 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5276 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5277 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5278 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5283 } while(point <= outline->contours[contour] &&
5284 (outline->tags[point] & FT_Curve_Tag_On) ==
5285 (outline->tags[point-1] & FT_Curve_Tag_On));
5286 /* At the end of a contour Windows adds the start point,
5287 but only for Beziers and we've already done that.
5289 if(point <= outline->contours[contour] &&
5290 outline->tags[point] & FT_Curve_Tag_On) {
5291 /* This is the closing pt of a bezier, but we've already
5292 added it, so just inc point and carry on */
5299 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5302 pph->cb = needed - pph_start;
5308 FIXME("Unsupported format %d\n", format);
5309 LeaveCriticalSection( &freetype_cs );
5312 LeaveCriticalSection( &freetype_cs );
5316 static BOOL get_bitmap_text_metrics(GdiFont *font)
5318 FT_Face ft_face = font->ft_face;
5319 #ifdef HAVE_FREETYPE_FTWINFNT_H
5320 FT_WinFNT_HeaderRec winfnt_header;
5322 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5323 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5324 font->potm->otmSize = size;
5326 #define TM font->potm->otmTextMetrics
5327 #ifdef HAVE_FREETYPE_FTWINFNT_H
5328 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5330 TM.tmHeight = winfnt_header.pixel_height;
5331 TM.tmAscent = winfnt_header.ascent;
5332 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5333 TM.tmInternalLeading = winfnt_header.internal_leading;
5334 TM.tmExternalLeading = winfnt_header.external_leading;
5335 TM.tmAveCharWidth = winfnt_header.avg_width;
5336 TM.tmMaxCharWidth = winfnt_header.max_width;
5337 TM.tmWeight = winfnt_header.weight;
5339 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5340 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5341 TM.tmFirstChar = winfnt_header.first_char;
5342 TM.tmLastChar = winfnt_header.last_char;
5343 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5344 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5345 TM.tmItalic = winfnt_header.italic;
5346 TM.tmUnderlined = font->underline;
5347 TM.tmStruckOut = font->strikeout;
5348 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5349 TM.tmCharSet = winfnt_header.charset;
5354 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5355 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5356 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5357 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5358 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5359 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5360 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5361 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5363 TM.tmDigitizedAspectX = 96; /* FIXME */
5364 TM.tmDigitizedAspectY = 96; /* FIXME */
5366 TM.tmLastChar = 255;
5367 TM.tmDefaultChar = 32;
5368 TM.tmBreakChar = 32;
5369 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5370 TM.tmUnderlined = font->underline;
5371 TM.tmStruckOut = font->strikeout;
5372 /* NB inverted meaning of TMPF_FIXED_PITCH */
5373 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5374 TM.tmCharSet = font->charset;
5382 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5384 double scale_x, scale_y;
5388 scale_x = (double)font->aveWidth;
5389 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5392 scale_x = font->scale_y;
5394 scale_x *= fabs(font->font_desc.matrix.eM11);
5395 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5397 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5398 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5400 SCALE_Y(ptm->tmHeight);
5401 SCALE_Y(ptm->tmAscent);
5402 SCALE_Y(ptm->tmDescent);
5403 SCALE_Y(ptm->tmInternalLeading);
5404 SCALE_Y(ptm->tmExternalLeading);
5405 SCALE_Y(ptm->tmOverhang);
5407 SCALE_X(ptm->tmAveCharWidth);
5408 SCALE_X(ptm->tmMaxCharWidth);
5414 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5416 double scale_x, scale_y;
5420 scale_x = (double)font->aveWidth;
5421 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5424 scale_x = font->scale_y;
5426 scale_x *= fabs(font->font_desc.matrix.eM11);
5427 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5429 scale_font_metrics(font, &potm->otmTextMetrics);
5431 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5432 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5434 SCALE_Y(potm->otmAscent);
5435 SCALE_Y(potm->otmDescent);
5436 SCALE_Y(potm->otmLineGap);
5437 SCALE_Y(potm->otmsCapEmHeight);
5438 SCALE_Y(potm->otmsXHeight);
5439 SCALE_Y(potm->otmrcFontBox.top);
5440 SCALE_Y(potm->otmrcFontBox.bottom);
5441 SCALE_X(potm->otmrcFontBox.left);
5442 SCALE_X(potm->otmrcFontBox.right);
5443 SCALE_Y(potm->otmMacAscent);
5444 SCALE_Y(potm->otmMacDescent);
5445 SCALE_Y(potm->otmMacLineGap);
5446 SCALE_X(potm->otmptSubscriptSize.x);
5447 SCALE_Y(potm->otmptSubscriptSize.y);
5448 SCALE_X(potm->otmptSubscriptOffset.x);
5449 SCALE_Y(potm->otmptSubscriptOffset.y);
5450 SCALE_X(potm->otmptSuperscriptSize.x);
5451 SCALE_Y(potm->otmptSuperscriptSize.y);
5452 SCALE_X(potm->otmptSuperscriptOffset.x);
5453 SCALE_Y(potm->otmptSuperscriptOffset.y);
5454 SCALE_Y(potm->otmsStrikeoutSize);
5455 SCALE_Y(potm->otmsStrikeoutPosition);
5456 SCALE_Y(potm->otmsUnderscoreSize);
5457 SCALE_Y(potm->otmsUnderscorePosition);
5463 /*************************************************************
5464 * WineEngGetTextMetrics
5467 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5470 EnterCriticalSection( &freetype_cs );
5472 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5473 if(!get_bitmap_text_metrics(font))
5475 LeaveCriticalSection( &freetype_cs );
5479 /* Make sure that the font has sane width/height ratio */
5482 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5484 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5490 *ptm = font->potm->otmTextMetrics;
5491 scale_font_metrics(font, ptm);
5492 LeaveCriticalSection( &freetype_cs );
5496 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5500 for(i = 0; i < ft_face->num_charmaps; i++)
5502 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5508 /*************************************************************
5509 * WineEngGetOutlineTextMetrics
5512 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5513 OUTLINETEXTMETRICW *potm)
5515 FT_Face ft_face = font->ft_face;
5516 UINT needed, lenfam, lensty, ret;
5518 TT_HoriHeader *pHori;
5519 TT_Postscript *pPost;
5520 FT_Fixed x_scale, y_scale;
5521 WCHAR *family_nameW, *style_nameW;
5522 static const WCHAR spaceW[] = {' ', '\0'};
5524 INT ascent, descent;
5526 TRACE("font=%p\n", font);
5528 if(!FT_IS_SCALABLE(ft_face))
5532 EnterCriticalSection( &freetype_cs );
5535 if(cbSize >= font->potm->otmSize)
5537 memcpy(potm, font->potm, font->potm->otmSize);
5538 scale_outline_font_metrics(font, potm);
5540 LeaveCriticalSection( &freetype_cs );
5541 return font->potm->otmSize;
5545 needed = sizeof(*potm);
5547 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5548 family_nameW = strdupW(font->name);
5550 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5552 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5553 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5554 style_nameW, lensty/sizeof(WCHAR));
5556 /* These names should be read from the TT name table */
5558 /* length of otmpFamilyName */
5561 /* length of otmpFaceName */
5562 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5563 needed += lenfam; /* just the family name */
5565 needed += lenfam + lensty; /* family + " " + style */
5568 /* length of otmpStyleName */
5571 /* length of otmpFullName */
5572 needed += lenfam + lensty;
5575 x_scale = ft_face->size->metrics.x_scale;
5576 y_scale = ft_face->size->metrics.y_scale;
5578 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5580 FIXME("Can't find OS/2 table - not TT font?\n");
5585 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5587 FIXME("Can't find HHEA table - not TT font?\n");
5592 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5594 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",
5595 pOS2->usWinAscent, pOS2->usWinDescent,
5596 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5597 ft_face->ascender, ft_face->descender, ft_face->height,
5598 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5599 ft_face->bbox.yMax, ft_face->bbox.yMin);
5601 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5602 font->potm->otmSize = needed;
5604 #define TM font->potm->otmTextMetrics
5606 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5607 ascent = pHori->Ascender;
5608 descent = -pHori->Descender;
5610 ascent = pOS2->usWinAscent;
5611 descent = pOS2->usWinDescent;
5615 TM.tmAscent = font->yMax;
5616 TM.tmDescent = -font->yMin;
5617 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5619 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5620 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5621 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5622 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5625 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5628 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5630 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5631 ((ascent + descent) -
5632 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5634 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5635 if (TM.tmAveCharWidth == 0) {
5636 TM.tmAveCharWidth = 1;
5638 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5639 TM.tmWeight = FW_REGULAR;
5640 if (font->fake_bold)
5641 TM.tmWeight = FW_BOLD;
5644 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5646 if (pOS2->usWeightClass > FW_MEDIUM)
5647 TM.tmWeight = pOS2->usWeightClass;
5649 else if (pOS2->usWeightClass <= FW_MEDIUM)
5650 TM.tmWeight = pOS2->usWeightClass;
5653 TM.tmDigitizedAspectX = 300;
5654 TM.tmDigitizedAspectY = 300;
5655 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5656 * symbol range to 0 - f0ff
5659 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5664 case 1257: /* Baltic */
5665 TM.tmLastChar = 0xf8fd;
5668 TM.tmLastChar = 0xf0ff;
5670 TM.tmBreakChar = 0x20;
5671 TM.tmDefaultChar = 0x1f;
5675 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5676 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5678 if(pOS2->usFirstCharIndex <= 1)
5679 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5680 else if (pOS2->usFirstCharIndex > 0xff)
5681 TM.tmBreakChar = 0x20;
5683 TM.tmBreakChar = pOS2->usFirstCharIndex;
5684 TM.tmDefaultChar = TM.tmBreakChar - 1;
5686 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5687 TM.tmUnderlined = font->underline;
5688 TM.tmStruckOut = font->strikeout;
5690 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5691 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5692 (pOS2->version == 0xFFFFU ||
5693 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5694 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5696 TM.tmPitchAndFamily = 0;
5698 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5700 case PAN_FAMILY_SCRIPT:
5701 TM.tmPitchAndFamily |= FF_SCRIPT;
5704 case PAN_FAMILY_DECORATIVE:
5705 TM.tmPitchAndFamily |= FF_DECORATIVE;
5710 case PAN_FAMILY_TEXT_DISPLAY:
5711 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5712 /* which is clearly not what the panose spec says. */
5714 if(TM.tmPitchAndFamily == 0 || /* fixed */
5715 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5716 TM.tmPitchAndFamily = FF_MODERN;
5719 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5724 TM.tmPitchAndFamily |= FF_DONTCARE;
5727 case PAN_SERIF_COVE:
5728 case PAN_SERIF_OBTUSE_COVE:
5729 case PAN_SERIF_SQUARE_COVE:
5730 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5731 case PAN_SERIF_SQUARE:
5732 case PAN_SERIF_THIN:
5733 case PAN_SERIF_BONE:
5734 case PAN_SERIF_EXAGGERATED:
5735 case PAN_SERIF_TRIANGLE:
5736 TM.tmPitchAndFamily |= FF_ROMAN;
5739 case PAN_SERIF_NORMAL_SANS:
5740 case PAN_SERIF_OBTUSE_SANS:
5741 case PAN_SERIF_PERP_SANS:
5742 case PAN_SERIF_FLARED:
5743 case PAN_SERIF_ROUNDED:
5744 TM.tmPitchAndFamily |= FF_SWISS;
5751 if(FT_IS_SCALABLE(ft_face))
5752 TM.tmPitchAndFamily |= TMPF_VECTOR;
5754 if(FT_IS_SFNT(ft_face))
5756 if (font->ntmFlags & NTM_PS_OPENTYPE)
5757 TM.tmPitchAndFamily |= TMPF_DEVICE;
5759 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5762 TM.tmCharSet = font->charset;
5764 font->potm->otmFiller = 0;
5765 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5766 font->potm->otmfsSelection = pOS2->fsSelection;
5767 font->potm->otmfsType = pOS2->fsType;
5768 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5769 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5770 font->potm->otmItalicAngle = 0; /* POST table */
5771 font->potm->otmEMSquare = ft_face->units_per_EM;
5772 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5773 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5774 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5775 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5776 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5777 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5778 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5779 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5780 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5781 font->potm->otmMacAscent = TM.tmAscent;
5782 font->potm->otmMacDescent = -TM.tmDescent;
5783 font->potm->otmMacLineGap = font->potm->otmLineGap;
5784 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5785 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5786 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5787 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5788 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5789 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5790 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5791 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5792 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5793 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5794 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5796 font->potm->otmsUnderscoreSize = 0;
5797 font->potm->otmsUnderscorePosition = 0;
5799 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5800 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5804 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5805 cp = (char*)font->potm + sizeof(*font->potm);
5806 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5807 strcpyW((WCHAR*)cp, family_nameW);
5809 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5810 strcpyW((WCHAR*)cp, style_nameW);
5812 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5813 strcpyW((WCHAR*)cp, family_nameW);
5814 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5815 strcatW((WCHAR*)cp, spaceW);
5816 strcatW((WCHAR*)cp, style_nameW);
5817 cp += lenfam + lensty;
5820 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5821 strcpyW((WCHAR*)cp, family_nameW);
5822 strcatW((WCHAR*)cp, spaceW);
5823 strcatW((WCHAR*)cp, style_nameW);
5826 if(potm && needed <= cbSize)
5828 memcpy(potm, font->potm, font->potm->otmSize);
5829 scale_outline_font_metrics(font, potm);
5833 HeapFree(GetProcessHeap(), 0, style_nameW);
5834 HeapFree(GetProcessHeap(), 0, family_nameW);
5836 LeaveCriticalSection( &freetype_cs );
5840 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5842 HFONTLIST *hfontlist;
5843 child->font = alloc_font();
5844 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5845 if(!child->font->ft_face)
5847 free_font(child->font);
5852 child->font->font_desc = font->font_desc;
5853 child->font->ntmFlags = child->face->ntmFlags;
5854 child->font->orientation = font->orientation;
5855 child->font->scale_y = font->scale_y;
5856 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5857 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5858 child->font->name = strdupW(child->face->family->FamilyName);
5859 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5860 child->font->base_font = font;
5861 list_add_head(&child_font_list, &child->font->entry);
5862 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5866 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5869 CHILD_FONT *child_font;
5872 font = font->base_font;
5874 *linked_font = font;
5876 if((*glyph = get_glyph_index(font, c)))
5879 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5881 if(!child_font->font)
5882 if(!load_child_font(font, child_font))
5885 if(!child_font->font->ft_face)
5887 g = get_glyph_index(child_font->font, c);
5891 *linked_font = child_font->font;
5898 /*************************************************************
5899 * WineEngGetCharWidth
5902 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5905 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5908 FT_UInt glyph_index;
5909 GdiFont *linked_font;
5911 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5914 EnterCriticalSection( &freetype_cs );
5915 for(c = firstChar; c <= lastChar; c++) {
5916 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5917 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5918 &gm, 0, NULL, &identity);
5919 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5921 LeaveCriticalSection( &freetype_cs );
5925 /*************************************************************
5926 * WineEngGetCharABCWidths
5929 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5932 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5935 FT_UInt glyph_index;
5936 GdiFont *linked_font;
5938 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5940 if(!FT_IS_SCALABLE(font->ft_face))
5944 EnterCriticalSection( &freetype_cs );
5946 for(c = firstChar; c <= lastChar; c++) {
5947 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5948 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5949 &gm, 0, NULL, &identity);
5950 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5951 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5952 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5953 FONT_GM(linked_font,glyph_index)->bbx;
5955 LeaveCriticalSection( &freetype_cs );
5959 /*************************************************************
5960 * WineEngGetCharABCWidthsFloat
5963 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
5965 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
5968 FT_UInt glyph_index;
5969 GdiFont *linked_font;
5971 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
5974 EnterCriticalSection( &freetype_cs );
5976 for (c = first; c <= last; c++)
5978 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5979 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5980 &gm, 0, NULL, &identity);
5981 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
5982 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
5983 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
5984 FONT_GM(linked_font, glyph_index)->lsb -
5985 FONT_GM(linked_font, glyph_index)->bbx;
5987 LeaveCriticalSection( &freetype_cs );
5991 /*************************************************************
5992 * WineEngGetCharABCWidthsI
5995 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5998 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6001 FT_UInt glyph_index;
6002 GdiFont *linked_font;
6004 if(!FT_HAS_HORIZONTAL(font->ft_face))
6008 EnterCriticalSection( &freetype_cs );
6010 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6012 for(c = firstChar; c < firstChar+count; c++) {
6013 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6014 &gm, 0, NULL, &identity);
6015 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6016 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6017 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6018 - FONT_GM(linked_font,c)->bbx;
6021 for(c = 0; c < count; c++) {
6022 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6023 &gm, 0, NULL, &identity);
6024 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6025 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6026 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6027 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6030 LeaveCriticalSection( &freetype_cs );
6034 /*************************************************************
6035 * WineEngGetTextExtentExPoint
6038 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6039 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6041 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6046 FT_UInt glyph_index;
6047 GdiFont *linked_font;
6049 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6053 EnterCriticalSection( &freetype_cs );
6056 WineEngGetTextMetrics(font, &tm);
6057 size->cy = tm.tmHeight;
6059 for(idx = 0; idx < count; idx++) {
6060 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6061 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6062 &gm, 0, NULL, &identity);
6063 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6065 if (! pnfit || ext <= max_ext) {
6075 LeaveCriticalSection( &freetype_cs );
6076 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6080 /*************************************************************
6081 * WineEngGetTextExtentExPointI
6084 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6085 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6087 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6093 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6096 EnterCriticalSection( &freetype_cs );
6099 WineEngGetTextMetrics(font, &tm);
6100 size->cy = tm.tmHeight;
6102 for(idx = 0; idx < count; idx++) {
6103 WineEngGetGlyphOutline(font, indices[idx],
6104 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6106 size->cx += FONT_GM(font,indices[idx])->adv;
6108 if (! pnfit || ext <= max_ext) {
6118 LeaveCriticalSection( &freetype_cs );
6119 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6123 /*************************************************************
6124 * WineEngGetFontData
6127 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6130 FT_Face ft_face = font->ft_face;
6134 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6135 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6136 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6138 if(!FT_IS_SFNT(ft_face))
6146 if(table) { /* MS tags differ in endianness from FT ones */
6147 table = table >> 24 | table << 24 |
6148 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6151 /* make sure value of len is the value freetype says it needs */
6154 FT_ULong needed = 0;
6155 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6156 if( !err && needed < len) len = needed;
6158 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6161 TRACE("Can't find table %c%c%c%c\n",
6162 /* bytes were reversed */
6163 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6164 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6170 /*************************************************************
6171 * WineEngGetTextFace
6174 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6176 INT n = strlenW(font->name) + 1;
6178 lstrcpynW(str, font->name, count);
6179 return min(count, n);
6184 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6186 if (fs) *fs = font->fs;
6187 return font->charset;
6190 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6192 GdiFont *font = dc->gdiFont, *linked_font;
6193 struct list *first_hfont;
6197 EnterCriticalSection( &freetype_cs );
6198 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6199 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6200 if(font == linked_font)
6201 *new_hfont = dc->hFont;
6204 first_hfont = list_head(&linked_font->hfontlist);
6205 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6207 LeaveCriticalSection( &freetype_cs );
6211 /* Retrieve a list of supported Unicode ranges for a given font.
6212 * Can be called with NULL gs to calculate the buffer size. Returns
6213 * the number of ranges found.
6215 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6217 DWORD num_ranges = 0;
6219 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6222 FT_ULong char_code, char_code_prev;
6225 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6227 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6228 face->num_glyphs, glyph_code, char_code);
6230 if (!glyph_code) return 0;
6234 gs->ranges[0].wcLow = (USHORT)char_code;
6235 gs->ranges[0].cGlyphs = 0;
6236 gs->cGlyphsSupported = 0;
6242 if (char_code < char_code_prev)
6244 ERR("expected increasing char code from FT_Get_Next_Char\n");
6247 if (char_code - char_code_prev > 1)
6252 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6253 gs->ranges[num_ranges - 1].cGlyphs = 1;
6254 gs->cGlyphsSupported++;
6259 gs->ranges[num_ranges - 1].cGlyphs++;
6260 gs->cGlyphsSupported++;
6262 char_code_prev = char_code;
6263 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6267 FIXME("encoding %u not supported\n", face->charmap->encoding);
6272 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6275 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6277 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6280 glyphset->cbThis = size;
6281 glyphset->cRanges = num_ranges;
6282 glyphset->flAccel = 0;
6287 /*************************************************************
6290 BOOL WineEngFontIsLinked(GdiFont *font)
6294 EnterCriticalSection( &freetype_cs );
6295 ret = !list_empty(&font->child_fonts);
6296 LeaveCriticalSection( &freetype_cs );
6300 static BOOL is_hinting_enabled(void)
6302 /* Use the >= 2.2.0 function if available */
6303 if(pFT_Get_TrueType_Engine_Type)
6305 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6306 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6308 #ifdef FT_DRIVER_HAS_HINTER
6313 /* otherwise if we've been compiled with < 2.2.0 headers
6314 use the internal macro */
6315 mod = pFT_Get_Module(library, "truetype");
6316 if(mod && FT_DRIVER_HAS_HINTER(mod))
6324 static BOOL is_subpixel_rendering_enabled( void )
6326 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6327 return pFT_Library_SetLcdFilter &&
6328 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6334 /*************************************************************************
6335 * GetRasterizerCaps (GDI32.@)
6337 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6339 static int hinting = -1;
6340 static int subpixel = -1;
6344 hinting = is_hinting_enabled();
6345 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6348 if ( subpixel == -1 )
6350 subpixel = is_subpixel_rendering_enabled();
6351 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6354 lprs->nSize = sizeof(RASTERIZER_STATUS);
6355 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6357 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6358 lprs->nLanguageID = 0;
6362 /*************************************************************
6363 * WineEngRealizationInfo
6365 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6367 FIXME("(%p, %p): stub!\n", font, info);
6370 if(FT_IS_SCALABLE(font->ft_face))
6373 info->cache_num = font->cache_num;
6374 info->unknown2 = -1;
6378 /*************************************************************************
6379 * Kerning support for TrueType fonts
6381 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6383 struct TT_kern_table
6389 struct TT_kern_subtable
6398 USHORT horizontal : 1;
6400 USHORT cross_stream: 1;
6401 USHORT override : 1;
6402 USHORT reserved1 : 4;
6408 struct TT_format0_kern_subtable
6412 USHORT entrySelector;
6423 static DWORD parse_format0_kern_subtable(GdiFont *font,
6424 const struct TT_format0_kern_subtable *tt_f0_ks,
6425 const USHORT *glyph_to_char,
6426 KERNINGPAIR *kern_pair, DWORD cPairs)
6429 const struct TT_kern_pair *tt_kern_pair;
6431 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6433 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6435 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6436 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6437 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6439 if (!kern_pair || !cPairs)
6442 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6444 nPairs = min(nPairs, cPairs);
6446 for (i = 0; i < nPairs; i++)
6448 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6449 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6450 /* this algorithm appears to better match what Windows does */
6451 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6452 if (kern_pair->iKernAmount < 0)
6454 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6455 kern_pair->iKernAmount -= font->ppem;
6457 else if (kern_pair->iKernAmount > 0)
6459 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6460 kern_pair->iKernAmount += font->ppem;
6462 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6464 TRACE("left %u right %u value %d\n",
6465 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6469 TRACE("copied %u entries\n", nPairs);
6473 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6477 const struct TT_kern_table *tt_kern_table;
6478 const struct TT_kern_subtable *tt_kern_subtable;
6480 USHORT *glyph_to_char;
6483 EnterCriticalSection( &freetype_cs );
6484 if (font->total_kern_pairs != (DWORD)-1)
6486 if (cPairs && kern_pair)
6488 cPairs = min(cPairs, font->total_kern_pairs);
6489 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6490 LeaveCriticalSection( &freetype_cs );
6493 LeaveCriticalSection( &freetype_cs );
6494 return font->total_kern_pairs;
6497 font->total_kern_pairs = 0;
6499 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6501 if (length == GDI_ERROR)
6503 TRACE("no kerning data in the font\n");
6504 LeaveCriticalSection( &freetype_cs );
6508 buf = HeapAlloc(GetProcessHeap(), 0, length);
6511 WARN("Out of memory\n");
6512 LeaveCriticalSection( &freetype_cs );
6516 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6518 /* build a glyph index to char code map */
6519 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6522 WARN("Out of memory allocating a glyph index to char code map\n");
6523 HeapFree(GetProcessHeap(), 0, buf);
6524 LeaveCriticalSection( &freetype_cs );
6528 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6534 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6536 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6537 font->ft_face->num_glyphs, glyph_code, char_code);
6541 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6543 /* FIXME: This doesn't match what Windows does: it does some fancy
6544 * things with duplicate glyph index to char code mappings, while
6545 * we just avoid overriding existing entries.
6547 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6548 glyph_to_char[glyph_code] = (USHORT)char_code;
6550 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6557 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6558 for (n = 0; n <= 65535; n++)
6559 glyph_to_char[n] = (USHORT)n;
6562 tt_kern_table = buf;
6563 nTables = GET_BE_WORD(tt_kern_table->nTables);
6564 TRACE("version %u, nTables %u\n",
6565 GET_BE_WORD(tt_kern_table->version), nTables);
6567 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6569 for (i = 0; i < nTables; i++)
6571 struct TT_kern_subtable tt_kern_subtable_copy;
6573 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6574 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6575 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6577 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6578 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6579 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6581 /* According to the TrueType specification this is the only format
6582 * that will be properly interpreted by Windows and OS/2
6584 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6586 DWORD new_chunk, old_total = font->total_kern_pairs;
6588 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6589 glyph_to_char, NULL, 0);
6590 font->total_kern_pairs += new_chunk;
6592 if (!font->kern_pairs)
6593 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6594 font->total_kern_pairs * sizeof(*font->kern_pairs));
6596 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6597 font->total_kern_pairs * sizeof(*font->kern_pairs));
6599 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6600 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6603 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6605 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6608 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6609 HeapFree(GetProcessHeap(), 0, buf);
6611 if (cPairs && kern_pair)
6613 cPairs = min(cPairs, font->total_kern_pairs);
6614 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6615 LeaveCriticalSection( &freetype_cs );
6618 LeaveCriticalSection( &freetype_cs );
6619 return font->total_kern_pairs;
6622 #else /* HAVE_FREETYPE */
6624 /*************************************************************************/
6626 BOOL WineEngInit(void)
6630 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6634 BOOL WineEngDestroyFontInstance(HFONT hfont)
6639 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6644 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6645 LPWORD pgi, DWORD flags)
6650 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6651 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6654 ERR("called but we don't have FreeType\n");
6658 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6660 ERR("called but we don't have FreeType\n");
6664 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6665 OUTLINETEXTMETRICW *potm)
6667 ERR("called but we don't have FreeType\n");
6671 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6674 ERR("called but we don't have FreeType\n");
6678 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6681 ERR("called but we don't have FreeType\n");
6685 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6687 ERR("called but we don't have FreeType\n");
6691 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6694 ERR("called but we don't have FreeType\n");
6698 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6699 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6701 ERR("called but we don't have FreeType\n");
6705 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6706 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6708 ERR("called but we don't have FreeType\n");
6712 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6715 ERR("called but we don't have FreeType\n");
6719 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6721 ERR("called but we don't have FreeType\n");
6725 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6727 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6731 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6733 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6737 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6739 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6743 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6745 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6746 return DEFAULT_CHARSET;
6749 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6754 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6756 FIXME("(%p, %p): stub\n", font, glyphset);
6760 BOOL WineEngFontIsLinked(GdiFont *font)
6765 /*************************************************************************
6766 * GetRasterizerCaps (GDI32.@)
6768 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6770 lprs->nSize = sizeof(RASTERIZER_STATUS);
6772 lprs->nLanguageID = 0;
6776 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6778 ERR("called but we don't have FreeType\n");
6782 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6784 ERR("called but we don't have FreeType\n");
6788 #endif /* HAVE_FREETYPE */