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 {
268 DWORD font_data_size;
271 FONTSIGNATURE fs_links;
273 FT_Fixed font_version;
275 Bitmap_Size size; /* set if face is a bitmap */
276 BOOL external; /* TRUE if we should manually add this font to the registry */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
282 typedef struct tagFamily {
284 const WCHAR *FamilyName;
290 INT adv; /* These three hold to widths of the unrotated chars */
308 typedef struct tagHFONTLIST {
323 struct list hfontlist;
324 OUTLINETEXTMETRICW *potm;
325 DWORD total_kern_pairs;
326 KERNINGPAIR *kern_pairs;
327 struct list child_fonts;
329 /* the following members can be accessed without locking, they are never modified after creation */
331 struct font_mapping *mapping;
354 const WCHAR *font_name;
358 struct enum_charset_element {
364 struct enum_charset_list {
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
383 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
384 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
386 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
387 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
388 'W','i','n','d','o','w','s','\\',
389 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
390 'F','o','n','t','s','\0'};
392 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
393 'W','i','n','d','o','w','s',' ','N','T','\\',
394 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
395 'F','o','n','t','s','\0'};
397 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
398 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
399 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
400 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
402 static const WCHAR * const SystemFontValues[4] = {
409 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
410 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
412 /* Interesting and well-known (frequently-assumed!) font names */
413 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
414 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 };
415 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
416 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
417 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
418 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
419 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
420 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
422 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
423 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
424 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
425 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
426 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
427 'E','u','r','o','p','e','a','n','\0'};
428 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
429 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
430 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
431 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
432 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
433 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
434 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
435 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
436 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
437 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
438 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
439 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
441 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
451 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
459 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
468 typedef struct tagFontSubst {
484 static struct list mappings_list = LIST_INIT( mappings_list );
486 static CRITICAL_SECTION freetype_cs;
487 static CRITICAL_SECTION_DEBUG critsect_debug =
490 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
491 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
493 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
495 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
497 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
498 static BOOL use_default_fallback = FALSE;
500 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
502 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
503 'W','i','n','d','o','w','s',' ','N','T','\\',
504 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
505 'S','y','s','t','e','m','L','i','n','k',0};
507 /****************************************
508 * Notes on .fon files
510 * The fonts System, FixedSys and Terminal are special. There are typically multiple
511 * versions installed for different resolutions and codepages. Windows stores which one to use
512 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
514 * FIXEDFON.FON FixedSys
516 * OEMFONT.FON Terminal
517 * LogPixels Current dpi set by the display control panel applet
518 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
519 * also has a LogPixels value that appears to mirror this)
521 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
522 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
523 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
524 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
525 * so that makes sense.
527 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
528 * to be mapped into the registry on Windows 2000 at least).
531 * ega80woa.fon=ega80850.fon
532 * ega40woa.fon=ega40850.fon
533 * cga80woa.fon=cga80850.fon
534 * cga40woa.fon=cga40850.fon
537 /* These are all structures needed for the GSUB table */
539 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
540 #define TATEGAKI_LOWER_BOUND 0x02F1
556 GSUB_ScriptRecord ScriptRecord[1];
562 } GSUB_LangSysRecord;
567 GSUB_LangSysRecord LangSysRecord[1];
571 WORD LookupOrder; /* Reserved */
572 WORD ReqFeatureIndex;
574 WORD FeatureIndex[1];
580 } GSUB_FeatureRecord;
584 GSUB_FeatureRecord FeatureRecord[1];
588 WORD FeatureParams; /* Reserved */
590 WORD LookupListIndex[1];
609 } GSUB_CoverageFormat1;
614 WORD StartCoverageIndex;
620 GSUB_RangeRecord RangeRecord[1];
621 } GSUB_CoverageFormat2;
624 WORD SubstFormat; /* = 1 */
627 } GSUB_SingleSubstFormat1;
630 WORD SubstFormat; /* = 2 */
634 }GSUB_SingleSubstFormat2;
636 #ifdef HAVE_CARBON_CARBON_H
637 static char *find_cache_dir(void)
641 static char cached_path[MAX_PATH];
642 static const char *wine = "/Wine", *fonts = "/Fonts";
644 if(*cached_path) return cached_path;
646 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
649 WARN("can't create cached data folder\n");
652 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
655 WARN("can't create cached data path\n");
659 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
661 ERR("Could not create full path\n");
665 strcat(cached_path, wine);
667 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
669 WARN("Couldn't mkdir %s\n", cached_path);
673 strcat(cached_path, fonts);
674 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
676 WARN("Couldn't mkdir %s\n", cached_path);
683 /******************************************************************
686 * Extracts individual TrueType font files from a Mac suitcase font
687 * and saves them into the user's caches directory (see
689 * Returns a NULL terminated array of filenames.
691 * We do this because they are apps that try to read ttf files
692 * themselves and they don't like Mac suitcase files.
694 static char **expand_mac_font(const char *path)
701 const char *filename;
705 unsigned int size, max_size;
708 TRACE("path %s\n", path);
710 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
713 WARN("failed to get ref\n");
717 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
720 TRACE("no data fork, so trying resource fork\n");
721 res_ref = FSOpenResFile(&ref, fsRdPerm);
724 TRACE("unable to open resource fork\n");
731 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
734 CloseResFile(res_ref);
738 out_dir = find_cache_dir();
740 filename = strrchr(path, '/');
741 if(!filename) filename = path;
744 /* output filename has the form out_dir/filename_%04x.ttf */
745 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
752 unsigned short *num_faces_ptr, num_faces, face;
755 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
757 fond = Get1IndResource(fond_res, idx);
759 TRACE("got fond resource %d\n", idx);
762 fam_rec = *(FamRec**)fond;
763 num_faces_ptr = (unsigned short *)(fam_rec + 1);
764 num_faces = GET_BE_WORD(*num_faces_ptr);
766 assoc = (AsscEntry*)(num_faces_ptr + 1);
767 TRACE("num faces %04x\n", num_faces);
768 for(face = 0; face < num_faces; face++, assoc++)
771 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
772 unsigned short size, font_id;
775 size = GET_BE_WORD(assoc->fontSize);
776 font_id = GET_BE_WORD(assoc->fontID);
779 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
783 TRACE("trying to load sfnt id %04x\n", font_id);
784 sfnt = GetResource(sfnt_res, font_id);
787 TRACE("can't get sfnt resource %04x\n", font_id);
791 output = HeapAlloc(GetProcessHeap(), 0, output_len);
796 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
798 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
799 if(fd != -1 || errno == EEXIST)
803 unsigned char *sfnt_data;
806 sfnt_data = *(unsigned char**)sfnt;
807 write(fd, sfnt_data, GetHandleSize(sfnt));
811 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
814 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
816 ret.array[ret.size++] = output;
820 WARN("unable to create %s\n", output);
821 HeapFree(GetProcessHeap(), 0, output);
824 ReleaseResource(sfnt);
827 ReleaseResource(fond);
830 CloseResFile(res_ref);
835 #endif /* HAVE_CARBON_CARBON_H */
837 static inline BOOL is_win9x(void)
839 return GetVersion() & 0x80000000;
842 This function builds an FT_Fixed from a double. It fails if the absolute
843 value of the float number is greater than 32768.
845 static inline FT_Fixed FT_FixedFromFloat(double f)
851 This function builds an FT_Fixed from a FIXED. It simply put f.value
852 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
854 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
856 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
860 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
865 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
866 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
868 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
869 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
871 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
873 if(face_name && strcmpiW(face_name, family->FamilyName))
875 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
879 file = strrchr(face->file, '/');
884 if(!strcasecmp(file, file_nameA))
886 HeapFree(GetProcessHeap(), 0, file_nameA);
891 HeapFree(GetProcessHeap(), 0, file_nameA);
895 static Family *find_family_from_name(const WCHAR *name)
899 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
901 if(!strcmpiW(family->FamilyName, name))
908 static void DumpSubstList(void)
912 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
914 if(psub->from.charset != -1 || psub->to.charset != -1)
915 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
916 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
918 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
919 debugstr_w(psub->to.name));
924 static LPWSTR strdupW(LPCWSTR p)
927 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
928 ret = HeapAlloc(GetProcessHeap(), 0, len);
933 static LPSTR strdupA(LPCSTR p)
936 DWORD len = (strlen(p) + 1);
937 ret = HeapAlloc(GetProcessHeap(), 0, len);
942 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
947 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
949 if(!strcmpiW(element->from.name, from_name) &&
950 (element->from.charset == from_charset ||
951 element->from.charset == -1))
958 #define ADD_FONT_SUBST_FORCE 1
960 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
962 FontSubst *from_exist, *to_exist;
964 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
966 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
968 list_remove(&from_exist->entry);
969 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
970 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
971 HeapFree(GetProcessHeap(), 0, from_exist);
977 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
981 HeapFree(GetProcessHeap(), 0, subst->to.name);
982 subst->to.name = strdupW(to_exist->to.name);
985 list_add_tail(subst_list, &subst->entry);
990 HeapFree(GetProcessHeap(), 0, subst->from.name);
991 HeapFree(GetProcessHeap(), 0, subst->to.name);
992 HeapFree(GetProcessHeap(), 0, subst);
996 static void split_subst_info(NameCs *nc, LPSTR str)
998 CHAR *p = strrchr(str, ',');
1003 nc->charset = strtol(p+1, NULL, 10);
1006 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1007 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1008 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1011 static void LoadSubstList(void)
1015 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1019 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1020 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1021 &hkey) == ERROR_SUCCESS) {
1023 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1024 &valuelen, &datalen, NULL, NULL);
1026 valuelen++; /* returned value doesn't include room for '\0' */
1027 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1028 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1032 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1033 &dlen) == ERROR_SUCCESS) {
1034 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1036 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1037 split_subst_info(&psub->from, value);
1038 split_subst_info(&psub->to, data);
1040 /* Win 2000 doesn't allow mapping between different charsets
1041 or mapping of DEFAULT_CHARSET */
1042 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1043 psub->to.charset == DEFAULT_CHARSET) {
1044 HeapFree(GetProcessHeap(), 0, psub->to.name);
1045 HeapFree(GetProcessHeap(), 0, psub->from.name);
1046 HeapFree(GetProcessHeap(), 0, psub);
1048 add_font_subst(&font_subst_list, psub, 0);
1050 /* reset dlen and vlen */
1054 HeapFree(GetProcessHeap(), 0, data);
1055 HeapFree(GetProcessHeap(), 0, value);
1061 /*****************************************************************
1062 * get_name_table_entry
1064 * Supply the platform, encoding, language and name ids in req
1065 * and if the name exists the function will fill in the string
1066 * and string_len members. The string is owned by FreeType so
1067 * don't free it. Returns TRUE if the name is found else FALSE.
1069 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1072 FT_UInt num_names, name_index;
1074 if(FT_IS_SFNT(ft_face))
1076 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1078 for(name_index = 0; name_index < num_names; name_index++)
1080 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1082 if((name.platform_id == req->platform_id) &&
1083 (name.encoding_id == req->encoding_id) &&
1084 (name.language_id == req->language_id) &&
1085 (name.name_id == req->name_id))
1087 req->string = name.string;
1088 req->string_len = name.string_len;
1095 req->string_len = 0;
1099 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1104 name.platform_id = TT_PLATFORM_MICROSOFT;
1105 name.encoding_id = TT_MS_ID_UNICODE_CS;
1106 name.language_id = language_id;
1107 name.name_id = name_id;
1109 if(get_name_table_entry(ft_face, &name))
1113 /* String is not nul terminated and string_len is a byte length. */
1114 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1115 for(i = 0; i < name.string_len / 2; i++)
1117 WORD *tmp = (WORD *)&name.string[i * 2];
1118 ret[i] = GET_BE_WORD(*tmp);
1121 TRACE("Got localised name %s\n", debugstr_w(ret));
1128 /*****************************************************************
1131 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1132 * of FreeType that don't export this function.
1135 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1140 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1141 if(pFT_Load_Sfnt_Table)
1143 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1145 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1146 else /* Do it the hard way */
1148 TT_Face tt_face = (TT_Face) ft_face;
1149 SFNT_Interface *sfnt;
1150 if (FT_Version.major==2 && FT_Version.minor==0)
1153 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1157 /* A field was added in the middle of the structure in 2.1.x */
1158 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1160 err = sfnt->load_any(tt_face, table, offset, buf, len);
1168 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1169 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1170 "Please upgrade your freetype library.\n");
1173 err = FT_Err_Unimplemented_Feature;
1179 static inline int TestStyles(DWORD flags, DWORD styles)
1181 return (flags & styles) == styles;
1184 static int StyleOrdering(Face *face)
1186 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1188 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1190 if (TestStyles(face->ntmFlags, NTM_BOLD))
1192 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1195 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1196 debugstr_w(face->family->FamilyName),
1197 debugstr_w(face->StyleName),
1203 /* Add a style of face to a font family using an ordering of the list such
1204 that regular fonts come before bold and italic, and single styles come
1205 before compound styles. */
1206 static void AddFaceToFamily(Face *face, Family *family)
1210 LIST_FOR_EACH( entry, &family->faces )
1212 Face *ent = LIST_ENTRY(entry, Face, entry);
1213 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1215 list_add_before( entry, &face->entry );
1218 #define ADDFONT_EXTERNAL_FONT 0x01
1219 #define ADDFONT_FORCE_BITMAP 0x02
1220 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1224 TT_Header *pHeader = NULL;
1225 WCHAR *english_family, *localised_family, *StyleW;
1229 struct list *family_elem_ptr, *face_elem_ptr;
1231 FT_Long face_index = 0, num_faces;
1232 #ifdef HAVE_FREETYPE_FTWINFNT_H
1233 FT_WinFNT_HeaderRec winfnt_header;
1235 int i, bitmap_num, internal_leading;
1238 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1239 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1241 #ifdef HAVE_CARBON_CARBON_H
1242 if(file && !fake_family)
1244 char **mac_list = expand_mac_font(file);
1247 BOOL had_one = FALSE;
1249 for(cursor = mac_list; *cursor; cursor++)
1252 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1253 HeapFree(GetProcessHeap(), 0, *cursor);
1255 HeapFree(GetProcessHeap(), 0, mac_list);
1260 #endif /* HAVE_CARBON_CARBON_H */
1263 char *family_name = fake_family;
1267 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1268 err = pFT_New_Face(library, file, face_index, &ft_face);
1271 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1272 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1276 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1280 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*/
1281 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1282 pFT_Done_Face(ft_face);
1286 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1287 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1288 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1289 pFT_Done_Face(ft_face);
1293 if(FT_IS_SFNT(ft_face))
1295 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1296 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1297 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1299 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1300 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1301 pFT_Done_Face(ft_face);
1305 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1306 we don't want to load these. */
1307 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1311 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1313 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1314 pFT_Done_Face(ft_face);
1320 if(!ft_face->family_name || !ft_face->style_name) {
1321 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1322 pFT_Done_Face(ft_face);
1326 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1328 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1329 pFT_Done_Face(ft_face);
1335 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1336 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1338 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1339 HeapFree(GetProcessHeap(), 0, localised_family);
1340 num_faces = ft_face->num_faces;
1341 pFT_Done_Face(ft_face);
1344 HeapFree(GetProcessHeap(), 0, localised_family);
1348 family_name = ft_face->family_name;
1352 My_FT_Bitmap_Size *size = NULL;
1355 if(!FT_IS_SCALABLE(ft_face))
1356 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1358 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1359 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1360 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1362 localised_family = NULL;
1364 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1365 if(localised_family && !strcmpiW(localised_family, english_family)) {
1366 HeapFree(GetProcessHeap(), 0, localised_family);
1367 localised_family = NULL;
1372 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1373 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1374 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1379 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1380 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1381 list_init(&family->faces);
1382 list_add_tail(&font_list, &family->entry);
1384 if(localised_family) {
1385 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1386 subst->from.name = strdupW(english_family);
1387 subst->from.charset = -1;
1388 subst->to.name = strdupW(localised_family);
1389 subst->to.charset = -1;
1390 add_font_subst(&font_subst_list, subst, 0);
1393 HeapFree(GetProcessHeap(), 0, localised_family);
1394 HeapFree(GetProcessHeap(), 0, english_family);
1396 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1397 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1398 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1400 internal_leading = 0;
1401 memset(&fs, 0, sizeof(fs));
1403 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1405 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1406 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1407 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1408 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1409 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1410 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1411 if(pOS2->version == 0) {
1414 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1415 fs.fsCsb[0] |= FS_LATIN1;
1417 fs.fsCsb[0] |= FS_SYMBOL;
1420 #ifdef HAVE_FREETYPE_FTWINFNT_H
1421 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1423 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1424 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1425 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1427 internal_leading = winfnt_header.internal_leading;
1431 face_elem_ptr = list_head(&family->faces);
1432 while(face_elem_ptr) {
1433 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1434 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1435 if(!strcmpiW(face->StyleName, StyleW) &&
1436 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1437 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1438 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1439 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1442 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1443 HeapFree(GetProcessHeap(), 0, StyleW);
1444 pFT_Done_Face(ft_face);
1447 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1448 TRACE("Original font is newer so skipping this one\n");
1449 HeapFree(GetProcessHeap(), 0, StyleW);
1450 pFT_Done_Face(ft_face);
1453 TRACE("Replacing original with this one\n");
1454 list_remove(&face->entry);
1455 HeapFree(GetProcessHeap(), 0, face->file);
1456 HeapFree(GetProcessHeap(), 0, face->StyleName);
1457 HeapFree(GetProcessHeap(), 0, face->FullName);
1458 HeapFree(GetProcessHeap(), 0, face);
1463 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1464 face->cached_enum_data = NULL;
1465 face->StyleName = StyleW;
1466 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1469 face->file = strdupA(file);
1470 face->font_data_ptr = NULL;
1471 face->font_data_size = 0;
1476 face->font_data_ptr = font_data_ptr;
1477 face->font_data_size = font_data_size;
1479 face->face_index = face_index;
1481 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1482 face->ntmFlags |= NTM_ITALIC;
1483 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1484 face->ntmFlags |= NTM_BOLD;
1485 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1486 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1487 face->family = family;
1488 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1490 memset(&face->fs_links, 0, sizeof(face->fs_links));
1492 if(FT_IS_SCALABLE(ft_face)) {
1493 memset(&face->size, 0, sizeof(face->size));
1494 face->scalable = TRUE;
1496 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1497 size->height, size->width, size->size >> 6,
1498 size->x_ppem >> 6, size->y_ppem >> 6);
1499 face->size.height = size->height;
1500 face->size.width = size->width;
1501 face->size.size = size->size;
1502 face->size.x_ppem = size->x_ppem;
1503 face->size.y_ppem = size->y_ppem;
1504 face->size.internal_leading = internal_leading;
1505 face->scalable = FALSE;
1508 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1510 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1512 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1513 face->ntmFlags |= NTM_PS_OPENTYPE;
1516 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1517 face->fs.fsCsb[0], face->fs.fsCsb[1],
1518 face->fs.fsUsb[0], face->fs.fsUsb[1],
1519 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1522 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1523 for(i = 0; i < ft_face->num_charmaps; i++) {
1524 switch(ft_face->charmaps[i]->encoding) {
1525 case FT_ENCODING_UNICODE:
1526 case FT_ENCODING_APPLE_ROMAN:
1527 face->fs.fsCsb[0] |= FS_LATIN1;
1529 case FT_ENCODING_MS_SYMBOL:
1530 face->fs.fsCsb[0] |= FS_SYMBOL;
1538 AddFaceToFamily(face, family);
1540 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1542 num_faces = ft_face->num_faces;
1543 pFT_Done_Face(ft_face);
1544 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1545 debugstr_w(StyleW));
1546 } while(num_faces > ++face_index);
1550 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1552 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1555 static void DumpFontList(void)
1559 struct list *family_elem_ptr, *face_elem_ptr;
1561 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1562 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1563 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1564 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1565 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1566 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1568 TRACE(" %d", face->size.height);
1575 /***********************************************************
1576 * The replacement list is a way to map an entire font
1577 * family onto another family. For example adding
1579 * [HKCU\Software\Wine\Fonts\Replacements]
1580 * "Wingdings"="Winedings"
1582 * would enumerate the Winedings font both as Winedings and
1583 * Wingdings. However if a real Wingdings font is present the
1584 * replacement does not take place.
1587 static void LoadReplaceList(void)
1590 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1595 struct list *family_elem_ptr, *face_elem_ptr;
1598 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1599 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1601 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1602 &valuelen, &datalen, NULL, NULL);
1604 valuelen++; /* returned value doesn't include room for '\0' */
1605 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1606 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1610 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1611 &dlen) == ERROR_SUCCESS) {
1612 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1613 /* "NewName"="Oldname" */
1614 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1616 if(!find_family_from_name(value))
1618 /* Find the old family and hence all of the font files
1620 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1621 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1622 if(!strcmpiW(family->FamilyName, data)) {
1623 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1624 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1625 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1626 debugstr_w(face->StyleName), familyA);
1627 /* Now add a new entry with the new family name */
1628 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1629 familyA, family->FamilyName,
1630 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1636 /* reset dlen and vlen */
1640 HeapFree(GetProcessHeap(), 0, data);
1641 HeapFree(GetProcessHeap(), 0, value);
1646 /*************************************************************
1649 static BOOL init_system_links(void)
1653 DWORD type, max_val, max_data, val_len, data_len, index;
1654 WCHAR *value, *data;
1655 WCHAR *entry, *next;
1656 SYSTEM_LINKS *font_link, *system_font_link;
1657 CHILD_FONT *child_font;
1658 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1659 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1665 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1667 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1668 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1669 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1670 val_len = max_val + 1;
1671 data_len = max_data;
1673 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1675 memset(&fs, 0, sizeof(fs));
1676 psub = get_font_subst(&font_subst_list, value, -1);
1677 /* Don't store fonts that are only substitutes for other fonts */
1680 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1683 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1684 font_link->font_name = strdupW(value);
1685 list_init(&font_link->links);
1686 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1689 CHILD_FONT *child_font;
1691 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1693 next = entry + strlenW(entry) + 1;
1695 face_name = strchrW(entry, ',');
1699 while(isspaceW(*face_name))
1702 psub = get_font_subst(&font_subst_list, face_name, -1);
1704 face_name = psub->to.name;
1706 face = find_face_from_filename(entry, face_name);
1709 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1713 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1714 child_font->face = face;
1715 child_font->font = NULL;
1716 fs.fsCsb[0] |= face->fs.fsCsb[0];
1717 fs.fsCsb[1] |= face->fs.fsCsb[1];
1718 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1719 list_add_tail(&font_link->links, &child_font->entry);
1721 family = find_family_from_name(font_link->font_name);
1724 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1726 face->fs_links = fs;
1729 list_add_tail(&system_links, &font_link->entry);
1731 val_len = max_val + 1;
1732 data_len = max_data;
1735 HeapFree(GetProcessHeap(), 0, value);
1736 HeapFree(GetProcessHeap(), 0, data);
1740 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1743 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1744 system_font_link->font_name = strdupW(System);
1745 list_init(&system_font_link->links);
1747 face = find_face_from_filename(tahoma_ttf, Tahoma);
1750 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1751 child_font->face = face;
1752 child_font->font = NULL;
1753 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1754 list_add_tail(&system_font_link->links, &child_font->entry);
1756 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1758 if(!strcmpiW(font_link->font_name, Tahoma))
1760 CHILD_FONT *font_link_entry;
1761 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1763 CHILD_FONT *new_child;
1764 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1765 new_child->face = font_link_entry->face;
1766 new_child->font = NULL;
1767 list_add_tail(&system_font_link->links, &new_child->entry);
1772 list_add_tail(&system_links, &system_font_link->entry);
1776 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1779 struct dirent *dent;
1780 char path[MAX_PATH];
1782 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1784 dir = opendir(dirname);
1786 WARN("Can't open directory %s\n", debugstr_a(dirname));
1789 while((dent = readdir(dir)) != NULL) {
1790 struct stat statbuf;
1792 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1795 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1797 sprintf(path, "%s/%s", dirname, dent->d_name);
1799 if(stat(path, &statbuf) == -1)
1801 WARN("Can't stat %s\n", debugstr_a(path));
1804 if(S_ISDIR(statbuf.st_mode))
1805 ReadFontDir(path, external_fonts);
1807 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1813 static void load_fontconfig_fonts(void)
1815 #ifdef SONAME_LIBFONTCONFIG
1816 void *fc_handle = NULL;
1825 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1827 TRACE("Wine cannot find the fontconfig library (%s).\n",
1828 SONAME_LIBFONTCONFIG);
1831 #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;}
1832 LOAD_FUNCPTR(FcConfigGetCurrent);
1833 LOAD_FUNCPTR(FcFontList);
1834 LOAD_FUNCPTR(FcFontSetDestroy);
1835 LOAD_FUNCPTR(FcInit);
1836 LOAD_FUNCPTR(FcObjectSetAdd);
1837 LOAD_FUNCPTR(FcObjectSetCreate);
1838 LOAD_FUNCPTR(FcObjectSetDestroy);
1839 LOAD_FUNCPTR(FcPatternCreate);
1840 LOAD_FUNCPTR(FcPatternDestroy);
1841 LOAD_FUNCPTR(FcPatternGetBool);
1842 LOAD_FUNCPTR(FcPatternGetString);
1845 if(!pFcInit()) return;
1847 config = pFcConfigGetCurrent();
1848 pat = pFcPatternCreate();
1849 os = pFcObjectSetCreate();
1850 pFcObjectSetAdd(os, FC_FILE);
1851 pFcObjectSetAdd(os, FC_SCALABLE);
1852 fontset = pFcFontList(config, pat, os);
1853 if(!fontset) return;
1854 for(i = 0; i < fontset->nfont; i++) {
1857 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1859 TRACE("fontconfig: %s\n", file);
1861 /* We're just interested in OT/TT fonts for now, so this hack just
1862 picks up the scalable fonts without extensions .pf[ab] to save time
1863 loading every other font */
1865 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1867 TRACE("not scalable\n");
1871 len = strlen( file );
1872 if(len < 4) continue;
1873 ext = &file[ len - 3 ];
1874 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1875 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1877 pFcFontSetDestroy(fontset);
1878 pFcObjectSetDestroy(os);
1879 pFcPatternDestroy(pat);
1885 static BOOL load_font_from_data_dir(LPCWSTR file)
1888 const char *data_dir = wine_get_data_dir();
1890 if (!data_dir) data_dir = wine_get_build_dir();
1897 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1899 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1901 strcpy(unix_name, data_dir);
1902 strcat(unix_name, "/fonts/");
1904 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1906 EnterCriticalSection( &freetype_cs );
1907 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1908 LeaveCriticalSection( &freetype_cs );
1909 HeapFree(GetProcessHeap(), 0, unix_name);
1914 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1916 static const WCHAR slashW[] = {'\\','\0'};
1918 WCHAR windowsdir[MAX_PATH];
1921 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1922 strcatW(windowsdir, fontsW);
1923 strcatW(windowsdir, slashW);
1924 strcatW(windowsdir, file);
1925 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1926 EnterCriticalSection( &freetype_cs );
1927 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1928 LeaveCriticalSection( &freetype_cs );
1929 HeapFree(GetProcessHeap(), 0, unixname);
1934 static void load_system_fonts(void)
1937 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1938 const WCHAR * const *value;
1940 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1943 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1944 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1945 strcatW(windowsdir, fontsW);
1946 for(value = SystemFontValues; *value; value++) {
1947 dlen = sizeof(data);
1948 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1952 sprintfW(pathW, fmtW, windowsdir, data);
1953 if((unixname = wine_get_unix_file_name(pathW))) {
1954 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1955 HeapFree(GetProcessHeap(), 0, unixname);
1958 load_font_from_data_dir(data);
1965 /*************************************************************
1967 * This adds registry entries for any externally loaded fonts
1968 * (fonts from fontconfig or FontDirs). It also deletes entries
1969 * of no longer existing fonts.
1972 static void update_reg_entries(void)
1974 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1979 struct list *family_elem_ptr, *face_elem_ptr;
1981 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1982 static const WCHAR spaceW[] = {' ', '\0'};
1985 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1986 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1987 ERR("Can't create Windows font reg key\n");
1991 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1992 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1993 ERR("Can't create Windows font reg key\n");
1997 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1998 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1999 ERR("Can't create external font reg key\n");
2003 /* enumerate the fonts and add external ones to the two keys */
2005 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2006 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2007 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2008 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2009 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2010 if(!face->external) continue;
2012 if (!(face->ntmFlags & NTM_REGULAR))
2013 len = len_fam + strlenW(face->StyleName) + 1;
2014 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2015 strcpyW(valueW, family->FamilyName);
2016 if(len != len_fam) {
2017 strcatW(valueW, spaceW);
2018 strcatW(valueW, face->StyleName);
2020 strcatW(valueW, TrueType);
2022 file = wine_get_dos_file_name(face->file);
2024 len = strlenW(file) + 1;
2027 if((path = strrchr(face->file, '/')) == NULL)
2031 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2033 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2036 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2037 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2038 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2040 HeapFree(GetProcessHeap(), 0, file);
2041 HeapFree(GetProcessHeap(), 0, valueW);
2045 if(external_key) RegCloseKey(external_key);
2046 if(win9x_key) RegCloseKey(win9x_key);
2047 if(winnt_key) RegCloseKey(winnt_key);
2051 static void delete_external_font_keys(void)
2053 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2054 DWORD dlen, vlen, datalen, valuelen, i, type;
2058 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2059 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2060 ERR("Can't create Windows font reg key\n");
2064 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2065 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2066 ERR("Can't create Windows font reg key\n");
2070 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2071 ERR("Can't create external font reg key\n");
2075 /* Delete all external fonts added last time */
2077 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2078 &valuelen, &datalen, NULL, NULL);
2079 valuelen++; /* returned value doesn't include room for '\0' */
2080 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2081 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2083 dlen = datalen * sizeof(WCHAR);
2086 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2087 &dlen) == ERROR_SUCCESS) {
2089 RegDeleteValueW(winnt_key, valueW);
2090 RegDeleteValueW(win9x_key, valueW);
2091 /* reset dlen and vlen */
2095 HeapFree(GetProcessHeap(), 0, data);
2096 HeapFree(GetProcessHeap(), 0, valueW);
2098 /* Delete the old external fonts key */
2099 RegCloseKey(external_key);
2100 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2103 if(win9x_key) RegCloseKey(win9x_key);
2104 if(winnt_key) RegCloseKey(winnt_key);
2107 /*************************************************************
2108 * WineEngAddFontResourceEx
2111 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2117 if (ft_handle) /* do it only if we have freetype up and running */
2122 FIXME("Ignoring flags %x\n", flags);
2124 if((unixname = wine_get_unix_file_name(file)))
2126 EnterCriticalSection( &freetype_cs );
2127 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2128 LeaveCriticalSection( &freetype_cs );
2129 HeapFree(GetProcessHeap(), 0, unixname);
2131 if (!ret && !strchrW(file, '\\')) {
2132 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2133 ret = load_font_from_winfonts_dir(file);
2135 /* Try in datadir/fonts (or builddir/fonts),
2136 * needed for Magic the Gathering Online
2138 ret = load_font_from_data_dir(file);
2145 /*************************************************************
2146 * WineEngAddFontMemResourceEx
2149 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2153 if (ft_handle) /* do it only if we have freetype up and running */
2155 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2157 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2158 memcpy(pFontCopy, pbFont, cbFont);
2160 EnterCriticalSection( &freetype_cs );
2161 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2162 LeaveCriticalSection( &freetype_cs );
2166 TRACE("AddFontToList failed\n");
2167 HeapFree(GetProcessHeap(), 0, pFontCopy);
2170 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2171 * For now return something unique but quite random
2173 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2174 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2181 /*************************************************************
2182 * WineEngRemoveFontResourceEx
2185 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2188 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2192 static const struct nls_update_font_list
2194 UINT ansi_cp, oem_cp;
2195 const char *oem, *fixed, *system;
2196 const char *courier, *serif, *small, *sserif;
2197 /* these are for font substitutes */
2198 const char *shelldlg, *tmsrmn;
2199 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2203 const char *from, *to;
2204 } arial_0, courier_new_0, times_new_roman_0;
2205 } nls_update_font_list[] =
2207 /* Latin 1 (United States) */
2208 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2209 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2210 "Tahoma","Times New Roman",
2211 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2214 /* Latin 1 (Multilingual) */
2215 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2216 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2217 "Tahoma","Times New Roman", /* FIXME unverified */
2218 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2221 /* Eastern Europe */
2222 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2223 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2224 "Tahoma","Times New Roman", /* FIXME unverified */
2225 "Fixedsys,238", "System,238",
2226 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2227 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2228 { "Arial CE,0", "Arial,238" },
2229 { "Courier New CE,0", "Courier New,238" },
2230 { "Times New Roman CE,0", "Times New Roman,238" }
2233 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2234 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2235 "Tahoma","Times New Roman", /* FIXME unverified */
2236 "Fixedsys,204", "System,204",
2237 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2238 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2239 { "Arial Cyr,0", "Arial,204" },
2240 { "Courier New Cyr,0", "Courier New,204" },
2241 { "Times New Roman Cyr,0", "Times New Roman,204" }
2244 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2245 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2246 "Tahoma","Times New Roman", /* FIXME unverified */
2247 "Fixedsys,161", "System,161",
2248 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2249 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2250 { "Arial Greek,0", "Arial,161" },
2251 { "Courier New Greek,0", "Courier New,161" },
2252 { "Times New Roman Greek,0", "Times New Roman,161" }
2255 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2256 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2257 "Tahoma","Times New Roman", /* FIXME unverified */
2258 "Fixedsys,162", "System,162",
2259 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2260 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2261 { "Arial Tur,0", "Arial,162" },
2262 { "Courier New Tur,0", "Courier New,162" },
2263 { "Times New Roman Tur,0", "Times New Roman,162" }
2266 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2267 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2268 "Tahoma","Times New Roman", /* FIXME unverified */
2269 "Fixedsys,177", "System,177",
2270 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2271 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2275 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2276 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2277 "Tahoma","Times New Roman", /* FIXME unverified */
2278 "Fixedsys,178", "System,178",
2279 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2280 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2284 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2285 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2286 "Tahoma","Times New Roman", /* FIXME unverified */
2287 "Fixedsys,186", "System,186",
2288 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2289 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2290 { "Arial Baltic,0", "Arial,186" },
2291 { "Courier New Baltic,0", "Courier New,186" },
2292 { "Times New Roman Baltic,0", "Times New Roman,186" }
2295 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2296 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2297 "Tahoma","Times New Roman", /* FIXME unverified */
2298 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2302 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2303 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2304 "Tahoma","Times New Roman", /* FIXME unverified */
2305 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2309 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2310 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2311 "MS UI Gothic","MS Serif",
2312 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2315 /* Chinese Simplified */
2316 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2317 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2318 "SimSun", "NSimSun",
2319 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2323 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2324 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2326 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2329 /* Chinese Traditional */
2330 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2331 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2332 "PMingLiU", "MingLiU",
2333 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2338 static const WCHAR *font_links_list[] =
2340 Lucida_Sans_Unicode,
2341 Microsoft_Sans_Serif,
2345 static const struct font_links_defaults_list
2347 /* Keyed off substitution for "MS Shell Dlg" */
2348 const WCHAR *shelldlg;
2349 /* Maximum of four substitutes, plus terminating NULL pointer */
2350 const WCHAR *substitutes[5];
2351 } font_links_defaults_list[] =
2353 /* Non East-Asian */
2354 { Tahoma, /* FIXME unverified ordering */
2355 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2357 /* Below lists are courtesy of
2358 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2362 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2364 /* Chinese Simplified */
2366 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2370 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2372 /* Chinese Traditional */
2374 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2378 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2380 return ( ansi_cp == 932 /* CP932 for Japanese */
2381 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2382 || ansi_cp == 949 /* CP949 for Korean */
2383 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2386 static inline HKEY create_fonts_NT_registry_key(void)
2390 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2391 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2395 static inline HKEY create_fonts_9x_registry_key(void)
2399 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2400 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2404 static inline HKEY create_config_fonts_registry_key(void)
2408 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2409 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2413 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2415 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2416 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2417 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2418 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2421 static void set_value_key(HKEY hkey, const char *name, const char *value)
2424 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2426 RegDeleteValueA(hkey, name);
2429 static void update_font_info(void)
2431 char buf[40], cpbuf[40];
2434 UINT i, ansi_cp = 0, oem_cp = 0;
2437 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2440 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2441 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2442 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2443 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2444 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2446 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2447 if (is_dbcs_ansi_cp(ansi_cp))
2448 use_default_fallback = TRUE;
2451 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2453 if (!strcmp( buf, cpbuf )) /* already set correctly */
2458 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2460 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2462 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2465 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2469 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2470 nls_update_font_list[i].oem_cp == oem_cp)
2472 hkey = create_config_fonts_registry_key();
2473 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2474 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2475 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2478 hkey = create_fonts_NT_registry_key();
2479 add_font_list(hkey, &nls_update_font_list[i]);
2482 hkey = create_fonts_9x_registry_key();
2483 add_font_list(hkey, &nls_update_font_list[i]);
2486 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2488 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2489 strlen(nls_update_font_list[i].shelldlg)+1);
2490 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2491 strlen(nls_update_font_list[i].tmsrmn)+1);
2493 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2494 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2495 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2496 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2497 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2498 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2499 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2500 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2502 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2503 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2504 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2512 /* Delete the FontSubstitutes from other locales */
2513 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2515 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2516 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2517 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2523 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2525 /* Clear out system links */
2526 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2529 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2539 WCHAR buff[MAX_PATH];
2543 static const WCHAR comma[] = {',',0};
2545 RegDeleteValueW(hkey, name);
2550 for (i = 0; values[i] != NULL; i++)
2553 if (!strcmpiW(name,value))
2555 psub = get_font_subst(&font_subst_list, value, -1);
2557 value = psub->to.name;
2558 family = find_family_from_name(value);
2562 /* Use first extant filename for this Family */
2563 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2567 file = strrchr(face->file, '/');
2576 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2577 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2578 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2579 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2580 if (sizeof(buff)-(data-buff) < entryLen + 1)
2582 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2583 HeapFree(GetProcessHeap(), 0, fileW);
2586 strcpyW(data, fileW);
2587 strcatW(data, comma);
2588 strcatW(data, value);
2590 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2591 HeapFree(GetProcessHeap(), 0, fileW);
2597 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2599 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2601 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2604 static void update_system_links(void)
2612 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2614 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2616 if (disposition == REG_OPENED_EXISTING_KEY)
2618 TRACE("SystemLink key already exists, doing nothing\n");
2623 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2625 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2630 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2632 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2634 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2635 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2637 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2638 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2641 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2643 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2648 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2650 WARN("failed to create SystemLink key\n");
2654 static BOOL init_freetype(void)
2656 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2659 "Wine cannot find the FreeType font library. To enable Wine to\n"
2660 "use TrueType fonts please install a version of FreeType greater than\n"
2661 "or equal to 2.0.5.\n"
2662 "http://www.freetype.org\n");
2666 #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;}
2668 LOAD_FUNCPTR(FT_Vector_Unit)
2669 LOAD_FUNCPTR(FT_Done_Face)
2670 LOAD_FUNCPTR(FT_Get_Char_Index)
2671 LOAD_FUNCPTR(FT_Get_Module)
2672 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2673 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2674 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2675 LOAD_FUNCPTR(FT_Init_FreeType)
2676 LOAD_FUNCPTR(FT_Load_Glyph)
2677 LOAD_FUNCPTR(FT_Matrix_Multiply)
2678 #ifndef FT_MULFIX_INLINED
2679 LOAD_FUNCPTR(FT_MulFix)
2681 LOAD_FUNCPTR(FT_New_Face)
2682 LOAD_FUNCPTR(FT_New_Memory_Face)
2683 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2684 LOAD_FUNCPTR(FT_Outline_Transform)
2685 LOAD_FUNCPTR(FT_Outline_Translate)
2686 LOAD_FUNCPTR(FT_Select_Charmap)
2687 LOAD_FUNCPTR(FT_Set_Charmap)
2688 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2689 LOAD_FUNCPTR(FT_Vector_Transform)
2690 LOAD_FUNCPTR(FT_Render_Glyph)
2693 /* Don't warn if these ones are missing */
2694 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2695 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2696 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2697 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2698 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2699 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2700 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2702 #ifdef HAVE_FREETYPE_FTWINFNT_H
2703 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2705 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2706 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2707 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2708 <= 2.0.3 has FT_Sqrt64 */
2712 if(pFT_Init_FreeType(&library) != 0) {
2713 ERR("Can't init FreeType library\n");
2714 wine_dlclose(ft_handle, NULL, 0);
2718 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2719 if (pFT_Library_Version)
2720 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2722 if (FT_Version.major<=0)
2728 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2729 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2730 ((FT_Version.minor << 8) & 0x00ff00) |
2731 ((FT_Version.patch ) & 0x0000ff);
2737 "Wine cannot find certain functions that it needs inside the FreeType\n"
2738 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2739 "FreeType to at least version 2.0.5.\n"
2740 "http://www.freetype.org\n");
2741 wine_dlclose(ft_handle, NULL, 0);
2746 /*************************************************************
2749 * Initialize FreeType library and create a list of available faces
2751 BOOL WineEngInit(void)
2753 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2754 static const WCHAR pathW[] = {'P','a','t','h',0};
2756 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2757 WCHAR windowsdir[MAX_PATH];
2760 const char *data_dir;
2764 /* update locale dependent font info in registry */
2767 if(!init_freetype()) return FALSE;
2769 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2770 ERR("Failed to create font mutex\n");
2773 WaitForSingleObject(font_mutex, INFINITE);
2775 delete_external_font_keys();
2777 /* load the system bitmap fonts */
2778 load_system_fonts();
2780 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2781 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2782 strcatW(windowsdir, fontsW);
2783 if((unixname = wine_get_unix_file_name(windowsdir)))
2785 ReadFontDir(unixname, FALSE);
2786 HeapFree(GetProcessHeap(), 0, unixname);
2789 /* load the system truetype fonts */
2790 data_dir = wine_get_data_dir();
2791 if (!data_dir) data_dir = wine_get_build_dir();
2792 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2793 strcpy(unixname, data_dir);
2794 strcat(unixname, "/fonts/");
2795 ReadFontDir(unixname, TRUE);
2796 HeapFree(GetProcessHeap(), 0, unixname);
2799 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2800 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2801 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2803 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2804 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2805 &hkey) == ERROR_SUCCESS) {
2806 LPWSTR data, valueW;
2807 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2808 &valuelen, &datalen, NULL, NULL);
2810 valuelen++; /* returned value doesn't include room for '\0' */
2811 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2812 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2815 dlen = datalen * sizeof(WCHAR);
2817 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2818 &dlen) == ERROR_SUCCESS) {
2819 if(data[0] && (data[1] == ':'))
2821 if((unixname = wine_get_unix_file_name(data)))
2823 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2824 HeapFree(GetProcessHeap(), 0, unixname);
2827 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2829 WCHAR pathW[MAX_PATH];
2830 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2833 sprintfW(pathW, fmtW, windowsdir, data);
2834 if((unixname = wine_get_unix_file_name(pathW)))
2836 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2837 HeapFree(GetProcessHeap(), 0, unixname);
2840 load_font_from_data_dir(data);
2842 /* reset dlen and vlen */
2847 HeapFree(GetProcessHeap(), 0, data);
2848 HeapFree(GetProcessHeap(), 0, valueW);
2852 load_fontconfig_fonts();
2854 /* then look in any directories that we've specified in the config file */
2855 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2856 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2862 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2864 len += sizeof(WCHAR);
2865 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2866 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2868 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2869 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2870 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2871 TRACE( "got font path %s\n", debugstr_a(valueA) );
2875 LPSTR next = strchr( ptr, ':' );
2876 if (next) *next++ = 0;
2877 ReadFontDir( ptr, TRUE );
2880 HeapFree( GetProcessHeap(), 0, valueA );
2882 HeapFree( GetProcessHeap(), 0, valueW );
2891 update_reg_entries();
2893 update_system_links();
2894 init_system_links();
2896 ReleaseMutex(font_mutex);
2901 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2904 TT_HoriHeader *pHori;
2908 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2909 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2911 if(height == 0) height = 16;
2913 /* Calc. height of EM square:
2915 * For +ve lfHeight we have
2916 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2917 * Re-arranging gives:
2918 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2920 * For -ve lfHeight we have
2922 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2923 * with il = winAscent + winDescent - units_per_em]
2928 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2929 ppem = MulDiv(ft_face->units_per_EM, height,
2930 pHori->Ascender - pHori->Descender);
2932 ppem = MulDiv(ft_face->units_per_EM, height,
2933 pOS2->usWinAscent + pOS2->usWinDescent);
2941 static struct font_mapping *map_font_file( const char *name )
2943 struct font_mapping *mapping;
2947 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2948 if (fstat( fd, &st ) == -1) goto error;
2950 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2952 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2954 mapping->refcount++;
2959 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2962 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2965 if (mapping->data == MAP_FAILED)
2967 HeapFree( GetProcessHeap(), 0, mapping );
2970 mapping->refcount = 1;
2971 mapping->dev = st.st_dev;
2972 mapping->ino = st.st_ino;
2973 mapping->size = st.st_size;
2974 list_add_tail( &mappings_list, &mapping->entry );
2982 static void unmap_font_file( struct font_mapping *mapping )
2984 if (!--mapping->refcount)
2986 list_remove( &mapping->entry );
2987 munmap( mapping->data, mapping->size );
2988 HeapFree( GetProcessHeap(), 0, mapping );
2992 static LONG load_VDMX(GdiFont*, LONG);
2994 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3001 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3005 if (!(font->mapping = map_font_file( face->file )))
3007 WARN("failed to map %s\n", debugstr_a(face->file));
3010 data_ptr = font->mapping->data;
3011 data_size = font->mapping->size;
3015 data_ptr = face->font_data_ptr;
3016 data_size = face->font_data_size;
3019 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3021 ERR("FT_New_Face rets %d\n", err);
3025 /* set it here, as load_VDMX needs it */
3026 font->ft_face = ft_face;
3028 if(FT_IS_SCALABLE(ft_face)) {
3029 /* load the VDMX table if we have one */
3030 font->ppem = load_VDMX(font, height);
3032 font->ppem = calc_ppem_for_height(ft_face, height);
3033 TRACE("height %d => ppem %d\n", height, font->ppem);
3035 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3036 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3038 font->ppem = height;
3039 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3040 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3046 static int get_nearest_charset(Face *face, int *cp)
3048 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3049 a single face with the requested charset. The idea is to check if
3050 the selected font supports the current ANSI codepage, if it does
3051 return the corresponding charset, else return the first charset */
3054 int acp = GetACP(), i;
3058 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3059 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3060 return csi.ciCharset;
3062 for(i = 0; i < 32; i++) {
3064 if(face->fs.fsCsb[0] & fs0) {
3065 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3067 return csi.ciCharset;
3070 FIXME("TCI failing on %x\n", fs0);
3074 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3075 face->fs.fsCsb[0], face->file);
3077 return DEFAULT_CHARSET;
3080 static GdiFont *alloc_font(void)
3082 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3084 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3085 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3087 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3088 ret->total_kern_pairs = (DWORD)-1;
3089 ret->kern_pairs = NULL;
3090 list_init(&ret->hfontlist);
3091 list_init(&ret->child_fonts);
3095 static void free_font(GdiFont *font)
3097 struct list *cursor, *cursor2;
3100 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3102 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3103 list_remove(cursor);
3105 free_font(child->font);
3106 HeapFree(GetProcessHeap(), 0, child);
3109 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3111 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3112 DeleteObject(hfontlist->hfont);
3113 list_remove(&hfontlist->entry);
3114 HeapFree(GetProcessHeap(), 0, hfontlist);
3117 if (font->ft_face) pFT_Done_Face(font->ft_face);
3118 if (font->mapping) unmap_font_file( font->mapping );
3119 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3120 HeapFree(GetProcessHeap(), 0, font->potm);
3121 HeapFree(GetProcessHeap(), 0, font->name);
3122 for (i = 0; i < font->gmsize; i++)
3123 HeapFree(GetProcessHeap(),0,font->gm[i]);
3124 HeapFree(GetProcessHeap(), 0, font->gm);
3125 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3126 HeapFree(GetProcessHeap(), 0, font);
3130 /*************************************************************
3133 * load the vdmx entry for the specified height
3136 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3137 ( ( (FT_ULong)_x4 << 24 ) | \
3138 ( (FT_ULong)_x3 << 16 ) | \
3139 ( (FT_ULong)_x2 << 8 ) | \
3142 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3157 static LONG load_VDMX(GdiFont *font, LONG height)
3161 BYTE devXRatio, devYRatio;
3162 USHORT numRecs, numRatios;
3163 DWORD result, offset = -1;
3167 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3169 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3172 /* FIXME: need the real device aspect ratio */
3176 numRecs = GET_BE_WORD(hdr[1]);
3177 numRatios = GET_BE_WORD(hdr[2]);
3179 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3180 for(i = 0; i < numRatios; i++) {
3183 offset = (3 * 2) + (i * sizeof(Ratios));
3184 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3187 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3189 if((ratio.xRatio == 0 &&
3190 ratio.yStartRatio == 0 &&
3191 ratio.yEndRatio == 0) ||
3192 (devXRatio == ratio.xRatio &&
3193 devYRatio >= ratio.yStartRatio &&
3194 devYRatio <= ratio.yEndRatio))
3196 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3197 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3198 offset = GET_BE_WORD(tmp);
3204 FIXME("No suitable ratio found\n");
3208 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3210 BYTE startsz, endsz;
3213 recs = GET_BE_WORD(group.recs);
3214 startsz = group.startsz;
3215 endsz = group.endsz;
3217 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3219 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3220 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3221 if(result == GDI_ERROR) {
3222 FIXME("Failed to retrieve vTable\n");
3227 for(i = 0; i < recs; i++) {
3228 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3229 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3230 ppem = GET_BE_WORD(vTable[i * 3]);
3232 if(yMax + -yMin == height) {
3235 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3238 if(yMax + -yMin > height) {
3241 goto end; /* failed */
3243 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3244 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3245 ppem = GET_BE_WORD(vTable[i * 3]);
3246 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3252 TRACE("ppem not found for height %d\n", height);
3256 HeapFree(GetProcessHeap(), 0, vTable);
3262 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3264 if(font->font_desc.hash != fd->hash) return TRUE;
3265 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3266 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3267 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3268 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3271 static void calc_hash(FONT_DESC *pfd)
3273 DWORD hash = 0, *ptr, two_chars;
3277 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3279 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3281 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3283 pwc = (WCHAR *)&two_chars;
3285 *pwc = toupperW(*pwc);
3287 *pwc = toupperW(*pwc);
3291 hash ^= !pfd->can_use_bitmap;
3296 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3301 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3305 fd.can_use_bitmap = can_use_bitmap;
3308 /* try the child list */
3309 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3310 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3311 if(!fontcmp(ret, &fd)) {
3312 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3313 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3314 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3315 if(hflist->hfont == hfont)
3321 /* try the in-use list */
3322 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3323 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3324 if(!fontcmp(ret, &fd)) {
3325 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3326 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3327 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3328 if(hflist->hfont == hfont)
3331 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3332 hflist->hfont = hfont;
3333 list_add_head(&ret->hfontlist, &hflist->entry);
3338 /* then the unused list */
3339 font_elem_ptr = list_head(&unused_gdi_font_list);
3340 while(font_elem_ptr) {
3341 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3342 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3343 if(!fontcmp(ret, &fd)) {
3344 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3345 assert(list_empty(&ret->hfontlist));
3346 TRACE("Found %p in unused list\n", ret);
3347 list_remove(&ret->entry);
3348 list_add_head(&gdi_font_list, &ret->entry);
3349 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3350 hflist->hfont = hfont;
3351 list_add_head(&ret->hfontlist, &hflist->entry);
3358 static void add_to_cache(GdiFont *font)
3360 static DWORD cache_num = 1;
3362 font->cache_num = cache_num++;
3363 list_add_head(&gdi_font_list, &font->entry);
3366 /*************************************************************
3367 * create_child_font_list
3369 static BOOL create_child_font_list(GdiFont *font)
3372 SYSTEM_LINKS *font_link;
3373 CHILD_FONT *font_link_entry, *new_child;
3377 psub = get_font_subst(&font_subst_list, font->name, -1);
3378 font_name = psub ? psub->to.name : font->name;
3379 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3381 if(!strcmpiW(font_link->font_name, font_name))
3383 TRACE("found entry in system list\n");
3384 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3386 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3387 new_child->face = font_link_entry->face;
3388 new_child->font = NULL;
3389 list_add_tail(&font->child_fonts, &new_child->entry);
3390 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3397 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3398 * Sans Serif. This is how asian windows get default fallbacks for fonts
3400 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3401 font->charset != OEM_CHARSET &&
3402 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3403 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3405 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3407 TRACE("found entry in default fallback list\n");
3408 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3410 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3411 new_child->face = font_link_entry->face;
3412 new_child->font = NULL;
3413 list_add_tail(&font->child_fonts, &new_child->entry);
3414 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3424 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3426 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3428 if (pFT_Set_Charmap)
3431 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3433 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3435 for (i = 0; i < ft_face->num_charmaps; i++)
3437 if (ft_face->charmaps[i]->encoding == encoding)
3439 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3440 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3442 switch (ft_face->charmaps[i]->platform_id)
3445 cmap_def = ft_face->charmaps[i];
3447 case 0: /* Apple Unicode */
3448 cmap0 = ft_face->charmaps[i];
3450 case 1: /* Macintosh */
3451 cmap1 = ft_face->charmaps[i];
3454 cmap2 = ft_face->charmaps[i];
3456 case 3: /* Microsoft */
3457 cmap3 = ft_face->charmaps[i];
3462 if (cmap3) /* prefer Microsoft cmap table */
3463 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3465 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3467 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3469 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3471 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3473 return ft_err == FT_Err_Ok;
3476 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3479 /*************************************************************
3480 * WineEngCreateFontInstance
3483 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3486 Face *face, *best, *best_bitmap;
3487 Family *family, *last_resort_family;
3488 struct list *family_elem_ptr, *face_elem_ptr;
3489 INT height, width = 0;
3490 unsigned int score = 0, new_score;
3491 signed int diff = 0, newdiff;
3492 BOOL bd, it, can_use_bitmap;
3497 FontSubst *psub = NULL;
3499 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3500 lf.lfWidth = abs(lf.lfWidth);
3502 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3504 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3505 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3506 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3509 if(dc->GraphicsMode == GM_ADVANCED)
3510 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3513 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3514 font scaling abilities. */
3515 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3516 dcmat.eM21 = dcmat.eM12 = 0;
3519 /* Try to avoid not necessary glyph transformations */
3520 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3522 lf.lfHeight *= fabs(dcmat.eM11);
3523 lf.lfWidth *= fabs(dcmat.eM11);
3524 dcmat.eM11 = dcmat.eM22 = 1.0;
3527 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3528 dcmat.eM21, dcmat.eM22);
3531 EnterCriticalSection( &freetype_cs );
3533 /* check the cache first */
3534 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3535 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3536 LeaveCriticalSection( &freetype_cs );
3540 TRACE("not in cache\n");
3541 if(list_empty(&font_list)) /* No fonts installed */
3543 TRACE("No fonts installed\n");
3544 LeaveCriticalSection( &freetype_cs );
3550 ret->font_desc.matrix = dcmat;
3551 ret->font_desc.lf = lf;
3552 ret->font_desc.can_use_bitmap = can_use_bitmap;
3553 calc_hash(&ret->font_desc);
3554 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3555 hflist->hfont = hfont;
3556 list_add_head(&ret->hfontlist, &hflist->entry);
3558 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3559 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3560 original value lfCharSet. Note this is a special case for
3561 Symbol and doesn't happen at least for "Wingdings*" */
3563 if(!strcmpiW(lf.lfFaceName, SymbolW))
3564 lf.lfCharSet = SYMBOL_CHARSET;
3566 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3567 switch(lf.lfCharSet) {
3568 case DEFAULT_CHARSET:
3569 csi.fs.fsCsb[0] = 0;
3572 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3573 csi.fs.fsCsb[0] = 0;
3579 if(lf.lfFaceName[0] != '\0') {
3580 SYSTEM_LINKS *font_link;
3581 CHILD_FONT *font_link_entry;
3582 LPWSTR FaceName = lf.lfFaceName;
3585 * Check for a leading '@' this signals that the font is being
3586 * requested in tategaki mode (vertical writing substitution) but
3587 * does not affect the fontface that is to be selected.
3589 if (lf.lfFaceName[0]=='@')
3590 FaceName = &lf.lfFaceName[1];
3592 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3595 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3596 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3597 if (psub->to.charset != -1)
3598 lf.lfCharSet = psub->to.charset;
3601 /* We want a match on name and charset or just name if
3602 charset was DEFAULT_CHARSET. If the latter then
3603 we fixup the returned charset later in get_nearest_charset
3604 where we'll either use the charset of the current ansi codepage
3605 or if that's unavailable the first charset that the font supports.
3607 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3608 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3609 if (!strcmpiW(family->FamilyName, FaceName) ||
3610 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3612 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3613 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3614 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3615 if(face->scalable || can_use_bitmap)
3621 /* Search by full face name. */
3622 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3623 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3624 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3625 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3626 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3627 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3629 if(face->scalable || can_use_bitmap)
3636 * Try check the SystemLink list first for a replacement font.
3637 * We may find good replacements there.
3639 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3641 if(!strcmpiW(font_link->font_name, FaceName) ||
3642 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3644 TRACE("found entry in system list\n");
3645 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3647 face = font_link_entry->face;
3648 family = face->family;
3649 if(csi.fs.fsCsb[0] &
3650 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3652 if(face->scalable || can_use_bitmap)
3660 psub = NULL; /* substitution is no more relevant */
3662 /* If requested charset was DEFAULT_CHARSET then try using charset
3663 corresponding to the current ansi codepage */
3664 if (!csi.fs.fsCsb[0])
3667 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3668 FIXME("TCI failed on codepage %d\n", acp);
3669 csi.fs.fsCsb[0] = 0;
3671 lf.lfCharSet = csi.ciCharset;
3674 /* Face families are in the top 4 bits of lfPitchAndFamily,
3675 so mask with 0xF0 before testing */
3677 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3678 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3679 strcpyW(lf.lfFaceName, defFixed);
3680 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3681 strcpyW(lf.lfFaceName, defSerif);
3682 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3683 strcpyW(lf.lfFaceName, defSans);
3685 strcpyW(lf.lfFaceName, defSans);
3686 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3687 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3688 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3689 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3690 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3691 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3692 if(face->scalable || can_use_bitmap)
3698 last_resort_family = NULL;
3699 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3700 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3701 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3702 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3703 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3706 if(can_use_bitmap && !last_resort_family)
3707 last_resort_family = family;
3712 if(last_resort_family) {
3713 family = last_resort_family;
3714 csi.fs.fsCsb[0] = 0;
3718 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3719 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3720 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3721 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3722 if(face->scalable) {
3723 csi.fs.fsCsb[0] = 0;
3724 WARN("just using first face for now\n");
3727 if(can_use_bitmap && !last_resort_family)
3728 last_resort_family = family;
3731 if(!last_resort_family) {
3732 FIXME("can't find a single appropriate font - bailing\n");
3734 LeaveCriticalSection( &freetype_cs );
3738 WARN("could only find a bitmap font - this will probably look awful!\n");
3739 family = last_resort_family;
3740 csi.fs.fsCsb[0] = 0;
3743 it = lf.lfItalic ? 1 : 0;
3744 bd = lf.lfWeight > 550 ? 1 : 0;
3746 height = lf.lfHeight;
3748 face = best = best_bitmap = NULL;
3749 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3751 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3755 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3756 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3757 new_score = (italic ^ it) + (bold ^ bd);
3758 if(!best || new_score <= score)
3760 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3761 italic, bold, it, bd);
3764 if(best->scalable && score == 0) break;
3768 newdiff = height - (signed int)(best->size.height);
3770 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3771 if(!best_bitmap || new_score < score ||
3772 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3774 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3777 if(score == 0 && diff == 0) break;
3784 face = best->scalable ? best : best_bitmap;
3785 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3786 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3789 height = lf.lfHeight;
3793 if(csi.fs.fsCsb[0]) {
3794 ret->charset = lf.lfCharSet;
3795 ret->codepage = csi.ciACP;
3798 ret->charset = get_nearest_charset(face, &ret->codepage);
3800 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3801 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3803 ret->aveWidth = height ? lf.lfWidth : 0;
3805 if(!face->scalable) {
3806 /* Windows uses integer scaling factors for bitmap fonts */
3807 INT scale, scaled_height;
3808 GdiFont *cachedfont;
3810 /* FIXME: rotation of bitmap fonts is ignored */
3811 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3813 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3814 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3815 dcmat.eM11 = dcmat.eM22 = 1.0;
3816 /* As we changed the matrix, we need to search the cache for the font again,
3817 * otherwise we might explode the cache. */
3818 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3819 TRACE("Found cached font after non-scalable matrix rescale!\n");
3821 LeaveCriticalSection( &freetype_cs );
3824 calc_hash(&ret->font_desc);
3826 if (height != 0) height = diff;
3827 height += face->size.height;
3829 scale = (height + face->size.height - 1) / face->size.height;
3830 scaled_height = scale * face->size.height;
3831 /* Only jump to the next height if the difference <= 25% original height */
3832 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3833 /* The jump between unscaled and doubled is delayed by 1 */
3834 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3835 ret->scale_y = scale;
3837 width = face->size.x_ppem >> 6;
3838 height = face->size.y_ppem >> 6;
3842 TRACE("font scale y: %f\n", ret->scale_y);
3844 ret->ft_face = OpenFontFace(ret, face, width, height);
3849 LeaveCriticalSection( &freetype_cs );
3853 ret->ntmFlags = face->ntmFlags;
3855 if (ret->charset == SYMBOL_CHARSET &&
3856 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3859 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3863 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3866 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3867 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3868 ret->underline = lf.lfUnderline ? 0xff : 0;
3869 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3870 create_child_font_list(ret);
3872 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3874 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3875 if (length != GDI_ERROR)
3877 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3878 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3879 TRACE("Loaded GSUB table of %i bytes\n",length);
3883 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3886 LeaveCriticalSection( &freetype_cs );
3890 static void dump_gdi_font_list(void)
3893 struct list *elem_ptr;
3895 TRACE("---------- gdiFont Cache ----------\n");
3896 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3897 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3898 TRACE("gdiFont=%p %s %d\n",
3899 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3902 TRACE("---------- Unused gdiFont Cache ----------\n");
3903 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3904 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3905 TRACE("gdiFont=%p %s %d\n",
3906 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3909 TRACE("---------- Child gdiFont Cache ----------\n");
3910 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3911 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3912 TRACE("gdiFont=%p %s %d\n",
3913 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3917 /*************************************************************
3918 * WineEngDestroyFontInstance
3920 * free the gdiFont associated with this handle
3923 BOOL WineEngDestroyFontInstance(HFONT handle)
3928 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3932 EnterCriticalSection( &freetype_cs );
3934 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3936 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3937 while(hfontlist_elem_ptr) {
3938 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3939 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3940 if(hflist->hfont == handle) {
3941 TRACE("removing child font %p from child list\n", gdiFont);
3942 list_remove(&gdiFont->entry);
3943 LeaveCriticalSection( &freetype_cs );
3949 TRACE("destroying hfont=%p\n", handle);
3951 dump_gdi_font_list();
3953 font_elem_ptr = list_head(&gdi_font_list);
3954 while(font_elem_ptr) {
3955 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3956 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3958 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3959 while(hfontlist_elem_ptr) {
3960 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3961 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3962 if(hflist->hfont == handle) {
3963 list_remove(&hflist->entry);
3964 HeapFree(GetProcessHeap(), 0, hflist);
3968 if(list_empty(&gdiFont->hfontlist)) {
3969 TRACE("Moving to Unused list\n");
3970 list_remove(&gdiFont->entry);
3971 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3976 font_elem_ptr = list_head(&unused_gdi_font_list);
3977 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3978 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3979 while(font_elem_ptr) {
3980 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3981 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3982 TRACE("freeing %p\n", gdiFont);
3983 list_remove(&gdiFont->entry);
3986 LeaveCriticalSection( &freetype_cs );
3990 /***************************************************
3991 * create_enum_charset_list
3993 * This function creates charset enumeration list because in DEFAULT_CHARSET
3994 * case, the ANSI codepage's charset takes precedence over other charsets.
3995 * This function works as a filter other than DEFAULT_CHARSET case.
3997 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4002 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4003 csi.fs.fsCsb[0] != 0) {
4004 list->element[n].mask = csi.fs.fsCsb[0];
4005 list->element[n].charset = csi.ciCharset;
4006 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4009 else { /* charset is DEFAULT_CHARSET or invalid. */
4012 /* Set the current codepage's charset as the first element. */
4014 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4015 csi.fs.fsCsb[0] != 0) {
4016 list->element[n].mask = csi.fs.fsCsb[0];
4017 list->element[n].charset = csi.ciCharset;
4018 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4022 /* Fill out left elements. */
4023 for (i = 0; i < 32; i++) {
4025 fs.fsCsb[0] = 1L << i;
4027 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4028 continue; /* skip, already added. */
4029 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4030 continue; /* skip, this is an invalid fsCsb bit. */
4032 list->element[n].mask = fs.fsCsb[0];
4033 list->element[n].charset = csi.ciCharset;
4034 list->element[n].name = ElfScriptsW[i];
4043 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4044 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4049 if (face->cached_enum_data)
4052 *pelf = face->cached_enum_data->elf;
4053 *pntm = face->cached_enum_data->ntm;
4054 *ptype = face->cached_enum_data->type;
4058 font = alloc_font();
4060 if(face->scalable) {
4061 height = -2048; /* 2048 is the most common em size */
4064 height = face->size.y_ppem >> 6;
4065 width = face->size.x_ppem >> 6;
4067 font->scale_y = 1.0;
4069 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4075 font->name = strdupW(face->family->FamilyName);
4076 font->ntmFlags = face->ntmFlags;
4078 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4080 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4082 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4084 lstrcpynW(pelf->elfLogFont.lfFaceName,
4085 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4087 lstrcpynW(pelf->elfFullName,
4088 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4090 lstrcpynW(pelf->elfStyle,
4091 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4096 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4098 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4100 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4101 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4102 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4105 pntm->ntmTm.ntmFlags = face->ntmFlags;
4106 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4107 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4108 pntm->ntmFontSig = face->fs;
4110 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4112 pelf->elfLogFont.lfEscapement = 0;
4113 pelf->elfLogFont.lfOrientation = 0;
4114 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4115 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4116 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4117 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4118 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4119 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4120 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4121 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4122 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4123 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4124 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4127 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4128 *ptype |= TRUETYPE_FONTTYPE;
4129 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4130 *ptype |= DEVICE_FONTTYPE;
4131 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4132 *ptype |= RASTER_FONTTYPE;
4134 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4135 if (face->cached_enum_data)
4137 face->cached_enum_data->elf = *pelf;
4138 face->cached_enum_data->ntm = *pntm;
4139 face->cached_enum_data->type = *ptype;
4145 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4147 struct list *face_elem_ptr;
4149 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4151 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4153 static const WCHAR spaceW[] = { ' ',0 };
4154 WCHAR full_family_name[LF_FULLFACESIZE];
4155 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4157 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4159 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4160 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4164 strcpyW(full_family_name, family->FamilyName);
4165 strcatW(full_family_name, spaceW);
4166 strcatW(full_family_name, face->StyleName);
4167 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4173 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4175 static const WCHAR spaceW[] = { ' ',0 };
4176 WCHAR full_family_name[LF_FULLFACESIZE];
4178 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4180 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4182 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4183 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4187 strcpyW(full_family_name, face->family->FamilyName);
4188 strcatW(full_family_name, spaceW);
4189 strcatW(full_family_name, face->StyleName);
4190 return !strcmpiW(lf->lfFaceName, full_family_name);
4193 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4194 FONTENUMPROCW proc, LPARAM lparam)
4197 NEWTEXTMETRICEXW ntm;
4201 GetEnumStructs(face, &elf, &ntm, &type);
4202 for(i = 0; i < list->total; i++) {
4203 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4204 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4205 strcpyW(elf.elfScript, OEM_DOSW);
4206 i = 32; /* break out of loop */
4207 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4210 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4211 if(list->element[i].name)
4212 strcpyW(elf.elfScript, list->element[i].name);
4214 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4216 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4217 debugstr_w(elf.elfLogFont.lfFaceName),
4218 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4219 list->element[i].charset, type, debugstr_w(elf.elfScript),
4220 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4221 ntm.ntmTm.ntmFlags);
4222 /* release section before callback (FIXME) */
4223 LeaveCriticalSection( &freetype_cs );
4224 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4225 EnterCriticalSection( &freetype_cs );
4230 /*************************************************************
4234 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4238 struct list *family_elem_ptr, *face_elem_ptr;
4240 struct enum_charset_list enum_charsets;
4244 lf.lfCharSet = DEFAULT_CHARSET;
4245 lf.lfPitchAndFamily = 0;
4246 lf.lfFaceName[0] = 0;
4250 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4252 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4255 EnterCriticalSection( &freetype_cs );
4256 if(plf->lfFaceName[0]) {
4258 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4261 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4262 debugstr_w(psub->to.name));
4264 strcpyW(lf.lfFaceName, psub->to.name);
4268 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4269 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4270 if(family_matches(family, plf)) {
4271 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4272 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4273 if (!face_matches(face, plf)) continue;
4274 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4279 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4280 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4281 face_elem_ptr = list_head(&family->faces);
4282 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4283 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4286 LeaveCriticalSection( &freetype_cs );
4290 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4292 pt->x.value = vec->x >> 6;
4293 pt->x.fract = (vec->x & 0x3f) << 10;
4294 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4295 pt->y.value = vec->y >> 6;
4296 pt->y.fract = (vec->y & 0x3f) << 10;
4297 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4301 /***************************************************
4302 * According to the MSDN documentation on WideCharToMultiByte,
4303 * certain codepages cannot set the default_used parameter.
4304 * This returns TRUE if the codepage can set that parameter, false else
4305 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4307 static BOOL codepage_sets_default_used(UINT codepage)
4321 * GSUB Table handling functions
4324 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4326 const GSUB_CoverageFormat1* cf1;
4330 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4332 int count = GET_BE_WORD(cf1->GlyphCount);
4334 TRACE("Coverage Format 1, %i glyphs\n",count);
4335 for (i = 0; i < count; i++)
4336 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4340 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4342 const GSUB_CoverageFormat2* cf2;
4345 cf2 = (const GSUB_CoverageFormat2*)cf1;
4347 count = GET_BE_WORD(cf2->RangeCount);
4348 TRACE("Coverage Format 2, %i ranges\n",count);
4349 for (i = 0; i < count; i++)
4351 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4353 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4354 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4356 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4357 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4363 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4368 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4370 const GSUB_ScriptList *script;
4371 const GSUB_Script *deflt = NULL;
4373 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4375 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4376 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4378 const GSUB_Script *scr;
4381 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4382 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4384 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4386 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4392 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4396 const GSUB_LangSys *Lang;
4398 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4400 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4402 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4403 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4405 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4408 offset = GET_BE_WORD(script->DefaultLangSys);
4411 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4417 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4420 const GSUB_FeatureList *feature;
4421 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4423 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4424 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4426 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4427 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4429 const GSUB_Feature *feat;
4430 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4437 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4441 const GSUB_LookupList *lookup;
4442 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4444 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4445 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4447 const GSUB_LookupTable *look;
4448 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4449 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4450 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4451 if (GET_BE_WORD(look->LookupType) != 1)
4452 FIXME("We only handle SubType 1\n");
4457 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4459 const GSUB_SingleSubstFormat1 *ssf1;
4460 offset = GET_BE_WORD(look->SubTable[j]);
4461 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4462 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4464 int offset = GET_BE_WORD(ssf1->Coverage);
4465 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4466 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4468 TRACE(" Glyph 0x%x ->",glyph);
4469 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4470 TRACE(" 0x%x\n",glyph);
4475 const GSUB_SingleSubstFormat2 *ssf2;
4479 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4480 offset = GET_BE_WORD(ssf1->Coverage);
4481 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4482 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4483 TRACE(" Coverage index %i\n",index);
4486 TRACE(" Glyph is 0x%x ->",glyph);
4487 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4488 TRACE("0x%x\n",glyph);
4497 static const char* get_opentype_script(const GdiFont *font)
4500 * I am not sure if this is the correct way to generate our script tag
4503 switch (font->charset)
4505 case ANSI_CHARSET: return "latn";
4506 case BALTIC_CHARSET: return "latn"; /* ?? */
4507 case CHINESEBIG5_CHARSET: return "hani";
4508 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4509 case GB2312_CHARSET: return "hani";
4510 case GREEK_CHARSET: return "grek";
4511 case HANGUL_CHARSET: return "hang";
4512 case RUSSIAN_CHARSET: return "cyrl";
4513 case SHIFTJIS_CHARSET: return "kana";
4514 case TURKISH_CHARSET: return "latn"; /* ?? */
4515 case VIETNAMESE_CHARSET: return "latn";
4516 case JOHAB_CHARSET: return "latn"; /* ?? */
4517 case ARABIC_CHARSET: return "arab";
4518 case HEBREW_CHARSET: return "hebr";
4519 case THAI_CHARSET: return "thai";
4520 default: return "latn";
4524 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4526 const GSUB_Header *header;
4527 const GSUB_Script *script;
4528 const GSUB_LangSys *language;
4529 const GSUB_Feature *feature;
4531 if (!font->GSUB_Table)
4534 header = font->GSUB_Table;
4536 script = GSUB_get_script_table(header, get_opentype_script(font));
4539 TRACE("Script not found\n");
4542 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4545 TRACE("Language not found\n");
4548 feature = GSUB_get_feature(header, language, "vrt2");
4550 feature = GSUB_get_feature(header, language, "vert");
4553 TRACE("vrt2/vert feature not found\n");
4556 return GSUB_apply_feature(header, feature, glyph);
4559 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4563 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4564 WCHAR wc = (WCHAR)glyph;
4566 BOOL *default_used_pointer;
4569 default_used_pointer = NULL;
4570 default_used = FALSE;
4571 if (codepage_sets_default_used(font->codepage))
4572 default_used_pointer = &default_used;
4573 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4576 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4577 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4578 return get_GSUB_vert_glyph(font,ret);
4581 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4583 if (glyph < 0x100) glyph += 0xf000;
4584 /* there is a number of old pre-Unicode "broken" TTFs, which
4585 do have symbols at U+00XX instead of U+f0XX */
4586 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4587 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4589 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4591 return get_GSUB_vert_glyph(font,glyphId);
4594 /*************************************************************
4595 * WineEngGetGlyphIndices
4598 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4599 LPWORD pgi, DWORD flags)
4602 int default_char = -1;
4604 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4606 for(i = 0; i < count; i++)
4608 pgi[i] = get_glyph_index(font, lpstr[i]);
4611 if (default_char == -1)
4613 if (FT_IS_SFNT(font->ft_face))
4615 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4616 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4621 WineEngGetTextMetrics(font, &textm);
4622 default_char = textm.tmDefaultChar;
4625 pgi[i] = default_char;
4631 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4633 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4634 return !memcmp(matrix, &identity, sizeof(FMAT2));
4637 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4639 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4640 return !memcmp(matrix, &identity, sizeof(MAT2));
4643 /*************************************************************
4644 * WineEngGetGlyphOutline
4646 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4647 * except that the first parameter is the HWINEENGFONT of the font in
4648 * question rather than an HDC.
4651 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4652 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4655 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4656 FT_Face ft_face = incoming_font->ft_face;
4657 GdiFont *font = incoming_font;
4658 FT_UInt glyph_index;
4659 DWORD width, height, pitch, needed = 0;
4660 FT_Bitmap ft_bitmap;
4662 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4664 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4665 double widthRatio = 1.0;
4666 FT_Matrix transMat = identityMat;
4667 FT_Matrix transMatUnrotated;
4668 BOOL needsTransform = FALSE;
4669 BOOL tategaki = (font->GSUB_Table != NULL);
4670 UINT original_index;
4672 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4673 buflen, buf, lpmat);
4675 TRACE("font transform %f %f %f %f\n",
4676 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4677 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4680 EnterCriticalSection( &freetype_cs );
4682 if(format & GGO_GLYPH_INDEX) {
4683 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4684 original_index = glyph;
4685 format &= ~GGO_GLYPH_INDEX;
4687 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4688 ft_face = font->ft_face;
4689 original_index = glyph_index;
4692 if(format & GGO_UNHINTED) {
4693 load_flags |= FT_LOAD_NO_HINTING;
4694 format &= ~GGO_UNHINTED;
4697 /* tategaki never appears to happen to lower glyph index */
4698 if (glyph_index < TATEGAKI_LOWER_BOUND )
4701 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4702 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4703 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4704 font->gmsize * sizeof(GM*));
4706 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4707 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4709 *lpgm = FONT_GM(font,original_index)->gm;
4710 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4711 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4712 lpgm->gmCellIncX, lpgm->gmCellIncY);
4713 LeaveCriticalSection( &freetype_cs );
4714 return 1; /* FIXME */
4718 if (!font->gm[original_index / GM_BLOCK_SIZE])
4719 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4721 /* Scaling factor */
4726 WineEngGetTextMetrics(font, &tm);
4728 widthRatio = (double)font->aveWidth;
4729 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4732 widthRatio = font->scale_y;
4734 /* Scaling transform */
4735 if (widthRatio != 1.0 || font->scale_y != 1.0)
4738 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4741 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4743 pFT_Matrix_Multiply(&scaleMat, &transMat);
4744 needsTransform = TRUE;
4747 /* Slant transform */
4748 if (font->fake_italic) {
4751 slantMat.xx = (1 << 16);
4752 slantMat.xy = ((1 << 16) >> 2);
4754 slantMat.yy = (1 << 16);
4755 pFT_Matrix_Multiply(&slantMat, &transMat);
4756 needsTransform = TRUE;
4759 /* Rotation transform */
4760 transMatUnrotated = transMat;
4761 if(font->orientation && !tategaki) {
4762 FT_Matrix rotationMat;
4764 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4765 pFT_Vector_Unit(&vecAngle, angle);
4766 rotationMat.xx = vecAngle.x;
4767 rotationMat.xy = -vecAngle.y;
4768 rotationMat.yx = -rotationMat.xy;
4769 rotationMat.yy = rotationMat.xx;
4771 pFT_Matrix_Multiply(&rotationMat, &transMat);
4772 needsTransform = TRUE;
4775 /* World transform */
4776 if (!is_identity_FMAT2(&font->font_desc.matrix))
4779 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4780 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4781 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4782 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4783 pFT_Matrix_Multiply(&worldMat, &transMat);
4784 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4785 needsTransform = TRUE;
4788 /* Extra transformation specified by caller */
4789 if (!is_identity_MAT2(lpmat))
4792 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4793 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4794 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4795 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4796 pFT_Matrix_Multiply(&extraMat, &transMat);
4797 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4798 needsTransform = TRUE;
4801 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4802 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4803 format == GGO_GRAY8_BITMAP))
4805 load_flags |= FT_LOAD_NO_BITMAP;
4808 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4811 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4812 LeaveCriticalSection( &freetype_cs );
4816 if(!needsTransform) {
4817 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4818 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4819 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4821 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4822 bottom = (ft_face->glyph->metrics.horiBearingY -
4823 ft_face->glyph->metrics.height) & -64;
4824 lpgm->gmCellIncX = adv;
4825 lpgm->gmCellIncY = 0;
4832 for(xc = 0; xc < 2; xc++) {
4833 for(yc = 0; yc < 2; yc++) {
4834 vec.x = (ft_face->glyph->metrics.horiBearingX +
4835 xc * ft_face->glyph->metrics.width);
4836 vec.y = ft_face->glyph->metrics.horiBearingY -
4837 yc * ft_face->glyph->metrics.height;
4838 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4839 pFT_Vector_Transform(&vec, &transMat);
4840 if(xc == 0 && yc == 0) {
4841 left = right = vec.x;
4842 top = bottom = vec.y;
4844 if(vec.x < left) left = vec.x;
4845 else if(vec.x > right) right = vec.x;
4846 if(vec.y < bottom) bottom = vec.y;
4847 else if(vec.y > top) top = vec.y;
4852 right = (right + 63) & -64;
4853 bottom = bottom & -64;
4854 top = (top + 63) & -64;
4856 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4857 vec.x = ft_face->glyph->metrics.horiAdvance;
4859 pFT_Vector_Transform(&vec, &transMat);
4860 lpgm->gmCellIncX = (vec.x+63) >> 6;
4861 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4863 vec.x = ft_face->glyph->metrics.horiAdvance;
4865 pFT_Vector_Transform(&vec, &transMatUnrotated);
4866 adv = (vec.x+63) >> 6;
4870 bbx = (right - left) >> 6;
4871 lpgm->gmBlackBoxX = (right - left) >> 6;
4872 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4873 lpgm->gmptGlyphOrigin.x = left >> 6;
4874 lpgm->gmptGlyphOrigin.y = top >> 6;
4876 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4877 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4878 lpgm->gmCellIncX, lpgm->gmCellIncY);
4880 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4881 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4883 FONT_GM(font,original_index)->gm = *lpgm;
4884 FONT_GM(font,original_index)->adv = adv;
4885 FONT_GM(font,original_index)->lsb = lsb;
4886 FONT_GM(font,original_index)->bbx = bbx;
4887 FONT_GM(font,original_index)->init = TRUE;
4890 if(format == GGO_METRICS)
4892 LeaveCriticalSection( &freetype_cs );
4893 return 1; /* FIXME */
4896 if(ft_face->glyph->format != ft_glyph_format_outline &&
4897 (format == GGO_NATIVE || format == GGO_BEZIER ||
4898 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4899 format == GGO_GRAY8_BITMAP))
4901 TRACE("loaded a bitmap\n");
4902 LeaveCriticalSection( &freetype_cs );
4908 width = lpgm->gmBlackBoxX;
4909 height = lpgm->gmBlackBoxY;
4910 pitch = ((width + 31) >> 5) << 2;
4911 needed = pitch * height;
4913 if(!buf || !buflen) break;
4915 switch(ft_face->glyph->format) {
4916 case ft_glyph_format_bitmap:
4918 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4919 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4920 INT h = ft_face->glyph->bitmap.rows;
4922 memcpy(dst, src, w);
4923 src += ft_face->glyph->bitmap.pitch;
4929 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_mono;
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 /* Note: FreeType will only set 'black' bits for us. */
4942 memset(buf, 0, needed);
4943 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4947 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4948 LeaveCriticalSection( &freetype_cs );
4953 case GGO_GRAY2_BITMAP:
4954 case GGO_GRAY4_BITMAP:
4955 case GGO_GRAY8_BITMAP:
4956 case WINE_GGO_GRAY16_BITMAP:
4958 unsigned int mult, row, col;
4961 width = lpgm->gmBlackBoxX;
4962 height = lpgm->gmBlackBoxY;
4963 pitch = (width + 3) / 4 * 4;
4964 needed = pitch * height;
4966 if(!buf || !buflen) break;
4968 switch(ft_face->glyph->format) {
4969 case ft_glyph_format_bitmap:
4971 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4972 INT h = ft_face->glyph->bitmap.rows;
4974 memset( buf, 0, needed );
4976 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4977 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4978 src += ft_face->glyph->bitmap.pitch;
4981 LeaveCriticalSection( &freetype_cs );
4984 case ft_glyph_format_outline:
4986 ft_bitmap.width = width;
4987 ft_bitmap.rows = height;
4988 ft_bitmap.pitch = pitch;
4989 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4990 ft_bitmap.buffer = buf;
4993 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4995 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4997 memset(ft_bitmap.buffer, 0, buflen);
4999 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5001 if(format == GGO_GRAY2_BITMAP)
5003 else if(format == GGO_GRAY4_BITMAP)
5005 else if(format == GGO_GRAY8_BITMAP)
5007 else /* format == WINE_GGO_GRAY16_BITMAP */
5009 LeaveCriticalSection( &freetype_cs );
5015 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5016 LeaveCriticalSection( &freetype_cs );
5021 for(row = 0; row < height; row++) {
5023 for(col = 0; col < width; col++, ptr++) {
5024 *ptr = (((int)*ptr) * mult + 128) / 256;
5031 case WINE_GGO_HRGB_BITMAP:
5032 case WINE_GGO_HBGR_BITMAP:
5033 case WINE_GGO_VRGB_BITMAP:
5034 case WINE_GGO_VBGR_BITMAP:
5035 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5037 switch (ft_face->glyph->format)
5039 case FT_GLYPH_FORMAT_BITMAP:
5044 width = lpgm->gmBlackBoxX;
5045 height = lpgm->gmBlackBoxY;
5047 needed = pitch * height;
5049 if (!buf || !buflen) break;
5051 memset(buf, 0, buflen);
5053 src = ft_face->glyph->bitmap.buffer;
5054 src_pitch = ft_face->glyph->bitmap.pitch;
5056 height = min( height, ft_face->glyph->bitmap.rows );
5059 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5061 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5062 ((unsigned int *)dst)[x] = ~0u;
5071 case FT_GLYPH_FORMAT_OUTLINE:
5075 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5076 INT x_shift, y_shift;
5078 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5079 FT_Render_Mode render_mode =
5080 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5081 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5083 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5085 if ( render_mode == FT_RENDER_MODE_LCD)
5087 lpgm->gmBlackBoxX += 2;
5088 lpgm->gmptGlyphOrigin.x -= 1;
5092 lpgm->gmBlackBoxY += 2;
5093 lpgm->gmptGlyphOrigin.y += 1;
5097 width = lpgm->gmBlackBoxX;
5098 height = lpgm->gmBlackBoxY;
5100 needed = pitch * height;
5102 if (!buf || !buflen) break;
5104 memset(buf, 0, buflen);
5106 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5108 if ( needsTransform )
5109 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5111 if ( pFT_Library_SetLcdFilter )
5112 pFT_Library_SetLcdFilter( library, lcdfilter );
5113 pFT_Render_Glyph (ft_face->glyph, render_mode);
5115 src = ft_face->glyph->bitmap.buffer;
5116 src_pitch = ft_face->glyph->bitmap.pitch;
5117 src_width = ft_face->glyph->bitmap.width;
5118 src_height = ft_face->glyph->bitmap.rows;
5120 if ( render_mode == FT_RENDER_MODE_LCD)
5128 rgb_interval = src_pitch;
5133 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5134 if ( x_shift < 0 ) x_shift = 0;
5135 if ( x_shift + (src_width / hmul) > width )
5136 x_shift = width - (src_width / hmul);
5138 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5139 if ( y_shift < 0 ) y_shift = 0;
5140 if ( y_shift + (src_height / vmul) > height )
5141 y_shift = height - (src_height / vmul);
5143 dst += x_shift + y_shift * ( pitch / 4 );
5144 while ( src_height )
5146 for ( x = 0; x < src_width / hmul; x++ )
5150 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5151 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5152 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5153 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5157 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5158 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5159 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5160 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5163 src += src_pitch * vmul;
5172 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5173 LeaveCriticalSection ( &freetype_cs );
5180 LeaveCriticalSection( &freetype_cs );
5186 int contour, point = 0, first_pt;
5187 FT_Outline *outline = &ft_face->glyph->outline;
5188 TTPOLYGONHEADER *pph;
5190 DWORD pph_start, cpfx, type;
5192 if(buflen == 0) buf = NULL;
5194 if (needsTransform && buf) {
5195 pFT_Outline_Transform(outline, &transMat);
5198 for(contour = 0; contour < outline->n_contours; contour++) {
5200 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5203 pph->dwType = TT_POLYGON_TYPE;
5204 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5206 needed += sizeof(*pph);
5208 while(point <= outline->contours[contour]) {
5209 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5210 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5211 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5215 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5218 } while(point <= outline->contours[contour] &&
5219 (outline->tags[point] & FT_Curve_Tag_On) ==
5220 (outline->tags[point-1] & FT_Curve_Tag_On));
5221 /* At the end of a contour Windows adds the start point, but
5223 if(point > outline->contours[contour] &&
5224 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5226 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5228 } else if(point <= outline->contours[contour] &&
5229 outline->tags[point] & FT_Curve_Tag_On) {
5230 /* add closing pt for bezier */
5232 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5240 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5243 pph->cb = needed - pph_start;
5249 /* Convert the quadratic Beziers to cubic Beziers.
5250 The parametric eqn for a cubic Bezier is, from PLRM:
5251 r(t) = at^3 + bt^2 + ct + r0
5252 with the control points:
5257 A quadratic Bezier has the form:
5258 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5260 So equating powers of t leads to:
5261 r1 = 2/3 p1 + 1/3 p0
5262 r2 = 2/3 p1 + 1/3 p2
5263 and of course r0 = p0, r3 = p2
5266 int contour, point = 0, first_pt;
5267 FT_Outline *outline = &ft_face->glyph->outline;
5268 TTPOLYGONHEADER *pph;
5270 DWORD pph_start, cpfx, type;
5271 FT_Vector cubic_control[4];
5272 if(buflen == 0) buf = NULL;
5274 if (needsTransform && buf) {
5275 pFT_Outline_Transform(outline, &transMat);
5278 for(contour = 0; contour < outline->n_contours; contour++) {
5280 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5283 pph->dwType = TT_POLYGON_TYPE;
5284 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5286 needed += sizeof(*pph);
5288 while(point <= outline->contours[contour]) {
5289 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5290 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5291 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5294 if(type == TT_PRIM_LINE) {
5296 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5300 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5303 /* FIXME: Possible optimization in endpoint calculation
5304 if there are two consecutive curves */
5305 cubic_control[0] = outline->points[point-1];
5306 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5307 cubic_control[0].x += outline->points[point].x + 1;
5308 cubic_control[0].y += outline->points[point].y + 1;
5309 cubic_control[0].x >>= 1;
5310 cubic_control[0].y >>= 1;
5312 if(point+1 > outline->contours[contour])
5313 cubic_control[3] = outline->points[first_pt];
5315 cubic_control[3] = outline->points[point+1];
5316 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5317 cubic_control[3].x += outline->points[point].x + 1;
5318 cubic_control[3].y += outline->points[point].y + 1;
5319 cubic_control[3].x >>= 1;
5320 cubic_control[3].y >>= 1;
5323 /* r1 = 1/3 p0 + 2/3 p1
5324 r2 = 1/3 p2 + 2/3 p1 */
5325 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5326 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5327 cubic_control[2] = cubic_control[1];
5328 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5329 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5330 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5331 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5333 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5334 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5335 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5340 } while(point <= outline->contours[contour] &&
5341 (outline->tags[point] & FT_Curve_Tag_On) ==
5342 (outline->tags[point-1] & FT_Curve_Tag_On));
5343 /* At the end of a contour Windows adds the start point,
5344 but only for Beziers and we've already done that.
5346 if(point <= outline->contours[contour] &&
5347 outline->tags[point] & FT_Curve_Tag_On) {
5348 /* This is the closing pt of a bezier, but we've already
5349 added it, so just inc point and carry on */
5356 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5359 pph->cb = needed - pph_start;
5365 FIXME("Unsupported format %d\n", format);
5366 LeaveCriticalSection( &freetype_cs );
5369 LeaveCriticalSection( &freetype_cs );
5373 static BOOL get_bitmap_text_metrics(GdiFont *font)
5375 FT_Face ft_face = font->ft_face;
5376 #ifdef HAVE_FREETYPE_FTWINFNT_H
5377 FT_WinFNT_HeaderRec winfnt_header;
5379 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5380 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5381 font->potm->otmSize = size;
5383 #define TM font->potm->otmTextMetrics
5384 #ifdef HAVE_FREETYPE_FTWINFNT_H
5385 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5387 TM.tmHeight = winfnt_header.pixel_height;
5388 TM.tmAscent = winfnt_header.ascent;
5389 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5390 TM.tmInternalLeading = winfnt_header.internal_leading;
5391 TM.tmExternalLeading = winfnt_header.external_leading;
5392 TM.tmAveCharWidth = winfnt_header.avg_width;
5393 TM.tmMaxCharWidth = winfnt_header.max_width;
5394 TM.tmWeight = winfnt_header.weight;
5396 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5397 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5398 TM.tmFirstChar = winfnt_header.first_char;
5399 TM.tmLastChar = winfnt_header.last_char;
5400 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5401 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5402 TM.tmItalic = winfnt_header.italic;
5403 TM.tmUnderlined = font->underline;
5404 TM.tmStruckOut = font->strikeout;
5405 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5406 TM.tmCharSet = winfnt_header.charset;
5411 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5412 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5413 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5414 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5415 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5416 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5417 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5418 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5420 TM.tmDigitizedAspectX = 96; /* FIXME */
5421 TM.tmDigitizedAspectY = 96; /* FIXME */
5423 TM.tmLastChar = 255;
5424 TM.tmDefaultChar = 32;
5425 TM.tmBreakChar = 32;
5426 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5427 TM.tmUnderlined = font->underline;
5428 TM.tmStruckOut = font->strikeout;
5429 /* NB inverted meaning of TMPF_FIXED_PITCH */
5430 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5431 TM.tmCharSet = font->charset;
5439 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5441 double scale_x, scale_y;
5445 scale_x = (double)font->aveWidth;
5446 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5449 scale_x = font->scale_y;
5451 scale_x *= fabs(font->font_desc.matrix.eM11);
5452 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5454 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5455 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5457 SCALE_Y(ptm->tmHeight);
5458 SCALE_Y(ptm->tmAscent);
5459 SCALE_Y(ptm->tmDescent);
5460 SCALE_Y(ptm->tmInternalLeading);
5461 SCALE_Y(ptm->tmExternalLeading);
5462 SCALE_Y(ptm->tmOverhang);
5464 SCALE_X(ptm->tmAveCharWidth);
5465 SCALE_X(ptm->tmMaxCharWidth);
5471 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5473 double scale_x, scale_y;
5477 scale_x = (double)font->aveWidth;
5478 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5481 scale_x = font->scale_y;
5483 scale_x *= fabs(font->font_desc.matrix.eM11);
5484 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5486 scale_font_metrics(font, &potm->otmTextMetrics);
5488 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5489 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5491 SCALE_Y(potm->otmAscent);
5492 SCALE_Y(potm->otmDescent);
5493 SCALE_Y(potm->otmLineGap);
5494 SCALE_Y(potm->otmsCapEmHeight);
5495 SCALE_Y(potm->otmsXHeight);
5496 SCALE_Y(potm->otmrcFontBox.top);
5497 SCALE_Y(potm->otmrcFontBox.bottom);
5498 SCALE_X(potm->otmrcFontBox.left);
5499 SCALE_X(potm->otmrcFontBox.right);
5500 SCALE_Y(potm->otmMacAscent);
5501 SCALE_Y(potm->otmMacDescent);
5502 SCALE_Y(potm->otmMacLineGap);
5503 SCALE_X(potm->otmptSubscriptSize.x);
5504 SCALE_Y(potm->otmptSubscriptSize.y);
5505 SCALE_X(potm->otmptSubscriptOffset.x);
5506 SCALE_Y(potm->otmptSubscriptOffset.y);
5507 SCALE_X(potm->otmptSuperscriptSize.x);
5508 SCALE_Y(potm->otmptSuperscriptSize.y);
5509 SCALE_X(potm->otmptSuperscriptOffset.x);
5510 SCALE_Y(potm->otmptSuperscriptOffset.y);
5511 SCALE_Y(potm->otmsStrikeoutSize);
5512 SCALE_Y(potm->otmsStrikeoutPosition);
5513 SCALE_Y(potm->otmsUnderscoreSize);
5514 SCALE_Y(potm->otmsUnderscorePosition);
5520 /*************************************************************
5521 * WineEngGetTextMetrics
5524 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5527 EnterCriticalSection( &freetype_cs );
5529 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5530 if(!get_bitmap_text_metrics(font))
5532 LeaveCriticalSection( &freetype_cs );
5536 /* Make sure that the font has sane width/height ratio */
5539 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5541 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5547 *ptm = font->potm->otmTextMetrics;
5548 scale_font_metrics(font, ptm);
5549 LeaveCriticalSection( &freetype_cs );
5553 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5557 for(i = 0; i < ft_face->num_charmaps; i++)
5559 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5565 /*************************************************************
5566 * WineEngGetOutlineTextMetrics
5569 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5570 OUTLINETEXTMETRICW *potm)
5572 FT_Face ft_face = font->ft_face;
5573 UINT needed, lenfam, lensty, ret;
5575 TT_HoriHeader *pHori;
5576 TT_Postscript *pPost;
5577 FT_Fixed x_scale, y_scale;
5578 WCHAR *family_nameW, *style_nameW;
5579 static const WCHAR spaceW[] = {' ', '\0'};
5581 INT ascent, descent;
5583 TRACE("font=%p\n", font);
5585 if(!FT_IS_SCALABLE(ft_face))
5589 EnterCriticalSection( &freetype_cs );
5592 if(cbSize >= font->potm->otmSize)
5594 memcpy(potm, font->potm, font->potm->otmSize);
5595 scale_outline_font_metrics(font, potm);
5597 LeaveCriticalSection( &freetype_cs );
5598 return font->potm->otmSize;
5602 needed = sizeof(*potm);
5604 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5605 family_nameW = strdupW(font->name);
5607 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5609 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5610 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5611 style_nameW, lensty/sizeof(WCHAR));
5613 /* These names should be read from the TT name table */
5615 /* length of otmpFamilyName */
5618 /* length of otmpFaceName */
5619 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5620 needed += lenfam; /* just the family name */
5622 needed += lenfam + lensty; /* family + " " + style */
5625 /* length of otmpStyleName */
5628 /* length of otmpFullName */
5629 needed += lenfam + lensty;
5632 x_scale = ft_face->size->metrics.x_scale;
5633 y_scale = ft_face->size->metrics.y_scale;
5635 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5637 FIXME("Can't find OS/2 table - not TT font?\n");
5642 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5644 FIXME("Can't find HHEA table - not TT font?\n");
5649 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5651 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",
5652 pOS2->usWinAscent, pOS2->usWinDescent,
5653 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5654 ft_face->ascender, ft_face->descender, ft_face->height,
5655 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5656 ft_face->bbox.yMax, ft_face->bbox.yMin);
5658 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5659 font->potm->otmSize = needed;
5661 #define TM font->potm->otmTextMetrics
5663 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5664 ascent = pHori->Ascender;
5665 descent = -pHori->Descender;
5667 ascent = pOS2->usWinAscent;
5668 descent = pOS2->usWinDescent;
5672 TM.tmAscent = font->yMax;
5673 TM.tmDescent = -font->yMin;
5674 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5676 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5677 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5678 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5679 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5682 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5685 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5687 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5688 ((ascent + descent) -
5689 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5691 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5692 if (TM.tmAveCharWidth == 0) {
5693 TM.tmAveCharWidth = 1;
5695 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5696 TM.tmWeight = FW_REGULAR;
5697 if (font->fake_bold)
5698 TM.tmWeight = FW_BOLD;
5701 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5703 if (pOS2->usWeightClass > FW_MEDIUM)
5704 TM.tmWeight = pOS2->usWeightClass;
5706 else if (pOS2->usWeightClass <= FW_MEDIUM)
5707 TM.tmWeight = pOS2->usWeightClass;
5710 TM.tmDigitizedAspectX = 300;
5711 TM.tmDigitizedAspectY = 300;
5712 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5713 * symbol range to 0 - f0ff
5716 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5721 case 1257: /* Baltic */
5722 TM.tmLastChar = 0xf8fd;
5725 TM.tmLastChar = 0xf0ff;
5727 TM.tmBreakChar = 0x20;
5728 TM.tmDefaultChar = 0x1f;
5732 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5733 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5735 if(pOS2->usFirstCharIndex <= 1)
5736 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5737 else if (pOS2->usFirstCharIndex > 0xff)
5738 TM.tmBreakChar = 0x20;
5740 TM.tmBreakChar = pOS2->usFirstCharIndex;
5741 TM.tmDefaultChar = TM.tmBreakChar - 1;
5743 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5744 TM.tmUnderlined = font->underline;
5745 TM.tmStruckOut = font->strikeout;
5747 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5748 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5749 (pOS2->version == 0xFFFFU ||
5750 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5751 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5753 TM.tmPitchAndFamily = 0;
5755 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5757 case PAN_FAMILY_SCRIPT:
5758 TM.tmPitchAndFamily |= FF_SCRIPT;
5761 case PAN_FAMILY_DECORATIVE:
5762 TM.tmPitchAndFamily |= FF_DECORATIVE;
5767 case PAN_FAMILY_TEXT_DISPLAY:
5768 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5769 /* which is clearly not what the panose spec says. */
5771 if(TM.tmPitchAndFamily == 0 || /* fixed */
5772 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5773 TM.tmPitchAndFamily = FF_MODERN;
5776 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5781 TM.tmPitchAndFamily |= FF_DONTCARE;
5784 case PAN_SERIF_COVE:
5785 case PAN_SERIF_OBTUSE_COVE:
5786 case PAN_SERIF_SQUARE_COVE:
5787 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5788 case PAN_SERIF_SQUARE:
5789 case PAN_SERIF_THIN:
5790 case PAN_SERIF_BONE:
5791 case PAN_SERIF_EXAGGERATED:
5792 case PAN_SERIF_TRIANGLE:
5793 TM.tmPitchAndFamily |= FF_ROMAN;
5796 case PAN_SERIF_NORMAL_SANS:
5797 case PAN_SERIF_OBTUSE_SANS:
5798 case PAN_SERIF_PERP_SANS:
5799 case PAN_SERIF_FLARED:
5800 case PAN_SERIF_ROUNDED:
5801 TM.tmPitchAndFamily |= FF_SWISS;
5808 if(FT_IS_SCALABLE(ft_face))
5809 TM.tmPitchAndFamily |= TMPF_VECTOR;
5811 if(FT_IS_SFNT(ft_face))
5813 if (font->ntmFlags & NTM_PS_OPENTYPE)
5814 TM.tmPitchAndFamily |= TMPF_DEVICE;
5816 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5819 TM.tmCharSet = font->charset;
5821 font->potm->otmFiller = 0;
5822 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5823 font->potm->otmfsSelection = pOS2->fsSelection;
5824 font->potm->otmfsType = pOS2->fsType;
5825 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5826 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5827 font->potm->otmItalicAngle = 0; /* POST table */
5828 font->potm->otmEMSquare = ft_face->units_per_EM;
5829 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5830 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5831 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5832 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5833 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5834 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5835 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5836 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5837 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5838 font->potm->otmMacAscent = TM.tmAscent;
5839 font->potm->otmMacDescent = -TM.tmDescent;
5840 font->potm->otmMacLineGap = font->potm->otmLineGap;
5841 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5842 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5843 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5844 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5845 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5846 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5847 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5848 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5849 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5850 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5851 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5853 font->potm->otmsUnderscoreSize = 0;
5854 font->potm->otmsUnderscorePosition = 0;
5856 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5857 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5861 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5862 cp = (char*)font->potm + sizeof(*font->potm);
5863 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5864 strcpyW((WCHAR*)cp, family_nameW);
5866 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5867 strcpyW((WCHAR*)cp, style_nameW);
5869 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5870 strcpyW((WCHAR*)cp, family_nameW);
5871 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5872 strcatW((WCHAR*)cp, spaceW);
5873 strcatW((WCHAR*)cp, style_nameW);
5874 cp += lenfam + lensty;
5877 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5878 strcpyW((WCHAR*)cp, family_nameW);
5879 strcatW((WCHAR*)cp, spaceW);
5880 strcatW((WCHAR*)cp, style_nameW);
5883 if(potm && needed <= cbSize)
5885 memcpy(potm, font->potm, font->potm->otmSize);
5886 scale_outline_font_metrics(font, potm);
5890 HeapFree(GetProcessHeap(), 0, style_nameW);
5891 HeapFree(GetProcessHeap(), 0, family_nameW);
5893 LeaveCriticalSection( &freetype_cs );
5897 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5899 HFONTLIST *hfontlist;
5900 child->font = alloc_font();
5901 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5902 if(!child->font->ft_face)
5904 free_font(child->font);
5909 child->font->font_desc = font->font_desc;
5910 child->font->ntmFlags = child->face->ntmFlags;
5911 child->font->orientation = font->orientation;
5912 child->font->scale_y = font->scale_y;
5913 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5914 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5915 child->font->name = strdupW(child->face->family->FamilyName);
5916 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5917 child->font->base_font = font;
5918 list_add_head(&child_font_list, &child->font->entry);
5919 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5923 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5926 CHILD_FONT *child_font;
5929 font = font->base_font;
5931 *linked_font = font;
5933 if((*glyph = get_glyph_index(font, c)))
5936 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5938 if(!child_font->font)
5939 if(!load_child_font(font, child_font))
5942 if(!child_font->font->ft_face)
5944 g = get_glyph_index(child_font->font, c);
5948 *linked_font = child_font->font;
5955 /*************************************************************
5956 * WineEngGetCharWidth
5959 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5962 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5965 FT_UInt glyph_index;
5966 GdiFont *linked_font;
5968 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5971 EnterCriticalSection( &freetype_cs );
5972 for(c = firstChar; c <= lastChar; c++) {
5973 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5974 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5975 &gm, 0, NULL, &identity);
5976 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5978 LeaveCriticalSection( &freetype_cs );
5982 /*************************************************************
5983 * WineEngGetCharABCWidths
5986 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5989 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5992 FT_UInt glyph_index;
5993 GdiFont *linked_font;
5995 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5997 if(!FT_IS_SCALABLE(font->ft_face))
6001 EnterCriticalSection( &freetype_cs );
6003 for(c = firstChar; c <= lastChar; c++) {
6004 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6005 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6006 &gm, 0, NULL, &identity);
6007 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6008 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6009 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6010 FONT_GM(linked_font,glyph_index)->bbx;
6012 LeaveCriticalSection( &freetype_cs );
6016 /*************************************************************
6017 * WineEngGetCharABCWidthsFloat
6020 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6022 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6025 FT_UInt glyph_index;
6026 GdiFont *linked_font;
6028 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6031 EnterCriticalSection( &freetype_cs );
6033 for (c = first; c <= last; c++)
6035 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6036 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6037 &gm, 0, NULL, &identity);
6038 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6039 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6040 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6041 FONT_GM(linked_font, glyph_index)->lsb -
6042 FONT_GM(linked_font, glyph_index)->bbx;
6044 LeaveCriticalSection( &freetype_cs );
6048 /*************************************************************
6049 * WineEngGetCharABCWidthsI
6052 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6055 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6058 FT_UInt glyph_index;
6059 GdiFont *linked_font;
6061 if(!FT_HAS_HORIZONTAL(font->ft_face))
6065 EnterCriticalSection( &freetype_cs );
6067 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6069 for(c = firstChar; c < firstChar+count; c++) {
6070 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6071 &gm, 0, NULL, &identity);
6072 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6073 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6074 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6075 - FONT_GM(linked_font,c)->bbx;
6078 for(c = 0; c < count; c++) {
6079 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6080 &gm, 0, NULL, &identity);
6081 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6082 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6083 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6084 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6087 LeaveCriticalSection( &freetype_cs );
6091 /*************************************************************
6092 * WineEngGetTextExtentExPoint
6095 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6096 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6098 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6103 FT_UInt glyph_index;
6104 GdiFont *linked_font;
6106 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6110 EnterCriticalSection( &freetype_cs );
6113 WineEngGetTextMetrics(font, &tm);
6114 size->cy = tm.tmHeight;
6116 for(idx = 0; idx < count; idx++) {
6117 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6118 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6119 &gm, 0, NULL, &identity);
6120 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6122 if (! pnfit || ext <= max_ext) {
6132 LeaveCriticalSection( &freetype_cs );
6133 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6137 /*************************************************************
6138 * WineEngGetTextExtentExPointI
6141 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6142 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6144 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6150 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6153 EnterCriticalSection( &freetype_cs );
6156 WineEngGetTextMetrics(font, &tm);
6157 size->cy = tm.tmHeight;
6159 for(idx = 0; idx < count; idx++) {
6160 WineEngGetGlyphOutline(font, indices[idx],
6161 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6163 size->cx += FONT_GM(font,indices[idx])->adv;
6165 if (! pnfit || ext <= max_ext) {
6175 LeaveCriticalSection( &freetype_cs );
6176 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6180 /*************************************************************
6181 * WineEngGetFontData
6184 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6187 FT_Face ft_face = font->ft_face;
6191 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6192 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6193 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6195 if(!FT_IS_SFNT(ft_face))
6203 if(table) { /* MS tags differ in endianness from FT ones */
6204 table = table >> 24 | table << 24 |
6205 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6208 /* make sure value of len is the value freetype says it needs */
6211 FT_ULong needed = 0;
6212 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6213 if( !err && needed < len) len = needed;
6215 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6218 TRACE("Can't find table %c%c%c%c\n",
6219 /* bytes were reversed */
6220 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6221 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6227 /*************************************************************
6228 * WineEngGetTextFace
6231 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6233 INT n = strlenW(font->name) + 1;
6235 lstrcpynW(str, font->name, count);
6236 return min(count, n);
6241 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6243 if (fs) *fs = font->fs;
6244 return font->charset;
6247 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6249 GdiFont *font = dc->gdiFont, *linked_font;
6250 struct list *first_hfont;
6254 EnterCriticalSection( &freetype_cs );
6255 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6256 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6257 if(font == linked_font)
6258 *new_hfont = dc->hFont;
6261 first_hfont = list_head(&linked_font->hfontlist);
6262 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6264 LeaveCriticalSection( &freetype_cs );
6268 /* Retrieve a list of supported Unicode ranges for a given font.
6269 * Can be called with NULL gs to calculate the buffer size. Returns
6270 * the number of ranges found.
6272 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6274 DWORD num_ranges = 0;
6276 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6279 FT_ULong char_code, char_code_prev;
6282 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6284 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6285 face->num_glyphs, glyph_code, char_code);
6287 if (!glyph_code) return 0;
6291 gs->ranges[0].wcLow = (USHORT)char_code;
6292 gs->ranges[0].cGlyphs = 0;
6293 gs->cGlyphsSupported = 0;
6299 if (char_code < char_code_prev)
6301 ERR("expected increasing char code from FT_Get_Next_Char\n");
6304 if (char_code - char_code_prev > 1)
6309 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6310 gs->ranges[num_ranges - 1].cGlyphs = 1;
6311 gs->cGlyphsSupported++;
6316 gs->ranges[num_ranges - 1].cGlyphs++;
6317 gs->cGlyphsSupported++;
6319 char_code_prev = char_code;
6320 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6324 FIXME("encoding %u not supported\n", face->charmap->encoding);
6329 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6332 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6334 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6337 glyphset->cbThis = size;
6338 glyphset->cRanges = num_ranges;
6339 glyphset->flAccel = 0;
6344 /*************************************************************
6347 BOOL WineEngFontIsLinked(GdiFont *font)
6351 EnterCriticalSection( &freetype_cs );
6352 ret = !list_empty(&font->child_fonts);
6353 LeaveCriticalSection( &freetype_cs );
6357 static BOOL is_hinting_enabled(void)
6359 /* Use the >= 2.2.0 function if available */
6360 if(pFT_Get_TrueType_Engine_Type)
6362 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6363 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6365 #ifdef FT_DRIVER_HAS_HINTER
6370 /* otherwise if we've been compiled with < 2.2.0 headers
6371 use the internal macro */
6372 mod = pFT_Get_Module(library, "truetype");
6373 if(mod && FT_DRIVER_HAS_HINTER(mod))
6381 static BOOL is_subpixel_rendering_enabled( void )
6383 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6384 return pFT_Library_SetLcdFilter &&
6385 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6391 /*************************************************************************
6392 * GetRasterizerCaps (GDI32.@)
6394 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6396 static int hinting = -1;
6397 static int subpixel = -1;
6401 hinting = is_hinting_enabled();
6402 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6405 if ( subpixel == -1 )
6407 subpixel = is_subpixel_rendering_enabled();
6408 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6411 lprs->nSize = sizeof(RASTERIZER_STATUS);
6412 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6414 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6415 lprs->nLanguageID = 0;
6419 /*************************************************************
6420 * WineEngRealizationInfo
6422 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6424 FIXME("(%p, %p): stub!\n", font, info);
6427 if(FT_IS_SCALABLE(font->ft_face))
6430 info->cache_num = font->cache_num;
6431 info->unknown2 = -1;
6435 /*************************************************************************
6436 * Kerning support for TrueType fonts
6438 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6440 struct TT_kern_table
6446 struct TT_kern_subtable
6455 USHORT horizontal : 1;
6457 USHORT cross_stream: 1;
6458 USHORT override : 1;
6459 USHORT reserved1 : 4;
6465 struct TT_format0_kern_subtable
6469 USHORT entrySelector;
6480 static DWORD parse_format0_kern_subtable(GdiFont *font,
6481 const struct TT_format0_kern_subtable *tt_f0_ks,
6482 const USHORT *glyph_to_char,
6483 KERNINGPAIR *kern_pair, DWORD cPairs)
6486 const struct TT_kern_pair *tt_kern_pair;
6488 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6490 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6492 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6493 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6494 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6496 if (!kern_pair || !cPairs)
6499 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6501 nPairs = min(nPairs, cPairs);
6503 for (i = 0; i < nPairs; i++)
6505 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6506 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6507 /* this algorithm appears to better match what Windows does */
6508 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6509 if (kern_pair->iKernAmount < 0)
6511 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6512 kern_pair->iKernAmount -= font->ppem;
6514 else if (kern_pair->iKernAmount > 0)
6516 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6517 kern_pair->iKernAmount += font->ppem;
6519 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6521 TRACE("left %u right %u value %d\n",
6522 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6526 TRACE("copied %u entries\n", nPairs);
6530 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6534 const struct TT_kern_table *tt_kern_table;
6535 const struct TT_kern_subtable *tt_kern_subtable;
6537 USHORT *glyph_to_char;
6540 EnterCriticalSection( &freetype_cs );
6541 if (font->total_kern_pairs != (DWORD)-1)
6543 if (cPairs && kern_pair)
6545 cPairs = min(cPairs, font->total_kern_pairs);
6546 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6547 LeaveCriticalSection( &freetype_cs );
6550 LeaveCriticalSection( &freetype_cs );
6551 return font->total_kern_pairs;
6554 font->total_kern_pairs = 0;
6556 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6558 if (length == GDI_ERROR)
6560 TRACE("no kerning data in the font\n");
6561 LeaveCriticalSection( &freetype_cs );
6565 buf = HeapAlloc(GetProcessHeap(), 0, length);
6568 WARN("Out of memory\n");
6569 LeaveCriticalSection( &freetype_cs );
6573 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6575 /* build a glyph index to char code map */
6576 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6579 WARN("Out of memory allocating a glyph index to char code map\n");
6580 HeapFree(GetProcessHeap(), 0, buf);
6581 LeaveCriticalSection( &freetype_cs );
6585 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6591 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6593 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6594 font->ft_face->num_glyphs, glyph_code, char_code);
6598 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6600 /* FIXME: This doesn't match what Windows does: it does some fancy
6601 * things with duplicate glyph index to char code mappings, while
6602 * we just avoid overriding existing entries.
6604 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6605 glyph_to_char[glyph_code] = (USHORT)char_code;
6607 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6614 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6615 for (n = 0; n <= 65535; n++)
6616 glyph_to_char[n] = (USHORT)n;
6619 tt_kern_table = buf;
6620 nTables = GET_BE_WORD(tt_kern_table->nTables);
6621 TRACE("version %u, nTables %u\n",
6622 GET_BE_WORD(tt_kern_table->version), nTables);
6624 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6626 for (i = 0; i < nTables; i++)
6628 struct TT_kern_subtable tt_kern_subtable_copy;
6630 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6631 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6632 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6634 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6635 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6636 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6638 /* According to the TrueType specification this is the only format
6639 * that will be properly interpreted by Windows and OS/2
6641 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6643 DWORD new_chunk, old_total = font->total_kern_pairs;
6645 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6646 glyph_to_char, NULL, 0);
6647 font->total_kern_pairs += new_chunk;
6649 if (!font->kern_pairs)
6650 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6651 font->total_kern_pairs * sizeof(*font->kern_pairs));
6653 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6654 font->total_kern_pairs * sizeof(*font->kern_pairs));
6656 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6657 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6660 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6662 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6665 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6666 HeapFree(GetProcessHeap(), 0, buf);
6668 if (cPairs && kern_pair)
6670 cPairs = min(cPairs, font->total_kern_pairs);
6671 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6672 LeaveCriticalSection( &freetype_cs );
6675 LeaveCriticalSection( &freetype_cs );
6676 return font->total_kern_pairs;
6679 #else /* HAVE_FREETYPE */
6681 /*************************************************************************/
6683 BOOL WineEngInit(void)
6687 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6691 BOOL WineEngDestroyFontInstance(HFONT hfont)
6696 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6701 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6702 LPWORD pgi, DWORD flags)
6707 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6708 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6711 ERR("called but we don't have FreeType\n");
6715 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6717 ERR("called but we don't have FreeType\n");
6721 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6722 OUTLINETEXTMETRICW *potm)
6724 ERR("called but we don't have FreeType\n");
6728 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6731 ERR("called but we don't have FreeType\n");
6735 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6738 ERR("called but we don't have FreeType\n");
6742 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6744 ERR("called but we don't have FreeType\n");
6748 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6751 ERR("called but we don't have FreeType\n");
6755 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6756 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6758 ERR("called but we don't have FreeType\n");
6762 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6763 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6765 ERR("called but we don't have FreeType\n");
6769 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6772 ERR("called but we don't have FreeType\n");
6776 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6778 ERR("called but we don't have FreeType\n");
6782 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6784 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6788 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6790 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6794 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6796 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6800 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6802 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6803 return DEFAULT_CHARSET;
6806 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6811 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6813 FIXME("(%p, %p): stub\n", font, glyphset);
6817 BOOL WineEngFontIsLinked(GdiFont *font)
6822 /*************************************************************************
6823 * GetRasterizerCaps (GDI32.@)
6825 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6827 lprs->nSize = sizeof(RASTERIZER_STATUS);
6829 lprs->nLanguageID = 0;
6833 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6835 ERR("called but we don't have FreeType\n");
6839 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6841 ERR("called but we don't have FreeType\n");
6845 #endif /* HAVE_FREETYPE */